00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "AbstractBidomainSolver.hpp"
00032 #include "TetrahedralMesh.hpp"
00033
00034 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00035 void AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::InitialiseForSolve(Vec initialSolution)
00036 {
00037 if (this->mpLinearSystem != NULL)
00038 {
00039 return;
00040 }
00041
00042
00043 AbstractDynamicLinearPdeSolver<ELEMENT_DIM,SPACE_DIM,2>::InitialiseForSolve(initialSolution);
00044
00045 if (HeartConfig::Instance()->GetUseAbsoluteTolerance())
00046 {
00047 #ifdef TRACE_KSP
00048 if (PetscTools::AmMaster())
00049 {
00050 std::cout << "Using absolute tolerance: " << mpConfig->GetAbsoluteTolerance() <<"\n";
00051 }
00052 #endif
00053 this->mpLinearSystem->SetAbsoluteTolerance(mpConfig->GetAbsoluteTolerance());
00054 }
00055 else
00056 {
00057 #ifdef TRACE_KSP
00058 if (PetscTools::AmMaster())
00059 {
00060 std::cout << "Using relative tolerance: " << mpConfig->GetRelativeTolerance() <<"\n";
00061 }
00062 #endif
00063 this->mpLinearSystem->SetRelativeTolerance(mpConfig->GetRelativeTolerance());
00064 }
00065
00066 this->mpLinearSystem->SetKspType(HeartConfig::Instance()->GetKSPSolver());
00067
00069 if(std::string("twolevelsblockdiagonal") == std::string(HeartConfig::Instance()->GetKSPPreconditioner()))
00070 {
00072 TetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* p_mesh = dynamic_cast<TetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(this->mpMesh);
00073 if (p_mesh && PetscTools::IsSequential())
00074 {
00075 boost::shared_ptr<std::vector<PetscInt> > p_bath_nodes(new std::vector<PetscInt>());
00076
00077 for(unsigned node_index=0; node_index<this->mpMesh->GetNumNodes(); node_index++)
00078 {
00079 if (this->mpMesh->GetNode(node_index)->GetRegion() == HeartRegionCode::BATH)
00080 {
00081 p_bath_nodes->push_back(node_index);
00082 }
00083 }
00084
00085 this->mpLinearSystem->SetPcType(HeartConfig::Instance()->GetKSPPreconditioner(), p_bath_nodes);
00086 }
00087 else
00088 {
00089 TERMINATE("Two levels block diagonal only works with TetrahedralMesh and p=1");
00090 }
00091 }
00092 else
00093 {
00094 this->mpLinearSystem->SetPcType(HeartConfig::Instance()->GetKSPPreconditioner());
00095 }
00096
00097 if (mRowForAverageOfPhiZeroed==INT_MAX)
00098 {
00099
00100 this->mpLinearSystem->SetMatrixIsSymmetric(true);
00101 }
00102 else
00103 {
00104
00105 this->mpLinearSystem->SetMatrixIsSymmetric(false);
00106 }
00107 }
00108
00109
00110
00111 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00112 void AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::PrepareForSetupLinearSystem(Vec existingSolution)
00113 {
00114 double time = PdeSimulationTime::GetTime();
00115 mpBidomainTissue->SolveCellSystems(existingSolution, time, time+this->mDt);
00116 }
00117
00118 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00119 Vec AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::GenerateNullBasis() const
00120 {
00121 double sqrt_num_nodes = sqrt((double) this->mpMesh->GetNumNodes());
00122
00123 Vec null_basis;
00124 DistributedVectorFactory* p_factory = this->mpMesh->GetDistributedVectorFactory();
00125 null_basis = p_factory->CreateVec(2);
00126
00127 DistributedVector dist_null_basis = p_factory->CreateDistributedVector(null_basis);
00128 DistributedVector::Stripe null_basis_stripe_0(dist_null_basis,0);
00129 DistributedVector::Stripe null_basis_stripe_1(dist_null_basis,1);
00130 for (DistributedVector::Iterator index = dist_null_basis.Begin();
00131 index != dist_null_basis.End();
00132 ++index)
00133 {
00134 null_basis_stripe_0[index] = 0.0;
00135 null_basis_stripe_1[index] = 1.0/sqrt_num_nodes;
00136 }
00137 dist_null_basis.Restore();
00138
00139 return null_basis;
00140 }
00141
00142
00143 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00144 void AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::FinaliseLinearSystem(Vec existingSolution)
00145 {
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 if (!(GetBoundaryConditions()->HasDirichletBoundaryConditions()))
00156 {
00157
00158 CheckCompatibilityCondition();
00159
00160
00161 if (mRowForAverageOfPhiZeroed==INT_MAX)
00162 {
00163
00164 if (!mNullSpaceCreated)
00165 {
00166
00167 Vec null_basis[] = {GenerateNullBasis()};
00168
00169 this->mpLinearSystem->SetNullBasis(null_basis, 1);
00170
00171 VecDestroy(null_basis[0]);
00172 mNullSpaceCreated = true;
00173 }
00174 }
00175 else
00176 {
00177
00178
00179
00180 this->mpLinearSystem->SetKspType("gmres");
00181 mpConfig->SetKSPSolver("gmres");
00182
00183
00184 unsigned matrix_size = this->mpLinearSystem->GetSize();
00185 if (!this->mMatrixIsAssembled)
00186 {
00187
00188
00189 std::vector<unsigned> row_for_average;
00190 row_for_average.push_back(mRowForAverageOfPhiZeroed);
00191 this->mpLinearSystem->ZeroMatrixRowsWithValueOnDiagonal(row_for_average, 0.0);
00192 for (unsigned col_index=0; col_index<matrix_size; col_index++)
00193 {
00194 if (col_index%2 == 1)
00195 {
00196 this->mpLinearSystem->SetMatrixElement(mRowForAverageOfPhiZeroed, col_index, 1);
00197 }
00198
00199 }
00200 this->mpLinearSystem->AssembleFinalLhsMatrix();
00201
00202 }
00203
00204 this->mpLinearSystem->SetRhsVectorElement(mRowForAverageOfPhiZeroed, 0);
00205
00206 this->mpLinearSystem->AssembleRhsVector();
00207 }
00208 }
00209 }
00210
00211 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00212 void AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::CheckCompatibilityCondition()
00213 {
00214 if (GetBoundaryConditions()->HasDirichletBoundaryConditions() )
00215 {
00216
00217 return;
00218 }
00219
00220 #ifndef NDEBUG
00222 ReplicatableVector rep(this->mpLinearSystem->rGetRhsVector());
00223 double sum = 0;
00224 for(unsigned i=1; i<rep.GetSize(); i+=2)
00225 {
00226 sum += rep[i];
00227 }
00228
00229 if(fabs(sum)>1e-6)
00230 {
00231 #define COVERAGE_IGNORE
00232
00233
00234 EXCEPTION("Linear system does not satisfy compatibility constraint!");
00235 #undef COVERAGE_IGNORE
00236 }
00237 #endif
00238 }
00239
00240
00241 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00242 AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::AbstractBidomainSolver(
00243 bool bathSimulation,
00244 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00245 BidomainTissue<SPACE_DIM>* pTissue,
00246 BoundaryConditionsContainer<ELEMENT_DIM,SPACE_DIM,2>* pBoundaryConditions,
00247 unsigned numQuadPoints)
00248 : AbstractDynamicLinearPdeSolver<ELEMENT_DIM,SPACE_DIM,2>(pMesh),
00249 mBathSimulation(bathSimulation),
00250 mpBidomainTissue(pTissue),
00251 mpBoundaryConditions(pBoundaryConditions),
00252 mNumQuadPoints(numQuadPoints)
00253 {
00254 assert(pTissue != NULL);
00255 assert(pBoundaryConditions != NULL);
00256
00257 mNullSpaceCreated = false;
00258
00259
00260 this->mMatrixIsConstant = true;
00261
00262 mRowForAverageOfPhiZeroed = INT_MAX;
00263 mpConfig = HeartConfig::Instance();
00264
00265 mpBidomainAssembler = NULL;
00266 }
00267
00268 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00269 AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::~AbstractBidomainSolver()
00270 {
00271 if(mpBidomainAssembler)
00272 {
00273 delete mpBidomainAssembler;
00274 }
00275 }
00276
00277 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00278 void AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::SetFixedExtracellularPotentialNodes(
00279 std::vector<unsigned> fixedExtracellularPotentialNodes)
00280 {
00281 for (unsigned i=0; i<fixedExtracellularPotentialNodes.size(); i++)
00282 {
00283 if (fixedExtracellularPotentialNodes[i] >= this->mpMesh->GetNumNodes() )
00284 {
00285 EXCEPTION("Fixed node number must be less than total number nodes");
00286 }
00287 }
00288
00289 mFixedExtracellularPotentialNodes = fixedExtracellularPotentialNodes;
00290
00291
00292 GetBoundaryConditions()->ResetDirichletCommunication();
00293
00294 for (unsigned i=0; i<mFixedExtracellularPotentialNodes.size(); i++)
00295 {
00296 if (this->mpMesh->GetDistributedVectorFactory()->IsGlobalIndexLocal(mFixedExtracellularPotentialNodes[i]))
00297 {
00298 ConstBoundaryCondition<SPACE_DIM>* p_boundary_condition
00299 = new ConstBoundaryCondition<SPACE_DIM>(0.0);
00300
00301
00302 Node<SPACE_DIM>* p_node = this->mpMesh->GetNode(mFixedExtracellularPotentialNodes[i]);
00303
00304 GetBoundaryConditions()->AddDirichletBoundaryCondition(p_node, p_boundary_condition, 1);
00305
00306 }
00307 }
00308 }
00309
00310 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00311 void AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::SetRowForAverageOfPhiZeroed(unsigned row)
00312 {
00313
00314 if (row%2 == 0)
00315 {
00316 EXCEPTION("Row for applying the constraint 'Average of phi_e = zero' should be odd in C++ like indexing");
00317 }
00318
00319 mRowForAverageOfPhiZeroed = row;
00320 }
00321
00322
00323 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00324 void AbstractBidomainSolver<ELEMENT_DIM,SPACE_DIM>::FinaliseForBath(bool computeMatrix, bool computeVector)
00325 {
00326 assert(mBathSimulation);
00327
00329
00330
00331
00332
00333 unsigned* is_node_bath = new unsigned[this->mpMesh->GetNumNodes()];
00334 for(unsigned i = 0; i < this->mpMesh->GetNumNodes(); ++i)
00335 {
00336 is_node_bath[i] = 0;
00337 }
00338
00339 for (typename AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator iter=this->mpMesh->GetNodeIteratorBegin();
00340 iter != this->mpMesh->GetNodeIteratorEnd();
00341 ++iter)
00342 {
00348 if ((*iter).GetRegion() == HeartRegionCode::BATH)
00349 {
00350 is_node_bath[(*iter).GetIndex()] = 1;
00351 }
00352 }
00353
00354 unsigned* is_node_bath_reduced = new unsigned[this->mpMesh->GetNumNodes()];
00355 MPI_Allreduce(is_node_bath, is_node_bath_reduced, this->mpMesh->GetNumNodes(), MPI_UNSIGNED, MPI_SUM, PETSC_COMM_WORLD);
00356
00357 for(unsigned i=0; i<this->mpMesh->GetNumNodes(); i++)
00358 {
00359 if(is_node_bath_reduced[i] > 0)
00360 {
00361 PetscInt index[1];
00362 index[0] = 2*i;
00363
00364 if(computeMatrix)
00365 {
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 #ifndef NDEBUG
00382 int num_equation = 2*i;
00383
00384
00385 MatAssemblyBegin(this->mpLinearSystem->rGetLhsMatrix(), MAT_FINAL_ASSEMBLY);
00386 MatAssemblyEnd(this->mpLinearSystem->rGetLhsMatrix(), MAT_FINAL_ASSEMBLY);
00387
00388 PetscInt local_lo, local_hi;
00389 this->mpLinearSystem->GetOwnershipRange(local_lo, local_hi);
00390
00391
00392 if ((local_lo <= (int)num_equation) && ((int)num_equation < local_hi))
00393 {
00394 for (unsigned column=0; column < this->mpLinearSystem->GetSize(); column++)
00395 {
00396 assert(this->mpLinearSystem->GetMatrixElement(num_equation, column)==0.0);
00397 }
00398 }
00399
00400
00401 for (int row=local_lo; row<local_hi; row++)
00402 {
00403 assert(this->mpLinearSystem->GetMatrixElement(row, num_equation)==0);
00404 }
00405 #endif
00406
00407 Mat& r_matrix = this->mpLinearSystem->rGetLhsMatrix();
00408 MatSetValue(r_matrix,index[0],index[0],1.0,INSERT_VALUES);
00409 }
00410
00411 if(computeVector)
00412 {
00413
00414 VecSetValue(this->mpLinearSystem->rGetRhsVector(), index[0], 0.0, INSERT_VALUES);
00415 }
00416 }
00417 }
00418
00419 delete[] is_node_bath;
00420 delete[] is_node_bath_reduced;
00421 }
00422
00423
00425
00427
00428 template class AbstractBidomainSolver<1,1>;
00429 template class AbstractBidomainSolver<2,2>;
00430 template class AbstractBidomainSolver<3,3>;