HeartConfigRelatedCellFactory.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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     }
00142     else
00143     {
00144         assert(ionic_model.Hardcoded().present());
00145         switch(ionic_model.Hardcoded().get())
00146         {
00147             case(cp::ionic_models_available_type::LuoRudyI):
00148             {
00149                 p_cell = new CellLuoRudy1991FromCellML(this->mpSolver, intracellularStimulus);
00150                 break;
00151             }
00152 
00153             case(cp::ionic_models_available_type::LuoRudyIBackwardEuler):
00154             {
00155                 p_cell = new CellLuoRudy1991FromCellMLBackwardEuler(this->mpSolver, intracellularStimulus);
00156                 break;
00157             }
00158 
00159             case(cp::ionic_models_available_type::Fox2002):
00160             {
00161                 p_cell = new CellFoxModel2002FromCellML(this->mpSolver, intracellularStimulus);
00162                 break;
00163             }
00164 
00165             case(cp::ionic_models_available_type::Fox2002BackwardEuler):
00166             {
00167                 p_cell = new CellFoxModel2002FromCellMLBackwardEuler(this->mpSolver, intracellularStimulus);
00168                 break;
00169             }
00170 
00171             case(cp::ionic_models_available_type::DifrancescoNoble):
00172             {
00173                 p_cell = new CellDiFrancescoNoble1985FromCellML(this->mpSolver, intracellularStimulus);
00174                 break;
00175             }
00176 
00177             case(cp::ionic_models_available_type::MahajanShiferaw):
00178             {
00179                 p_cell = new CellMahajan2008FromCellML(this->mpSolver, intracellularStimulus);
00180                 break;
00181             }
00182 
00183             case(cp::ionic_models_available_type::MahajanShiferawBackwardEuler):
00184             {
00185                 p_cell = new CellMahajan2008FromCellMLBackwardEuler(this->mpSolver, intracellularStimulus);
00186                 break;
00187             }
00188 
00189             case(cp::ionic_models_available_type::tenTusscher2006):
00190             {
00191                 p_cell = new CellTenTusscher2006EpiFromCellML(this->mpSolver, intracellularStimulus);
00192                 break;
00193             }
00194 
00195             case(cp::ionic_models_available_type::tenTusscher2006BackwardEuler):
00196             {
00197                 p_cell = new CellTenTusscher2006EpiFromCellMLBackwardEuler(this->mpSolver, intracellularStimulus);
00198                 break;
00199             }
00200 
00201             case(cp::ionic_models_available_type::Maleckar):
00202             {
00203                 p_cell = new CellMaleckar2008FromCellML(this->mpSolver, intracellularStimulus);
00204                 break;
00205             }
00206 
00207             case(cp::ionic_models_available_type::HodgkinHuxley):
00208             {
00209                 p_cell = new CellHodgkinHuxley1952FromCellML(this->mpSolver, intracellularStimulus);
00210                 break;
00211             }
00212 
00213             case(cp::ionic_models_available_type::FaberRudy2000):
00214             {
00215                 p_cell = new CellFaberRudy2000FromCellML(this->mpSolver, intracellularStimulus);
00216                 break;
00217             }
00218 
00219             case(cp::ionic_models_available_type::FaberRudy2000Optimised):
00220             {
00221                 p_cell = new CellFaberRudy2000FromCellMLOpt(this->mpSolver, intracellularStimulus);
00222                 break;
00223             }
00224 
00225             default:
00226             {
00227                //If the ionic model is not in the current enumeration then the XML parser will have picked it up before now!
00228                NEVER_REACHED;
00229             }
00230         }
00231     }
00232 
00233     // Set parameters
00234     try
00235     {
00236         SetCellParameters(p_cell, nodeIndex);
00237     }
00238     catch (const Exception& e)
00239     {
00240         delete p_cell;
00241         throw e;
00242     }
00243     // Generate lookup tables if present
00244     p_cell->GetLookupTableCollection();
00245 
00246     return p_cell;
00247 }
00248 
00249 
00250 template<unsigned SPACE_DIM>
00251 void HeartConfigRelatedCellFactory<SPACE_DIM>::SetCellParameters(AbstractCardiacCellInterface* pCell,
00252                                                                  unsigned nodeIndex)
00253 {
00254     // Special case for backwards-compatibility: scale factors
00255     for (unsigned ht_index = 0;
00256          ht_index < mCellHeterogeneityAreas.size();
00257          ++ht_index)
00258     {
00259         if ( mCellHeterogeneityAreas[ht_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00260         {
00261             try
00262             {
00263                 pCell->SetParameter("ScaleFactorGks", mScaleFactorGks[ht_index]);
00264                 pCell->SetParameter("ScaleFactorGkr", mScaleFactorGkr[ht_index]);
00265                 pCell->SetParameter("ScaleFactorIto", mScaleFactorIto[ht_index]);
00266             }
00267             catch (const Exception&)
00268             {
00269                 // Just ignore missing parameter errors in this case
00270             }
00271         }
00272     }
00273 
00275     if (HeartConfig::Instance()->HasDrugDose())
00276     {
00277         double drug_dose = HeartConfig::Instance()->GetDrugDose();
00278         std::map<std::string, std::pair<double, double> > ic50_values = HeartConfig::Instance()->GetIc50Values();
00279         for (std::map<std::string, std::pair<double, double> >::iterator it = ic50_values.begin();
00280              it != ic50_values.end();
00281              ++it)
00282         {
00283             const std::string param_name = it->first + "_conductance";
00284             if (dynamic_cast<AbstractUntemplatedParameterisedSystem*>(pCell)->HasParameter(param_name))
00285             {
00286                 const double original_conductance = pCell->GetParameter(param_name);
00287                 const double ic50 = it->second.first;
00288                 const double hill = it->second.second;
00289                 const double new_conductance = original_conductance/(1.0 + pow(drug_dose/ic50, hill));
00290                 pCell->SetParameter(param_name, new_conductance);
00291             }
00292             else
00293             {
00294                 WARNING("Cannot apply drug to cell at node " << nodeIndex << " as it has no parameter named '" << param_name << "'.");
00295             }
00296         }
00297     }
00298 
00299     // SetParameter elements go next so they override the old ScaleFactor* elements.
00300     for (unsigned ht_index = 0;
00301          ht_index < mCellHeterogeneityAreas.size();
00302          ++ht_index)
00303     {
00304         if ( mCellHeterogeneityAreas[ht_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00305         {
00306             for (std::map<std::string, double>::iterator param_it = mParameterSettings[ht_index].begin();
00307                  param_it != mParameterSettings[ht_index].end();
00308                  ++param_it)
00309             {
00310                 pCell->SetParameter(param_it->first, param_it->second);
00311             }
00312         }
00313     }
00314 }
00315 
00316 
00317 template<unsigned SPACE_DIM>
00318 void HeartConfigRelatedCellFactory<SPACE_DIM>::SetCellIntracellularStimulus(AbstractCardiacCellInterface* pCell,
00319                                                                             unsigned nodeIndex)
00320 {
00321     boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus());
00322     // Check which of the defined stimuli contain the current node
00323     for (unsigned stimulus_index = 0;
00324          stimulus_index < mStimuliApplied.size();
00325          ++stimulus_index)
00326     {
00327         if ( mStimulatedAreas[stimulus_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00328         {
00329             node_specific_stimulus->AddStimulus(mStimuliApplied[stimulus_index]);
00330         }
00331     }
00332     pCell->SetIntracellularStimulusFunction(node_specific_stimulus);
00333 }
00334 
00335 
00336 template<unsigned SPACE_DIM>
00337 AbstractCardiacCellInterface* HeartConfigRelatedCellFactory<SPACE_DIM>::CreateCardiacCellForTissueNode(Node<SPACE_DIM>* pNode)
00338 {
00339     boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus());
00340 
00341     // Check which of the defined stimuli contain the current node
00342     for (unsigned stimulus_index = 0;
00343          stimulus_index < mStimuliApplied.size();
00344          ++stimulus_index)
00345     {
00346         if ( mStimulatedAreas[stimulus_index]->DoesContain(pNode->GetPoint()) )
00347         {
00348             node_specific_stimulus->AddStimulus(mStimuliApplied[stimulus_index]);
00349         }
00350     }
00351 
00352     unsigned node_index = pNode->GetIndex();
00353     return CreateCellWithIntracellularStimulus(node_specific_stimulus, node_index);
00354 }
00355 
00356 template<unsigned SPACE_DIM>
00357 void HeartConfigRelatedCellFactory<SPACE_DIM>::FillInCellularTransmuralAreas()
00358 {
00359     NEVER_REACHED;
00360 }
00361 
00362 template<>
00363 void HeartConfigRelatedCellFactory<3u>::FillInCellularTransmuralAreas()
00364 {
00365     std::string mesh_file_name = HeartConfig::Instance()->GetMeshName();
00366     //files containing list of nodes on each surface
00367     std::string epi_surface = mesh_file_name + ".epi";
00368     std::string lv_surface = mesh_file_name + ".lv";
00369     std::string rv_surface = mesh_file_name + ".rv";
00370 
00371 
00372     //create the HeartGeometryInformation object
00373     //HeartGeometryInformation<3u> info(mesh, epi_surface, lv_surface, rv_surface, true);
00374     HeartGeometryInformation<3u> info(*(this->GetMesh()), epi_surface, lv_surface, rv_surface, true);
00375 
00376     //We need the fractions of epi and endo layer supplied by the user
00377     double epi_fraction = HeartConfig::Instance()->GetEpiLayerFraction();
00378     double endo_fraction = HeartConfig::Instance()->GetEndoLayerFraction();
00379 
00380     //given the fraction of each layer, compute the distance map and fill in the vector
00381     info.DetermineLayerForEachNode(epi_fraction,endo_fraction);
00382     //get the big heterogeneity vector
00383     std::vector<unsigned> heterogeneity_node_list;
00384     for (unsigned index=0; index<this->GetMesh()->GetNumNodes(); index++)
00385     {
00386         heterogeneity_node_list.push_back(info.rGetLayerForEachNode()[index]);
00387     }
00388 
00389     std::vector<Node<3u>*> epi_nodes;
00390     std::vector<Node<3u>*> mid_nodes;
00391     std::vector<Node<3u>*> endo_nodes;
00392 
00393     //create the list of (pointer to object) nodes in each layer from the heterogeneities vector that was just filled in
00394     for (unsigned node_index = 0; node_index < this->GetMesh()->GetNumNodes(); node_index++)
00395     {
00396         if (this->GetMesh()->GetDistributedVectorFactory()->IsGlobalIndexLocal(node_index) )
00397         {
00398             switch (heterogeneity_node_list[node_index])
00399             {
00400                 //epi
00401                 case 2u:
00402                 {
00403                     epi_nodes.push_back(this->GetMesh()->GetNode(node_index));
00404                     break;
00405                 }
00406                 //mid
00407                 case 1u:
00408                 {
00409                     mid_nodes.push_back(this->GetMesh()->GetNode(node_index));
00410                     break;
00411                 }
00412                 //endo
00413                 case 0u:
00414                 {
00415                     endo_nodes.push_back(this->GetMesh()->GetNode(node_index));
00416                     break;
00417                 }
00418                 default:
00419                 NEVER_REACHED;
00420             }
00421         }
00422     }
00423     //assert((endo_nodes.size()+epi_nodes.size()+mid_nodes.size())==this->GetMesh()->GetNumNodes());
00424 
00425     // now the 3 list of pointer to nodes need to be pushed into the mCellHeterogeneityAreas vector,
00426     // IN THE ORDER PRESCRIBED BY THE USER IN THE XML FILE!
00427     // This is because the corresponding scale factors are already read in that order.
00428 
00429     //these three unsigned tell us in which order the user supplied each layer in the XML file
00430     unsigned user_supplied_epi_index = HeartConfig::Instance()->GetEpiLayerIndex();
00431     unsigned user_supplied_mid_index = HeartConfig::Instance()->GetMidLayerIndex();
00432     unsigned user_supplied_endo_index = HeartConfig::Instance()->GetEndoLayerIndex();
00433 
00434     //these three should have been set to 0, 1 and 2 by HeartConfig::GetCellHeterogeneities
00435     assert(user_supplied_epi_index<3);
00436     assert(user_supplied_mid_index<3);
00437     assert(user_supplied_endo_index<3);
00438 
00439     //pute them in a vector
00440     std::vector<unsigned> user_supplied_indices;
00441     user_supplied_indices.push_back(user_supplied_epi_index);
00442     user_supplied_indices.push_back(user_supplied_mid_index);
00443     user_supplied_indices.push_back(user_supplied_endo_index);
00444 
00445     //figure out who goes first
00446 
00447     //loop three times
00448     for (unsigned layer_index=0; layer_index<3; layer_index++)
00449     {
00450         unsigned counter = 0;
00451         //find the corresponding index
00452         for (unsigned supplied_index = 0; supplied_index<user_supplied_indices.size(); supplied_index++)
00453         {
00454             if (user_supplied_indices[supplied_index] == layer_index)
00455             {
00456                 break;
00457             }
00458             counter++;
00459         }
00460 
00461         //create the node lists based on the calculations above
00462         if (counter==0)
00463         {
00464             mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(epi_nodes)) );
00465         }
00466         if (counter==1)
00467         {
00468             mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(mid_nodes)) );
00469         }
00470         if (counter==2)
00471         {
00472             mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(endo_nodes)) );
00473         }
00474         assert(counter<3);
00475     }
00476     assert(mCellHeterogeneityAreas.size()==3);
00477 }
00478 
00479 // Explicit instantiation
00480 template class HeartConfigRelatedCellFactory<1u>;
00481 template class HeartConfigRelatedCellFactory<2u>;
00482 template class HeartConfigRelatedCellFactory<3u>;

Generated by  doxygen 1.6.2