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