Chaste Release::3.1
AbstractCardiacProblem.hpp
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_*/