AbstractCardiacTissue.hpp

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 #ifndef ABSTRACTCARDIACTISSUE_HPP_
00029 #define ABSTRACTCARDIACTISSUE_HPP_
00030 
00031 #include <set>
00032 #include <vector>
00033 #include <boost/shared_ptr.hpp>
00034 
00035 #include "UblasMatrixInclude.hpp"
00036 
00037 #include "ChasteSerialization.hpp"
00038 #include "ClassIsAbstract.hpp"
00039 #include "ChasteSerializationVersion.hpp"
00040 #include <boost/serialization/base_object.hpp>
00041 #include <boost/serialization/shared_ptr.hpp>
00042 #include <boost/serialization/vector.hpp>
00043 #include <boost/serialization/string.hpp>
00044 #include <boost/serialization/split_member.hpp>
00045 
00046 #include "AbstractCardiacCell.hpp"
00047 #include "FakeBathCell.hpp"
00048 #include "AbstractCardiacCellFactory.hpp"
00049 #include "AbstractConductivityTensors.hpp"
00050 #include "AbstractPurkinjeCellFactory.hpp"
00051 #include "ReplicatableVector.hpp"
00052 #include "HeartConfig.hpp"
00053 #include "ArchiveLocationInfo.hpp"
00054 #include "AbstractDynamicallyLoadableEntity.hpp"
00055 #include "DynamicModelLoaderRegistry.hpp"
00056 #include "AbstractConductivityModifier.hpp"
00057 
00070 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM = ELEMENT_DIM>
00071 class AbstractCardiacTissue : boost::noncopyable
00072 {
00073 private:
00074 
00076     friend class boost::serialization::access;
00077     friend class TestMonodomainTissue;
00078 
00085     template<class Archive>
00086     void save(Archive & archive, const unsigned int version) const
00087     {
00088         if (version >= 3)
00089         {
00090             archive & mHasPurkinje;
00091         }
00092         if (version >= 2)
00093         {
00094             archive & mExchangeHalos;
00095         }
00096         // Don't use the std::vector serialization for cardiac cells, so that we can load them
00097         // more cleverly when migrating checkpoints.
00098         SaveCardiacCells(*ProcessSpecificArchive<Archive>::Get(), version);
00099 
00100         // archive & mpMesh; Archived in save/load_constructs at the bottom of Mono/BidomainTissue.hpp
00101         // archive & mpIntracellularConductivityTensors; Loaded from HeartConfig every time constructor is called
00102         if (HeartConfig::Instance()->IsMeshProvided() && HeartConfig::Instance()->GetLoadMesh())
00103         {
00104             switch (HeartConfig::Instance()->GetConductivityMedia())
00105             {
00106                 case cp::media_type::Orthotropic:
00107                 {
00108                     FileFinder source_file(mFibreFilePathNoExtension + ".ortho", RelativeTo::AbsoluteOrCwd);
00109                     assert(source_file.Exists());
00110                     FileFinder dest_file(ArchiveLocationInfo::GetArchiveRelativePath() + ArchiveLocationInfo::GetMeshFilename() + ".ortho", RelativeTo::ChasteTestOutput);
00111 
00112                     if (PetscTools::AmMaster())
00113                     {
00114                         ABORT_IF_NON0(system,"cp " + source_file.GetAbsolutePath() + " " + dest_file.GetAbsolutePath());
00115                     }
00116                     PetscTools::Barrier();
00117                     break;
00118                 }
00119 
00120                 case cp::media_type::Axisymmetric:
00121                 {
00122                     FileFinder source_file(mFibreFilePathNoExtension + ".axi", RelativeTo::AbsoluteOrCwd);
00123                     assert(source_file.Exists());
00124                     FileFinder dest_file(ArchiveLocationInfo::GetArchiveRelativePath() + ArchiveLocationInfo::GetMeshFilename() + ".axi", RelativeTo::ChasteTestOutput);
00125 
00126                     if (PetscTools::AmMaster())
00127                     {
00128                         ABORT_IF_NON0(system,"cp " + source_file.GetAbsolutePath() + " " + dest_file.GetAbsolutePath());
00129                     }
00130                     PetscTools::Barrier();
00131 
00132                     break;
00133                 }
00134 
00135                 case cp::media_type::NoFibreOrientation:
00136                     break;
00137 
00138                 default :
00139                     NEVER_REACHED;
00140             }
00141         }
00142 
00143         // archive & mIionicCacheReplicated; // will be regenerated
00144         // archive & mIntracellularStimulusCacheReplicated; // will be regenerated
00145         archive & mDoCacheReplication;
00146         // archive & mMeshUnarchived; Not archived since set to true when archiving constructor is called.
00147 
00148         (*ProcessSpecificArchive<Archive>::Get()) & mpDistributedVectorFactory;
00149 
00150         // Paranoia: check we agree with the mesh on who owns what
00151         assert(mpDistributedVectorFactory->GetLow()==mpMesh->GetDistributedVectorFactory()->GetLow());
00152         assert(mpDistributedVectorFactory->GetLocalOwnership()==mpMesh->GetDistributedVectorFactory()->GetLocalOwnership());
00153     }
00154 
00161     template<class Archive>
00162     void load(Archive & archive, const unsigned int version)
00163     {
00164         // archive & mpMesh; Archived in save/load_constructs at the bottom of Mono/BidomainTissue.hpp
00165         // archive & mpIntracellularConductivityTensors; Loaded from HeartConfig every time constructor is called
00166 
00167         if (version >= 3)
00168         {
00169             archive & mHasPurkinje;
00170             if (mHasPurkinje)
00171             {
00172                 mPurkinjeIionicCacheReplicated.Resize(mpDistributedVectorFactory->GetProblemSize());
00173             }
00174         }
00175         if (version >= 2)
00176         {
00177             archive & mExchangeHalos;
00178             if (mExchangeHalos)
00179             {
00180                 mpMesh->CalculateNodeExchange(mNodesToSendPerProcess, mNodesToReceivePerProcess);
00181                 CalculateHaloNodesFromNodeExchange();
00182                 unsigned num_halo_nodes = mHaloNodes.size();
00183                 mHaloCellsDistributed.resize( num_halo_nodes );
00184                 for (unsigned local_index = 0; local_index < num_halo_nodes; local_index++)
00185                 {
00186                     unsigned global_index = mHaloNodes[local_index];
00187                     mHaloGlobalToLocalIndexMap[global_index] = local_index;
00188                 }
00189             }
00190         }
00191 
00192         // mCellsDistributed & mHaloCellsDistributed:
00193         LoadCardiacCells(*ProcessSpecificArchive<Archive>::Get(), version);
00194 
00195         // archive & mIionicCacheReplicated; // will be regenerated
00196         // archive & mIntracellularStimulusCacheReplicated; // will be regenerated
00197         archive & mDoCacheReplication;
00198 
00199         // we no longer have a bool mDoOneCacheReplication, but to maintain backwards compatibility
00200         // we archive something if version==0
00201         if (version==0)
00202         {
00203             bool do_one_cache_replication = true;
00204             archive & do_one_cache_replication;
00205         }
00206 
00207         (*ProcessSpecificArchive<Archive>::Get()) & mpDistributedVectorFactory;
00208 
00209         // Paranoia: check we agree with the mesh on who owns what
00210         assert(mpDistributedVectorFactory->GetLow()==mpMesh->GetDistributedVectorFactory()->GetLow());
00211         assert(mpDistributedVectorFactory->GetLocalOwnership()==mpMesh->GetDistributedVectorFactory()->GetLocalOwnership());
00212         // archive & mMeshUnarchived; Not archived since set to true when archiving constructor is called.
00213 
00214         // not archiving mpConductivityModifier for the time being (mechanics simulations are only use-case at the moment, and they
00215         // do not get archived...). mpConductivityModifier has to be reset to NULL upon load.
00216         mpConductivityModifier = NULL;
00217     }
00218     BOOST_SERIALIZATION_SPLIT_MEMBER()
00219 
00220     
00223     void CreateIntracellularConductivityTensor();
00224 
00225 protected:
00226 
00228     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* mpMesh;
00229 
00232     AbstractConductivityTensors<ELEMENT_DIM,SPACE_DIM>* mpIntracellularConductivityTensors;
00233 
00235     std::vector< AbstractCardiacCell* > mCellsDistributed;
00236 
00238     std::vector< AbstractCardiacCell* > mPurkinjeCellsDistributed;
00239 
00244     ReplicatableVector mIionicCacheReplicated;
00245 
00250     ReplicatableVector mPurkinjeIionicCacheReplicated;
00251 
00256     ReplicatableVector mIntracellularStimulusCacheReplicated;
00257 
00259     HeartConfig* mpConfig;
00260 
00269     DistributedVectorFactory* mpDistributedVectorFactory;
00270 
00274     std::string mFibreFilePathNoExtension;
00275 
00281     AbstractConductivityModifier<ELEMENT_DIM,SPACE_DIM>* mpConductivityModifier;
00282 
00284     bool mHasPurkinje;
00285 
00295     bool mDoCacheReplication;
00296 
00300     bool mMeshUnarchived;
00301 
00306     bool mExchangeHalos;
00307 
00309     std::vector<unsigned> mHaloNodes;
00310 
00312     std::vector< AbstractCardiacCell* > mHaloCellsDistributed;
00313 
00315     std::map<unsigned, unsigned> mHaloGlobalToLocalIndexMap;
00316 
00322     std::vector<std::vector<unsigned> > mNodesToSendPerProcess;
00323 
00328     std::vector<std::vector<unsigned> > mNodesToReceivePerProcess;
00329 
00335     void CalculateHaloNodesFromNodeExchange();
00336 
00343     void SetUpHaloCells(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory);
00344 
00345 public:
00356     AbstractCardiacTissue(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory, bool exchangeHalos=false);
00357 
00363     AbstractCardiacTissue(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00364 
00366     virtual ~AbstractCardiacTissue();
00367 
00369     bool HasPurkinje();
00370 
00377     void SetCacheReplication(bool doCacheReplication);
00378 
00384     bool GetDoCacheReplication();
00385 
00389     const c_matrix<double, SPACE_DIM, SPACE_DIM>& rGetIntracellularConductivityTensor(unsigned elementIndex);
00390 
00398     virtual const c_matrix<double, SPACE_DIM, SPACE_DIM>& rGetExtracellularConductivityTensor(unsigned elementIndex);
00399 
00408     AbstractCardiacCell* GetCardiacCell( unsigned globalIndex );
00409 
00418     AbstractCardiacCell* GetPurkinjeCell( unsigned globalIndex );
00419 
00428     AbstractCardiacCell* GetCardiacCellOrHaloCell( unsigned globalIndex );
00429 
00439     virtual void SolveCellSystems(Vec existingSolution, double time, double nextTime, bool updateVoltage=false);
00440 
00442     ReplicatableVector& rGetIionicCacheReplicated();
00443 
00445     ReplicatableVector& rGetIntracellularStimulusCacheReplicated();
00446 
00448     ReplicatableVector& rGetPurkinjeIionicCacheReplicated();
00449 
00450 
00458     void UpdateCaches(unsigned globalIndex, unsigned localIndex, double nextTime);
00459 
00463     void ReplicateCaches();
00464 
00468     const std::vector<AbstractCardiacCell*>& rGetCellsDistributed() const;
00469 
00473     const std::vector<AbstractCardiacCell*>& rGetPurkinjeCellsDistributed() const;
00474 
00480     const AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pGetMesh() const;
00481 
00487     void SetConductivityModifier(AbstractConductivityModifier<ELEMENT_DIM,SPACE_DIM>* pModifier);
00488 
00500     template<class Archive>
00501     void SaveCardiacCells(Archive & archive, const unsigned int version) const
00502     {
00503         const std::vector<AbstractCardiacCell*> & r_cells_distributed = rGetCellsDistributed();
00504         archive & mpDistributedVectorFactory; // Needed when loading
00505         const unsigned num_cells = r_cells_distributed.size();
00506         archive & num_cells;
00507         for (unsigned i=0; i<num_cells; i++)
00508         {
00509             AbstractDynamicallyLoadableEntity* p_entity = dynamic_cast<AbstractDynamicallyLoadableEntity*>(r_cells_distributed[i]);
00510             bool is_dynamic = (p_entity != NULL);
00511             archive & is_dynamic;
00512             if (is_dynamic)
00513             {
00514 #ifdef CHASTE_CAN_CHECKPOINT_DLLS
00515                 archive & p_entity->GetLoader()->GetLoadableModulePath();
00516 #else
00517                 // We should have thrown an exception before this point
00518                 NEVER_REACHED;
00519 #endif // CHASTE_CAN_CHECKPOINT_DLLS
00520             }
00521             archive & r_cells_distributed[i];
00522             if (mHasPurkinje)
00523             {
00524                 archive & rGetPurkinjeCellsDistributed()[i];
00525             }
00526         }
00527     }
00528 
00541     template<class Archive>
00542     void LoadCardiacCells(Archive & archive, const unsigned int version)
00543     {
00544         DistributedVectorFactory* p_factory;
00545         DistributedVectorFactory* p_mesh_factory = this->mpMesh->GetDistributedVectorFactory();
00546         archive & p_factory;
00547         unsigned num_cells;
00548         archive & num_cells;
00549         if (mCellsDistributed.empty())
00550         {
00551             mCellsDistributed.resize(p_factory->GetLocalOwnership());
00552 #ifndef NDEBUG
00553             // Paranoia
00554             for (unsigned i=0; i<mCellsDistributed.size(); i++)
00555             {
00556                 assert(mCellsDistributed[i] == NULL);
00557             }
00558 #endif
00559         }
00560         else
00561         {
00562             assert(mCellsDistributed.size() == p_mesh_factory->GetLocalOwnership());
00563         }
00564         if (mHasPurkinje)
00565         {
00566             if (mPurkinjeCellsDistributed.empty())
00567             {
00568                 mPurkinjeCellsDistributed.resize(p_factory->GetLocalOwnership());
00569             }
00570             else
00571             {
00572                 assert(mPurkinjeCellsDistributed.size() == p_mesh_factory->GetLocalOwnership());
00573             }
00574         }
00575 
00576         // We don't store a cell index in the archive, so need to work out what global index this tissue starts at.
00577         // If we have an original factory we use the original low index; otherwise we use the current low index.
00578         unsigned index_low = p_factory->GetOriginalFactory() ? p_factory->GetOriginalFactory()->GetLow() : p_mesh_factory->GetLow();
00579 
00580         // Track fake cells (which might have multiple pointers to the same object) to make sure we only delete non-local ones
00581         std::set<FakeBathCell*> fake_cells_non_local, fake_cells_local;
00582 
00583         const std::vector<unsigned>& r_permutation = this->mpMesh->rGetNodePermutation();
00584         for (unsigned local_index=0; local_index<num_cells; local_index++)
00585         {
00586             // If we're permuting, figure out where this cell goes
00587             unsigned original_global_index = index_low + local_index;
00588             unsigned new_global_index;
00589             if (r_permutation.empty())
00590             {
00591                 new_global_index = original_global_index;
00592             }
00593             else
00594             {
00596 //                new_global_index = r_permutation[original_global_index];
00597                 NEVER_REACHED;
00598             }
00599             unsigned new_local_index = new_global_index - p_mesh_factory->GetLow();
00600             bool local = p_mesh_factory->IsGlobalIndexLocal(new_global_index);
00601 
00602             // Check if this will be a halo cell
00603             std::map<unsigned, unsigned>::const_iterator halo_position;
00604             bool halo = ((halo_position=mHaloGlobalToLocalIndexMap.find(new_global_index)) != mHaloGlobalToLocalIndexMap.end());
00605             // halo_position->second is local halo index
00606 
00607             bool is_dynamic;
00608             archive & is_dynamic;
00609             if (is_dynamic)
00610             {
00611 #ifdef CHASTE_CAN_CHECKPOINT_DLLS
00612                 // Ensure the shared object file for this cell model is loaded.
00613                 // We need to do this here, rather than in the class' serialization code,
00614                 // because that code won't be available until this is done...
00615                 std::string shared_object_path;
00616                 archive & shared_object_path;
00617                 DynamicModelLoaderRegistry::Instance()->GetLoader(shared_object_path);
00618 #else
00619                 // Since checkpoints with dynamically loadable cells can only be
00620                 // created on Boost>=1.37, trying to load such a checkpoint on an
00621                 // earlier Boost would give an error when first opening the archive.
00622                 NEVER_REACHED;
00623 #endif // CHASTE_CAN_CHECKPOINT_DLLS
00624             }
00625             AbstractCardiacCell* p_cell;
00626             archive & p_cell;
00627             AbstractCardiacCell* p_purkinje_cell = NULL;
00628             if (mHasPurkinje)
00629             {
00630                 archive & p_purkinje_cell;
00631             }
00632             // Check if it's a fake cell
00633             FakeBathCell* p_fake = dynamic_cast<FakeBathCell*>(p_cell);
00634             if (p_fake)
00635             {
00636                 if (halo || local)
00637                 {
00638                     fake_cells_local.insert(p_fake);
00639                 }
00640                 else
00641                 {
00642                     fake_cells_non_local.insert(p_fake);
00643                 }
00644             }
00645             FakeBathCell* p_fake_purkinje = dynamic_cast<FakeBathCell*>(p_purkinje_cell);
00646             if (p_fake_purkinje)
00647             {
00648                 if (halo || local)
00649                 {
00650                     fake_cells_local.insert(p_fake_purkinje);
00651                 }
00652                 else
00653                 {
00654                     fake_cells_non_local.insert(p_fake_purkinje);
00655                 }
00656             }
00657             // Add real cells to the local or halo vectors
00658             if (local)
00659             {
00660                 assert(mCellsDistributed[new_local_index] == NULL);
00661                 mCellsDistributed[new_local_index] = p_cell;
00662                 if (mHasPurkinje)
00663                 {
00664                     assert(mPurkinjeCellsDistributed[new_local_index] == NULL);
00665                     mPurkinjeCellsDistributed[new_local_index] = p_purkinje_cell;
00666                 }
00667             }
00668             else if (halo)
00669             {
00670                 assert(mHaloCellsDistributed[halo_position->second] == NULL);
00671                 mHaloCellsDistributed[halo_position->second] = p_cell;
00672                 if (mHasPurkinje)
00673                 {
00675                     NEVER_REACHED;
00676                 }
00677             }
00678             else
00679             {
00680                 if (!p_fake)
00681                 {
00682                     // Non-local real cell, so free the memory.
00683                     delete p_cell;
00684                 }
00685                 if (!p_fake_purkinje)
00686                 {
00687                     // This will be NULL if there's no Purkinje, so a delete is OK.
00688                     delete p_purkinje_cell;
00689                 }
00690             }
00691         }
00692 
00693         // Delete any unused fake cells
00694         for (std::set<FakeBathCell*>::iterator it = fake_cells_non_local.begin();
00695              it != fake_cells_non_local.end();
00696              ++it)
00697         {
00698             if (fake_cells_local.find(*it) == fake_cells_local.end())
00699             {
00700                 delete (*it);
00701             }
00702         }
00703     }
00704 };
00705 
00706 TEMPLATED_CLASS_IS_ABSTRACT_2_UNSIGNED(AbstractCardiacTissue)
00707 
00708 namespace boost {
00709 namespace serialization {
00716 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00717 struct version<AbstractCardiacTissue<ELEMENT_DIM, SPACE_DIM> >
00718 {
00720     CHASTE_VERSION_CONTENT(3);
00721 };
00722 } // namespace serialization
00723 } // namespace boost
00724 
00725 #endif /*ABSTRACTCARDIACTISSUE_HPP_*/
00726 
Generated on Thu Dec 22 13:00:07 2011 for Chaste by  doxygen 1.6.3