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 (unsigned i=0; i<this->mpMesh->GetNumNodes(); i++)
00048 {
00049 this->mpMesh->GetNode(i)->SetRegion(HeartRegionCode::BATH);
00050 }
00051
00052 bool any_bath_element_found = false;
00053
00054
00055 for (unsigned i=0; i<this->mpMesh->GetNumElements(); i++)
00056 {
00057 Element<DIM, DIM>& r_element = *(this->mpMesh->GetElement(i));
00058
00059 if (r_element.GetRegion() == HeartRegionCode::TISSUE)
00060 {
00061 for (unsigned j=0; j<r_element.GetNumNodes(); j++)
00062 {
00063 r_element.GetNode(j)->SetRegion(HeartRegionCode::TISSUE);
00064 }
00065 }
00066 else
00067 {
00068 assert(r_element.GetRegion() == HeartRegionCode::BATH);
00069 any_bath_element_found = true;
00070 }
00071 }
00072
00073 if (!any_bath_element_found)
00074 {
00075 EXCEPTION("No bath element found");
00076 }
00077 }
00078 }
00079
00080
00081 template<unsigned DIM>
00082 Vec BidomainProblem<DIM>::CreateInitialCondition()
00083 {
00084 Vec init_cond = AbstractCardiacProblem<DIM,2>::CreateInitialCondition();
00085 if (mHasBath)
00086 {
00087
00088 DistributedVector ic(init_cond);
00089 DistributedVector::Stripe voltage_stripe = DistributedVector::Stripe(ic,0);
00090
00091 for (DistributedVector::Iterator index = DistributedVector::Begin();
00092 index!= DistributedVector::End();
00093 ++index)
00094 {
00095 if (this->mpMesh->GetNode( index.Global )->GetRegion() == HeartRegionCode::BATH)
00096 {
00097 voltage_stripe[index] = 0.0;
00098 }
00099 }
00100 ic.Restore();
00101 }
00102
00103 return init_cond;
00104 }
00105
00106 template<unsigned DIM>
00107 AbstractCardiacPde<DIM> * BidomainProblem<DIM>::CreateCardiacPde()
00108 {
00109 AnalyseMeshForBath();
00110 mpBidomainPde = new BidomainPde<DIM>(this->mpCellFactory);
00111 return mpBidomainPde;
00112 }
00113
00114 template<unsigned DIM>
00115 AbstractDynamicAssemblerMixin<DIM, DIM, 2>* BidomainProblem<DIM>::CreateAssembler()
00116 {
00117 if (mHasBath)
00118 {
00119 if (!this->mUseMatrixBasedRhsAssembly)
00120 {
00121 mpAssembler
00122 = new BidomainWithBathAssembler<DIM,DIM>(this->mpMesh,
00123 mpBidomainPde,
00124 this->mpBoundaryConditionsContainer,
00125 2);
00126 }
00127 else
00128 {
00129 mpAssembler
00130 = new BidomainWithBathMatrixBasedAssembler<DIM,DIM>(this->mpMesh,
00131 mpBidomainPde,
00132 this->mpBoundaryConditionsContainer,
00133 2);
00134 }
00135
00136 }
00137 else
00138 {
00139 if (!this->mUseMatrixBasedRhsAssembly)
00140 {
00141 mpAssembler
00142 = new BidomainDg0Assembler<DIM,DIM>(this->mpMesh,
00143 mpBidomainPde,
00144 this->mpBoundaryConditionsContainer,
00145 2);
00146 }
00147 else
00148 {
00149 mpAssembler
00150 = new BidomainMatrixBasedAssembler<DIM,DIM>(this->mpMesh,
00151 mpBidomainPde,
00152 this->mpBoundaryConditionsContainer,
00153 2);
00154 }
00155 }
00156
00157 try
00158 {
00159 mpAssembler->SetFixedExtracellularPotentialNodes(mFixedExtracellularPotentialNodes);
00160 mpAssembler->SetRowForAverageOfPhiZeroed(mRowForAverageOfPhiZeroed);
00161 }
00162 catch (const Exception& e)
00163 {
00164 delete mpAssembler;
00165 throw e;
00166 }
00167
00168 return mpAssembler;
00169 }
00170
00171 template<unsigned DIM>
00172 BidomainProblem<DIM>::BidomainProblem(
00173 AbstractCardiacCellFactory<DIM>* pCellFactory, bool hasBath)
00174 : AbstractCardiacProblem<DIM, 2>(pCellFactory),
00175 mpBidomainPde(NULL),
00176 mRowForAverageOfPhiZeroed(INT_MAX),
00177 mHasBath(hasBath),
00178 mpElectrodes(NULL)
00179 {
00180 mFixedExtracellularPotentialNodes.resize(0);
00181 }
00182
00183 template<unsigned DIM>
00184 void BidomainProblem<DIM>::SetFixedExtracellularPotentialNodes(std::vector<unsigned> nodes)
00185 {
00186 mFixedExtracellularPotentialNodes.resize(nodes.size());
00187 for (unsigned i=0; i<nodes.size(); i++)
00188 {
00189
00190
00191 mFixedExtracellularPotentialNodes[i] = nodes[i];
00192 }
00193 }
00194
00195 template<unsigned DIM>
00196 void BidomainProblem<DIM>::SetNodeForAverageOfPhiZeroed(unsigned node)
00197 {
00198 mRowForAverageOfPhiZeroed = 2*node+1;
00199 }
00200
00201 template<unsigned DIM>
00202 BidomainPde<DIM>* BidomainProblem<DIM>::GetBidomainPde()
00203 {
00204 assert(mpBidomainPde!=NULL);
00205 return mpBidomainPde;
00206 }
00207
00208 template<unsigned DIM>
00209 void BidomainProblem<DIM>::WriteInfo(double time)
00210 {
00211 std::cout << "Solved to time " << time << "\n" << std::flush;
00212 ReplicatableVector voltage_replicated;
00213 voltage_replicated.ReplicatePetscVector(this->mSolution);
00214 double v_max = -1e5, v_min = 1e5, phi_max = -1e5, phi_min = 1e5;
00215
00216 for (unsigned i=0; i<this->mpMesh->GetNumNodes(); i++)
00217 {
00218 double v=voltage_replicated[2*i];
00219 double phi=voltage_replicated[2*i+1];
00220
00221 #define COVERAGE_IGNORE
00222 if (isnan(v) || isnan(phi))
00223 {
00224 EXCEPTION("Not-a-number encountered");
00225 }
00226 #undef COVERAGE_IGNORE
00227 if ( v > v_max)
00228 {
00229 v_max = v;
00230 }
00231 if ( v < v_min)
00232 {
00233 v_min = v;
00234 }
00235 if ( phi > phi_max)
00236 {
00237 phi_max = phi;
00238 }
00239 if ( phi < phi_min)
00240 {
00241 phi_min = phi;
00242 }
00243 }
00244 std::cout << " V; phi_e = " << "[" <<v_min << ", " << v_max << "]" << ";\t"
00245 << "[" <<phi_min << ", " << phi_max << "]" << "\n"
00246 << std::flush;
00247 }
00248
00249 template<unsigned DIM>
00250 void BidomainProblem<DIM>::DefineWriterColumns()
00251 {
00252 AbstractCardiacProblem<DIM,2>::DefineWriterColumns();
00253 mExtracelluarColumnId = this->mpWriter->DefineVariable("Phi_e","mV");
00254 }
00255
00256 template<unsigned DIM>
00257 void BidomainProblem<DIM>::WriteOneStep(double time, Vec voltageVec)
00258 {
00259 this->mpWriter->PutUnlimitedVariable(time);
00260 this->mpWriter->PutStripedVector(this->mVoltageColumnId, mExtracelluarColumnId, voltageVec);
00261 }
00262
00263 template<unsigned DIM>
00264 void BidomainProblem<DIM>::PreSolveChecks()
00265 {
00266 AbstractCardiacProblem<DIM, 2>::PreSolveChecks();
00267 if (mFixedExtracellularPotentialNodes.empty())
00268 {
00269
00270 if (mRowForAverageOfPhiZeroed==INT_MAX)
00271 {
00272
00273
00274
00275 if (HeartConfig::Instance()->GetUseRelativeTolerance())
00276 {
00277 EXCEPTION("Bidomain external voltage is not bounded in this simulation - use KSP *absolute* tolerance");
00278 }
00279 }
00280 }
00281 }
00282
00283 template<unsigned DIM>
00284 void BidomainProblem<DIM>::SetElectrodes(Electrodes<DIM>& rElectrodes)
00285 {
00286 if(!mHasBath)
00287 {
00288 EXCEPTION("Cannot set electrodes when problem has been defined to not have a bath");
00289 }
00290
00291 mpElectrodes = &rElectrodes;
00292
00293 SetBoundaryConditionsContainer(mpElectrodes->GetBoundaryConditionsContainer());
00294 }
00295
00296
00297 template<unsigned DIM>
00298 void BidomainProblem<DIM>::OnEndOfTimestep(double time)
00299 {
00300 if( (mpElectrodes!=NULL) && (mpElectrodes->SwitchOff(time)) )
00301 {
00302
00303
00304 assert(this->mpBoundaryConditionsContainer!=NULL);
00305 assert(this->mpDefaultBoundaryConditionsContainer==NULL);
00306
00310
00311
00312
00313 if(this->mpDefaultBoundaryConditionsContainer==NULL)
00314 {
00315 this->mpDefaultBoundaryConditionsContainer = new BoundaryConditionsContainer<DIM,DIM,2>;
00316 for (unsigned problem_index=0; problem_index<2; problem_index++)
00317 {
00318 this->mpDefaultBoundaryConditionsContainer->DefineZeroNeumannOnMeshBoundary(this->mpMesh, problem_index);
00319 }
00320 }
00321
00322
00323 mpAssembler->SetBoundaryConditionsContainer(this->mpDefaultBoundaryConditionsContainer);
00324
00325
00326
00327 this->mpBoundaryConditionsContainer = this->mpDefaultBoundaryConditionsContainer;
00328 }
00329 }
00330
00332
00334
00335 template class BidomainProblem<1>;
00336 template class BidomainProblem<2>;
00337 template class BidomainProblem<3>;