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