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

Generated by  doxygen 1.6.2