AbstractCardiacProblem.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2014, 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 #include "Warnings.hpp"
00066 
00067 /*
00068  * Archiving extravaganza:
00069  *
00070  * We archive mesh and tissue through a pointer to an abstract class.  All the potential concrete
00071  * classes need to be included here, so they are registered with boost.  If not, boost won't be
00072  * able to find the archiving methods of the concrete class and will throw the following
00073  * exception:
00074  *
00075  *       terminate called after throwing an instance of 'boost::archive::archive_exception'
00076  *       what():  unregistered class
00077  *
00078  * No member variable is defined to be of any of these clases, so removing them won't
00079  * produce any compiler error.  The exception above will occur at runtime.
00080  *
00081  * This might not be even necessary in certain cases, if the file is included implicitly by another
00082  * header file or by the test itself.  It's safer though.
00083  */
00084 #include "DistributedTetrahedralMesh.hpp"
00085 #include "TetrahedralMesh.hpp" //May be needed for unarchiving a mesh
00086 #include "MonodomainTissue.hpp"
00087 #include "BidomainTissue.hpp"
00088 
00092 class AbstractUntemplatedCardiacProblem : private boost::noncopyable
00093 {
00094 public:
00096     virtual ~AbstractUntemplatedCardiacProblem()
00097     {}
00098 };
00099 
00114 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00115 class AbstractCardiacProblem : public AbstractUntemplatedCardiacProblem
00116 {
00117     friend class TestBidomainWithBath;
00118     friend class TestCardiacSimulationArchiver;
00119 
00121     typedef typename boost::shared_ptr<BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
00122         BccType;
00123 
00124 private:
00126     friend class boost::serialization::access;
00127 
00134     template<class Archive>
00135     void save(Archive & archive, const unsigned int version) const
00136     {
00137         if (version >= 1)
00138         {
00139             const unsigned element_dim=ELEMENT_DIM;
00140             archive & element_dim;
00141             const unsigned space_dim=SPACE_DIM;
00142             archive & space_dim;
00143             const unsigned problem_dim=PROBLEM_DIM;
00144             archive & problem_dim;
00145         }
00146         archive & mMeshFilename;
00147         archive & mpMesh;
00148         //archive & mAllocatedMemoryForMesh; // Mesh is deleted by AbstractCardiacTissue
00149 
00150         // We shouldn't ever have to save the old version
00151         assert(version >= 2);
00152 //        {
00153 //            bool use_matrix_based_assembly = true;
00154 //            archive & use_matrix_based_assembly;
00155 //        }
00156 
00157         archive & mWriteInfo;
00158         archive & mPrintOutput;
00159         archive & mNodesToOutput;
00160         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00161         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00162         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00163         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00164         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00165         archive & mpCardiacTissue;
00166         //archive & mpSolver; // Only exists during calls to the Solve method
00167         bool has_solution = (mSolution != NULL);
00168         archive & has_solution;
00169         if (has_solution)
00170         {
00172             Hdf5DataWriter writer(*mpMesh->GetDistributedVectorFactory(), ArchiveLocationInfo::GetArchiveRelativePath(), "AbstractCardiacProblem_mSolution", false);
00173             writer.DefineFixedDimension(mpMesh->GetDistributedVectorFactory()->GetProblemSize());
00174             writer.DefineUnlimitedDimension("Time", "msec", 1);
00175 
00176             int vm_col = writer.DefineVariable("Vm","mV");
00177 
00178             if (PROBLEM_DIM==1)
00179             {
00180                 writer.EndDefineMode();
00181                 writer.PutUnlimitedVariable(0.0);
00182                 writer.PutVector(vm_col, mSolution);
00183             }
00184 
00185             if (PROBLEM_DIM==2)
00186             {
00187                 int phie_col = writer.DefineVariable("Phie","mV");
00188                 std::vector<int> variable_ids;
00189                 variable_ids.push_back(vm_col);
00190                 variable_ids.push_back(phie_col);
00191                 writer.EndDefineMode();
00192                 writer.PutUnlimitedVariable(0.0);
00193                 writer.PutStripedVector(variable_ids, mSolution);
00194             }
00195 
00196             writer.Close();
00197 
00198         }
00199         archive & mCurrentTime;
00200 
00201         // Save boundary conditions
00202         SaveBoundaryConditions(archive, mpMesh, mpBoundaryConditionsContainer);
00203         SaveBoundaryConditions(archive, mpMesh, mpDefaultBoundaryConditionsContainer);
00204     }
00205 
00212     template<class Archive>
00213     void load(Archive & archive, const unsigned int version)
00214     {
00215         if (version >= 1)
00216         {
00217             unsigned element_dim;
00218             unsigned space_dim;
00219             unsigned problem_dim;
00220             archive & element_dim;
00221             archive & space_dim;
00222             archive & problem_dim;
00223             if ( (element_dim != ELEMENT_DIM) ||(space_dim != SPACE_DIM) ||(problem_dim != PROBLEM_DIM) )
00224             {
00225                 /*If we carry on from this point then the mesh produced by unarchiving from the
00226                  * archive is templated as AbstractTetrahedralMesh<element_dim, space_dim>
00227                  * which doesn't match AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>*  mpMesh.
00228                  * Boost will through away the unarchived one, without deleting it properly and
00229                  * then set mpMesh=NULL.  We need to avoid this happening by bailing out.
00230                  */
00231                 EXCEPTION("Failed to load from checkpoint because the dimensions of the archive do not match the object it's being read into.");
00232             }
00233         }
00234         archive & mMeshFilename;
00235         archive & mpMesh;
00236         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.
00237         //archive & mAllocatedMemoryForMesh; // Will always be true after a load
00238 
00239         if (version < 2)
00240         {
00241             bool use_matrix_based_assembly;
00242             archive & use_matrix_based_assembly;
00243         }
00244 
00245         archive & mWriteInfo;
00246         archive & mPrintOutput;
00247         archive & mNodesToOutput;
00248         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00249         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00250         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00251         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00252         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00253         archive & mpCardiacTissue;
00254         //archive & mpSolver; // Only exists during calls to the Solve method
00255         bool has_solution;
00256         archive & has_solution;
00257         if ((has_solution) && PROBLEM_DIM < 3)
00258         {
00261             mSolution = mpMesh->GetDistributedVectorFactory()->CreateVec(PROBLEM_DIM);
00262             DistributedVector mSolution_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
00263 
00264             Vec vm = mpMesh->GetDistributedVectorFactory()->CreateVec();
00265             Vec phie = mpMesh->GetDistributedVectorFactory()->CreateVec();
00266 
00267             std::string archive_dir = ArchiveLocationInfo::GetArchiveRelativePath();
00268             Hdf5DataReader reader(archive_dir, "AbstractCardiacProblem_mSolution", !FileFinder::IsAbsolutePath(archive_dir));
00269             reader.GetVariableOverNodes(vm, "Vm", 0);
00270 
00271             if (PROBLEM_DIM==1)
00272             {
00273                 //reader.Close(); // no need to call close explicitly, done in the destructor
00274 
00275                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00276 
00277                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
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                 }
00285             }
00286 
00287             if (PROBLEM_DIM==2)
00288             {
00289                 reader.GetVariableOverNodes(phie, "Phie", 0);
00290                 //reader.Close(); // no need to call close explicitly, done in the destructor
00291 
00292                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00293                 DistributedVector phie_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(phie);
00294 
00295                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00296                 DistributedVector::Stripe mSolution_phie(mSolution_distri,1);
00297 
00298                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00299                      index != mSolution_distri.End();
00300                      ++index)
00301                 {
00302                     mSolution_vm[index] = vm_distri[index];
00303                     mSolution_phie[index] = phie_distri[index];
00304                 }
00305             }
00306 
00307             mSolution_distri.Restore();
00308 
00309             PetscTools::Destroy(vm);
00310             PetscTools::Destroy(phie);
00311 
00312         }
00313         archive & mCurrentTime;
00314 
00315         // Load boundary conditions
00316         mpBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00317         mpDefaultBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00318     }
00319 
00320     BOOST_SERIALIZATION_SPLIT_MEMBER()
00321 
00322     
00329     template<class Archive>
00330     void SaveBoundaryConditions(Archive & archive,
00331                                 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00332                                 BccType pBcc) const
00333     {
00334         (*ProcessSpecificArchive<Archive>::Get()) & pBcc;
00335     }
00336 
00344     template<class Archive>
00345     BccType LoadBoundaryConditions(
00346             Archive & archive,
00347             AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00348     {
00349         // Load pointer from archive
00350         BccType p_bcc;
00351         (*ProcessSpecificArchive<Archive>::Get()) & p_bcc;
00352 
00353         // Fill in the conditions, if we have a container and it's not already full
00354         if (p_bcc)
00355         {
00356             p_bcc->LoadFromArchive(*ProcessSpecificArchive<Archive>::Get(), pMesh);
00357         }
00358 
00359         return p_bcc;
00360     }
00361 
00362 protected:
00365     std::string mMeshFilename;
00366 
00368     bool mAllocatedMemoryForMesh;
00370     bool mWriteInfo;
00372     bool mPrintOutput;
00373 
00375     std::vector<unsigned> mNodesToOutput;
00376 
00378     unsigned mVoltageColumnId;
00380     std::vector<unsigned> mExtraVariablesId;
00382     unsigned mTimeColumnId;
00384     unsigned mNodeColumnId;
00385 
00387     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* mpCardiacTissue;
00388 
00390     BccType mpBoundaryConditionsContainer;
00392     BccType mpDefaultBoundaryConditionsContainer;
00394     AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* mpSolver;
00396     AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* mpCellFactory;
00398     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* mpMesh;
00399 
00402     Vec mSolution;
00403 
00411     double mCurrentTime;
00412 
00414     AbstractTimeAdaptivityController* mpTimeAdaptivityController;
00415 
00416 
00417 
00424     virtual AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* CreateCardiacTissue() =0;
00425 
00432     virtual AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* CreateSolver() =0;
00433 
00441     virtual void CreateMeshFromHeartConfig();
00442 
00446     template<unsigned DIM, unsigned ELEC_PROB_DIM>
00447     friend class CardiacElectroMechanicsProblem;
00448 
00452     Hdf5DataWriter* mpWriter;
00453 
00454 public:
00460     AbstractCardiacProblem(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory);
00461 
00465     AbstractCardiacProblem();
00466 
00470     virtual ~AbstractCardiacProblem();
00471 
00479     void Initialise();
00480 
00486     void SetNodesPerProcessorFilename(const std::string& rFilename);
00487 
00492     void SetBoundaryConditionsContainer(BccType pBcc);
00493 
00501     virtual void PreSolveChecks();
00502 
00516     virtual Vec CreateInitialCondition();
00517 
00523     void SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00524 
00530     void PrintOutput(bool rPrintOutput);
00531 
00537     void SetWriteInfo(bool writeInfo = true);
00538 
00549     Vec GetSolution();
00550 
00556     DistributedVector GetSolutionDistributedVector();
00557 
00561     double GetCurrentTime();
00562 
00566     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & rGetMesh();
00567 
00571     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* GetTissue();
00572 
00582     void Solve();
00583 
00591     void CloseFilesAndPostProcess();
00592 
00600     virtual void WriteInfo(double time)=0;
00601 
00606     virtual void DefineWriterColumns(bool extending);
00607 
00612     void DefineExtraVariablesWriterColumns(bool extending);
00613 
00620     virtual void WriteOneStep(double time, Vec voltageVec) = 0;
00621 
00625     void WriteExtraVariablesOneStep();
00626 
00637     bool InitialiseWriter();
00638 
00648     void SetOutputNodes(std::vector<unsigned> & rNodesToOutput);
00649 
00653     Hdf5DataReader GetDataReader();
00654 
00662     virtual void AtBeginningOfTimestep(double time)
00663     {}
00664 
00672     virtual void OnEndOfTimestep(double time)
00673     {}
00674 
00682     virtual void SetUpAdditionalStoppingTimes(std::vector<double>& rAdditionalStoppingTimes)
00683     {}
00684 
00685 
00686 
00688     // and no controller, in which case the default is used.
00689 
00695     void SetUseTimeAdaptivityController(bool useAdaptivity,
00696                                         AbstractTimeAdaptivityController* pController = NULL);
00697 
00718     template<class Archive>
00719     void LoadExtraArchive(Archive & archive, unsigned version);
00720 
00724     virtual bool GetHasBath();
00725 
00730     virtual void SetElectrodes();
00731 };
00732 
00733 TEMPLATED_CLASS_IS_ABSTRACT_3_UNSIGNED(AbstractCardiacProblem)
00734 
00735 
00736 template<unsigned DIM>
00737 class BidomainProblem;
00738 
00739 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00740 template<class Archive>
00741 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::LoadExtraArchive(Archive & archive, unsigned version)
00742 {
00743     // The vector factory must be loaded, but isn't needed for anything.
00744     DistributedVectorFactory* p_mesh_factory;
00745     archive >> p_mesh_factory;
00746 
00747     // How many processes were used by the saving simulation?
00748     DistributedVectorFactory* p_original_factory = p_mesh_factory->GetOriginalFactory();
00749     unsigned orig_num_procs = 1;
00750     if (p_original_factory)
00751     {
00752         orig_num_procs = p_original_factory->GetNumProcs();
00753     }
00754 
00755     // The cardiac cells - load only the cells we actually own
00756     mpCardiacTissue->LoadCardiacCells(archive, version);
00757 
00758     {
00759         DistributedVectorFactory* p_pde_factory;
00760         archive >> p_pde_factory;
00761         assert(p_pde_factory == p_mesh_factory); // Paranoia...
00762     }
00763     // We no longer need this vector factory, since we already have our own.
00764     delete p_mesh_factory;
00765 
00766     // The boundary conditions
00767     BccType p_bcc;
00768     archive >> p_bcc;
00769     if (p_bcc)
00770     {
00771         if (!mpBoundaryConditionsContainer)
00772         {
00773             mpBoundaryConditionsContainer = p_bcc;
00774             mpBoundaryConditionsContainer->LoadFromArchive(archive, mpMesh);
00775         }
00776         else
00777         {
00778             // If the mesh which was archived was a TetrahedralMesh then we have all the boundary conditions
00779             // in every process-specific archive.  We no longer test for this.
00780 #define COVERAGE_IGNORE
00781             if(!dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(mpMesh) && orig_num_procs > 1)
00782             {
00783                 // The correct way to do this should be:
00784                 // p_bcc->LoadFromArchive(archive, mpMesh);
00785                 WARNING("Loading from a parallel archive which used a non-distributed mesh.  This scenario should work but is not fully tested.");
00786             }
00787 #undef COVERAGE_IGNORE
00788             mpBoundaryConditionsContainer->MergeFromArchive(archive, mpMesh);
00789         }
00790     }
00791     BccType p_default_bcc;
00792     archive >> p_default_bcc;
00793     if (p_default_bcc)
00794     {
00795         // This always holds, so we never need to load the default BCs
00796         assert(p_bcc == p_default_bcc);
00797     }
00798 
00799     // Are we a bidomain problem?
00800     BidomainProblem<ELEMENT_DIM>* p_bidomain_problem = dynamic_cast<BidomainProblem<ELEMENT_DIM>*>(this);
00801     if (p_bidomain_problem)
00802     {
00803         assert(ELEMENT_DIM == SPACE_DIM);
00804         p_bidomain_problem->LoadExtraArchiveForBidomain(archive, version);
00805     }
00806 }
00807 
00808 namespace boost {
00809 namespace serialization {
00816 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM,  unsigned PROBLEM_DIM>
00817 struct version<AbstractCardiacProblem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
00818 {
00820     CHASTE_VERSION_CONTENT(2);
00821 };
00822 } // namespace serialization
00823 } // namespace boost
00824 #endif /*ABSTRACTCARDIACPROBLEM_HPP_*/

Generated by  doxygen 1.6.2