Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 00036 #include "HeartConfigRelatedCellFactory.hpp" 00037 00038 #include <sstream> 00039 #include "HeartGeometryInformation.hpp" 00040 #include "ChasteNodesList.hpp" 00041 #include "HeartFileFinder.hpp" 00042 #include "CellMLToSharedLibraryConverter.hpp" 00043 #include "AbstractCardiacCellInterface.hpp" 00044 #include "Warnings.hpp" 00045 // This is needed to prevent the chaste_libs=0 build failing 00046 // on tests that use a dynamically loaded CVODE model 00047 #include "AbstractCvodeCell.hpp" 00048 00049 template<unsigned SPACE_DIM> 00050 HeartConfigRelatedCellFactory<SPACE_DIM>::HeartConfigRelatedCellFactory() 00051 : AbstractCardiacCellFactory<SPACE_DIM>(), 00052 mDefaultIonicModel(HeartConfig::Instance()->GetDefaultIonicModel()) 00053 { 00054 // Read and store possible region definitions 00055 HeartConfig::Instance()->GetIonicModelRegions(mIonicModelRegions, 00056 mIonicModelsDefined); 00057 00058 // Read and store Stimuli 00059 HeartConfig::Instance()->GetStimuli(mStimuliApplied, mStimulatedAreas); 00060 00061 // if no stimuli provided in XML, need electrodes instead 00062 if (mStimuliApplied.size()==0 && (HeartConfig::Instance()->IsElectrodesPresent() == false) ) 00063 { 00064 EXCEPTION("Simulation needs a stimulus (either <Stimuli> or <Electrodes>)."); 00065 } 00066 00067 // Read and store Cell Heterogeneities 00068 HeartConfig::Instance()->GetCellHeterogeneities(mCellHeterogeneityAreas, 00069 mScaleFactorGks, 00070 mScaleFactorIto, 00071 mScaleFactorGkr, 00072 &mParameterSettings); 00073 00074 // Do we need to convert any CellML files? 00075 PreconvertCellmlFiles(); 00076 } 00077 00078 template<unsigned SPACE_DIM> 00079 void HeartConfigRelatedCellFactory<SPACE_DIM>::PreconvertCellmlFiles() 00080 { 00081 if (mDefaultIonicModel.Dynamic().present()) 00082 { 00083 LoadDynamicModel(mDefaultIonicModel, true); 00084 } 00085 for (unsigned i=0; i<mIonicModelsDefined.size(); i++) 00086 { 00087 if (mIonicModelsDefined[i].Dynamic().present()) 00088 { 00089 LoadDynamicModel(mIonicModelsDefined[i], true); 00090 } 00091 } 00092 } 00093 00094 template<unsigned SPACE_DIM> 00095 DynamicCellModelLoaderPtr HeartConfigRelatedCellFactory<SPACE_DIM>::LoadDynamicModel( 00096 const cp::ionic_model_selection_type& rModel, 00097 bool isCollective) 00098 { 00099 assert(rModel.Dynamic().present()); 00100 HeartFileFinder file_finder(rModel.Dynamic()->Path()); 00101 CellMLToSharedLibraryConverter converter; 00102 return converter.Convert(file_finder, isCollective); 00103 } 00104 00105 template<unsigned SPACE_DIM> 00106 HeartConfigRelatedCellFactory<SPACE_DIM>::~HeartConfigRelatedCellFactory() 00107 { 00108 } 00109 00110 template<unsigned SPACE_DIM> 00111 AbstractCardiacCellInterface* HeartConfigRelatedCellFactory<SPACE_DIM>::CreateCellWithIntracellularStimulus( 00112 boost::shared_ptr<AbstractStimulusFunction> intracellularStimulus, 00113 unsigned nodeIndex) 00114 { 00115 cp::ionic_model_selection_type ionic_model = mDefaultIonicModel; 00116 00117 for (unsigned ionic_model_region_index = 0; 00118 ionic_model_region_index < mIonicModelRegions.size(); 00119 ++ionic_model_region_index) 00120 { 00121 if ( mIonicModelRegions[ionic_model_region_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) ) 00122 { 00123 ionic_model = mIonicModelsDefined[ionic_model_region_index]; 00124 break; 00125 } 00126 } 00127 00128 AbstractCardiacCellInterface* p_cell = NULL; 00129 00130 if (ionic_model.Dynamic().present()) 00131 { 00132 #ifndef CHASTE_CAN_CHECKPOINT_DLLS 00133 if (HeartConfig::Instance()->GetCheckpointSimulation()) 00134 { 00135 EXCEPTION("Checkpointing is not compatible with dynamically loaded cell models on Boost<1.37."); 00136 } 00137 #endif // CHASTE_CAN_CHECKPOINT_DLLS 00138 // Load model from shared library 00139 DynamicCellModelLoaderPtr p_loader = LoadDynamicModel(ionic_model, false); 00140 p_cell = p_loader->CreateCell(this->mpSolver, intracellularStimulus); 00141 if (!dynamic_cast<AbstractCardiacCell*>(p_cell)) 00142 { 00143 delete p_cell; 00144 EXCEPTION("CVODE cannot be used as a cell model solver in tissue simulations: do not use the --cvode flag."); 00145 } 00146 } 00147 else 00148 { 00149 assert(ionic_model.Hardcoded().present()); 00150 switch(ionic_model.Hardcoded().get()) 00151 { 00152 case(cp::ionic_models_available_type::LuoRudyI): 00153 { 00154 p_cell = new CellLuoRudy1991FromCellML(this->mpSolver, intracellularStimulus); 00155 break; 00156 } 00157 00158 case(cp::ionic_models_available_type::LuoRudyIBackwardEuler): 00159 { 00160 p_cell = new CellLuoRudy1991FromCellMLBackwardEuler(this->mpSolver, intracellularStimulus); 00161 break; 00162 } 00163 00164 case(cp::ionic_models_available_type::Fox2002): 00165 { 00166 p_cell = new CellFoxModel2002FromCellML(this->mpSolver, intracellularStimulus); 00167 break; 00168 } 00169 00170 case(cp::ionic_models_available_type::Fox2002BackwardEuler): 00171 { 00172 p_cell = new CellFoxModel2002FromCellMLBackwardEuler(this->mpSolver, intracellularStimulus); 00173 break; 00174 } 00175 00176 case(cp::ionic_models_available_type::DifrancescoNoble): 00177 { 00178 p_cell = new CellDiFrancescoNoble1985FromCellML(this->mpSolver, intracellularStimulus); 00179 break; 00180 } 00181 00182 case(cp::ionic_models_available_type::MahajanShiferaw): 00183 { 00184 p_cell = new CellMahajan2008FromCellML(this->mpSolver, intracellularStimulus); 00185 break; 00186 } 00187 00188 case(cp::ionic_models_available_type::MahajanShiferawBackwardEuler): 00189 { 00190 p_cell = new CellMahajan2008FromCellMLBackwardEuler(this->mpSolver, intracellularStimulus); 00191 break; 00192 } 00193 00194 case(cp::ionic_models_available_type::tenTusscher2006): 00195 { 00196 p_cell = new CellTenTusscher2006EpiFromCellML(this->mpSolver, intracellularStimulus); 00197 break; 00198 } 00199 00200 case(cp::ionic_models_available_type::tenTusscher2006BackwardEuler): 00201 { 00202 p_cell = new CellTenTusscher2006EpiFromCellMLBackwardEuler(this->mpSolver, intracellularStimulus); 00203 break; 00204 } 00205 00206 case(cp::ionic_models_available_type::Maleckar): 00207 { 00208 p_cell = new CellMaleckar2008FromCellML(this->mpSolver, intracellularStimulus); 00209 break; 00210 } 00211 00212 case(cp::ionic_models_available_type::HodgkinHuxley): 00213 { 00214 p_cell = new CellHodgkinHuxley1952FromCellML(this->mpSolver, intracellularStimulus); 00215 break; 00216 } 00217 00218 case(cp::ionic_models_available_type::FaberRudy2000): 00219 { 00220 p_cell = new CellFaberRudy2000FromCellML(this->mpSolver, intracellularStimulus); 00221 break; 00222 } 00223 00224 case(cp::ionic_models_available_type::FaberRudy2000Optimised): 00225 { 00226 p_cell = new CellFaberRudy2000FromCellMLOpt(this->mpSolver, intracellularStimulus); 00227 break; 00228 } 00229 00230 default: 00231 { 00232 //If the ionic model is not in the current enumeration then the XML parser will have picked it up before now! 00233 NEVER_REACHED; 00234 } 00235 } 00236 } 00237 00238 // Set parameters 00239 try 00240 { 00241 SetCellParameters(p_cell, nodeIndex); 00242 } 00243 catch (const Exception& e) 00244 { 00245 delete p_cell; 00246 throw e; 00247 } 00248 // Generate lookup tables if present 00249 p_cell->GetLookupTableCollection(); 00250 00251 return p_cell; 00252 } 00253 00254 00255 template<unsigned SPACE_DIM> 00256 void HeartConfigRelatedCellFactory<SPACE_DIM>::SetCellParameters(AbstractCardiacCellInterface* pCell, 00257 unsigned nodeIndex) 00258 { 00259 // Special case for backwards-compatibility: scale factors 00260 for (unsigned ht_index = 0; 00261 ht_index < mCellHeterogeneityAreas.size(); 00262 ++ht_index) 00263 { 00264 if ( mCellHeterogeneityAreas[ht_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) ) 00265 { 00266 try 00267 { 00268 pCell->SetParameter("ScaleFactorGks", mScaleFactorGks[ht_index]); 00269 pCell->SetParameter("ScaleFactorGkr", mScaleFactorGkr[ht_index]); 00270 pCell->SetParameter("ScaleFactorIto", mScaleFactorIto[ht_index]); 00271 } 00272 catch (const Exception& e) 00273 { 00274 // Just ignore missing parameter errors in this case 00275 } 00276 } 00277 } 00278 00280 if (HeartConfig::Instance()->HasDrugDose()) 00281 { 00282 double drug_dose = HeartConfig::Instance()->GetDrugDose(); 00283 std::map<std::string, std::pair<double, double> > ic50_values = HeartConfig::Instance()->GetIc50Values(); 00284 for (std::map<std::string, std::pair<double, double> >::iterator it = ic50_values.begin(); 00285 it != ic50_values.end(); 00286 ++it) 00287 { 00288 const std::string param_name = it->first + "_conductance"; 00289 if (dynamic_cast<AbstractUntemplatedParameterisedSystem*>(pCell)->HasParameter(param_name)) 00290 { 00291 const double original_conductance = pCell->GetParameter(param_name); 00292 const double ic50 = it->second.first; 00293 const double hill = it->second.second; 00294 const double new_conductance = original_conductance/(1.0 + pow(drug_dose/ic50, hill)); 00295 pCell->SetParameter(param_name, new_conductance); 00296 } 00297 else 00298 { 00299 WARNING("Cannot apply drug to cell at node " << nodeIndex << " as it has no parameter named '" << param_name << "'."); 00300 } 00301 } 00302 } 00303 00304 // SetParameter elements go next so they override the old ScaleFactor* elements. 00305 for (unsigned ht_index = 0; 00306 ht_index < mCellHeterogeneityAreas.size(); 00307 ++ht_index) 00308 { 00309 if ( mCellHeterogeneityAreas[ht_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) ) 00310 { 00311 for (std::map<std::string, double>::iterator param_it = mParameterSettings[ht_index].begin(); 00312 param_it != mParameterSettings[ht_index].end(); 00313 ++param_it) 00314 { 00315 pCell->SetParameter(param_it->first, param_it->second); 00316 } 00317 } 00318 } 00319 } 00320 00321 00322 template<unsigned SPACE_DIM> 00323 void HeartConfigRelatedCellFactory<SPACE_DIM>::SetCellIntracellularStimulus(AbstractCardiacCellInterface* pCell, 00324 unsigned nodeIndex) 00325 { 00326 boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus()); 00327 // Check which of the defined stimuli contain the current node 00328 for (unsigned stimulus_index = 0; 00329 stimulus_index < mStimuliApplied.size(); 00330 ++stimulus_index) 00331 { 00332 if ( mStimulatedAreas[stimulus_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) ) 00333 { 00334 node_specific_stimulus->AddStimulus(mStimuliApplied[stimulus_index]); 00335 } 00336 } 00337 pCell->SetIntracellularStimulusFunction(node_specific_stimulus); 00338 } 00339 00340 00341 template<unsigned SPACE_DIM> 00342 AbstractCardiacCellInterface* HeartConfigRelatedCellFactory<SPACE_DIM>::CreateCardiacCellForTissueNode(unsigned nodeIndex) 00343 { 00344 boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus()); 00345 00346 // Check which of the defined stimuli contain the current node 00347 for (unsigned stimulus_index = 0; 00348 stimulus_index < mStimuliApplied.size(); 00349 ++stimulus_index) 00350 { 00351 if ( mStimulatedAreas[stimulus_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) ) 00352 { 00353 node_specific_stimulus->AddStimulus(mStimuliApplied[stimulus_index]); 00354 } 00355 } 00356 00357 return CreateCellWithIntracellularStimulus(node_specific_stimulus, nodeIndex); 00358 } 00359 00360 template<unsigned SPACE_DIM> 00361 void HeartConfigRelatedCellFactory<SPACE_DIM>::FillInCellularTransmuralAreas() 00362 { 00363 NEVER_REACHED; 00364 } 00365 00366 template<> 00367 void HeartConfigRelatedCellFactory<3u>::FillInCellularTransmuralAreas() 00368 { 00369 std::string mesh_file_name = HeartConfig::Instance()->GetMeshName(); 00370 //files containing list of nodes on each surface 00371 std::string epi_surface = mesh_file_name + ".epi"; 00372 std::string lv_surface = mesh_file_name + ".lv"; 00373 std::string rv_surface = mesh_file_name + ".rv"; 00374 00375 00376 //create the HeartGeometryInformation object 00377 //HeartGeometryInformation<3u> info(mesh, epi_surface, lv_surface, rv_surface, true); 00378 HeartGeometryInformation<3u> info(*(this->GetMesh()), epi_surface, lv_surface, rv_surface, true); 00379 00380 //We need the fractions of epi and endo layer supplied by the user 00381 double epi_fraction = HeartConfig::Instance()->GetEpiLayerFraction(); 00382 double endo_fraction = HeartConfig::Instance()->GetEndoLayerFraction(); 00383 00384 //given the fraction of each layer, compute the distance map and fill in the vector 00385 info.DetermineLayerForEachNode(epi_fraction,endo_fraction); 00386 //get the big heterogeneity vector 00387 std::vector<unsigned> heterogeneity_node_list; 00388 for (unsigned index=0; index<this->GetMesh()->GetNumNodes(); index++) 00389 { 00390 heterogeneity_node_list.push_back(info.rGetLayerForEachNode()[index]); 00391 } 00392 00393 std::vector<Node<3u>*> epi_nodes; 00394 std::vector<Node<3u>*> mid_nodes; 00395 std::vector<Node<3u>*> endo_nodes; 00396 00397 //create the list of (pointer to object) nodes in each layer from the heterogeneities vector that was just filled in 00398 for (unsigned node_index = 0; node_index < this->GetMesh()->GetNumNodes(); node_index++) 00399 { 00400 if (this->GetMesh()->GetDistributedVectorFactory()->IsGlobalIndexLocal(node_index) ) 00401 { 00402 switch (heterogeneity_node_list[node_index]) 00403 { 00404 //epi 00405 case 2u: 00406 { 00407 epi_nodes.push_back(this->GetMesh()->GetNode(node_index)); 00408 break; 00409 } 00410 //mid 00411 case 1u: 00412 { 00413 mid_nodes.push_back(this->GetMesh()->GetNode(node_index)); 00414 break; 00415 } 00416 //endo 00417 case 0u: 00418 { 00419 endo_nodes.push_back(this->GetMesh()->GetNode(node_index)); 00420 break; 00421 } 00422 default: 00423 NEVER_REACHED; 00424 } 00425 } 00426 } 00427 //assert((endo_nodes.size()+epi_nodes.size()+mid_nodes.size())==this->GetMesh()->GetNumNodes()); 00428 00429 // now the 3 list of pointer to nodes need to be pushed into the mCellHeterogeneityAreas vector, 00430 // IN THE ORDER PRESCRIBED BY THE USER IN THE XML FILE! 00431 // This is because the corresponding scale factors are already read in that order. 00432 00433 //these three unsigned tell us in which order the user supplied each layer in the XML file 00434 unsigned user_supplied_epi_index = HeartConfig::Instance()->GetEpiLayerIndex(); 00435 unsigned user_supplied_mid_index = HeartConfig::Instance()->GetMidLayerIndex(); 00436 unsigned user_supplied_endo_index = HeartConfig::Instance()->GetEndoLayerIndex(); 00437 00438 //these three should have been set to 0, 1 and 2 by HeartConfig::GetCellHeterogeneities 00439 assert(user_supplied_epi_index<3); 00440 assert(user_supplied_mid_index<3); 00441 assert(user_supplied_endo_index<3); 00442 00443 //pute them in a vector 00444 std::vector<unsigned> user_supplied_indices; 00445 user_supplied_indices.push_back(user_supplied_epi_index); 00446 user_supplied_indices.push_back(user_supplied_mid_index); 00447 user_supplied_indices.push_back(user_supplied_endo_index); 00448 00449 //figure out who goes first 00450 00451 //loop three times 00452 for (unsigned layer_index=0; layer_index<3; layer_index++) 00453 { 00454 unsigned counter = 0; 00455 //find the corresponding index 00456 for (unsigned supplied_index = 0; supplied_index<user_supplied_indices.size(); supplied_index++) 00457 { 00458 if (user_supplied_indices[supplied_index] == layer_index) 00459 { 00460 break; 00461 } 00462 counter++; 00463 } 00464 00465 //create the node lists based on the calculations above 00466 if (counter==0) 00467 { 00468 mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(epi_nodes)) ); 00469 } 00470 if (counter==1) 00471 { 00472 mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(mid_nodes)) ); 00473 } 00474 if (counter==2) 00475 { 00476 mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(endo_nodes)) ); 00477 } 00478 assert(counter<3); 00479 } 00480 assert(mCellHeterogeneityAreas.size()==3); 00481 } 00482 00483 // Explicit instantiation 00484 template class HeartConfigRelatedCellFactory<1u>; 00485 template class HeartConfigRelatedCellFactory<2u>; 00486 template class HeartConfigRelatedCellFactory<3u>;