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