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

Generated on Mon Apr 18 11:35:28 2011 for Chaste by  doxygen 1.5.5