HeartConfigRelatedCellFactory.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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 #include "HeartGeometryInformation.hpp"
00031 #include "ChasteNodesList.hpp"
00032 #include "HeartFileFinder.hpp"
00033 #include "CellMLToSharedLibraryConverter.hpp"
00034 #include "AbstractCardiacCellInterface.hpp"
00035 // This is needed to prevent the chaste_libs=0 build failing on tests that use a dynamically loaded CVODE model
00036 #include "AbstractCvodeCell.hpp"
00037 
00038 template<unsigned SPACE_DIM>
00039 HeartConfigRelatedCellFactory<SPACE_DIM>::HeartConfigRelatedCellFactory()
00040     : AbstractCardiacCellFactory<SPACE_DIM>(),
00041       mDefaultIonicModel(HeartConfig::Instance()->GetDefaultIonicModel())
00042 {
00043     // Read and store possible region definitions
00044     HeartConfig::Instance()->GetIonicModelRegions(mIonicModelRegions,
00045                                                   mIonicModelsDefined);
00046 
00047     // Read and store Stimuli
00048     try
00049     {
00050         HeartConfig::Instance()->GetStimuli(mStimuliApplied, mStimulatedAreas);
00051     }
00052     catch (Exception& e)
00053     {
00054         // No stimuli provided in XML - let's hope that there are some electrodes instead
00055         if(HeartConfig::Instance()->IsElectrodesPresent() == false)
00056         {
00057             EXCEPTION("Simulation needs a stimulus (either <Stimuli> or <Electrodes>).");
00058         }
00059     }
00060 
00061     // Read and store Cell Heterogeneities
00062     try
00063     {
00064         HeartConfig::Instance()->GetCellHeterogeneities(mCellHeterogeneityAreas,
00065                                                         mScaleFactorGks,
00066                                                         mScaleFactorIto,
00067                                                         mScaleFactorGkr,
00068                                                         &mParameterSettings);
00069     }
00070     catch (Exception& e)
00071     {
00072         // No cell heterogeneities provided
00073     }
00074 
00075     // Do we need to convert any CellML files?
00076     PreconvertCellmlFiles();
00077 }
00078 
00079 template<unsigned SPACE_DIM>
00080 void HeartConfigRelatedCellFactory<SPACE_DIM>::PreconvertCellmlFiles()
00081 {
00082     if (mDefaultIonicModel.Dynamic().present())
00083     {
00084         LoadDynamicModel(mDefaultIonicModel, true);
00085     }
00086     for (unsigned i=0; i<mIonicModelsDefined.size(); i++)
00087     {
00088         if (mIonicModelsDefined[i].Dynamic().present())
00089         {
00090             LoadDynamicModel(mIonicModelsDefined[i], true);
00091         }
00092     }
00093 }
00094 
00095 template<unsigned SPACE_DIM>
00096 DynamicCellModelLoader* HeartConfigRelatedCellFactory<SPACE_DIM>::LoadDynamicModel(
00097         const cp::ionic_model_selection_type& rModel,
00098         bool isCollective)
00099 {
00100     assert(rModel.Dynamic().present());
00101     HeartFileFinder file_finder(rModel.Dynamic()->Path());
00102     CellMLToSharedLibraryConverter converter;
00103     return converter.Convert(file_finder, isCollective);
00104 }
00105 
00106 template<unsigned SPACE_DIM>
00107 HeartConfigRelatedCellFactory<SPACE_DIM>::~HeartConfigRelatedCellFactory()
00108 {
00109     for (unsigned i = 0; i<mCellHeterogeneityAreas.size();i++)
00110     {
00111         delete mCellHeterogeneityAreas[i];
00112     }
00113 }
00114 
00115 template<unsigned SPACE_DIM>
00116 AbstractCardiacCell* HeartConfigRelatedCellFactory<SPACE_DIM>::CreateCellWithIntracellularStimulus(
00117         boost::shared_ptr<AbstractStimulusFunction> intracellularStimulus,
00118         unsigned nodeIndex)
00119 {
00120     cp::ionic_model_selection_type ionic_model = mDefaultIonicModel;
00121 
00122     for (unsigned ionic_model_region_index = 0;
00123          ionic_model_region_index < mIonicModelRegions.size();
00124          ++ionic_model_region_index)
00125     {
00126         if ( mIonicModelRegions[ionic_model_region_index].DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00127         {
00128             ionic_model = mIonicModelsDefined[ionic_model_region_index];
00129             break;
00130         }
00131     }
00132     
00133     AbstractCardiacCell* p_cell = NULL;
00134 
00135     if (ionic_model.Dynamic().present())
00136     {
00137 #ifndef CHASTE_CAN_CHECKPOINT_DLLS
00138         if (HeartConfig::Instance()->GetCheckpointSimulation())
00139         {
00140             EXCEPTION("Checkpointing is not compatible with dynamically loaded cell models on Boost<1.37.");
00141         }
00142 #endif // CHASTE_CAN_CHECKPOINT_DLLS
00143         // Load model from shared library
00144         DynamicCellModelLoader* p_loader = LoadDynamicModel(ionic_model, false);
00145         AbstractCardiacCellInterface* p_loaded_cell = p_loader->CreateCell(this->mpSolver, intracellularStimulus);
00146         p_cell = dynamic_cast<AbstractCardiacCell*>(p_loaded_cell);
00147         if (!p_cell)
00148         {
00149             delete p_loaded_cell;
00150             EXCEPTION("CVODE cannot be used as a cell model solver in tissue simulations: do not use the --cvode flag.");
00151         }
00152     }
00153     else
00154     {
00155         assert(ionic_model.Hardcoded().present());
00156         switch(ionic_model.Hardcoded().get())
00157         {
00158             case(cp::ionic_models_available_type::LuoRudyI):
00159             {
00160                 p_cell = new CellLuoRudy1991FromCellML(this->mpSolver, intracellularStimulus);
00161                 break;
00162             }
00163 
00164             case(cp::ionic_models_available_type::LuoRudyIBackwardEuler):
00165             {
00166                 p_cell = new CellLuoRudy1991FromCellMLBackwardEuler(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::tenTusscher2006):
00189             {
00190                 p_cell = new CellTenTusscher2006EpiFromCellML(this->mpSolver, intracellularStimulus);
00191                 break;
00192             }
00193 
00194             case(cp::ionic_models_available_type::Maleckar):
00195             {
00196                 p_cell = new CellMaleckar2008FromCellML(this->mpSolver, intracellularStimulus);
00197                 break;
00198             }
00199 
00200             case(cp::ionic_models_available_type::HodgkinHuxley):
00201             {
00202                 p_cell = new CellHodgkinHuxley1952FromCellML(this->mpSolver, intracellularStimulus);
00203                 break;
00204             }
00205 
00206             case(cp::ionic_models_available_type::FaberRudy2000):
00207             {
00208                 p_cell = new CellFaberRudy2000FromCellML(this->mpSolver, intracellularStimulus);
00209                 break;
00210             }
00211 
00212             case(cp::ionic_models_available_type::FaberRudy2000Optimised):
00213             {
00214                 p_cell = new CellFaberRudy2000FromCellMLOpt(this->mpSolver, intracellularStimulus);
00215                 break;
00216             }
00217 
00218             default:
00219             {
00220                //If the ionic model is not in the current enumeration then the XML parser will have picked it up before now!
00221                NEVER_REACHED;
00222             }
00223         }
00224     }
00225     
00226     // Set parameters
00227     try
00228     {
00229         SetCellParameters(p_cell, nodeIndex);
00230     }
00231     catch (const Exception& e)
00232     {
00233         delete p_cell;
00234         throw e;
00235     }
00236 
00237     return p_cell;
00238 }
00239 
00240 
00241 template<unsigned SPACE_DIM>
00242 void HeartConfigRelatedCellFactory<SPACE_DIM>::SetCellParameters(AbstractCardiacCell* pCell,
00243                                                                  unsigned nodeIndex)
00244 {
00245     // Special case for backwards-compatibility: scale factors
00246     for (unsigned ht_index = 0;
00247          ht_index < mCellHeterogeneityAreas.size();
00248          ++ht_index)
00249     {
00250         if ( mCellHeterogeneityAreas[ht_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00251         {
00252             try
00253             {
00254                 pCell->SetParameter("ScaleFactorGks", mScaleFactorGks[ht_index]);
00255                 pCell->SetParameter("ScaleFactorGkr", mScaleFactorGkr[ht_index]);
00256                 pCell->SetParameter("ScaleFactorIto", mScaleFactorIto[ht_index]);
00257             }
00258             catch (const Exception& e)
00259             {
00260                 // Just ignore missing parameter errors in this case
00261             }
00262         }
00263     }
00264     // SetParameter elements go next so they override the old ScaleFactor* elements.
00265     for (unsigned ht_index = 0;
00266          ht_index < mCellHeterogeneityAreas.size();
00267          ++ht_index)
00268     {
00269         if ( mCellHeterogeneityAreas[ht_index]->DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00270         {
00271             for (std::map<std::string, double>::iterator param_it = mParameterSettings[ht_index].begin();
00272                  param_it != mParameterSettings[ht_index].end();
00273                  ++param_it)
00274             {
00275                 unsigned param_index = pCell->GetParameterIndex(param_it->first);
00276                 pCell->SetParameter(param_index, param_it->second);
00277             }
00278         }
00279     }
00280 }
00281 
00282 
00283 template<unsigned SPACE_DIM>
00284 void HeartConfigRelatedCellFactory<SPACE_DIM>::SetCellIntracellularStimulus(AbstractCardiacCell* pCell,
00285                                                                             unsigned nodeIndex)
00286 {
00287     boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus());
00288     // Check which of the defined stimuli contain the current node
00289     for (unsigned stimulus_index = 0;
00290          stimulus_index < mStimuliApplied.size();
00291          ++stimulus_index)
00292     {
00293         if ( mStimulatedAreas[stimulus_index].DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00294         {
00295             node_specific_stimulus->AddStimulus(mStimuliApplied[stimulus_index]);
00296         }
00297     }
00298     pCell->SetIntracellularStimulusFunction(node_specific_stimulus);
00299 }
00300 
00301 
00302 template<unsigned SPACE_DIM>
00303 AbstractCardiacCell* HeartConfigRelatedCellFactory<SPACE_DIM>::CreateCardiacCellForTissueNode(unsigned nodeIndex)
00304 {
00305     boost::shared_ptr<MultiStimulus> node_specific_stimulus(new MultiStimulus());
00306 
00307     // Check which of the defined stimuli contain the current node
00308     for (unsigned stimulus_index = 0;
00309          stimulus_index < mStimuliApplied.size();
00310          ++stimulus_index)
00311     {
00312         if ( mStimulatedAreas[stimulus_index].DoesContain(this->GetMesh()->GetNode(nodeIndex)->GetPoint()) )
00313         {
00314             node_specific_stimulus->AddStimulus(mStimuliApplied[stimulus_index]);
00315         }
00316     }
00317 
00318     return CreateCellWithIntracellularStimulus(node_specific_stimulus, nodeIndex);
00319 }
00320 
00321 template<unsigned SPACE_DIM>
00322 void HeartConfigRelatedCellFactory<SPACE_DIM>::FillInCellularTransmuralAreas()
00323 {
00324     NEVER_REACHED;
00325 }
00326 
00327 template<>
00328 void HeartConfigRelatedCellFactory<3u>::FillInCellularTransmuralAreas()
00329 {
00330     std::string mesh_file_name = HeartConfig::Instance()->GetMeshName();
00331     //files containing list of nodes on each surface
00332     std::string epi_surface = mesh_file_name + ".epi";
00333     std::string lv_surface = mesh_file_name + ".lv";
00334     std::string rv_surface = mesh_file_name + ".rv";
00335 
00336 
00337     //create the HeartGeometryInformation object
00338     //HeartGeometryInformation<3u> info(mesh, epi_surface, lv_surface, rv_surface, true);
00339     HeartGeometryInformation<3u> info(*(this->GetMesh()), epi_surface, lv_surface, rv_surface, true);
00340 
00341     //We need the fractions of epi and endo layer supplied by the user
00342     double epi_fraction = HeartConfig::Instance()->GetEpiLayerFraction();
00343     double endo_fraction = HeartConfig::Instance()->GetEndoLayerFraction();
00344 
00345     //given the fraction of each layer, compute the distance map and fill in the vector
00346     info.DetermineLayerForEachNode(epi_fraction,endo_fraction);
00347     //get the big heterogeneity vector
00348     std::vector<unsigned> heterogeneity_node_list;
00349     for (unsigned index=0; index<this->GetMesh()->GetNumNodes(); index++)
00350     {
00351         heterogeneity_node_list.push_back(info.rGetLayerForEachNode()[index]);
00352     }
00353 
00354     std::vector<Node<3u>*> epi_nodes;
00355     std::vector<Node<3u>*> mid_nodes;
00356     std::vector<Node<3u>*> endo_nodes;
00357 
00358     //create the list of (pointer to object) nodes in each layer from the heterogeneities vector that was just filled in
00359     for (unsigned node_index = 0; node_index < this->GetMesh()->GetNumNodes(); node_index++)
00360     {
00361         if (this->GetMesh()->GetDistributedVectorFactory()->IsGlobalIndexLocal(node_index) )
00362         {
00363             switch (heterogeneity_node_list[node_index])
00364             {
00365                 //epi
00366                 case 2u:
00367                 {
00368                     epi_nodes.push_back(this->GetMesh()->GetNode(node_index));
00369                     break;
00370                 }
00371                 //mid
00372                 case 1u:
00373                 {
00374                     mid_nodes.push_back(this->GetMesh()->GetNode(node_index));
00375                     break;
00376                 }
00377                 //endo
00378                 case 0u:
00379                 {
00380                     endo_nodes.push_back(this->GetMesh()->GetNode(node_index));
00381                     break;
00382                 }
00383                 default:
00384                 NEVER_REACHED;
00385             }
00386         }
00387     }
00388     //assert((endo_nodes.size()+epi_nodes.size()+mid_nodes.size())==this->GetMesh()->GetNumNodes());
00389 
00390     // now the 3 list of pointer to nodes need to be pushed into the mCellHeterogeneityAreas vector,
00391     // IN THE ORDER PRESCRIBED BY THE USER IN THE XML FILE!
00392     // This is because the corresponding scale factors are already read in that order.
00393 
00394     //these three unsigned tell us in which order the user supplied each layer in the XML file
00395     unsigned user_supplied_epi_index = HeartConfig::Instance()->GetEpiLayerIndex();
00396     unsigned user_supplied_mid_index = HeartConfig::Instance()->GetMidLayerIndex();
00397     unsigned user_supplied_endo_index = HeartConfig::Instance()->GetEndoLayerIndex();
00398 
00399     //these three should have been set to 0, 1 and 2 by HeartConfig::GetCellHeterogeneities
00400     assert(user_supplied_epi_index<3);
00401     assert(user_supplied_mid_index<3);
00402     assert(user_supplied_endo_index<3);
00403 
00404     //pute them in a vector
00405     std::vector<unsigned> user_supplied_indices;
00406     user_supplied_indices.push_back(user_supplied_epi_index);
00407     user_supplied_indices.push_back(user_supplied_mid_index);
00408     user_supplied_indices.push_back(user_supplied_endo_index);
00409 
00410     //figure out who goes first
00411 
00412     //loop three times
00413     for (unsigned layer_index=0; layer_index<3; layer_index++)
00414     {
00415         unsigned counter = 0;
00416         //find the corresponding index
00417         for (unsigned supplied_index = 0; supplied_index<user_supplied_indices.size(); supplied_index++)
00418         {
00419             if (user_supplied_indices[supplied_index] == layer_index)
00420             {
00421                 break;
00422             }
00423             counter++;
00424         }
00425 
00426         //create the node lists based on the calculations above
00427         if (counter==0)
00428         {
00429             mCellHeterogeneityAreas.push_back(new ChasteNodesList<3u>(epi_nodes));
00430         }
00431         if (counter==1)
00432         {
00433             mCellHeterogeneityAreas.push_back(new ChasteNodesList<3u>(mid_nodes));
00434         }
00435         if (counter==2)
00436         {
00437             mCellHeterogeneityAreas.push_back(new ChasteNodesList<3u>(endo_nodes));
00438         }
00439         assert(counter<3);
00440     }
00441     assert(mCellHeterogeneityAreas.size()==3);
00442 }
00443 
00444 // Explicit instantiation
00445 template class HeartConfigRelatedCellFactory<1u>;
00446 template class HeartConfigRelatedCellFactory<2u>;
00447 template class HeartConfigRelatedCellFactory<3u>;

Generated on Mon Nov 1 12:35:17 2010 for Chaste by  doxygen 1.5.5