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 #include "HeartConfigRelatedCellFactory.hpp"
00030
00031 #include <sstream>
00032 #include "HeartGeometryInformation.hpp"
00033 #include "ChasteNodesList.hpp"
00034 #include "HeartFileFinder.hpp"
00035 #include "CellMLToSharedLibraryConverter.hpp"
00036 #include "AbstractCardiacCellInterface.hpp"
00037 #include "Warnings.hpp"
00038
00039 #include "AbstractCvodeCell.hpp"
00040
00041 template<unsigned SPACE_DIM>
00042 HeartConfigRelatedCellFactory<SPACE_DIM>::HeartConfigRelatedCellFactory()
00043 : AbstractCardiacCellFactory<SPACE_DIM>(),
00044 mDefaultIonicModel(HeartConfig::Instance()->GetDefaultIonicModel())
00045 {
00046
00047 HeartConfig::Instance()->GetIonicModelRegions(mIonicModelRegions,
00048 mIonicModelsDefined);
00049
00050
00051 HeartConfig::Instance()->GetStimuli(mStimuliApplied, mStimulatedAreas);
00052
00053
00054 if (mStimuliApplied.size()==0 && (HeartConfig::Instance()->IsElectrodesPresent() == false) )
00055 {
00056 EXCEPTION("Simulation needs a stimulus (either <Stimuli> or <Electrodes>).");
00057 }
00058
00059
00060 HeartConfig::Instance()->GetCellHeterogeneities(mCellHeterogeneityAreas,
00061 mScaleFactorGks,
00062 mScaleFactorIto,
00063 mScaleFactorGkr,
00064 &mParameterSettings);
00065
00066
00067 PreconvertCellmlFiles();
00068 }
00069
00070 template<unsigned SPACE_DIM>
00071 void HeartConfigRelatedCellFactory<SPACE_DIM>::PreconvertCellmlFiles()
00072 {
00073 if (mDefaultIonicModel.Dynamic().present())
00074 {
00075 LoadDynamicModel(mDefaultIonicModel, true);
00076 }
00077 for (unsigned i=0; i<mIonicModelsDefined.size(); i++)
00078 {
00079 if (mIonicModelsDefined[i].Dynamic().present())
00080 {
00081 LoadDynamicModel(mIonicModelsDefined[i], true);
00082 }
00083 }
00084 }
00085
00086 template<unsigned SPACE_DIM>
00087 DynamicCellModelLoader* HeartConfigRelatedCellFactory<SPACE_DIM>::LoadDynamicModel(
00088 const cp::ionic_model_selection_type& rModel,
00089 bool isCollective)
00090 {
00091 assert(rModel.Dynamic().present());
00092 HeartFileFinder file_finder(rModel.Dynamic()->Path());
00093 CellMLToSharedLibraryConverter converter;
00094 return converter.Convert(file_finder, isCollective);
00095 }
00096
00097 template<unsigned SPACE_DIM>
00098 HeartConfigRelatedCellFactory<SPACE_DIM>::~HeartConfigRelatedCellFactory()
00099 {
00100 }
00101
00102 template<unsigned SPACE_DIM>
00103 AbstractCardiacCell* HeartConfigRelatedCellFactory<SPACE_DIM>::CreateCellWithIntracellularStimulus(
00104 boost::shared_ptr<AbstractStimulusFunction> intracellularStimulus,
00105 unsigned nodeIndex)
00106 {
00107 cp::ionic_model_selection_type ionic_model = mDefaultIonicModel;
00108
00109 for (unsigned ionic_model_region_index = 0;
00110 ionic_model_region_index < mIonicModelRegions.size();
00111 ++ionic_model_region_index)
00112 {
00113 if ( mIonicModelRegions[ionic_model_region_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00114 {
00115 ionic_model = mIonicModelsDefined[ionic_model_region_index];
00116 break;
00117 }
00118 }
00119
00120 AbstractCardiacCell* p_cell = NULL;
00121
00122 if (ionic_model.Dynamic().present())
00123 {
00124 #ifndef CHASTE_CAN_CHECKPOINT_DLLS
00125 if (HeartConfig::Instance()->GetCheckpointSimulation())
00126 {
00127 EXCEPTION("Checkpointing is not compatible with dynamically loaded cell models on Boost<1.37.");
00128 }
00129 #endif // CHASTE_CAN_CHECKPOINT_DLLS
00130
00131 DynamicCellModelLoader* p_loader = LoadDynamicModel(ionic_model, false);
00132 AbstractCardiacCellInterface* p_loaded_cell = p_loader->CreateCell(this->mpSolver, intracellularStimulus);
00133 p_cell = dynamic_cast<AbstractCardiacCell*>(p_loaded_cell);
00134 if (!p_cell)
00135 {
00136 delete p_loaded_cell;
00137 EXCEPTION("CVODE cannot be used as a cell model solver in tissue simulations: do not use the --cvode flag.");
00138 }
00139 }
00140 else
00141 {
00142 assert(ionic_model.Hardcoded().present());
00143 switch(ionic_model.Hardcoded().get())
00144 {
00145 case(cp::ionic_models_available_type::LuoRudyI):
00146 {
00147 p_cell = new CellLuoRudy1991FromCellML(this->mpSolver, intracellularStimulus);
00148 break;
00149 }
00150
00151 case(cp::ionic_models_available_type::LuoRudyIBackwardEuler):
00152 {
00153 p_cell = new CellLuoRudy1991FromCellMLBackwardEuler(this->mpSolver, intracellularStimulus);
00154 break;
00155 }
00156
00157 case(cp::ionic_models_available_type::Fox2002BackwardEuler):
00158 {
00159 p_cell = new CellFoxModel2002FromCellMLBackwardEuler(this->mpSolver, intracellularStimulus);
00160 break;
00161 }
00162
00163 case(cp::ionic_models_available_type::DifrancescoNoble):
00164 {
00165 p_cell = new CellDiFrancescoNoble1985FromCellML(this->mpSolver, intracellularStimulus);
00166 break;
00167 }
00168
00169 case(cp::ionic_models_available_type::MahajanShiferaw):
00170 {
00171 p_cell = new CellMahajan2008FromCellML(this->mpSolver, intracellularStimulus);
00172 break;
00173 }
00174
00175 case(cp::ionic_models_available_type::tenTusscher2006):
00176 {
00177 p_cell = new CellTenTusscher2006EpiFromCellML(this->mpSolver, intracellularStimulus);
00178 break;
00179 }
00180
00181 case(cp::ionic_models_available_type::Maleckar):
00182 {
00183 p_cell = new CellMaleckar2008FromCellML(this->mpSolver, intracellularStimulus);
00184 break;
00185 }
00186
00187 case(cp::ionic_models_available_type::HodgkinHuxley):
00188 {
00189 p_cell = new CellHodgkinHuxley1952FromCellML(this->mpSolver, intracellularStimulus);
00190 break;
00191 }
00192
00193 case(cp::ionic_models_available_type::FaberRudy2000):
00194 {
00195 p_cell = new CellFaberRudy2000FromCellML(this->mpSolver, intracellularStimulus);
00196 break;
00197 }
00198
00199 case(cp::ionic_models_available_type::FaberRudy2000Optimised):
00200 {
00201 p_cell = new CellFaberRudy2000FromCellMLOpt(this->mpSolver, intracellularStimulus);
00202 break;
00203 }
00204
00205 default:
00206 {
00207
00208 NEVER_REACHED;
00209 }
00210 }
00211 }
00212
00213
00214 try
00215 {
00216 SetCellParameters(p_cell, nodeIndex);
00217 }
00218 catch (const Exception& e)
00219 {
00220 delete p_cell;
00221 throw e;
00222 }
00223
00224 p_cell->GetLookupTableCollection();
00225
00226 return p_cell;
00227 }
00228
00229
00230 template<unsigned SPACE_DIM>
00231 void HeartConfigRelatedCellFactory<SPACE_DIM>::SetCellParameters(AbstractCardiacCell* pCell,
00232 unsigned nodeIndex)
00233 {
00234
00235 for (unsigned ht_index = 0;
00236 ht_index < mCellHeterogeneityAreas.size();
00237 ++ht_index)
00238 {
00239 if ( mCellHeterogeneityAreas[ht_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00240 {
00241 try
00242 {
00243 pCell->SetParameter("ScaleFactorGks", mScaleFactorGks[ht_index]);
00244 pCell->SetParameter("ScaleFactorGkr", mScaleFactorGkr[ht_index]);
00245 pCell->SetParameter("ScaleFactorIto", mScaleFactorIto[ht_index]);
00246 }
00247 catch (const Exception& e)
00248 {
00249
00250 }
00251 }
00252 }
00253
00255 if (HeartConfig::Instance()->HasDrugDose())
00256 {
00257 double drug_dose = HeartConfig::Instance()->GetDrugDose();
00258 std::map<std::string, std::pair<double, double> > ic50_values = HeartConfig::Instance()->GetIc50Values();
00259 for (std::map<std::string, std::pair<double, double> >::iterator it = ic50_values.begin();
00260 it != ic50_values.end();
00261 ++it)
00262 {
00263 const std::string param_name = it->first + "_conductance";
00264 if (pCell->HasParameter(param_name))
00265 {
00266 const double original_conductance = pCell->GetParameter(param_name);
00267 const double ic50 = it->second.first;
00268 const double hill = it->second.second;
00269 const double new_conductance = original_conductance/(1.0 + pow(drug_dose/ic50, hill));
00270 pCell->SetParameter(param_name, new_conductance);
00271 }
00272 else
00273 {
00274 std::stringstream msg;
00275 msg << "Cannot apply drug to cell at node " << nodeIndex << " as it has no parameter named '" << param_name << "'.";
00276 WARNING(msg.str());
00277 }
00278 }
00279 }
00280
00281
00282 for (unsigned ht_index = 0;
00283 ht_index < mCellHeterogeneityAreas.size();
00284 ++ht_index)
00285 {
00286 if ( mCellHeterogeneityAreas[ht_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00287 {
00288 for (std::map<std::string, double>::iterator param_it = mParameterSettings[ht_index].begin();
00289 param_it != mParameterSettings[ht_index].end();
00290 ++param_it)
00291 {
00292 unsigned param_index = pCell->GetParameterIndex(param_it->first);
00293 pCell->SetParameter(param_index, param_it->second);
00294 }
00295 }
00296 }
00297 }
00298
00299
00300 template<unsigned SPACE_DIM>
00301 void HeartConfigRelatedCellFactory<SPACE_DIM>::SetCellIntracellularStimulus(AbstractCardiacCell* pCell,
00302 unsigned nodeIndex)
00303 {
00304 boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus());
00305
00306 for (unsigned stimulus_index = 0;
00307 stimulus_index < mStimuliApplied.size();
00308 ++stimulus_index)
00309 {
00310 if ( mStimulatedAreas[stimulus_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00311 {
00312 node_specific_stimulus->AddStimulus(mStimuliApplied[stimulus_index]);
00313 }
00314 }
00315 pCell->SetIntracellularStimulusFunction(node_specific_stimulus);
00316 }
00317
00318
00319 template<unsigned SPACE_DIM>
00320 AbstractCardiacCell* HeartConfigRelatedCellFactory<SPACE_DIM>::CreateCardiacCellForTissueNode(unsigned nodeIndex)
00321 {
00322 boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus());
00323
00324
00325 for (unsigned stimulus_index = 0;
00326 stimulus_index < mStimuliApplied.size();
00327 ++stimulus_index)
00328 {
00329 if ( mStimulatedAreas[stimulus_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00330 {
00331 node_specific_stimulus->AddStimulus(mStimuliApplied[stimulus_index]);
00332 }
00333 }
00334
00335 return CreateCellWithIntracellularStimulus(node_specific_stimulus, nodeIndex);
00336 }
00337
00338 template<unsigned SPACE_DIM>
00339 void HeartConfigRelatedCellFactory<SPACE_DIM>::FillInCellularTransmuralAreas()
00340 {
00341 NEVER_REACHED;
00342 }
00343
00344 template<>
00345 void HeartConfigRelatedCellFactory<3u>::FillInCellularTransmuralAreas()
00346 {
00347 std::string mesh_file_name = HeartConfig::Instance()->GetMeshName();
00348
00349 std::string epi_surface = mesh_file_name + ".epi";
00350 std::string lv_surface = mesh_file_name + ".lv";
00351 std::string rv_surface = mesh_file_name + ".rv";
00352
00353
00354
00355
00356 HeartGeometryInformation<3u> info(*(this->GetMesh()), epi_surface, lv_surface, rv_surface, true);
00357
00358
00359 double epi_fraction = HeartConfig::Instance()->GetEpiLayerFraction();
00360 double endo_fraction = HeartConfig::Instance()->GetEndoLayerFraction();
00361
00362
00363 info.DetermineLayerForEachNode(epi_fraction,endo_fraction);
00364
00365 std::vector<unsigned> heterogeneity_node_list;
00366 for (unsigned index=0; index<this->GetMesh()->GetNumNodes(); index++)
00367 {
00368 heterogeneity_node_list.push_back(info.rGetLayerForEachNode()[index]);
00369 }
00370
00371 std::vector<Node<3u>*> epi_nodes;
00372 std::vector<Node<3u>*> mid_nodes;
00373 std::vector<Node<3u>*> endo_nodes;
00374
00375
00376 for (unsigned node_index = 0; node_index < this->GetMesh()->GetNumNodes(); node_index++)
00377 {
00378 if (this->GetMesh()->GetDistributedVectorFactory()->IsGlobalIndexLocal(node_index) )
00379 {
00380 switch (heterogeneity_node_list[node_index])
00381 {
00382
00383 case 2u:
00384 {
00385 epi_nodes.push_back(this->GetMesh()->GetNode(node_index));
00386 break;
00387 }
00388
00389 case 1u:
00390 {
00391 mid_nodes.push_back(this->GetMesh()->GetNode(node_index));
00392 break;
00393 }
00394
00395 case 0u:
00396 {
00397 endo_nodes.push_back(this->GetMesh()->GetNode(node_index));
00398 break;
00399 }
00400 default:
00401 NEVER_REACHED;
00402 }
00403 }
00404 }
00405
00406
00407
00408
00409
00410
00411
00412 unsigned user_supplied_epi_index = HeartConfig::Instance()->GetEpiLayerIndex();
00413 unsigned user_supplied_mid_index = HeartConfig::Instance()->GetMidLayerIndex();
00414 unsigned user_supplied_endo_index = HeartConfig::Instance()->GetEndoLayerIndex();
00415
00416
00417 assert(user_supplied_epi_index<3);
00418 assert(user_supplied_mid_index<3);
00419 assert(user_supplied_endo_index<3);
00420
00421
00422 std::vector<unsigned> user_supplied_indices;
00423 user_supplied_indices.push_back(user_supplied_epi_index);
00424 user_supplied_indices.push_back(user_supplied_mid_index);
00425 user_supplied_indices.push_back(user_supplied_endo_index);
00426
00427
00428
00429
00430 for (unsigned layer_index=0; layer_index<3; layer_index++)
00431 {
00432 unsigned counter = 0;
00433
00434 for (unsigned supplied_index = 0; supplied_index<user_supplied_indices.size(); supplied_index++)
00435 {
00436 if (user_supplied_indices[supplied_index] == layer_index)
00437 {
00438 break;
00439 }
00440 counter++;
00441 }
00442
00443
00444 if (counter==0)
00445 {
00446 mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(epi_nodes)) );
00447 }
00448 if (counter==1)
00449 {
00450 mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(mid_nodes)) );
00451 }
00452 if (counter==2)
00453 {
00454 mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(endo_nodes)) );
00455 }
00456 assert(counter<3);
00457 }
00458 assert(mCellHeterogeneityAreas.size()==3);
00459 }
00460
00461
00462 template class HeartConfigRelatedCellFactory<1u>;
00463 template class HeartConfigRelatedCellFactory<2u>;
00464 template class HeartConfigRelatedCellFactory<3u>;