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