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 00036 00037 #ifndef ABSTRACTCARDIACPROBLEM_HPP_ 00038 #define ABSTRACTCARDIACPROBLEM_HPP_ 00039 00040 00041 00042 #include <string> 00043 #include <vector> 00044 #include <cassert> 00045 #include <climits> 00046 #include <boost/shared_ptr.hpp> 00047 00048 #include "ChasteSerialization.hpp" 00049 #include <boost/serialization/vector.hpp> 00050 #include <boost/serialization/string.hpp> 00051 #include <boost/serialization/split_member.hpp> 00052 #include <boost/serialization/shared_ptr.hpp> 00053 #include "ClassIsAbstract.hpp" 00054 #include "ChasteSerializationVersion.hpp" 00055 00056 #include "AbstractTetrahedralMesh.hpp" 00057 #include "AbstractCardiacCell.hpp" 00058 #include "AbstractCardiacCellFactory.hpp" 00059 #include "AbstractCardiacTissue.hpp" 00060 #include "AbstractDynamicLinearPdeSolver.hpp" 00061 #include "BoundaryConditionsContainer.hpp" 00062 #include "DistributedVectorFactory.hpp" 00063 #include "Hdf5DataReader.hpp" 00064 #include "Hdf5DataWriter.hpp" 00065 00066 /* 00067 * Archiving extravaganza: 00068 * 00069 * We archive mesh and tissue through a pointer to an abstract class. All the potential concrete 00070 * classes need to be included here, so they are registered with boost. If not, boost won't be 00071 * able to find the archiving methods of the concrete class and will throw the following 00072 * exception: 00073 * 00074 * terminate called after throwing an instance of 'boost::archive::archive_exception' 00075 * what(): unregistered class 00076 * 00077 * No member variable is defined to be of any of these clases, so removing them won't 00078 * produce any compiler error. The exception above will occur at runtime. 00079 * 00080 * This might not be even necessary in certain cases, if the file is included implicitly by another 00081 * header file or by the test itself. It's safer though. 00082 */ 00083 #include "DistributedTetrahedralMesh.hpp" 00084 #include "TetrahedralMesh.hpp" //May be needed for unarchiving a mesh 00085 #include "MonodomainTissue.hpp" 00086 #include "BidomainTissue.hpp" 00087 00091 class AbstractUntemplatedCardiacProblem : private boost::noncopyable 00092 { 00093 public: 00095 virtual ~AbstractUntemplatedCardiacProblem() 00096 {} 00097 }; 00098 00104 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM> 00105 class AbstractCardiacProblem : public AbstractUntemplatedCardiacProblem 00106 { 00107 friend class TestBidomainWithBath; 00108 friend class TestCardiacSimulationArchiver; 00109 00111 typedef typename boost::shared_ptr<BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> > 00112 BccType; 00113 00114 private: 00116 friend class boost::serialization::access; 00117 00124 template<class Archive> 00125 void save(Archive & archive, const unsigned int version) const 00126 { 00127 if (version >= 1) 00128 { 00129 const unsigned element_dim=ELEMENT_DIM; 00130 archive & element_dim; 00131 const unsigned space_dim=SPACE_DIM; 00132 archive & space_dim; 00133 const unsigned problem_dim=PROBLEM_DIM; 00134 archive & problem_dim; 00135 } 00136 archive & mMeshFilename; 00137 archive & mpMesh; 00138 //archive & mAllocatedMemoryForMesh; // Mesh is deleted by AbstractCardiacTissue 00139 00140 // We shouldn't ever have to save the old version 00141 assert(version >= 2); 00142 // { 00143 // bool use_matrix_based_assembly = true; 00144 // archive & use_matrix_based_assembly; 00145 // } 00146 00147 archive & mWriteInfo; 00148 archive & mPrintOutput; 00149 archive & mNodesToOutput; 00150 //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve 00151 //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve 00152 //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve 00153 //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve 00154 //archive & mpWriter; // Created by InitialiseWriter, called from Solve 00155 archive & mpCardiacTissue; 00156 //archive & mpSolver; // Only exists during calls to the Solve method 00157 bool has_solution = (mSolution != NULL); 00158 archive & has_solution; 00159 if (has_solution) 00160 { 00162 std::string filename = ArchiveLocationInfo::GetArchiveDirectory() + "AbstractCardiacProblem_mSolution.vec"; 00163 00164 Hdf5DataWriter writer(*mpMesh->GetDistributedVectorFactory(), ArchiveLocationInfo::GetArchiveRelativePath(), "AbstractCardiacProblem_mSolution", false); 00165 writer.DefineFixedDimension(mpMesh->GetDistributedVectorFactory()->GetProblemSize()); 00166 00167 writer.DefineUnlimitedDimension("Time", "msec", 1); 00168 00169 // Make sure the file does not take more disc space than really needed (related to #1200) 00170 writer.SetFixedChunkSize(1); 00171 00172 int vm_col = writer.DefineVariable("Vm","mV"); 00173 00175 assert(HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering() == false ); 00176 00177 if (PROBLEM_DIM==1) 00178 { 00179 writer.EndDefineMode(); 00180 writer.PutUnlimitedVariable(0.0); 00181 writer.PutVector(vm_col, mSolution); 00182 } 00183 00184 if (PROBLEM_DIM==2) 00185 { 00186 int phie_col = writer.DefineVariable("Phie","mV"); 00187 std::vector<int> variable_ids; 00188 variable_ids.push_back(vm_col); 00189 variable_ids.push_back(phie_col); 00190 writer.EndDefineMode(); 00191 writer.PutUnlimitedVariable(0.0); 00192 writer.PutStripedVector(variable_ids, mSolution); 00193 } 00194 00195 writer.Close(); 00196 00197 } 00198 archive & mCurrentTime; 00199 00200 // Save boundary conditions 00201 SaveBoundaryConditions(archive, mpMesh, mpBoundaryConditionsContainer); 00202 SaveBoundaryConditions(archive, mpMesh, mpDefaultBoundaryConditionsContainer); 00203 } 00204 00211 template<class Archive> 00212 void load(Archive & archive, const unsigned int version) 00213 { 00214 if (version >= 1) 00215 { 00216 unsigned element_dim; 00217 unsigned space_dim; 00218 unsigned problem_dim; 00219 archive & element_dim; 00220 archive & space_dim; 00221 archive & problem_dim; 00222 if ( (element_dim != ELEMENT_DIM) ||(space_dim != SPACE_DIM) ||(problem_dim != PROBLEM_DIM) ) 00223 { 00224 /*If we carry on from this point then the mesh produced by unarchiving from the 00225 * archive is templated as AbstractTetrahedralMesh<element_dim, space_dim> 00226 * which doesn't match AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>* mpMesh. 00227 * Boost will through away the unarchived one, without deleting it properly and 00228 * then set mpMesh=NULL. We need to avoid this happening by bailing out. 00229 */ 00230 EXCEPTION("Failed to load from checkpoint because the dimensions of the archive do not match the object it's being read into."); 00231 } 00232 } 00233 archive & mMeshFilename; 00234 archive & mpMesh; 00235 assert(mpMesh != NULL); //If NULL then loading mesh has failed without an exception so Boost has given up on the mesh. This would happen if a 2-dimensional mesh was successfully unarchived but mpMesh was expecting a 3-d mesh etc. 00236 //archive & mAllocatedMemoryForMesh; // Will always be true after a load 00237 00238 if (version < 2) 00239 { 00240 bool use_matrix_based_assembly; 00241 archive & use_matrix_based_assembly; 00242 } 00243 00244 archive & mWriteInfo; 00245 archive & mPrintOutput; 00246 archive & mNodesToOutput; 00247 //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve 00248 //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve 00249 //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve 00250 //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve 00251 //archive & mpWriter; // Created by InitialiseWriter, called from Solve 00252 archive & mpCardiacTissue; 00253 //archive & mpSolver; // Only exists during calls to the Solve method 00254 bool has_solution; 00255 archive & has_solution; 00256 if ((has_solution) && PROBLEM_DIM < 3) 00257 { 00260 std::string filename = ArchiveLocationInfo::GetArchiveDirectory() + "AbstractCardiacProblem_mSolution.vec"; 00261 00262 mSolution = mpMesh->GetDistributedVectorFactory()->CreateVec(PROBLEM_DIM); 00263 DistributedVector mSolution_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution); 00264 00265 Vec vm = mpMesh->GetDistributedVectorFactory()->CreateVec(); 00266 Vec phie = mpMesh->GetDistributedVectorFactory()->CreateVec(); 00267 00268 std::string archive_dir = ArchiveLocationInfo::GetArchiveRelativePath(); 00269 Hdf5DataReader reader(archive_dir, "AbstractCardiacProblem_mSolution", !FileFinder::IsAbsolutePath(archive_dir)); 00270 reader.GetVariableOverNodes(vm, "Vm", 0); 00271 00272 if (PROBLEM_DIM==1) 00273 { 00274 //reader.Close(); // no need to call close explicitly, done in the destructor 00275 00276 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm); 00277 00278 DistributedVector::Stripe mSolution_vm(mSolution_distri,0); 00279 00280 for (DistributedVector::Iterator index = mSolution_distri.Begin(); 00281 index != mSolution_distri.End(); 00282 ++index) 00283 { 00284 mSolution_vm[index] = vm_distri[index]; 00285 } 00286 } 00287 00288 if (PROBLEM_DIM==2) 00289 { 00290 reader.GetVariableOverNodes(phie, "Phie", 0); 00291 //reader.Close(); // no need to call close explicitly, done in the destructor 00292 00293 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm); 00294 DistributedVector phie_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(phie); 00295 00296 DistributedVector::Stripe mSolution_vm(mSolution_distri,0); 00297 DistributedVector::Stripe mSolution_phie(mSolution_distri,1); 00298 00299 for (DistributedVector::Iterator index = mSolution_distri.Begin(); 00300 index != mSolution_distri.End(); 00301 ++index) 00302 { 00303 mSolution_vm[index] = vm_distri[index]; 00304 mSolution_phie[index] = phie_distri[index]; 00305 } 00306 } 00307 00308 mSolution_distri.Restore(); 00309 00310 PetscTools::Destroy(vm); 00311 PetscTools::Destroy(phie); 00312 00313 } 00314 archive & mCurrentTime; 00315 00316 // Load boundary conditions 00317 mpBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh); 00318 mpDefaultBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh); 00319 } 00320 00321 BOOST_SERIALIZATION_SPLIT_MEMBER() 00322 00323 00330 template<class Archive> 00331 void SaveBoundaryConditions(Archive & archive, 00332 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh, 00333 BccType pBcc) const 00334 { 00335 (*ProcessSpecificArchive<Archive>::Get()) & pBcc; 00336 } 00337 00345 template<class Archive> 00346 BccType LoadBoundaryConditions( 00347 Archive & archive, 00348 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh) 00349 { 00350 // Load pointer from archive 00351 BccType p_bcc; 00352 (*ProcessSpecificArchive<Archive>::Get()) & p_bcc; 00353 00354 // Fill in the conditions, if we have a container and it's not already full 00355 if (p_bcc) 00356 { 00357 p_bcc->LoadFromArchive(*ProcessSpecificArchive<Archive>::Get(), pMesh); 00358 } 00359 00360 return p_bcc; 00361 } 00362 00363 protected: 00366 std::string mMeshFilename; 00367 00369 bool mAllocatedMemoryForMesh; 00371 bool mWriteInfo; 00373 bool mPrintOutput; 00374 00376 std::vector<unsigned> mNodesToOutput; 00377 00379 unsigned mVoltageColumnId; 00381 std::vector<unsigned> mExtraVariablesId; 00383 unsigned mTimeColumnId; 00385 unsigned mNodeColumnId; 00386 00388 AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* mpCardiacTissue; 00389 00391 BccType mpBoundaryConditionsContainer; 00393 BccType mpDefaultBoundaryConditionsContainer; 00395 AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* mpSolver; 00397 AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* mpCellFactory; 00399 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* mpMesh; 00400 00403 Vec mSolution; 00404 00412 double mCurrentTime; 00413 00415 AbstractTimeAdaptivityController* mpTimeAdaptivityController; 00416 00417 00418 00424 virtual AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* CreateCardiacTissue() =0; 00425 00431 virtual AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* CreateSolver() =0; 00432 00440 virtual void CreateMeshFromHeartConfig(); 00441 00445 template<unsigned DIM, unsigned ELEC_PROB_DIM> 00446 friend class CardiacElectroMechanicsProblem; 00450 Hdf5DataWriter* mpWriter; 00451 00452 public: 00458 AbstractCardiacProblem(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory); 00459 00463 AbstractCardiacProblem(); 00464 00468 virtual ~AbstractCardiacProblem(); 00469 00477 void Initialise(); 00478 00484 void SetNodesPerProcessorFilename(const std::string& rFilename); 00485 00490 void SetBoundaryConditionsContainer(BccType pBcc); 00491 00499 virtual void PreSolveChecks(); 00500 00513 virtual Vec CreateInitialCondition(); 00514 00520 void SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh); 00521 00527 void PrintOutput(bool rPrintOutput); 00528 00534 void SetWriteInfo(bool writeInfo = true); 00535 00546 Vec GetSolution(); 00547 00553 DistributedVector GetSolutionDistributedVector(); 00554 00558 double GetCurrentTime(); 00559 00563 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & rGetMesh(); 00564 00568 AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* GetTissue(); 00569 00579 void Solve(); 00580 00588 void CloseFilesAndPostProcess(); 00589 00597 virtual void WriteInfo(double time)=0; 00598 00603 virtual void DefineWriterColumns(bool extending); 00604 00609 void DefineExtraVariablesWriterColumns(bool extending); 00610 00617 virtual void WriteOneStep(double time, Vec voltageVec) = 0; 00618 00622 void WriteExtraVariablesOneStep(); 00623 00634 bool InitialiseWriter(); 00635 00643 void SetOutputNodes(std::vector<unsigned> & rNodesToOutput); 00644 00648 Hdf5DataReader GetDataReader(); 00649 00657 virtual void AtBeginningOfTimestep(double time) 00658 {} 00659 00667 virtual void OnEndOfTimestep(double time) 00668 {} 00669 00677 virtual void SetUpAdditionalStoppingTimes(std::vector<double>& rAdditionalStoppingTimes) 00678 {} 00679 00680 00681 00683 // and no controller, in which case the default is used. 00684 00690 void SetUseTimeAdaptivityController(bool useAdaptivity, 00691 AbstractTimeAdaptivityController* pController = NULL); 00692 00713 template<class Archive> 00714 void LoadExtraArchive(Archive & archive, unsigned version); 00715 00719 virtual bool GetHasBath(); 00720 00725 virtual void SetElectrodes(); 00726 }; 00727 00728 TEMPLATED_CLASS_IS_ABSTRACT_3_UNSIGNED(AbstractCardiacProblem) 00729 00730 00731 template<unsigned DIM> 00732 class BidomainProblem; 00733 00734 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM> 00735 template<class Archive> 00736 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::LoadExtraArchive(Archive & archive, unsigned version) 00737 { 00738 // The vector factory must be loaded, but isn't needed for anything. 00739 DistributedVectorFactory* p_mesh_factory; 00740 archive >> p_mesh_factory; 00741 00742 // The cardiac cells - load only the cells we actually own 00743 mpCardiacTissue->LoadCardiacCells(archive, version); 00744 00745 { 00746 DistributedVectorFactory* p_pde_factory; 00747 archive >> p_pde_factory; 00748 assert(p_pde_factory == p_mesh_factory); // Paranoia... 00749 } 00750 // We no longer need this vector factory, since we already have our own. 00751 delete p_mesh_factory; 00752 00753 // The boundary conditions 00754 BccType p_bcc; 00755 archive >> p_bcc; 00756 if (p_bcc) 00757 { 00758 if (!mpBoundaryConditionsContainer) 00759 { 00760 mpBoundaryConditionsContainer = p_bcc; 00761 mpBoundaryConditionsContainer->LoadFromArchive(archive, mpMesh); 00762 } 00763 else 00764 { 00765 // The BCs will only actually be different if using a distributed tetrahedral mesh 00766 DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* p_dist_mesh = dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(mpMesh); 00767 if (p_dist_mesh) 00768 { 00769 mpBoundaryConditionsContainer->MergeFromArchive(archive, mpMesh); 00770 } 00771 else 00772 { 00773 // Load into the temporary container, which will get thrown away shortly 00774 p_bcc->LoadFromArchive(archive, mpMesh); 00776 } 00777 } 00778 } 00779 BccType p_default_bcc; 00780 archive >> p_default_bcc; 00781 if (p_default_bcc) 00782 { 00783 // This always holds, so we never need to load the default BCs 00784 assert(p_bcc == p_default_bcc); 00785 } 00786 00787 // Are we a bidomain problem? 00788 BidomainProblem<ELEMENT_DIM>* p_bidomain_problem = dynamic_cast<BidomainProblem<ELEMENT_DIM>*>(this); 00789 if (p_bidomain_problem) 00790 { 00791 assert(ELEMENT_DIM == SPACE_DIM); 00792 p_bidomain_problem->LoadExtraArchiveForBidomain(archive, version); 00793 } 00794 } 00795 00796 namespace boost { 00797 namespace serialization { 00804 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM> 00805 struct version<AbstractCardiacProblem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> > 00806 { 00808 CHASTE_VERSION_CONTENT(2); 00809 }; 00810 } // namespace serialization 00811 } // namespace boost 00812 #endif /*ABSTRACTCARDIACPROBLEM_HPP_*/