HeartConfigRelatedCellFactory.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
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 // This is needed to prevent the chaste_libs=0 build failing on tests that use a dynamically loaded CVODE model
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     // Read and store possible region definitions
00047     HeartConfig::Instance()->GetIonicModelRegions(mIonicModelRegions,
00048                                                   mIonicModelsDefined);
00049 
00050     // Read and store Stimuli
00051     HeartConfig::Instance()->GetStimuli(mStimuliApplied, mStimulatedAreas);
00052 
00053     // if no stimuli provided in XML, need electrodes instead
00054     if (mStimuliApplied.size()==0  &&  (HeartConfig::Instance()->IsElectrodesPresent() == false) )
00055     {
00056          EXCEPTION("Simulation needs a stimulus (either <Stimuli> or <Electrodes>).");
00057     }
00058 
00059     // Read and store Cell Heterogeneities
00060     HeartConfig::Instance()->GetCellHeterogeneities(mCellHeterogeneityAreas,
00061                                                     mScaleFactorGks,
00062                                                     mScaleFactorIto,
00063                                                     mScaleFactorGkr,
00064                                                     &mParameterSettings);
00065 
00066     // Do we need to convert any CellML files?
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         // Load model from shared library
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                //If the ionic model is not in the current enumeration then the XML parser will have picked it up before now!
00208                NEVER_REACHED;
00209             }
00210         }
00211     }
00212 
00213     // Set parameters
00214     try
00215     {
00216         SetCellParameters(p_cell, nodeIndex);
00217     }
00218     catch (const Exception& e)
00219     {
00220         delete p_cell;
00221         throw e;
00222     }
00223     // Generate lookup tables if present
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     // Special case for backwards-compatibility: scale factors
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                 // Just ignore missing parameter errors in this case
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                 WARNING("Cannot apply drug to cell at node " << nodeIndex << " as it has no parameter named '" << param_name << "'.");
00275             }
00276         }
00277     }
00278 
00279     // SetParameter elements go next so they override the old ScaleFactor* elements.
00280     for (unsigned ht_index = 0;
00281          ht_index < mCellHeterogeneityAreas.size();
00282          ++ht_index)
00283     {
00284         if ( mCellHeterogeneityAreas[ht_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00285         {
00286             for (std::map<std::string, double>::iterator param_it = mParameterSettings[ht_index].begin();
00287                  param_it != mParameterSettings[ht_index].end();
00288                  ++param_it)
00289             {
00290                 unsigned param_index = pCell->GetParameterIndex(param_it->first);
00291                 pCell->SetParameter(param_index, param_it->second);
00292             }
00293         }
00294     }
00295 }
00296 
00297 
00298 template<unsigned SPACE_DIM>
00299 void HeartConfigRelatedCellFactory<SPACE_DIM>::SetCellIntracellularStimulus(AbstractCardiacCell* pCell,
00300                                                                             unsigned nodeIndex)
00301 {
00302     boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus());
00303     // Check which of the defined stimuli contain the current node
00304     for (unsigned stimulus_index = 0;
00305          stimulus_index < mStimuliApplied.size();
00306          ++stimulus_index)
00307     {
00308         if ( mStimulatedAreas[stimulus_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00309         {
00310             node_specific_stimulus->AddStimulus(mStimuliApplied[stimulus_index]);
00311         }
00312     }
00313     pCell->SetIntracellularStimulusFunction(node_specific_stimulus);
00314 }
00315 
00316 
00317 template<unsigned SPACE_DIM>
00318 AbstractCardiacCell* HeartConfigRelatedCellFactory<SPACE_DIM>::CreateCardiacCellForTissueNode(unsigned nodeIndex)
00319 {
00320     boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus());
00321 
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 
00333     return CreateCellWithIntracellularStimulus(node_specific_stimulus, nodeIndex);
00334 }
00335 
00336 template<unsigned SPACE_DIM>
00337 void HeartConfigRelatedCellFactory<SPACE_DIM>::FillInCellularTransmuralAreas()
00338 {
00339     NEVER_REACHED;
00340 }
00341 
00342 template<>
00343 void HeartConfigRelatedCellFactory<3u>::FillInCellularTransmuralAreas()
00344 {
00345     std::string mesh_file_name = HeartConfig::Instance()->GetMeshName();
00346     //files containing list of nodes on each surface
00347     std::string epi_surface = mesh_file_name + ".epi";
00348     std::string lv_surface = mesh_file_name + ".lv";
00349     std::string rv_surface = mesh_file_name + ".rv";
00350 
00351 
00352     //create the HeartGeometryInformation object
00353     //HeartGeometryInformation<3u> info(mesh, epi_surface, lv_surface, rv_surface, true);
00354     HeartGeometryInformation<3u> info(*(this->GetMesh()), epi_surface, lv_surface, rv_surface, true);
00355 
00356     //We need the fractions of epi and endo layer supplied by the user
00357     double epi_fraction = HeartConfig::Instance()->GetEpiLayerFraction();
00358     double endo_fraction = HeartConfig::Instance()->GetEndoLayerFraction();
00359 
00360     //given the fraction of each layer, compute the distance map and fill in the vector
00361     info.DetermineLayerForEachNode(epi_fraction,endo_fraction);
00362     //get the big heterogeneity vector
00363     std::vector<unsigned> heterogeneity_node_list;
00364     for (unsigned index=0; index<this->GetMesh()->GetNumNodes(); index++)
00365     {
00366         heterogeneity_node_list.push_back(info.rGetLayerForEachNode()[index]);
00367     }
00368 
00369     std::vector<Node<3u>*> epi_nodes;
00370     std::vector<Node<3u>*> mid_nodes;
00371     std::vector<Node<3u>*> endo_nodes;
00372 
00373     //create the list of (pointer to object) nodes in each layer from the heterogeneities vector that was just filled in
00374     for (unsigned node_index = 0; node_index < this->GetMesh()->GetNumNodes(); node_index++)
00375     {
00376         if (this->GetMesh()->GetDistributedVectorFactory()->IsGlobalIndexLocal(node_index) )
00377         {
00378             switch (heterogeneity_node_list[node_index])
00379             {
00380                 //epi
00381                 case 2u:
00382                 {
00383                     epi_nodes.push_back(this->GetMesh()->GetNode(node_index));
00384                     break;
00385                 }
00386                 //mid
00387                 case 1u:
00388                 {
00389                     mid_nodes.push_back(this->GetMesh()->GetNode(node_index));
00390                     break;
00391                 }
00392                 //endo
00393                 case 0u:
00394                 {
00395                     endo_nodes.push_back(this->GetMesh()->GetNode(node_index));
00396                     break;
00397                 }
00398                 default:
00399                 NEVER_REACHED;
00400             }
00401         }
00402     }
00403     //assert((endo_nodes.size()+epi_nodes.size()+mid_nodes.size())==this->GetMesh()->GetNumNodes());
00404 
00405     // now the 3 list of pointer to nodes need to be pushed into the mCellHeterogeneityAreas vector,
00406     // IN THE ORDER PRESCRIBED BY THE USER IN THE XML FILE!
00407     // This is because the corresponding scale factors are already read in that order.
00408 
00409     //these three unsigned tell us in which order the user supplied each layer in the XML file
00410     unsigned user_supplied_epi_index = HeartConfig::Instance()->GetEpiLayerIndex();
00411     unsigned user_supplied_mid_index = HeartConfig::Instance()->GetMidLayerIndex();
00412     unsigned user_supplied_endo_index = HeartConfig::Instance()->GetEndoLayerIndex();
00413 
00414     //these three should have been set to 0, 1 and 2 by HeartConfig::GetCellHeterogeneities
00415     assert(user_supplied_epi_index<3);
00416     assert(user_supplied_mid_index<3);
00417     assert(user_supplied_endo_index<3);
00418 
00419     //pute them in a vector
00420     std::vector<unsigned> user_supplied_indices;
00421     user_supplied_indices.push_back(user_supplied_epi_index);
00422     user_supplied_indices.push_back(user_supplied_mid_index);
00423     user_supplied_indices.push_back(user_supplied_endo_index);
00424 
00425     //figure out who goes first
00426 
00427     //loop three times
00428     for (unsigned layer_index=0; layer_index<3; layer_index++)
00429     {
00430         unsigned counter = 0;
00431         //find the corresponding index
00432         for (unsigned supplied_index = 0; supplied_index<user_supplied_indices.size(); supplied_index++)
00433         {
00434             if (user_supplied_indices[supplied_index] == layer_index)
00435             {
00436                 break;
00437             }
00438             counter++;
00439         }
00440 
00441         //create the node lists based on the calculations above
00442         if (counter==0)
00443         {
00444             mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(epi_nodes)) );
00445         }
00446         if (counter==1)
00447         {
00448             mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(mid_nodes)) );
00449         }
00450         if (counter==2)
00451         {
00452             mCellHeterogeneityAreas.push_back(boost::shared_ptr<AbstractChasteRegion<3u> >(new ChasteNodesList<3u>(endo_nodes)) );
00453         }
00454         assert(counter<3);
00455     }
00456     assert(mCellHeterogeneityAreas.size()==3);
00457 }
00458 
00459 // Explicit instantiation
00460 template class HeartConfigRelatedCellFactory<1u>;
00461 template class HeartConfigRelatedCellFactory<2u>;
00462 template class HeartConfigRelatedCellFactory<3u>;
Generated on Thu Dec 22 13:00:06 2011 for Chaste by  doxygen 1.6.3