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                 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     // SetParameter elements go next so they override the old ScaleFactor* elements.
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     // Check which of the defined stimuli contain the current node
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     // Check which of the defined stimuli contain the current node
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     //files containing list of nodes on each surface
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     //create the HeartGeometryInformation object
00355     //HeartGeometryInformation<3u> info(mesh, epi_surface, lv_surface, rv_surface, true);
00356     HeartGeometryInformation<3u> info(*(this->GetMesh()), epi_surface, lv_surface, rv_surface, true);
00357 
00358     //We need the fractions of epi and endo layer supplied by the user
00359     double epi_fraction = HeartConfig::Instance()->GetEpiLayerFraction();
00360     double endo_fraction = HeartConfig::Instance()->GetEndoLayerFraction();
00361 
00362     //given the fraction of each layer, compute the distance map and fill in the vector
00363     info.DetermineLayerForEachNode(epi_fraction,endo_fraction);
00364     //get the big heterogeneity vector
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     //create the list of (pointer to object) nodes in each layer from the heterogeneities vector that was just filled in
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                 //epi
00383                 case 2u:
00384                 {
00385                     epi_nodes.push_back(this->GetMesh()->GetNode(node_index));
00386                     break;
00387                 }
00388                 //mid
00389                 case 1u:
00390                 {
00391                     mid_nodes.push_back(this->GetMesh()->GetNode(node_index));
00392                     break;
00393                 }
00394                 //endo
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     //assert((endo_nodes.size()+epi_nodes.size()+mid_nodes.size())==this->GetMesh()->GetNumNodes());
00406 
00407     // now the 3 list of pointer to nodes need to be pushed into the mCellHeterogeneityAreas vector,
00408     // IN THE ORDER PRESCRIBED BY THE USER IN THE XML FILE!
00409     // This is because the corresponding scale factors are already read in that order.
00410 
00411     //these three unsigned tell us in which order the user supplied each layer in the XML file
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     //these three should have been set to 0, 1 and 2 by HeartConfig::GetCellHeterogeneities
00417     assert(user_supplied_epi_index<3);
00418     assert(user_supplied_mid_index<3);
00419     assert(user_supplied_endo_index<3);
00420 
00421     //pute them in a vector
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     //figure out who goes first
00428 
00429     //loop three times
00430     for (unsigned layer_index=0; layer_index<3; layer_index++)
00431     {
00432         unsigned counter = 0;
00433         //find the corresponding index
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         //create the node lists based on the calculations above
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 // Explicit instantiation
00462 template class HeartConfigRelatedCellFactory<1u>;
00463 template class HeartConfigRelatedCellFactory<2u>;
00464 template class HeartConfigRelatedCellFactory<3u>;

Generated on Tue May 31 14:31:41 2011 for Chaste by  doxygen 1.5.5