Chaste Release::3.1
AbstractCardiacTissue.hpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 #ifndef ABSTRACTCARDIACTISSUE_HPP_
00036 #define ABSTRACTCARDIACTISSUE_HPP_
00037 
00038 #include <set>
00039 #include <vector>
00040 #include <boost/shared_ptr.hpp>
00041 
00042 #include "UblasMatrixInclude.hpp"
00043 
00044 #include "ChasteSerialization.hpp"
00045 #include "ClassIsAbstract.hpp"
00046 #include "ChasteSerializationVersion.hpp"
00047 #include <boost/serialization/base_object.hpp>
00048 #include <boost/serialization/shared_ptr.hpp>
00049 #include <boost/serialization/vector.hpp>
00050 #include <boost/serialization/string.hpp>
00051 #include <boost/serialization/split_member.hpp>
00052 
00053 #include "AbstractCardiacCellInterface.hpp"
00054 #include "FakeBathCell.hpp"
00055 #include "AbstractCardiacCellFactory.hpp"
00056 #include "AbstractConductivityTensors.hpp"
00057 #include "AbstractPurkinjeCellFactory.hpp"
00058 #include "ReplicatableVector.hpp"
00059 #include "HeartConfig.hpp"
00060 #include "ArchiveLocationInfo.hpp"
00061 #include "AbstractDynamicallyLoadableEntity.hpp"
00062 #include "DynamicModelLoaderRegistry.hpp"
00063 #include "AbstractConductivityModifier.hpp"
00064 
00077 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM = ELEMENT_DIM>
00078 class AbstractCardiacTissue : private boost::noncopyable
00079 {
00080 private:
00081 
00083     friend class boost::serialization::access;
00084     friend class TestMonodomainTissue;
00085 
00092     template<class Archive>
00093     void save(Archive & archive, const unsigned int version) const
00094     {
00095         if (version >= 3)
00096         {
00097             archive & mHasPurkinje;
00098         }
00099         if (version >= 2)
00100         {
00101             archive & mExchangeHalos;
00102         }
00103         // Don't use the std::vector serialization for cardiac cells, so that we can load them
00104         // more cleverly when migrating checkpoints.
00105         SaveCardiacCells(*ProcessSpecificArchive<Archive>::Get(), version);
00106 
00107         // archive & mpMesh; Archived in save/load_constructs at the bottom of Mono/BidomainTissue.hpp
00108         // archive & mpIntracellularConductivityTensors; Loaded from HeartConfig every time constructor is called
00109         if (HeartConfig::Instance()->IsMeshProvided() && HeartConfig::Instance()->GetLoadMesh())
00110         {
00111             switch (HeartConfig::Instance()->GetConductivityMedia())
00112             {
00113                 case cp::media_type::Orthotropic:
00114                 {
00115                     FileFinder source_file(mFibreFilePathNoExtension + ".ortho", RelativeTo::AbsoluteOrCwd);
00116                     assert(source_file.Exists());
00117                     FileFinder dest_file(ArchiveLocationInfo::GetArchiveRelativePath() + ArchiveLocationInfo::GetMeshFilename() + ".ortho", RelativeTo::ChasteTestOutput);
00118 
00119                     if (PetscTools::AmMaster())
00120                     {
00121                         ABORT_IF_NON0(system,"cp " + source_file.GetAbsolutePath() + " " + dest_file.GetAbsolutePath());
00122                     }
00123                     PetscTools::Barrier();
00124                     break;
00125                 }
00126 
00127                 case cp::media_type::Axisymmetric:
00128                 {
00129                     FileFinder source_file(mFibreFilePathNoExtension + ".axi", RelativeTo::AbsoluteOrCwd);
00130                     assert(source_file.Exists());
00131                     FileFinder dest_file(ArchiveLocationInfo::GetArchiveRelativePath() + ArchiveLocationInfo::GetMeshFilename() + ".axi", RelativeTo::ChasteTestOutput);
00132 
00133                     if (PetscTools::AmMaster())
00134                     {
00135                         ABORT_IF_NON0(system,"cp " + source_file.GetAbsolutePath() + " " + dest_file.GetAbsolutePath());
00136                     }
00137                     PetscTools::Barrier();
00138 
00139                     break;
00140                 }
00141 
00142                 case cp::media_type::NoFibreOrientation:
00143                     break;
00144 
00145                 default :
00146                     NEVER_REACHED;
00147             }
00148         }
00149 
00150         // archive & mIionicCacheReplicated; // will be regenerated
00151         // archive & mIntracellularStimulusCacheReplicated; // will be regenerated
00152         archive & mDoCacheReplication;
00153         // archive & mMeshUnarchived; Not archived since set to true when archiving constructor is called.
00154 
00155         (*ProcessSpecificArchive<Archive>::Get()) & mpDistributedVectorFactory;
00156 
00157         // Paranoia: check we agree with the mesh on who owns what
00158         assert(mpDistributedVectorFactory->GetLow()==mpMesh->GetDistributedVectorFactory()->GetLow());
00159         assert(mpDistributedVectorFactory->GetLocalOwnership()==mpMesh->GetDistributedVectorFactory()->GetLocalOwnership());
00160     }
00161 
00168     template<class Archive>
00169     void load(Archive & archive, const unsigned int version)
00170     {
00171         // archive & mpMesh; Archived in save/load_constructs at the bottom of Mono/BidomainTissue.hpp
00172         // archive & mpIntracellularConductivityTensors; Loaded from HeartConfig every time constructor is called
00173 
00174         if (version >= 3)
00175         {
00176             archive & mHasPurkinje;
00177             if (mHasPurkinje)
00178             {
00179                 mPurkinjeIionicCacheReplicated.Resize(mpDistributedVectorFactory->GetProblemSize());
00180             }
00181         }
00182         if (version >= 2)
00183         {
00184             archive & mExchangeHalos;
00185             if (mExchangeHalos)
00186             {
00187                 mpMesh->CalculateNodeExchange(mNodesToSendPerProcess, mNodesToReceivePerProcess);
00188                 CalculateHaloNodesFromNodeExchange();
00189                 unsigned num_halo_nodes = mHaloNodes.size();
00190                 mHaloCellsDistributed.resize( num_halo_nodes );
00191                 for (unsigned local_index = 0; local_index < num_halo_nodes; local_index++)
00192                 {
00193                     unsigned global_index = mHaloNodes[local_index];
00194                     mHaloGlobalToLocalIndexMap[global_index] = local_index;
00195                 }
00196             }
00197         }
00198 
00199         // mCellsDistributed & mHaloCellsDistributed:
00200         LoadCardiacCells(*ProcessSpecificArchive<Archive>::Get(), version);
00201 
00202         // archive & mIionicCacheReplicated; // will be regenerated
00203         // archive & mIntracellularStimulusCacheReplicated; // will be regenerated
00204         archive & mDoCacheReplication;
00205 
00206         // we no longer have a bool mDoOneCacheReplication, but to maintain backwards compatibility
00207         // we archive something if version==0
00208         if (version==0)
00209         {
00210             bool do_one_cache_replication = true;
00211             archive & do_one_cache_replication;
00212         }
00213 
00214         (*ProcessSpecificArchive<Archive>::Get()) & mpDistributedVectorFactory;
00215 
00216         // Paranoia: check we agree with the mesh on who owns what
00217         assert(mpDistributedVectorFactory->GetLow()==mpMesh->GetDistributedVectorFactory()->GetLow());
00218         assert(mpDistributedVectorFactory->GetLocalOwnership()==mpMesh->GetDistributedVectorFactory()->GetLocalOwnership());
00219         // archive & mMeshUnarchived; Not archived since set to true when archiving constructor is called.
00220 
00221         // not archiving mpConductivityModifier for the time being (mechanics simulations are only use-case at the moment, and they
00222         // do not get archived...). mpConductivityModifier has to be reset to NULL upon load.
00223         mpConductivityModifier = NULL;
00224     }
00225     BOOST_SERIALIZATION_SPLIT_MEMBER()
00226 
00227     
00230     void CreateIntracellularConductivityTensor();
00231 
00232 protected:
00233 
00235     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* mpMesh;
00236 
00239     AbstractConductivityTensors<ELEMENT_DIM,SPACE_DIM>* mpIntracellularConductivityTensors;
00240 
00242     std::vector< AbstractCardiacCellInterface* > mCellsDistributed;
00243 
00245     std::vector< AbstractCardiacCellInterface* > mPurkinjeCellsDistributed;
00246 
00251     ReplicatableVector mIionicCacheReplicated;
00252 
00257     ReplicatableVector mPurkinjeIionicCacheReplicated;
00258 
00263     ReplicatableVector mIntracellularStimulusCacheReplicated;
00264 
00269     ReplicatableVector mPurkinjeIntracellularStimulusCacheReplicated;
00270 
00272     HeartConfig* mpConfig;
00273 
00282     DistributedVectorFactory* mpDistributedVectorFactory;
00283 
00287     std::string mFibreFilePathNoExtension;
00288 
00294     AbstractConductivityModifier<ELEMENT_DIM,SPACE_DIM>* mpConductivityModifier;
00295 
00297     bool mHasPurkinje;
00298 
00308     bool mDoCacheReplication;
00309 
00313     bool mMeshUnarchived;
00314 
00319     bool mExchangeHalos;
00320 
00322     std::vector<unsigned> mHaloNodes;
00323 
00325     std::vector< AbstractCardiacCellInterface* > mHaloCellsDistributed;
00326 
00328     std::map<unsigned, unsigned> mHaloGlobalToLocalIndexMap;
00329 
00335     std::vector<std::vector<unsigned> > mNodesToSendPerProcess;
00336 
00341     std::vector<std::vector<unsigned> > mNodesToReceivePerProcess;
00342 
00348     void CalculateHaloNodesFromNodeExchange();
00349 
00356     void SetUpHaloCells(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory);
00357 
00358 public:
00369     AbstractCardiacTissue(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory, bool exchangeHalos=false);
00370 
00376     AbstractCardiacTissue(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00377 
00379     virtual ~AbstractCardiacTissue();
00380 
00382     bool HasPurkinje();
00383 
00390     void SetCacheReplication(bool doCacheReplication);
00391 
00397     bool GetDoCacheReplication();
00398 
00402     const c_matrix<double, SPACE_DIM, SPACE_DIM>& rGetIntracellularConductivityTensor(unsigned elementIndex);
00403 
00411     virtual const c_matrix<double, SPACE_DIM, SPACE_DIM>& rGetExtracellularConductivityTensor(unsigned elementIndex);
00412 
00421     AbstractCardiacCellInterface* GetCardiacCell( unsigned globalIndex );
00422 
00431     AbstractCardiacCellInterface* GetPurkinjeCell( unsigned globalIndex );
00432 
00441     AbstractCardiacCellInterface* GetCardiacCellOrHaloCell( unsigned globalIndex );
00442 
00452     virtual void SolveCellSystems(Vec existingSolution, double time, double nextTime, bool updateVoltage=false);
00453 
00455     ReplicatableVector& rGetIionicCacheReplicated();
00456 
00458     ReplicatableVector& rGetIntracellularStimulusCacheReplicated();
00459 
00461     ReplicatableVector& rGetPurkinjeIionicCacheReplicated();
00462 
00464     ReplicatableVector& rGetPurkinjeIntracellularStimulusCacheReplicated();
00465 
00466 
00474     void UpdateCaches(unsigned globalIndex, unsigned localIndex, double nextTime);
00475 
00483     void UpdatePurkinjeCaches(unsigned globalIndex, unsigned localIndex, double nextTime);
00484 
00488     void ReplicateCaches();
00489 
00493     const std::vector<AbstractCardiacCellInterface*>& rGetCellsDistributed() const;
00494 
00498     const std::vector<AbstractCardiacCellInterface*>& rGetPurkinjeCellsDistributed() const;
00499 
00505     const AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pGetMesh() const;
00506 
00512     void SetConductivityModifier(AbstractConductivityModifier<ELEMENT_DIM,SPACE_DIM>* pModifier);
00513 
00525     template<class Archive>
00526     void SaveCardiacCells(Archive & archive, const unsigned int version) const
00527     {
00528         const std::vector<AbstractCardiacCellInterface*> & r_cells_distributed = rGetCellsDistributed();
00529         archive & mpDistributedVectorFactory; // Needed when loading
00530         const unsigned num_cells = r_cells_distributed.size();
00531         archive & num_cells;
00532         for (unsigned i=0; i<num_cells; i++)
00533         {
00534             AbstractDynamicallyLoadableEntity* p_entity = dynamic_cast<AbstractDynamicallyLoadableEntity*>(r_cells_distributed[i]);
00535             bool is_dynamic = (p_entity != NULL);
00536             archive & is_dynamic;
00537             if (is_dynamic)
00538             {
00539 #ifdef CHASTE_CAN_CHECKPOINT_DLLS
00540                 archive & p_entity->GetLoader()->GetLoadableModulePath();
00541 #else
00542                 // We should have thrown an exception before this point
00543                 NEVER_REACHED;
00544 #endif // CHASTE_CAN_CHECKPOINT_DLLS
00545             }
00546             archive & r_cells_distributed[i];
00547             if (mHasPurkinje)
00548             {
00549                 archive & rGetPurkinjeCellsDistributed()[i];
00550             }
00551         }
00552     }
00553 
00566     template<class Archive>
00567     void LoadCardiacCells(Archive & archive, const unsigned int version)
00568     {
00569         DistributedVectorFactory* p_factory;
00570         DistributedVectorFactory* p_mesh_factory = this->mpMesh->GetDistributedVectorFactory();
00571         archive & p_factory;
00572         unsigned num_cells;
00573         archive & num_cells;
00574         if (mCellsDistributed.empty())
00575         {
00576             mCellsDistributed.resize(p_factory->GetLocalOwnership());
00577 #ifndef NDEBUG
00578             // Paranoia
00579             for (unsigned i=0; i<mCellsDistributed.size(); i++)
00580             {
00581                 assert(mCellsDistributed[i] == NULL);
00582             }
00583 #endif
00584         }
00585         else
00586         {
00587             assert(mCellsDistributed.size() == p_mesh_factory->GetLocalOwnership());
00588         }
00589         if (mHasPurkinje)
00590         {
00591             if (mPurkinjeCellsDistributed.empty())
00592             {
00593                 mPurkinjeCellsDistributed.resize(p_factory->GetLocalOwnership());
00594             }
00595             else
00596             {
00597                 assert(mPurkinjeCellsDistributed.size() == p_mesh_factory->GetLocalOwnership());
00598             }
00599         }
00600 
00601         // We don't store a cell index in the archive, so need to work out what global index this tissue starts at.
00602         // If we have an original factory we use the original low index; otherwise we use the current low index.
00603         unsigned index_low = p_factory->GetOriginalFactory() ? p_factory->GetOriginalFactory()->GetLow() : p_mesh_factory->GetLow();
00604 
00605         // Track fake cells (which might have multiple pointers to the same object) to make sure we only delete non-local ones
00606         std::set<FakeBathCell*> fake_cells_non_local, fake_cells_local;
00607 
00608         const std::vector<unsigned>& r_permutation = this->mpMesh->rGetNodePermutation();
00609         for (unsigned local_index=0; local_index<num_cells; local_index++)
00610         {
00611             // If we're permuting, figure out where this cell goes
00612             unsigned original_global_index = index_low + local_index;
00613             unsigned new_global_index;
00614             if (r_permutation.empty())
00615             {
00616                 new_global_index = original_global_index;
00617             }
00618             else
00619             {
00621 //                new_global_index = r_permutation[original_global_index];
00622                 NEVER_REACHED;
00623             }
00624             unsigned new_local_index = new_global_index - p_mesh_factory->GetLow();
00625             bool local = p_mesh_factory->IsGlobalIndexLocal(new_global_index);
00626 
00627             // Check if this will be a halo cell
00628             std::map<unsigned, unsigned>::const_iterator halo_position;
00629             bool halo = ((halo_position=mHaloGlobalToLocalIndexMap.find(new_global_index)) != mHaloGlobalToLocalIndexMap.end());
00630             // halo_position->second is local halo index
00631 
00632             bool is_dynamic;
00633             archive & is_dynamic;
00634             if (is_dynamic)
00635             {
00636 #ifdef CHASTE_CAN_CHECKPOINT_DLLS
00637                 // Ensure the shared object file for this cell model is loaded.
00638                 // We need to do this here, rather than in the class' serialization code,
00639                 // because that code won't be available until this is done...
00640                 std::string shared_object_path;
00641                 archive & shared_object_path;
00642                 DynamicModelLoaderRegistry::Instance()->GetLoader(shared_object_path);
00643 #else
00644                 // Since checkpoints with dynamically loadable cells can only be
00645                 // created on Boost>=1.37, trying to load such a checkpoint on an
00646                 // earlier Boost would give an error when first opening the archive.
00647                 NEVER_REACHED;
00648 #endif // CHASTE_CAN_CHECKPOINT_DLLS
00649             }
00650             AbstractCardiacCellInterface* p_cell;
00651             archive & p_cell;
00652             AbstractCardiacCellInterface* p_purkinje_cell = NULL;
00653             if (mHasPurkinje)
00654             {
00655                 archive & p_purkinje_cell;
00656             }
00657             // Check if it's a fake cell
00658             FakeBathCell* p_fake = dynamic_cast<FakeBathCell*>(p_cell);
00659             if (p_fake)
00660             {
00661                 if (halo || local)
00662                 {
00663                     fake_cells_local.insert(p_fake);
00664                 }
00665                 else
00666                 {
00667                     fake_cells_non_local.insert(p_fake);
00668                 }
00669             }
00670             FakeBathCell* p_fake_purkinje = dynamic_cast<FakeBathCell*>(p_purkinje_cell);
00671             if (p_fake_purkinje)
00672             {
00673                 if (halo || local)
00674                 {
00675                     fake_cells_local.insert(p_fake_purkinje);
00676                 }
00677                 else
00678                 {
00679                     fake_cells_non_local.insert(p_fake_purkinje);
00680                 }
00681             }
00682             // Add real cells to the local or halo vectors
00683             if (local)
00684             {
00685                 assert(mCellsDistributed[new_local_index] == NULL);
00686                 mCellsDistributed[new_local_index] = p_cell;
00687                 if (mHasPurkinje)
00688                 {
00689                     assert(mPurkinjeCellsDistributed[new_local_index] == NULL);
00690                     mPurkinjeCellsDistributed[new_local_index] = p_purkinje_cell;
00691                 }
00692             }
00693             else if (halo)
00694             {
00695                 assert(mHaloCellsDistributed[halo_position->second] == NULL);
00696                 mHaloCellsDistributed[halo_position->second] = p_cell;
00697             }
00698             else
00699             {
00700                 if (!p_fake)
00701                 {
00702                     // Non-local real cell, so free the memory.
00703                     delete p_cell;
00704                 }
00705                 if (!p_fake_purkinje)
00706                 {
00707                     // This will be NULL if there's no Purkinje, so a delete is OK.
00708                     delete p_purkinje_cell;
00709                 }
00710             }
00711         }
00712 
00713         // Delete any unused fake cells
00714         for (std::set<FakeBathCell*>::iterator it = fake_cells_non_local.begin();
00715              it != fake_cells_non_local.end();
00716              ++it)
00717         {
00718             if (fake_cells_local.find(*it) == fake_cells_local.end())
00719             {
00720                 delete (*it);
00721             }
00722         }
00723     }
00724 };
00725 
00726 TEMPLATED_CLASS_IS_ABSTRACT_2_UNSIGNED(AbstractCardiacTissue)
00727 
00728 namespace boost {
00729 namespace serialization {
00736 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00737 struct version<AbstractCardiacTissue<ELEMENT_DIM, SPACE_DIM> >
00738 {
00740     CHASTE_VERSION_CONTENT(3);
00741 };
00742 } // namespace serialization
00743 } // namespace boost
00744 
00745 #endif /*ABSTRACTCARDIACTISSUE_HPP_*/
00746