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 "BidomainProblem.hpp"
00038 #include "BidomainSolver.hpp"
00039 #include "HeartConfig.hpp"
00040 #include "Exception.hpp"
00041 #include "DistributedVector.hpp"
00042 #include "ReplicatableVector.hpp"
00043
00044 template <unsigned DIM>
00045 void BidomainProblem<DIM>::AnalyseMeshForBath()
00046 {
00047
00048 if (mHasBath)
00049 {
00050
00051 for (typename AbstractTetrahedralMesh<DIM,DIM>::NodeIterator iter=this->mpMesh->GetNodeIteratorBegin();
00052 iter != this->mpMesh->GetNodeIteratorEnd();
00053 ++iter)
00054 {
00055 (*iter).SetRegion(HeartRegionCode::GetValidBathId());
00056 }
00057
00058 bool any_bath_element_found = false;
00059
00060
00061
00062 for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator it = this->mpMesh->GetElementIteratorBegin();
00063 it != this->mpMesh->GetElementIteratorEnd();
00064 ++it)
00065 {
00066 Element<DIM, DIM>& r_element = *it;
00067
00068 if (HeartRegionCode::IsRegionTissue( r_element.GetUnsignedAttribute() ))
00069 {
00070 for (unsigned j=0; j<r_element.GetNumNodes(); j++)
00071 {
00072 r_element.GetNode(j)->SetRegion(HeartRegionCode::GetValidTissueId());
00073 }
00074 }
00075 else
00076 {
00077 assert(HeartRegionCode::IsRegionBath( r_element.GetUnsignedAttribute() ));
00078 any_bath_element_found = true;
00079 }
00080 }
00081
00082 if (!PetscTools::ReplicateBool(any_bath_element_found))
00083 {
00084 EXCEPTION("No bath element found");
00085 }
00086 }
00087 else
00088 {
00089
00090
00091 std::set<unsigned> bath_identifiers = HeartConfig::Instance()->rGetBathIdentifiers();
00092 if ( !(bath_identifiers.size()==1 && bath_identifiers.find(1)==bath_identifiers.begin()) )
00093 {
00094 EXCEPTION("User has set bath identifiers, but the BidomainProblem isn't expecting a bath. Did you mean to use BidomainProblem(..., true)? Or alternatively, BidomainWithBathProblem(...)?");
00095 }
00096 }
00097 }
00098
00099
00100 template<unsigned DIM>
00101 Vec BidomainProblem<DIM>::CreateInitialCondition()
00102 {
00103 Vec init_cond = AbstractCardiacProblem<DIM,DIM,2>::CreateInitialCondition();
00104 if (mHasBath)
00105 {
00106
00107 DistributedVector ic = this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(init_cond);
00108 DistributedVector::Stripe voltage_stripe = DistributedVector::Stripe(ic,0);
00109
00110 for (DistributedVector::Iterator index = ic.Begin();
00111 index!= ic.End();
00112 ++index)
00113 {
00114 if (HeartRegionCode::IsRegionBath( this->mpMesh->GetNode( index.Global )->GetRegion() ))
00115 {
00116 voltage_stripe[index] = 0.0;
00117 }
00118 }
00119 ic.Restore();
00120 }
00121
00122 return init_cond;
00123 }
00124
00125 template<unsigned DIM>
00126 AbstractCardiacTissue<DIM> * BidomainProblem<DIM>::CreateCardiacTissue()
00127 {
00128 AnalyseMeshForBath();
00129 mpBidomainTissue = new BidomainTissue<DIM>(this->mpCellFactory, HeartConfig::Instance()->GetUseStateVariableInterpolation());
00130 return mpBidomainTissue;
00131 }
00132
00133 template<unsigned DIM>
00134 AbstractDynamicLinearPdeSolver<DIM, DIM, 2>* BidomainProblem<DIM>::CreateSolver()
00135 {
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 mpSolver = new BidomainSolver<DIM,DIM>(mHasBath,
00146 this->mpMesh,
00147 mpBidomainTissue,
00148 this->mpBoundaryConditionsContainer.get());
00149
00150 try
00151 {
00152 mpSolver->SetFixedExtracellularPotentialNodes(mFixedExtracellularPotentialNodes);
00153 mpSolver->SetRowForAverageOfPhiZeroed(mRowForAverageOfPhiZeroed);
00154 }
00155 catch (const Exception& e)
00156 {
00157 delete mpSolver;
00158 throw e;
00159 }
00160
00161 return mpSolver;
00162 }
00163
00164 template<unsigned DIM>
00165 BidomainProblem<DIM>::BidomainProblem(
00166 AbstractCardiacCellFactory<DIM>* pCellFactory, bool hasBath)
00167 : AbstractCardiacProblem<DIM,DIM, 2>(pCellFactory),
00168 mpBidomainTissue(NULL),
00169 mRowForAverageOfPhiZeroed(INT_MAX),
00170 mHasBath(hasBath)
00171 {
00172 mFixedExtracellularPotentialNodes.resize(0);
00173 }
00174
00175 template<unsigned DIM>
00176 BidomainProblem<DIM>::BidomainProblem()
00177 : AbstractCardiacProblem<DIM, DIM, 2>(),
00178 mpBidomainTissue(NULL),
00179 mRowForAverageOfPhiZeroed(INT_MAX)
00180 {
00181 mFixedExtracellularPotentialNodes.resize(0);
00182 }
00183
00184
00185
00186 template<unsigned DIM>
00187 void BidomainProblem<DIM>::SetFixedExtracellularPotentialNodes(std::vector<unsigned> nodes)
00188 {
00189 mFixedExtracellularPotentialNodes.resize(nodes.size());
00190 for (unsigned i=0; i<nodes.size(); i++)
00191 {
00192
00193
00194 mFixedExtracellularPotentialNodes[i] = nodes[i];
00195 }
00196 }
00197
00198 template<unsigned DIM>
00199 void BidomainProblem<DIM>::SetNodeForAverageOfPhiZeroed(unsigned node)
00200 {
00201 mRowForAverageOfPhiZeroed = 2*node+1;
00202 }
00203
00204 template<unsigned DIM>
00205 BidomainTissue<DIM>* BidomainProblem<DIM>::GetBidomainTissue()
00206 {
00207 assert(mpBidomainTissue!=NULL);
00208 return mpBidomainTissue;
00209 }
00210
00211 template<unsigned DIM>
00212 void BidomainProblem<DIM>::WriteInfo(double time)
00213 {
00214 if (PetscTools::AmMaster())
00215 {
00216 std::cout << "Solved to time " << time << "\n" << std::flush;
00217 }
00218
00219 double v_max, v_min, phi_max, phi_min;
00220
00221 VecStrideMax( this->mSolution, 0, PETSC_NULL, &v_max );
00222 VecStrideMin( this->mSolution, 0, PETSC_NULL, &v_min );
00223
00224 VecStrideMax( this->mSolution, 1, PETSC_NULL, &phi_max );
00225 VecStrideMin( this->mSolution, 1, PETSC_NULL, &phi_min );
00226
00227 if (PetscTools::AmMaster())
00228 {
00229 std::cout << " V; phi_e = " << "[" <<v_min << ", " << v_max << "]" << ";\t"
00230 << "[" <<phi_min << ", " << phi_max << "]" << "\n"
00231 << std::flush;
00232 }
00233 }
00234
00235 template<unsigned DIM>
00236 void BidomainProblem<DIM>::DefineWriterColumns(bool extending)
00237 {
00238 AbstractCardiacProblem<DIM,DIM,2>::DefineWriterColumns(extending);
00239 if (extending)
00240 {
00241 mExtracelluarColumnId = this->mpWriter->GetVariableByName("Phi_e");
00242 }
00243 else
00244 {
00245 mExtracelluarColumnId = this->mpWriter->DefineVariable("Phi_e","mV");
00246 }
00247 AbstractCardiacProblem<DIM,DIM,2>::DefineExtraVariablesWriterColumns(extending);
00248 }
00249
00250 template<unsigned DIM>
00251 void BidomainProblem<DIM>::WriteOneStep(double time, Vec voltageVec)
00252 {
00253 this->mpWriter->PutUnlimitedVariable(time);
00254 std::vector<int> variable_ids;
00255 variable_ids.push_back(this->mVoltageColumnId);
00256 variable_ids.push_back(mExtracelluarColumnId);
00257 this->mpWriter->PutStripedVector(variable_ids, voltageVec);
00258 AbstractCardiacProblem<DIM,DIM,2>::WriteExtraVariablesOneStep();
00259 }
00260
00261 template<unsigned DIM>
00262 void BidomainProblem<DIM>::PreSolveChecks()
00263 {
00264 AbstractCardiacProblem<DIM,DIM, 2>::PreSolveChecks();
00265 if (mFixedExtracellularPotentialNodes.empty())
00266 {
00267
00268 if (mRowForAverageOfPhiZeroed==INT_MAX)
00269 {
00270
00271
00272
00273 if (HeartConfig::Instance()->GetUseRelativeTolerance())
00274 {
00275 EXCEPTION("Bidomain external voltage is not bounded in this simulation - use KSP *absolute* tolerance");
00276 }
00277 }
00278 }
00279 }
00280
00281 template<unsigned DIM>
00282 void BidomainProblem<DIM>::SetElectrodes()
00283 {
00284 if (!mHasBath)
00285 {
00286
00287 return;
00288 }
00289
00290 assert(this->mpMesh!=NULL);
00291
00292 if (HeartConfig::Instance()->IsElectrodesPresent())
00293 {
00294 mpElectrodes = (boost::shared_ptr<Electrodes<DIM> >) new Electrodes<DIM>(*(this->mpMesh));
00295 }
00296 }
00297
00298 template<unsigned DIM>
00299 void BidomainProblem<DIM>::AtBeginningOfTimestep(double time)
00300 {
00301 if ( mpElectrodes && mpElectrodes->SwitchOn(time) )
00302 {
00303
00304 assert(this->mpBoundaryConditionsContainer);
00305
00306
00307
00308
00309 mpSolver->ResetBoundaryConditionsContainer(mpElectrodes->GetBoundaryConditionsContainer().get());
00310
00311
00312
00313 this->mpBoundaryConditionsContainer = mpElectrodes->GetBoundaryConditionsContainer();
00314
00316 this->mpDefaultBoundaryConditionsContainer = this->mpBoundaryConditionsContainer;
00317
00318
00319
00320 if ( mpSolver->GetLinearSystem() != NULL )
00321 {
00322
00323
00324 if (mpElectrodes->HasGroundedElectrode())
00325 {
00326 this->mpBoundaryConditionsContainer->ApplyDirichletToLinearProblem( *(mpSolver->GetLinearSystem()),
00327 true, false);
00328 }
00329
00330
00331 if (mpElectrodes->HasGroundedElectrode())
00332 {
00333 mpSolver->GetLinearSystem()->RemoveNullSpace();
00334 }
00335 }
00336 }
00337 }
00338
00339 template<unsigned DIM>
00340 void BidomainProblem<DIM>::OnEndOfTimestep(double time)
00341 {
00342 if ( mpElectrodes && mpElectrodes->SwitchOff(time) )
00343 {
00344
00345
00346 assert(this->mpBoundaryConditionsContainer);
00347
00348
00349
00350
00351 this->mpDefaultBoundaryConditionsContainer.reset(new BoundaryConditionsContainer<DIM,DIM,2>);
00352 for (unsigned problem_index=0; problem_index<2; problem_index++)
00353 {
00354 this->mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(this->mpMesh, problem_index);
00355 }
00356
00357
00358
00359 if (mpElectrodes->HasGroundedElectrode())
00360 {
00361 delete mpSolver;
00362 AbstractCardiacProblem<DIM,DIM,2>::mpSolver = CreateSolver();
00363 mpSolver->SetTimeStep(HeartConfig::Instance()->GetPdeTimeStep());
00364 }
00365
00366
00367
00368 mpSolver->ResetBoundaryConditionsContainer(this->mpDefaultBoundaryConditionsContainer.get());
00369
00370
00371 this->mpBoundaryConditionsContainer = this->mpDefaultBoundaryConditionsContainer;
00372 }
00373 }
00374
00375
00376
00377 template<unsigned DIM>
00378 void BidomainProblem<DIM>::SetUpAdditionalStoppingTimes(std::vector<double>& rAdditionalStoppingTimes)
00379 {
00380 if ( mpElectrodes )
00381 {
00382 rAdditionalStoppingTimes.push_back( mpElectrodes->GetSwitchOnTime() );
00383 rAdditionalStoppingTimes.push_back( mpElectrodes->GetSwitchOffTime() );
00384 }
00385 }
00386
00387 template<unsigned DIM>
00388 bool BidomainProblem<DIM>::GetHasBath()
00389 {
00390 return mHasBath;
00391 }
00392
00394
00396
00397 template class BidomainProblem<1>;
00398 template class BidomainProblem<2>;
00399 template class BidomainProblem<3>;
00400
00401
00402
00403 #include "SerializationExportWrapperForCpp.hpp"
00404 EXPORT_TEMPLATE_CLASS_SAME_DIMS(BidomainProblem)