Chaste Release::3.1
|
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