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 
00133         // We shouldn't ever have to save the old version
00134         assert(version >= 2);
00135 //        {
00136 //            bool use_matrix_based_assembly = true;
00137 //            archive & use_matrix_based_assembly;
00138 //        }
00139 
00140         archive & mWriteInfo;
00141         archive & mPrintOutput;
00142         archive & mNodesToOutput;
00143         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00144         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00145         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00146         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00147         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00148         archive & mpCardiacTissue;
00149         //archive & mpSolver; // Only exists during calls to the Solve method
00150         bool has_solution = (mSolution != NULL);
00151         archive & has_solution;
00152         if (has_solution)
00153         {
00155             std::string filename = ArchiveLocationInfo::GetArchiveDirectory() + "AbstractCardiacProblem_mSolution.vec";
00156 
00157             Hdf5DataWriter writer(*mpMesh->GetDistributedVectorFactory(), ArchiveLocationInfo::GetArchiveRelativePath(), "AbstractCardiacProblem_mSolution", false);
00158             writer.DefineFixedDimension(mpMesh->GetDistributedVectorFactory()->GetProblemSize());
00159 
00160             writer.DefineUnlimitedDimension("Time", "msec", 1);
00161 
00162             // Make sure the file does not take more disc space than really needed (related to #1200)
00163             writer.SetFixedChunkSize(1);
00164 
00165             int vm_col = writer.DefineVariable("Vm","mV");
00166 
00168             assert(HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering() == false );
00169 
00170             if (PROBLEM_DIM==1)
00171             {
00172                 writer.EndDefineMode();
00173                 writer.PutUnlimitedVariable(0.0);
00174                 writer.PutVector(vm_col, mSolution);
00175             }
00176 
00177             if (PROBLEM_DIM==2)
00178             {
00179                 int phie_col = writer.DefineVariable("Phie","mV");
00180                 std::vector<int> variable_ids;
00181                 variable_ids.push_back(vm_col);
00182                 variable_ids.push_back(phie_col);
00183                 writer.EndDefineMode();
00184                 writer.PutUnlimitedVariable(0.0);
00185                 writer.PutStripedVector(variable_ids, mSolution);
00186             }
00187 
00188             writer.Close();
00189 
00190         }
00191         archive & mCurrentTime;
00192 
00193         // Save boundary conditions
00194         SaveBoundaryConditions(archive, mpMesh, mpBoundaryConditionsContainer);
00195         SaveBoundaryConditions(archive, mpMesh, mpDefaultBoundaryConditionsContainer);
00196     }
00197 
00204     template<class Archive>
00205     void load(Archive & archive, const unsigned int version)
00206     {
00207         if (version >= 1)
00208         {
00209             unsigned element_dim;
00210             unsigned space_dim;
00211             unsigned problem_dim;
00212             archive & element_dim;
00213             archive & space_dim;
00214             archive & problem_dim;
00215             if ( (element_dim != ELEMENT_DIM) ||(space_dim != SPACE_DIM) ||(problem_dim != PROBLEM_DIM) )
00216             {
00217                 /*If we carry on from this point then the mesh produced by unarchiving from the
00218                  * archive is templated as AbstractTetrahedralMesh<element_dim, space_dim>
00219                  * which doesn't match AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>*  mpMesh.
00220                  * Boost will through away the unarchived one, without deleting it properly and
00221                  * then set mpMesh=NULL.  We need to avoid this happening by bailing out.
00222                  */
00223                 EXCEPTION("Failed to load from checkpoint because the dimensions of the archive do not match the object it's being read into.");
00224             }
00225         }
00226         archive & mMeshFilename;
00227         archive & mpMesh;
00228         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.
00229         //archive & mAllocatedMemoryForMesh; // Will always be true after a load
00230 
00231         if (version < 2)
00232         {
00233             bool use_matrix_based_assembly;
00234             archive & use_matrix_based_assembly;
00235         }
00236 
00237         archive & mWriteInfo;
00238         archive & mPrintOutput;
00239         archive & mNodesToOutput;
00240         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00241         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00242         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00243         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00244         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00245         archive & mpCardiacTissue;
00246         //archive & mpSolver; // Only exists during calls to the Solve method
00247         bool has_solution;
00248         archive & has_solution;
00249         if ((has_solution) && PROBLEM_DIM < 3)
00250         {
00253             std::string filename = ArchiveLocationInfo::GetArchiveDirectory() + "AbstractCardiacProblem_mSolution.vec";
00254 
00255             mSolution = mpMesh->GetDistributedVectorFactory()->CreateVec(PROBLEM_DIM);
00256             DistributedVector mSolution_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
00257 
00258             Vec vm = mpMesh->GetDistributedVectorFactory()->CreateVec();
00259             Vec phie = mpMesh->GetDistributedVectorFactory()->CreateVec();
00260 
00261             std::string archive_dir = ArchiveLocationInfo::GetArchiveRelativePath();
00262             Hdf5DataReader reader(archive_dir, "AbstractCardiacProblem_mSolution", !FileFinder::IsAbsolutePath(archive_dir));
00263             reader.GetVariableOverNodes(vm, "Vm", 0);
00264 
00265             if (PROBLEM_DIM==1)
00266             {
00267                 //reader.Close(); // no need to call close explicitly, done in the destructor
00268 
00269                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00270 
00271                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00272 
00273                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00274                      index != mSolution_distri.End();
00275                      ++index)
00276                 {
00277                     mSolution_vm[index] = vm_distri[index];
00278                 }
00279             }
00280 
00281             if (PROBLEM_DIM==2)
00282             {
00283                 reader.GetVariableOverNodes(phie, "Phie", 0);
00284                 //reader.Close(); // no need to call close explicitly, done in the destructor
00285 
00286                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00287                 DistributedVector phie_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(phie);
00288 
00289                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00290                 DistributedVector::Stripe mSolution_phie(mSolution_distri,1);
00291 
00292                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00293                      index != mSolution_distri.End();
00294                      ++index)
00295                 {
00296                     mSolution_vm[index] = vm_distri[index];
00297                     mSolution_phie[index] = phie_distri[index];
00298                 }
00299             }
00300 
00301             mSolution_distri.Restore();
00302 
00303             VecDestroy(vm);
00304             VecDestroy(phie);
00305 
00306         }
00307         archive & mCurrentTime;
00308 
00309         // Load boundary conditions
00310         mpBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00311         mpDefaultBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00312     }
00313 
00314     BOOST_SERIALIZATION_SPLIT_MEMBER()
00315 
00316     
00323     template<class Archive>
00324     void SaveBoundaryConditions(Archive & archive,
00325                                 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00326                                 BccType pBcc) const
00327     {
00328         (*ProcessSpecificArchive<Archive>::Get()) & pBcc;
00329     }
00330 
00338     template<class Archive>
00339     BccType LoadBoundaryConditions(
00340             Archive & archive,
00341             AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00342     {
00343         // Load pointer from archive
00344         BccType p_bcc;
00345         (*ProcessSpecificArchive<Archive>::Get()) & p_bcc;
00346 
00347         // Fill in the conditions, if we have a container and it's not already full
00348         if (p_bcc)
00349         {
00350             p_bcc->LoadFromArchive(*ProcessSpecificArchive<Archive>::Get(), pMesh);
00351         }
00352 
00353         return p_bcc;
00354     }
00355 
00356 protected:
00359     std::string mMeshFilename;
00360 
00362     bool mAllocatedMemoryForMesh;
00364     bool mWriteInfo;
00366     bool mPrintOutput;
00367 
00369     std::vector<unsigned> mNodesToOutput;
00370 
00372     unsigned mVoltageColumnId;
00374     std::vector<unsigned> mExtraVariablesId;
00376     unsigned mTimeColumnId;
00378     unsigned mNodeColumnId;
00379 
00381     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* mpCardiacTissue;
00382 
00384     BccType mpBoundaryConditionsContainer;
00386     BccType mpDefaultBoundaryConditionsContainer;
00388     AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* mpSolver;
00390     AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* mpCellFactory;
00392     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* mpMesh;
00393 
00396     Vec mSolution;
00397 
00405     double mCurrentTime;
00406 
00408     AbstractTimeAdaptivityController* mpTimeAdaptivityController;
00409 
00410 
00411 
00417     virtual AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* CreateCardiacTissue() =0;
00418 
00424     virtual AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* CreateSolver() =0;
00425 
00426 protected:
00430     template<unsigned DIM>
00431     friend class CardiacElectroMechanicsProblem;
00435     Hdf5DataWriter* mpWriter;
00436 
00437 public:
00443     AbstractCardiacProblem(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory);
00444 
00448     AbstractCardiacProblem();
00449 
00453     virtual ~AbstractCardiacProblem();
00454 
00462     void Initialise();
00463 
00469     void SetNodesPerProcessorFilename(const std::string& rFilename);
00470 
00475     void SetBoundaryConditionsContainer(BccType pBcc);
00476 
00484     virtual void PreSolveChecks();
00485 
00491     virtual Vec CreateInitialCondition();
00492 
00498     void SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00499 
00505     void PrintOutput(bool rPrintOutput);
00506 
00512     void SetWriteInfo(bool writeInfo = true);
00513 
00524     Vec GetSolution();
00525 
00531     DistributedVector GetSolutionDistributedVector();
00532 
00536     double GetCurrentTime();
00537 
00541     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & rGetMesh();
00542 
00546     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* GetTissue();
00547 
00557     void Solve();
00558 
00566     void CloseFilesAndPostProcess();
00567 
00575     virtual void WriteInfo(double time)=0;
00576 
00581     virtual void DefineWriterColumns(bool extending);
00582 
00587     void DefineExtraVariablesWriterColumns(bool extending);
00588 
00595     virtual void WriteOneStep(double time, Vec voltageVec) = 0;
00596 
00600     void WriteExtraVariablesOneStep();
00601 
00607     void InitialiseWriter();
00608 
00616     void SetOutputNodes(std::vector<unsigned> & rNodesToOutput);
00617 
00621     Hdf5DataReader GetDataReader();
00622 
00630     virtual void AtBeginningOfTimestep(double time)
00631     {}
00632 
00640     virtual void OnEndOfTimestep(double time)
00641     {}
00642 
00650     virtual void SetUpAdditionalStoppingTimes(std::vector<double>& rAdditionalStoppingTimes)
00651     {}
00652 
00653 
00654 
00656     // and no controller, in which case the default is used.
00657 
00663     void SetUseTimeAdaptivityController(bool useAdaptivity,
00664                                         AbstractTimeAdaptivityController* pController = NULL);
00665 
00686     template<class Archive>
00687     void LoadExtraArchive(Archive & archive, unsigned version);
00688 
00692     virtual bool GetHasBath();
00693 
00698     virtual void SetElectrodes();
00699 };
00700 
00701 TEMPLATED_CLASS_IS_ABSTRACT_3_UNSIGNED(AbstractCardiacProblem)
00702 
00703 
00704 template<unsigned DIM>
00705 class BidomainProblem;
00706 
00707 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00708 template<class Archive>
00709 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::LoadExtraArchive(Archive & archive, unsigned version)
00710 {
00711     // The vector factory must be loaded, but isn't needed for anything.
00712     DistributedVectorFactory* p_mesh_factory;
00713     archive >> p_mesh_factory;
00714 
00715     // The cardiac cells - load only the cells we actually own
00716     mpCardiacTissue->LoadCardiacCells(archive, version);
00717 
00718     {
00719         DistributedVectorFactory* p_pde_factory;
00720         archive >> p_pde_factory;
00721         assert(p_pde_factory == p_mesh_factory); // Paranoia...
00722     }
00723     // We no longer need this vector factory, since we already have our own.
00724     delete p_mesh_factory;
00725 
00726     // The boundary conditions
00727     BccType p_bcc;
00728     archive >> p_bcc;
00729     if (p_bcc)
00730     {
00731         if (!mpBoundaryConditionsContainer)
00732         {
00733             mpBoundaryConditionsContainer = p_bcc;
00734             mpBoundaryConditionsContainer->LoadFromArchive(archive, mpMesh);
00735         }
00736         else
00737         {
00738             // The BCs will only actually be different if using a distributed tetrahedral mesh
00739             DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* p_dist_mesh = dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(mpMesh);
00740             if (p_dist_mesh)
00741             {
00742                 mpBoundaryConditionsContainer->MergeFromArchive(archive, mpMesh);
00743             }
00744             else
00745             {
00746                 // Load into the temporary container, which will get thrown away shortly
00747                 p_bcc->LoadFromArchive(archive, mpMesh);
00749             }
00750         }
00751     }
00752     BccType p_default_bcc;
00753     archive >> p_default_bcc;
00754     if (p_default_bcc)
00755     {
00756         // This always holds, so we never need to load the default BCs
00757         assert(p_bcc == p_default_bcc);
00758     }
00759 
00760     // Are we a bidomain problem?
00761     if (PROBLEM_DIM == 2)
00762     {
00763         assert(ELEMENT_DIM == SPACE_DIM);
00764         BidomainProblem<ELEMENT_DIM>* p_problem = dynamic_cast<BidomainProblem<ELEMENT_DIM>*>(this);
00765         assert(p_problem);
00766         p_problem->LoadExtraArchiveForBidomain(archive, version);
00767     }
00768 }
00769 
00770 namespace boost {
00771 namespace serialization {
00778 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM,  unsigned PROBLEM_DIM>
00779 struct version<AbstractCardiacProblem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
00780 {
00782     CHASTE_VERSION_CONTENT(2);
00783 };
00784 } // namespace serialization
00785 } // namespace boost
00786 #endif /*ABSTRACTCARDIACPROBLEM_HPP_*/
Generated on Thu Dec 22 13:00:06 2011 for Chaste by  doxygen 1.6.3