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 "ExtendedBidomainProblem.hpp"
00031 #include "ExtendedBidomainSolver.hpp"
00032 #include "AbstractDynamicLinearPdeSolver.hpp"
00033 #include "HeartConfig.hpp"
00034 #include "Exception.hpp"
00035 #include "DistributedVector.hpp"
00036 #include "ReplicatableVector.hpp"
00037
00038
00039
00040 template<unsigned DIM>
00041 ExtendedBidomainProblem<DIM>::ExtendedBidomainProblem(
00042 AbstractCardiacCellFactory<DIM>* pCellFactory, AbstractCardiacCellFactory<DIM>* pSecondCellFactory, bool hasBath)
00043 : AbstractCardiacProblem<DIM,DIM, 3>(pCellFactory),
00044 mpSecondCellFactory(pSecondCellFactory),
00045 mpExtendedBidomainTissue(NULL),
00046 mUserSpecifiedSecondCellConductivities(false),
00047 mUserHasSetBidomainValuesExplicitly(false),
00048 mpExtracellularStimulusFactory(NULL),
00049 mRowForAverageOfPhiZeroed(INT_MAX),
00050 mApplyAveragePhieZeroConstraintAfterSolving(false),
00051 mUserSuppliedExtracellularStimulus(false),
00052 mHasBath(hasBath)
00053 {
00054 mFixedExtracellularPotentialNodes.resize(0);
00055 }
00056
00057 template<unsigned DIM>
00058 ExtendedBidomainProblem<DIM>::ExtendedBidomainProblem()
00059 : AbstractCardiacProblem<DIM,DIM, 3>(),
00060 mpSecondCellFactory(NULL),
00061 mpExtendedBidomainTissue(NULL),
00062 mUserSpecifiedSecondCellConductivities(false),
00063 mUserHasSetBidomainValuesExplicitly(false),
00064 mpExtracellularStimulusFactory(NULL),
00065 mRowForAverageOfPhiZeroed(INT_MAX),
00066 mApplyAveragePhieZeroConstraintAfterSolving(false),
00067 mUserSuppliedExtracellularStimulus(false)
00068 {
00069 mFixedExtracellularPotentialNodes.resize(0);
00070 }
00071
00072
00073 template<unsigned DIM>
00074 Vec ExtendedBidomainProblem<DIM>::CreateInitialCondition()
00075 {
00076
00077 DistributedVectorFactory* p_factory = this->mpMesh->GetDistributedVectorFactory();
00078 Vec initial_condition = p_factory->CreateVec(3);
00079 DistributedVector ic = p_factory->CreateDistributedVector(initial_condition);
00080 std::vector<DistributedVector::Stripe> stripe;
00081 stripe.reserve(3);
00082
00083 stripe.push_back(DistributedVector::Stripe(ic, 0));
00084 stripe.push_back(DistributedVector::Stripe(ic, 1));
00085 stripe.push_back(DistributedVector::Stripe(ic, 2));
00086
00087 for (DistributedVector::Iterator index = ic.Begin();
00088 index != ic.End();
00089 ++index)
00090 {
00091 stripe[0][index] = mpExtendedBidomainTissue->GetCardiacCell(index.Global)->GetVoltage();
00092 stripe[1][index] = mpExtendedBidomainTissue->GetCardiacSecondCell(index.Global)->GetVoltage();
00093 stripe[2][index] = 0.0;
00094 }
00095 ic.Restore();
00096
00097 return initial_condition;
00098 }
00099
00100 template<unsigned DIM>
00101 void ExtendedBidomainProblem<DIM>::ProcessExtracellularStimulus()
00102 {
00103 if ((mpExtracellularStimulusFactory == NULL))
00104 {
00105 mpExtracellularStimulusFactory = new AbstractStimulusFactory<DIM>();
00106
00107 }
00108
00109 assert(mpExtracellularStimulusFactory);
00110 mpExtracellularStimulusFactory->SetMesh(this->mpMesh);
00111 mpExtracellularStimulusFactory->SetCompatibleExtracellularStimulus();
00112
00113 std::vector<AbstractChasteRegion<DIM>* > grounded_regions = mpExtracellularStimulusFactory->GetRegionsToBeGrounded();
00114
00115 if ( (mUserSuppliedExtracellularStimulus) && grounded_regions.size() > 0 )
00116 {
00117 std::vector<unsigned> grounded_indices;
00118 for (unsigned global_node_index = 0; global_node_index < this->mpMesh->GetNumNodes(); global_node_index++)
00119 {
00120 if (this->mpMesh->GetDistributedVectorFactory()->IsGlobalIndexLocal(global_node_index))
00121 {
00122 for (unsigned region_index = 0; region_index <grounded_regions.size(); region_index++)
00123 {
00124 if ( grounded_regions[region_index]->DoesContain( this->mpMesh->GetNode(global_node_index)->GetPoint() ) )
00125 {
00126 grounded_indices.push_back( this->mpMesh->GetNode(global_node_index)->GetIndex() );
00127 }
00128 }
00129 }
00130 }
00131 PetscTools::Barrier();
00132 SetFixedExtracellularPotentialNodes(grounded_indices);
00133 }
00134 }
00135
00136 template<unsigned DIM>
00137 AbstractCardiacTissue<DIM> * ExtendedBidomainProblem<DIM>::CreateCardiacTissue()
00138 {
00139
00140 mpSecondCellFactory->SetMesh(this->mpMesh);
00141
00142
00143 ProcessExtracellularStimulus();
00144
00145
00146 mpExtendedBidomainTissue = new ExtendedBidomainTissue<DIM>(this->mpCellFactory, mpSecondCellFactory,mpExtracellularStimulusFactory);
00147
00148
00149 mpExtendedBidomainTissue->SetUserSuppliedExtracellularStimulus(mUserSuppliedExtracellularStimulus);
00150
00151
00152 if (mUserSpecifiedSecondCellConductivities)
00153 {
00154 mpExtendedBidomainTissue->SetIntracellularConductivitiesSecondCell(mIntracellularConductivitiesSecondCell);
00155 }
00156 else
00157 {
00158 c_vector<double, DIM> intra_conductivities;
00159 HeartConfig::Instance()->GetIntracellularConductivities(intra_conductivities);
00160 mpExtendedBidomainTissue->SetIntracellularConductivitiesSecondCell(intra_conductivities);
00161 }
00162
00163
00164
00165 mpExtendedBidomainTissue->CreateIntracellularConductivityTensorSecondCell();
00166
00167 if (mUserHasSetBidomainValuesExplicitly)
00168 {
00169 mpExtendedBidomainTissue->SetAmFirstCell(mAmFirstCell);
00170 mpExtendedBidomainTissue->SetAmSecondCell(mAmSecondCell);
00171 mpExtendedBidomainTissue->SetAmGap(mAmGap);
00172 mpExtendedBidomainTissue->SetGGap(mGGap);
00173 mpExtendedBidomainTissue->SetCmFirstCell(mCmFirstCell);
00174 mpExtendedBidomainTissue->SetCmSecondCell(mCmSecondCell);
00175 }
00176 else
00177 {
00178 mpExtendedBidomainTissue->SetAmFirstCell(HeartConfig::Instance()->GetSurfaceAreaToVolumeRatio());
00179 mpExtendedBidomainTissue->SetAmSecondCell(HeartConfig::Instance()->GetSurfaceAreaToVolumeRatio());
00180 mpExtendedBidomainTissue->SetAmGap(HeartConfig::Instance()->GetSurfaceAreaToVolumeRatio());
00181 mpExtendedBidomainTissue->SetGGap(0.0);
00182 mpExtendedBidomainTissue->SetCmFirstCell(HeartConfig::Instance()->GetCapacitance());
00183 mpExtendedBidomainTissue->SetCmSecondCell(HeartConfig::Instance()->GetCapacitance());
00184 }
00185
00186 mpExtendedBidomainTissue->SetGgapHeterogeneities(mGgapHeterogeneityRegions, mGgapHeterogenousValues);
00187 mpExtendedBidomainTissue->CreateGGapConductivities();
00188
00189 return mpExtendedBidomainTissue;
00190 }
00191
00192 template<unsigned DIM>
00193 void ExtendedBidomainProblem<DIM>::SetExtendedBidomainParameters(double Am1, double Am2, double AmGap, double Cm1, double Cm2, double Ggap)
00194 {
00195 mAmFirstCell = Am1;
00196 mAmSecondCell = Am2;
00197 mAmGap = AmGap;
00198 mCmFirstCell = Cm1;
00199 mCmSecondCell = Cm2;
00200 mGGap = Ggap;
00201
00202 mUserHasSetBidomainValuesExplicitly = true;
00203 }
00204
00205 template <unsigned DIM>
00206 void ExtendedBidomainProblem<DIM>::SetGgapHeterogeneities ( std::vector<boost::shared_ptr<AbstractChasteRegion<DIM> > >& rGgapHeterogeneityRegions, std::vector<double>& rGgapValues)
00207 {
00208 if (rGgapHeterogeneityRegions.size() != rGgapValues.size() )
00209 {
00210 EXCEPTION ("Gap junction heterogeneity areas must be of the same number as the heterogeneity values");
00211 }
00212 mGgapHeterogeneityRegions = rGgapHeterogeneityRegions;
00213 mGgapHeterogenousValues =rGgapValues;
00214 }
00215
00216 template <unsigned DIM>
00217 void ExtendedBidomainProblem<DIM>::SetExtracellularStimulusFactory( AbstractStimulusFactory<DIM>* pFactory)
00218 {
00219 mpExtracellularStimulusFactory = pFactory;
00220 mUserSuppliedExtracellularStimulus = true;
00221 }
00222
00223 template<unsigned DIM>
00224 AbstractDynamicLinearPdeSolver<DIM, DIM, 3>* ExtendedBidomainProblem<DIM>::CreateSolver()
00225 {
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 mpSolver = new ExtendedBidomainSolver<DIM,DIM>( mHasBath,
00238 this->mpMesh,
00239 mpExtendedBidomainTissue,
00240 this->mpBoundaryConditionsContainer.get(),
00241 2);
00242
00243
00244 try
00245 {
00246 mpSolver->SetFixedExtracellularPotentialNodes(mFixedExtracellularPotentialNodes);
00247 mpSolver->SetRowForAverageOfPhiZeroed(mRowForAverageOfPhiZeroed);
00248 }
00249 catch (const Exception& e)
00250 {
00251 delete mpSolver;
00252 throw e;
00253 }
00254
00255 return mpSolver;
00256 }
00257
00258 template<unsigned DIM>
00259 ExtendedBidomainProblem<DIM>::~ExtendedBidomainProblem()
00260 {
00261 if (!mUserSuppliedExtracellularStimulus)
00262 {
00263 delete mpExtracellularStimulusFactory;
00264 }
00265 }
00266
00267 template<unsigned DIM>
00268 void ExtendedBidomainProblem<DIM>::SetIntracellularConductivitiesForSecondCell(c_vector<double, DIM> conductivities)
00269 {
00270 for (unsigned i = 0; i < DIM; i++)
00271 {
00272 mIntracellularConductivitiesSecondCell[i] = conductivities[i];
00273 }
00274 mUserSpecifiedSecondCellConductivities = true;
00275 }
00276
00277 template<unsigned DIM>
00278 void ExtendedBidomainProblem<DIM>::SetFixedExtracellularPotentialNodes(std::vector<unsigned> nodes)
00279 {
00280 assert(mFixedExtracellularPotentialNodes.size() == 0);
00281 mFixedExtracellularPotentialNodes.resize(nodes.size());
00282 for (unsigned i=0; i<nodes.size(); i++)
00283 {
00284
00285
00286 mFixedExtracellularPotentialNodes[i] = nodes[i];
00287 }
00288 }
00289
00290 template<unsigned DIM>
00291 void ExtendedBidomainProblem<DIM>::SetNodeForAverageOfPhiZeroed(unsigned node)
00292 {
00293 if (node==0)
00294 {
00295 mRowForAverageOfPhiZeroed = 2;
00296 }
00297 else
00298 {
00299
00300 mRowForAverageOfPhiZeroed = 3*node - 1;
00301 }
00302 }
00303
00304 template<unsigned DIM>
00305 ExtendedBidomainTissue<DIM>* ExtendedBidomainProblem<DIM>::GetExtendedBidomainTissue()
00306 {
00307 assert(mpExtendedBidomainTissue!=NULL);
00308 return mpExtendedBidomainTissue;
00309 }
00310
00311 template<unsigned DIM>
00312 void ExtendedBidomainProblem<DIM>::WriteInfo(double time)
00313 {
00314 if (PetscTools::AmMaster())
00315 {
00316 std::cout << "Solved to time " << time << "\n" << std::flush;
00317 }
00318
00319 double phi_i_max_first_cell, phi_i_min_first_cell, phi_i_max_second_cell, phi_i_min_second_cell, phi_e_min, phi_e_max;
00320
00321 VecSetBlockSize( this->mSolution, 3 );
00322
00323 VecStrideMax( this->mSolution, 0, PETSC_NULL, &phi_i_max_first_cell );
00324 VecStrideMin( this->mSolution, 0, PETSC_NULL, &phi_i_min_first_cell );
00325
00326 VecStrideMax( this->mSolution, 1, PETSC_NULL, &phi_i_max_second_cell );
00327 VecStrideMin( this->mSolution, 1, PETSC_NULL, &phi_i_min_second_cell );
00328
00329 VecStrideMax( this->mSolution, 2, PETSC_NULL, &phi_e_max );
00330 VecStrideMin( this->mSolution, 2, PETSC_NULL, &phi_e_min );
00331
00332 if (PetscTools::AmMaster())
00333 {
00334 std::cout << " Phi_i first cell = " << "[" <<phi_i_max_first_cell << ", " << phi_i_min_first_cell << "]" << ";\n"
00335 << " Phi_i second cell = " << "[" <<phi_i_max_second_cell << ", " << phi_i_min_second_cell << "]" << ";\n"
00336 << " Phi_e = " << "[" <<phi_e_max << ", " << phi_e_min << "]" << ";\n"
00337 << std::flush;
00338 }
00339 }
00340
00341 template<unsigned DIM>
00342 void ExtendedBidomainProblem<DIM>::DefineWriterColumns(bool extending)
00343 {
00344 if (!extending)
00345 {
00346 if ( this->mNodesToOutput.empty() )
00347 {
00348
00349 this->mpWriter->DefineFixedDimension( this->mpMesh->GetNumNodes() );
00350 }
00351
00352
00353
00354
00355
00356
00357 mVoltageColumnId_Vm1 = this->mpWriter->DefineVariable("V","mV");
00358 mVoltageColumnId_Vm2 = this->mpWriter->DefineVariable("V_2","mV");
00359 mVoltageColumnId_Phie = this->mpWriter->DefineVariable("Phi_e","mV");
00360 mVariablesIDs.push_back(mVoltageColumnId_Vm1);
00361 mVariablesIDs.push_back(mVoltageColumnId_Vm2);
00362 mVariablesIDs.push_back(mVoltageColumnId_Phie);
00363 this->mpWriter->DefineUnlimitedDimension("Time","msecs");
00364 }
00365 else
00366 {
00367 mVoltageColumnId_Vm1 = this->mpWriter->GetVariableByName("V");
00368 mVoltageColumnId_Vm2 = this->mpWriter->GetVariableByName("V_2");
00369 mVoltageColumnId_Phie = this->mpWriter->GetVariableByName("Phi_e");
00370 }
00371
00372 AbstractCardiacProblem<DIM,DIM,3>::DefineExtraVariablesWriterColumns(extending);
00373
00374 }
00375
00376 template<unsigned DIM>
00377 void ExtendedBidomainProblem<DIM>::WriteOneStep(double time, Vec voltageVec)
00378 {
00379 this->mpWriter->PutUnlimitedVariable(time);
00380
00381
00382 Vec ordered_voltages = this->mpMesh->GetDistributedVectorFactory()->CreateVec(3);
00383 DistributedVector wrapped_ordered_solution = this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(ordered_voltages);
00384 DistributedVector wrapped_solution = this->mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(voltageVec);
00385
00386 DistributedVector::Stripe phi_i_first_cell_stripe(wrapped_solution,0);
00387 DistributedVector::Stripe phi_i_second_cell_stripe(wrapped_solution,1);
00388 DistributedVector::Stripe phi_e_stripe(wrapped_solution,2);
00389
00390 DistributedVector::Stripe wrapped_ordered_solution_first_stripe(wrapped_ordered_solution,0);
00391 DistributedVector::Stripe wrapped_ordered_solution_second_stripe(wrapped_ordered_solution,1);
00392 DistributedVector::Stripe wrapped_ordered_solution_third_stripe(wrapped_ordered_solution,2);
00393
00394 for (DistributedVector::Iterator index = wrapped_solution.Begin();
00395 index != wrapped_solution.End();
00396 ++index)
00397 {
00398 wrapped_ordered_solution_first_stripe[index] = phi_i_first_cell_stripe[index] - phi_e_stripe[index];
00399 wrapped_ordered_solution_second_stripe[index] = phi_i_second_cell_stripe[index] - phi_e_stripe[index];
00400 wrapped_ordered_solution_third_stripe[index] = phi_e_stripe[index];
00401 }
00402 wrapped_solution.Restore();
00403 wrapped_ordered_solution.Restore();
00404
00405 this->mpWriter->PutStripedVector(mVariablesIDs, ordered_voltages);
00406 VecDestroy(ordered_voltages);
00407
00408
00409 AbstractCardiacProblem<DIM,DIM,3>::WriteExtraVariablesOneStep();
00410 }
00411
00412 template<unsigned DIM>
00413 void ExtendedBidomainProblem<DIM>::PreSolveChecks()
00414 {
00415 AbstractCardiacProblem<DIM,DIM, 3>::PreSolveChecks();
00416 if (mFixedExtracellularPotentialNodes.empty())
00417 {
00418
00419 if (mRowForAverageOfPhiZeroed==INT_MAX)
00420 {
00421
00422
00423
00424 if (HeartConfig::Instance()->GetUseRelativeTolerance())
00425 {
00426 EXCEPTION("Bidomain external voltage is not bounded in this simulation - use KSP *absolute* tolerance");
00427 }
00428 }
00429 }
00430 }
00431
00432 template<unsigned DIM>
00433 bool ExtendedBidomainProblem<DIM>::GetHasBath()
00434 {
00435 return mHasBath;
00436 }
00437
00438
00439 template<unsigned DIM>
00440 void ExtendedBidomainProblem<DIM>::SetHasBath(bool hasBath)
00441 {
00442 mHasBath = hasBath;
00443 }
00444
00446
00448
00449 template class ExtendedBidomainProblem<1>;
00450 template class ExtendedBidomainProblem<2>;
00451 template class ExtendedBidomainProblem<3>;
00452
00453
00454 #include "SerializationExportWrapperForCpp.hpp"
00455 EXPORT_TEMPLATE_CLASS_SAME_DIMS(ExtendedBidomainProblem)