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 if (mHasBath)
00123 {
00124 if (!this->mUseMatrixBasedRhsAssembly)
00125 {
00126 mpAssembler
00127 = new BidomainWithBathAssembler<DIM,DIM>(this->mpMesh,
00128 mpBidomainPde,
00129 this->mpBoundaryConditionsContainer,
00130 2);
00131 }
00132 else
00133 {
00134 mpAssembler
00135 = new BidomainWithBathMatrixBasedAssembler<DIM,DIM>(this->mpMesh,
00136 mpBidomainPde,
00137 this->mpBoundaryConditionsContainer,
00138 2);
00139 }
00140
00141 }
00142 else
00143 {
00144 if (!this->mUseMatrixBasedRhsAssembly)
00145 {
00146 mpAssembler
00147 = new BidomainDg0Assembler<DIM,DIM>(this->mpMesh,
00148 mpBidomainPde,
00149 this->mpBoundaryConditionsContainer,
00150 2);
00151 }
00152 else
00153 {
00154 mpAssembler
00155 = new BidomainMatrixBasedAssembler<DIM,DIM>(this->mpMesh,
00156 mpBidomainPde,
00157 this->mpBoundaryConditionsContainer,
00158 2);
00159 }
00160 }
00161
00162 try
00163 {
00164 mpAssembler->SetFixedExtracellularPotentialNodes(mFixedExtracellularPotentialNodes);
00165 mpAssembler->SetRowForAverageOfPhiZeroed(mRowForAverageOfPhiZeroed);
00166 }
00167 catch (const Exception& e)
00168 {
00169 delete mpAssembler;
00170 throw e;
00171 }
00172
00173 return mpAssembler;
00174 }
00175
00176 template<unsigned DIM>
00177 BidomainProblem<DIM>::BidomainProblem(
00178 AbstractCardiacCellFactory<DIM>* pCellFactory, bool hasBath)
00179 : AbstractCardiacProblem<DIM,DIM, 2>(pCellFactory),
00180 mpBidomainPde(NULL),
00181 mRowForAverageOfPhiZeroed(INT_MAX),
00182 mHasBath(hasBath),
00183 mpElectrodes(NULL)
00184 {
00185 mFixedExtracellularPotentialNodes.resize(0);
00186 }
00187
00188 template<unsigned DIM>
00189 void BidomainProblem<DIM>::SetFixedExtracellularPotentialNodes(std::vector<unsigned> nodes)
00190 {
00191 mFixedExtracellularPotentialNodes.resize(nodes.size());
00192 for (unsigned i=0; i<nodes.size(); i++)
00193 {
00194
00195
00196 mFixedExtracellularPotentialNodes[i] = nodes[i];
00197 }
00198 }
00199
00200 template<unsigned DIM>
00201 void BidomainProblem<DIM>::SetNodeForAverageOfPhiZeroed(unsigned node)
00202 {
00203 mRowForAverageOfPhiZeroed = 2*node+1;
00204 }
00205
00206 template<unsigned DIM>
00207 BidomainPde<DIM>* BidomainProblem<DIM>::GetBidomainPde()
00208 {
00209 assert(mpBidomainPde!=NULL);
00210 return mpBidomainPde;
00211 }
00212
00213 template<unsigned DIM>
00214 void BidomainProblem<DIM>::WriteInfo(double time)
00215 {
00216 std::cout << "Solved to time " << time << "\n" << std::flush;
00217 ReplicatableVector voltage_replicated;
00218 voltage_replicated.ReplicatePetscVector(this->mSolution);
00219 double v_max = -1e5, v_min = 1e5, phi_max = -1e5, phi_min = 1e5;
00220
00221 for (unsigned i=0; i<this->mpMesh->GetNumNodes(); i++)
00222 {
00223 double v=voltage_replicated[2*i];
00224 double phi=voltage_replicated[2*i+1];
00225
00226 #define COVERAGE_IGNORE
00227 if (std::isnan(v) || std::isnan(phi))
00228 {
00229 EXCEPTION("Not-a-number encountered");
00230 }
00231 #undef COVERAGE_IGNORE
00232 if ( v > v_max)
00233 {
00234 v_max = v;
00235 }
00236 if ( v < v_min)
00237 {
00238 v_min = v;
00239 }
00240 if ( phi > phi_max)
00241 {
00242 phi_max = phi;
00243 }
00244 if ( phi < phi_min)
00245 {
00246 phi_min = phi;
00247 }
00248 }
00249 std::cout << " V; phi_e = " << "[" <<v_min << ", " << v_max << "]" << ";\t"
00250 << "[" <<phi_min << ", " << phi_max << "]" << "\n"
00251 << std::flush;
00252 }
00253
00254 template<unsigned DIM>
00255 void BidomainProblem<DIM>::DefineWriterColumns()
00256 {
00257 AbstractCardiacProblem<DIM,DIM,2>::DefineWriterColumns();
00258 mExtracelluarColumnId = this->mpWriter->DefineVariable("Phi_e","mV");
00259 }
00260
00261 template<unsigned DIM>
00262 void BidomainProblem<DIM>::WriteOneStep(double time, Vec voltageVec)
00263 {
00264 this->mpWriter->PutUnlimitedVariable(time);
00265 this->mpWriter->PutStripedVector(this->mVoltageColumnId, mExtracelluarColumnId, voltageVec);
00266 }
00267
00268 template<unsigned DIM>
00269 void BidomainProblem<DIM>::PreSolveChecks()
00270 {
00271 AbstractCardiacProblem<DIM,DIM, 2>::PreSolveChecks();
00272 if (mFixedExtracellularPotentialNodes.empty())
00273 {
00274
00275 if (mRowForAverageOfPhiZeroed==INT_MAX)
00276 {
00277
00278
00279
00280 if (HeartConfig::Instance()->GetUseRelativeTolerance())
00281 {
00282 EXCEPTION("Bidomain external voltage is not bounded in this simulation - use KSP *absolute* tolerance");
00283 }
00284 }
00285 }
00286 }
00287
00288 template<unsigned DIM>
00289 void BidomainProblem<DIM>::SetElectrodes(Electrodes<DIM>& rElectrodes)
00290 {
00291 if(!mHasBath)
00292 {
00293 EXCEPTION("Cannot set electrodes when problem has been defined to not have a bath");
00294 }
00295
00296 mpElectrodes = &rElectrodes;
00297
00298 SetBoundaryConditionsContainer(mpElectrodes->GetBoundaryConditionsContainer());
00299 }
00300
00301
00302 template<unsigned DIM>
00303 void BidomainProblem<DIM>::OnEndOfTimestep(double time)
00304 {
00305 if( (mpElectrodes!=NULL) && (mpElectrodes->SwitchOff(time)) )
00306 {
00307
00308
00309 assert(this->mpBoundaryConditionsContainer!=NULL);
00310 assert(this->mpDefaultBoundaryConditionsContainer==NULL);
00311
00315
00316
00317
00318 if(this->mpDefaultBoundaryConditionsContainer==NULL)
00319 {
00320 this->mpDefaultBoundaryConditionsContainer = new BoundaryConditionsContainer<DIM,DIM,2>;
00321 for (unsigned problem_index=0; problem_index<2; problem_index++)
00322 {
00323 this->mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(this->mpMesh, problem_index);
00324 }
00325 }
00326
00327
00328 mpAssembler->SetBoundaryConditionsContainer(this->mpDefaultBoundaryConditionsContainer);
00329
00330
00331
00332 this->mpBoundaryConditionsContainer = this->mpDefaultBoundaryConditionsContainer;
00333 }
00334 }
00335
00337
00339
00340 template class BidomainProblem<1>;
00341 template class BidomainProblem<2>;
00342 template class BidomainProblem<3>;