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