AbstractCardiacProblem.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 
00029 
00030 #ifndef ABSTRACTCARDIACPROBLEM_HPP_
00031 #define ABSTRACTCARDIACPROBLEM_HPP_
00032 
00033 
00034 
00035 #include <string>
00036 #include <vector>
00037 #include <cassert>
00038 #include <climits>
00039 #include <boost/shared_ptr.hpp>
00040 
00041 #include "ChasteSerialization.hpp"
00042 #include <boost/serialization/vector.hpp>
00043 #include <boost/serialization/string.hpp>
00044 #include <boost/serialization/split_member.hpp>
00045 #include <boost/serialization/shared_ptr.hpp>
00046 #include "ClassIsAbstract.hpp"
00047 #include "ChasteSerializationVersion.hpp"
00048 
00049 #include "AbstractTetrahedralMesh.hpp"
00050 #include "AbstractCardiacCell.hpp"
00051 #include "AbstractCardiacCellFactory.hpp"
00052 #include "AbstractCardiacTissue.hpp"
00053 #include "AbstractDynamicLinearPdeSolver.hpp"
00054 #include "BoundaryConditionsContainer.hpp"
00055 #include "DistributedVectorFactory.hpp"
00056 #include "Hdf5DataReader.hpp"
00057 #include "Hdf5DataWriter.hpp"
00058 
00059 /*
00060  * Archiving extravaganza:
00061  *
00062  * We archive mesh and tissue through a pointer to an abstract class.  All the potential concrete
00063  * classes need to be included here, so they are registered with boost.  If not, boost won't be
00064  * able to find the archiving methods of the concrete class and will throw the following
00065  * exception:
00066  *
00067  *       terminate called after throwing an instance of 'boost::archive::archive_exception'
00068  *       what():  unregistered class
00069  *
00070  * No member variable is defined to be of any of these clases, so removing them won't
00071  * produce any compiler error.  The exception above will occur at runtime.
00072  *
00073  * This might not be even necessary in certain cases, if the file is included implicitly by another
00074  * header file or by the test itself.  It's safer though.
00075  */
00076 #include "DistributedTetrahedralMesh.hpp"
00077 #include "TetrahedralMesh.hpp" //May be needed for unarchiving a mesh
00078 #include "MonodomainTissue.hpp"
00079 #include "BidomainTissue.hpp"
00080 
00084 class AbstractUntemplatedCardiacProblem : boost::noncopyable
00085 {
00086 public:
00088     virtual ~AbstractUntemplatedCardiacProblem()
00089     {}
00090 };
00091 
00097 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00098 class AbstractCardiacProblem : public AbstractUntemplatedCardiacProblem
00099 {
00100     friend class TestBidomainWithBath;
00101     friend class TestCardiacSimulationArchiver;
00102 
00104     typedef typename boost::shared_ptr<BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
00105         BccType;
00106 
00107 private:
00109     friend class boost::serialization::access;
00110 
00117     template<class Archive>
00118     void save(Archive & archive, const unsigned int version) const
00119     {
00120         if (version >= 1)
00121         {
00122             const unsigned element_dim=ELEMENT_DIM;
00123             archive & element_dim;
00124             const unsigned space_dim=SPACE_DIM;
00125             archive & space_dim;
00126             const unsigned problem_dim=PROBLEM_DIM;
00127             archive & problem_dim;
00128         }
00129         archive & mMeshFilename;
00130         archive & mpMesh;
00131         //archive & mAllocatedMemoryForMesh; // Mesh is deleted by AbstractCardiacTissue
00132         archive & mUseMatrixBasedRhsAssembly;
00133         archive & mWriteInfo;
00134         archive & mPrintOutput;
00135         archive & mNodesToOutput;
00136         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00137         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00138         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00139         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00140         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00141         archive & mpCardiacTissue;
00142         //archive & mpSolver; // Only exists during calls to the Solve method
00143         bool has_solution = (mSolution != NULL);
00144         archive & has_solution;
00145         if (has_solution)
00146         {
00148             std::string filename = ArchiveLocationInfo::GetArchiveDirectory() + "AbstractCardiacProblem_mSolution.vec";
00149 
00150             Hdf5DataWriter writer(*mpMesh->GetDistributedVectorFactory(), ArchiveLocationInfo::GetArchiveRelativePath(), "AbstractCardiacProblem_mSolution", false);
00151             writer.DefineFixedDimension(mpMesh->GetDistributedVectorFactory()->GetProblemSize());
00152 
00153             writer.DefineUnlimitedDimension("Time", "msec", 1);
00154 
00155             // Make sure the file does not take more disc space than really needed (related to #1200)
00156             writer.SetFixedChunkSize(1);
00157 
00158             int vm_col = writer.DefineVariable("Vm","mV");
00159 
00161             assert(HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering() == false );
00162 
00163             if (PROBLEM_DIM==1)
00164             {
00165                 writer.EndDefineMode();
00166                 writer.PutUnlimitedVariable(0.0);
00167                 writer.PutVector(vm_col, mSolution);
00168             }
00169 
00170             if (PROBLEM_DIM==2)
00171             {
00172                 int phie_col = writer.DefineVariable("Phie","mV");
00173                 std::vector<int> variable_ids;
00174                 variable_ids.push_back(vm_col);
00175                 variable_ids.push_back(phie_col);
00176                 writer.EndDefineMode();
00177                 writer.PutUnlimitedVariable(0.0);
00178                 writer.PutStripedVector(variable_ids, mSolution);
00179             }
00180 
00181             writer.Close();
00182 
00183         }
00184         archive & mCurrentTime;
00185 
00186         // Save boundary conditions
00187         SaveBoundaryConditions(archive, mpMesh, mpBoundaryConditionsContainer);
00188         SaveBoundaryConditions(archive, mpMesh, mpDefaultBoundaryConditionsContainer);
00189     }
00190 
00197     template<class Archive>
00198     void load(Archive & archive, const unsigned int version)
00199     {
00200         if (version >= 1)
00201         {
00202             unsigned element_dim;
00203             unsigned space_dim;
00204             unsigned problem_dim;
00205             archive & element_dim;
00206             archive & space_dim;
00207             archive & problem_dim;
00208             if ( (element_dim != ELEMENT_DIM) ||(space_dim != SPACE_DIM) ||(problem_dim != PROBLEM_DIM) )
00209             {
00210                 /*If we carry on from this point then the mesh produced by unarchiving from the
00211                  * archive is templated as AbstractTetrahedralMesh<element_dim, space_dim>
00212                  * which doesn't match AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>*  mpMesh.
00213                  * Boost will through away the unarchived one, without deleting it properly and
00214                  * then set mpMesh=NULL.  We need to avoid this happening by bailing out.
00215                  */
00216                 EXCEPTION("Failed to load from checkpoint because the dimensions of the archive do not match the object it's being read into.");
00217             }
00218         }
00219         archive & mMeshFilename;
00220         archive & mpMesh;
00221         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.
00222         //archive & mAllocatedMemoryForMesh; // Will always be true after a load
00223         archive & mUseMatrixBasedRhsAssembly;
00224         archive & mWriteInfo;
00225         archive & mPrintOutput;
00226         archive & mNodesToOutput;
00227         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00228         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00229         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00230         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00231         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00232         archive & mpCardiacTissue;
00233         //archive & mpSolver; // Only exists during calls to the Solve method
00234         bool has_solution;
00235         archive & has_solution;
00236         if ((has_solution) && PROBLEM_DIM < 3)
00237         {
00240             std::string filename = ArchiveLocationInfo::GetArchiveDirectory() + "AbstractCardiacProblem_mSolution.vec";
00241 
00242             mSolution = mpMesh->GetDistributedVectorFactory()->CreateVec(PROBLEM_DIM);
00243             DistributedVector mSolution_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
00244 
00245             Vec vm = mpMesh->GetDistributedVectorFactory()->CreateVec();
00246             Vec phie = mpMesh->GetDistributedVectorFactory()->CreateVec();
00247 
00248             std::string archive_dir = ArchiveLocationInfo::GetArchiveRelativePath();
00249             Hdf5DataReader reader(archive_dir, "AbstractCardiacProblem_mSolution", !FileFinder::IsAbsolutePath(archive_dir));
00250             reader.GetVariableOverNodes(vm, "Vm", 0);
00251 
00252             if (PROBLEM_DIM==1)
00253             {
00254                 //reader.Close(); // no need to call close explicitly, done in the destructor
00255 
00256                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00257 
00258                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00259 
00260                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00261                      index != mSolution_distri.End();
00262                      ++index)
00263                 {
00264                     mSolution_vm[index] = vm_distri[index];
00265                 }
00266             }
00267 
00268             if (PROBLEM_DIM==2)
00269             {
00270                 reader.GetVariableOverNodes(phie, "Phie", 0);
00271                 //reader.Close(); // no need to call close explicitly, done in the destructor
00272 
00273                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00274                 DistributedVector phie_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(phie);
00275 
00276                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00277                 DistributedVector::Stripe mSolution_phie(mSolution_distri,1);
00278 
00279                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00280                      index != mSolution_distri.End();
00281                      ++index)
00282                 {
00283                     mSolution_vm[index] = vm_distri[index];
00284                     mSolution_phie[index] = phie_distri[index];
00285                 }
00286             }
00287 
00288             mSolution_distri.Restore();
00289 
00290             VecDestroy(vm);
00291             VecDestroy(phie);
00292 
00293         }
00294         archive & mCurrentTime;
00295 
00296         // Load boundary conditions
00297         mpBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00298         mpDefaultBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00299     }
00300 
00301     BOOST_SERIALIZATION_SPLIT_MEMBER()
00302 
00303     
00310     template<class Archive>
00311     void SaveBoundaryConditions(Archive & archive,
00312                                 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00313                                 BccType pBcc) const
00314     {
00315         (*ProcessSpecificArchive<Archive>::Get()) & pBcc;
00316     }
00317 
00325     template<class Archive>
00326     BccType LoadBoundaryConditions(
00327             Archive & archive,
00328             AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00329     {
00330         // Load pointer from archive
00331         BccType p_bcc;
00332         (*ProcessSpecificArchive<Archive>::Get()) & p_bcc;
00333 
00334         // Fill in the conditions, if we have a container and it's not already full
00335         if (p_bcc)
00336         {
00337             p_bcc->LoadFromArchive(*ProcessSpecificArchive<Archive>::Get(), pMesh);
00338         }
00339 
00340         return p_bcc;
00341     }
00342 
00343 protected:
00346     std::string mMeshFilename;
00347 
00352     bool mUseMatrixBasedRhsAssembly;
00354     bool mAllocatedMemoryForMesh;
00356     bool mWriteInfo;
00358     bool mPrintOutput;
00359 
00361     std::vector<unsigned> mNodesToOutput;
00362 
00364     unsigned mVoltageColumnId;
00366     std::vector<unsigned> mExtraVariablesId;
00368     unsigned mTimeColumnId;
00370     unsigned mNodeColumnId;
00371 
00373     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* mpCardiacTissue;
00374 
00376     BccType mpBoundaryConditionsContainer;
00378     BccType mpDefaultBoundaryConditionsContainer;
00380     AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* mpSolver;
00382     AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* mpCellFactory;
00384     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* mpMesh;
00385 
00388     Vec mSolution;
00389 
00397     double mCurrentTime;
00398 
00400     AbstractTimeAdaptivityController* mpTimeAdaptivityController;
00401 
00402 
00403 
00409     virtual AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* CreateCardiacTissue() =0;
00410 
00416     virtual AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* CreateSolver() =0;
00417 
00418 protected:
00422     template<unsigned DIM>
00423     friend class CardiacElectroMechanicsProblem;
00427     Hdf5DataWriter* mpWriter;
00428 
00429 public:
00435     AbstractCardiacProblem(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory);
00436 
00440     AbstractCardiacProblem();
00441 
00445     virtual ~AbstractCardiacProblem();
00446 
00454     void Initialise();
00455 
00461     void SetNodesPerProcessorFilename(const std::string& rFilename);
00462 
00467     void SetBoundaryConditionsContainer(BccType pBcc);
00468 
00476     virtual void PreSolveChecks();
00477 
00483     virtual Vec CreateInitialCondition();
00484 
00490     void SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00491 
00497     void PrintOutput(bool rPrintOutput);
00498 
00504     void SetWriteInfo(bool writeInfo = true);
00505 
00516     Vec GetSolution();
00517 
00523     DistributedVector GetSolutionDistributedVector();
00524 
00528     double GetCurrentTime();
00529 
00533     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & rGetMesh();
00534 
00538     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* GetTissue();
00539 
00549     void Solve();
00550 
00558     void CloseFilesAndPostProcess();
00559 
00567     virtual void WriteInfo(double time)=0;
00568 
00573     virtual void DefineWriterColumns(bool extending);
00574 
00579     void DefineExtraVariablesWriterColumns(bool extending);
00580 
00587     virtual void WriteOneStep(double time, Vec voltageVec) = 0;
00588 
00592     void WriteExtraVariablesOneStep();
00593 
00599     void InitialiseWriter();
00600 
00608     void SetOutputNodes(std::vector<unsigned> & rNodesToOutput);
00609 
00613     Hdf5DataReader GetDataReader();
00614 
00620     void UseMatrixBasedRhsAssembly(bool useMatrixBasedRhsAssembly=true);
00621 
00629     virtual void AtBeginningOfTimestep(double time)
00630     {}
00631 
00639     virtual void OnEndOfTimestep(double time)
00640     {}
00641 
00649     virtual void SetUpAdditionalStoppingTimes(std::vector<double>& rAdditionalStoppingTimes)
00650     {}
00651 
00652 
00653 
00655     // and no controller, in which case the default is used.
00656 
00662     void SetUseTimeAdaptivityController(bool useAdaptivity,
00663                                         AbstractTimeAdaptivityController* pController = NULL);
00664 
00685     template<class Archive>
00686     void LoadExtraArchive(Archive & archive, unsigned version);
00687 
00691     virtual bool GetHasBath();
00692     
00697     virtual void SetElectrodes();
00698 };
00699 
00700 TEMPLATED_CLASS_IS_ABSTRACT_3_UNSIGNED(AbstractCardiacProblem)
00701 
00702 
00703 template<unsigned DIM>
00704 class BidomainProblem;
00705 
00706 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00707 template<class Archive>
00708 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::LoadExtraArchive(Archive & archive, unsigned version)
00709 {
00710     // The vector factory must be loaded, but isn't needed for anything.
00711     DistributedVectorFactory* p_mesh_factory;
00712     archive >> p_mesh_factory;
00713 
00714     // The cardiac cells - load only the cells we actually own
00715     mpCardiacTissue->LoadCardiacCells(archive, version);
00716     
00717     {
00718         DistributedVectorFactory* p_pde_factory;
00719         archive >> p_pde_factory;
00720         assert(p_pde_factory == p_mesh_factory); // Paranoia...
00721     }
00722     // We no longer need this vector factory, since we already have our own.
00723     delete p_mesh_factory;
00724 
00725     // The boundary conditions
00726     BccType p_bcc;
00727     archive >> p_bcc;
00728     if (p_bcc)
00729     {
00730         if (!mpBoundaryConditionsContainer)
00731         {
00732             mpBoundaryConditionsContainer = p_bcc;
00733             mpBoundaryConditionsContainer->LoadFromArchive(archive, mpMesh);
00734         }
00735         else
00736         {
00737             // The BCs will only actually be different if using a distributed tetrahedral mesh
00738             DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* p_dist_mesh = dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(mpMesh);
00739             if (p_dist_mesh)
00740             {
00741                 mpBoundaryConditionsContainer->MergeFromArchive(archive, mpMesh);
00742             }
00743             else
00744             {
00745                 // Load into the temporary container, which will get thrown away shortly
00746                 p_bcc->LoadFromArchive(archive, mpMesh);
00748             }
00749         }
00750     }
00751     BccType p_default_bcc;
00752     archive >> p_default_bcc;
00753     if (p_default_bcc)
00754     {
00755         // This always holds, so we never need to load the default BCs
00756         assert(p_bcc == p_default_bcc);
00757     }
00758 
00759     // Are we a bidomain problem?
00760     if (PROBLEM_DIM == 2)
00761     {
00762         assert(ELEMENT_DIM == SPACE_DIM);
00763         BidomainProblem<ELEMENT_DIM>* p_problem = dynamic_cast<BidomainProblem<ELEMENT_DIM>*>(this);
00764         assert(p_problem);
00765         p_problem->LoadExtraArchiveForBidomain(archive, version);
00766     }
00767 }
00768 
00769 namespace boost {
00770 namespace serialization {
00777 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM,  unsigned PROBLEM_DIM>
00778 struct version<AbstractCardiacProblem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
00779 {
00781     CHASTE_VERSION_CONTENT(1);
00782 };
00783 } // namespace serialization
00784 } // namespace boost
00785 #endif /*ABSTRACTCARDIACPROBLEM_HPP_*/

Generated on Mon Apr 18 11:35:28 2011 for Chaste by  doxygen 1.5.5