AbstractCardiacProblem.hpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 #include "AbstractOutputModifier.hpp"
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 TestMonodomainProblem;
00119     friend class TestCardiacSimulationArchiver;
00120 
00122     typedef typename boost::shared_ptr<BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
00123         BccType;
00124 
00125 private:
00127     friend class boost::serialization::access;
00128 
00135     template<class Archive>
00136     void save(Archive & archive, const unsigned int version) const
00137     {
00138         if (version >= 1)
00139         {
00140             const unsigned element_dim=ELEMENT_DIM;
00141             archive & element_dim;
00142             const unsigned space_dim=SPACE_DIM;
00143             archive & space_dim;
00144             const unsigned problem_dim=PROBLEM_DIM;
00145             archive & problem_dim;
00146         }
00147         archive & mMeshFilename;
00148         archive & mpMesh;
00149         //archive & mAllocatedMemoryForMesh; // Mesh is deleted by AbstractCardiacTissue
00150 
00151         // We shouldn't ever have to save the old version
00152         assert(version >= 2);
00153 //        {
00154 //            bool use_matrix_based_assembly = true;
00155 //            archive & use_matrix_based_assembly;
00156 //        }
00157 
00158         archive & mWriteInfo;
00159         archive & mPrintOutput;
00160         archive & mNodesToOutput;
00161         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00162         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00163         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00164         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00165         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00166         archive & mpCardiacTissue;
00167         //archive & mpSolver; // Only exists during calls to the Solve method
00168         bool has_solution = (mSolution != NULL);
00169         archive & has_solution;
00170         if (has_solution)
00171         {
00174             Hdf5DataWriter writer(*mpMesh->GetDistributedVectorFactory(), ArchiveLocationInfo::GetArchiveRelativePath(), "AbstractCardiacProblem_mSolution", false);
00175             writer.DefineFixedDimension(mpMesh->GetDistributedVectorFactory()->GetProblemSize());
00176             writer.DefineUnlimitedDimension("Time", "msec", 1);
00177 
00178             int vm_col = writer.DefineVariable("Vm","mV");
00179 
00180             if (PROBLEM_DIM==1)
00181             {
00182                 writer.EndDefineMode();
00183                 writer.PutUnlimitedVariable(0.0);
00184                 writer.PutVector(vm_col, mSolution);
00185             }
00186 
00187             if (PROBLEM_DIM==2)
00188             {
00189                 int phie_col = writer.DefineVariable("Phie","mV");
00190                 std::vector<int> variable_ids;
00191                 variable_ids.push_back(vm_col);
00192                 variable_ids.push_back(phie_col);
00193                 writer.EndDefineMode();
00194                 writer.PutUnlimitedVariable(0.0);
00195                 writer.PutStripedVector(variable_ids, mSolution);
00196             }
00197 
00198             writer.Close();
00199 
00200         }
00201         archive & mCurrentTime;
00202 
00203         // Save boundary conditions
00204         SaveBoundaryConditions(archive, mpMesh, mpBoundaryConditionsContainer);
00205         SaveBoundaryConditions(archive, mpMesh, mpDefaultBoundaryConditionsContainer);
00206 
00207         if (version>= 3)
00208         {
00209             archive & mOutputModifiers;
00210         }
00211     }
00212 
00219     template<class Archive>
00220     void load(Archive & archive, const unsigned int version)
00221     {
00222         if (version >= 1)
00223         {
00224             unsigned element_dim;
00225             unsigned space_dim;
00226             unsigned problem_dim;
00227             archive & element_dim;
00228             archive & space_dim;
00229             archive & problem_dim;
00230             if ( (element_dim != ELEMENT_DIM) ||(space_dim != SPACE_DIM) ||(problem_dim != PROBLEM_DIM) )
00231             {
00232                 /*If we carry on from this point then the mesh produced by unarchiving from the
00233                  * archive is templated as AbstractTetrahedralMesh<element_dim, space_dim>
00234                  * which doesn't match AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>*  mpMesh.
00235                  * Boost will through away the unarchived one, without deleting it properly and
00236                  * then set mpMesh=NULL.  We need to avoid this happening by bailing out.
00237                  */
00238                 EXCEPTION("Failed to load from checkpoint because the dimensions of the archive do not match the object it's being read into.");
00239             }
00240         }
00241         archive & mMeshFilename;
00242         archive & mpMesh;
00243         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.
00244         //archive & mAllocatedMemoryForMesh; // Will always be true after a load
00245 
00246         if (version < 2)
00247         {
00248             bool use_matrix_based_assembly;
00249             archive & use_matrix_based_assembly;
00250         }
00251 
00252         archive & mWriteInfo;
00253         archive & mPrintOutput;
00254         archive & mNodesToOutput;
00255         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00256         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00257         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00258         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00259         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00260         archive & mpCardiacTissue;
00261         //archive & mpSolver; // Only exists during calls to the Solve method
00262         bool has_solution;
00263         archive & has_solution;
00264         if ((has_solution) && PROBLEM_DIM < 3)
00265         {
00268             mSolution = mpMesh->GetDistributedVectorFactory()->CreateVec(PROBLEM_DIM);
00269             DistributedVector mSolution_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
00270 
00271             Vec vm = mpMesh->GetDistributedVectorFactory()->CreateVec();
00272             Vec phie = mpMesh->GetDistributedVectorFactory()->CreateVec();
00273 
00274             std::string archive_dir = ArchiveLocationInfo::GetArchiveRelativePath();
00275             Hdf5DataReader reader(archive_dir, "AbstractCardiacProblem_mSolution", !FileFinder::IsAbsolutePath(archive_dir));
00276             reader.GetVariableOverNodes(vm, "Vm", 0);
00277 
00278             if (PROBLEM_DIM==1)
00279             {
00280                 //reader.Close(); // no need to call close explicitly, done in the destructor
00281 
00282                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00283 
00284                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00285 
00286                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00287                      index != mSolution_distri.End();
00288                      ++index)
00289                 {
00290                     mSolution_vm[index] = vm_distri[index];
00291                 }
00292             }
00293 
00294             if (PROBLEM_DIM==2)
00295             {
00296                 reader.GetVariableOverNodes(phie, "Phie", 0);
00297                 //reader.Close(); // no need to call close explicitly, done in the destructor
00298 
00299                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00300                 DistributedVector phie_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(phie);
00301 
00302                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00303                 DistributedVector::Stripe mSolution_phie(mSolution_distri,1);
00304 
00305                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00306                      index != mSolution_distri.End();
00307                      ++index)
00308                 {
00309                     mSolution_vm[index] = vm_distri[index];
00310                     mSolution_phie[index] = phie_distri[index];
00311                 }
00312             }
00313 
00314             mSolution_distri.Restore();
00315 
00316             PetscTools::Destroy(vm);
00317             PetscTools::Destroy(phie);
00318 
00319         }
00320         archive & mCurrentTime;
00321 
00322         // Load boundary conditions
00323         mpBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00324         mpDefaultBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00325 
00326         if (version>= 3)
00327         {
00328             archive & mOutputModifiers;
00329         }
00330     }
00331 
00332     BOOST_SERIALIZATION_SPLIT_MEMBER()
00333 
00334     
00341     template<class Archive>
00342     void SaveBoundaryConditions(Archive & archive,
00343                                 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00344                                 BccType pBcc) const
00345     {
00346         (*ProcessSpecificArchive<Archive>::Get()) & pBcc;
00347     }
00348 
00356     template<class Archive>
00357     BccType LoadBoundaryConditions(
00358             Archive & archive,
00359             AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00360     {
00361         // Load pointer from archive
00362         BccType p_bcc;
00363         (*ProcessSpecificArchive<Archive>::Get()) & p_bcc;
00364 
00365         // Fill in the conditions, if we have a container and it's not already full
00366         if (p_bcc)
00367         {
00368             p_bcc->LoadFromArchive(*ProcessSpecificArchive<Archive>::Get(), pMesh);
00369         }
00370 
00371         return p_bcc;
00372     }
00373 
00374 protected:
00377     std::string mMeshFilename;
00378 
00380     bool mAllocatedMemoryForMesh;
00382     bool mWriteInfo;
00384     bool mPrintOutput;
00385 
00387     std::vector<unsigned> mNodesToOutput;
00388 
00390     unsigned mVoltageColumnId;
00392     std::vector<unsigned> mExtraVariablesId;
00394     unsigned mTimeColumnId;
00396     unsigned mNodeColumnId;
00397 
00399     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* mpCardiacTissue;
00400 
00402     BccType mpBoundaryConditionsContainer;
00404     BccType mpDefaultBoundaryConditionsContainer;
00406     AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* mpSolver;
00408     AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* mpCellFactory;
00410     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* mpMesh;
00411 
00414     Vec mSolution;
00415 
00423     double mCurrentTime;
00424 
00426     AbstractTimeAdaptivityController* mpTimeAdaptivityController;
00427 
00428 
00429 
00436     virtual AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* CreateCardiacTissue() =0;
00437 
00444     virtual AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* CreateSolver() =0;
00445 
00453     virtual void CreateMeshFromHeartConfig();
00454 
00458     template<unsigned DIM, unsigned ELEC_PROB_DIM>
00459     friend class CardiacElectroMechanicsProblem;
00460 
00464     Hdf5DataWriter* mpWriter;
00465 
00469     std::vector<boost::shared_ptr<AbstractOutputModifier> > mOutputModifiers;
00470 
00471 public:
00477     AbstractCardiacProblem(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory);
00478 
00482     AbstractCardiacProblem();
00483 
00487     virtual ~AbstractCardiacProblem();
00488 
00496     void Initialise();
00497 
00503     void SetNodesPerProcessorFilename(const std::string& rFilename);
00504 
00509     void SetBoundaryConditionsContainer(BccType pBcc);
00510 
00518     virtual void PreSolveChecks();
00519 
00533     virtual Vec CreateInitialCondition();
00534 
00540     void SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00541 
00547     void PrintOutput(bool rPrintOutput);
00548 
00554     void SetWriteInfo(bool writeInfo = true);
00555 
00566     Vec GetSolution();
00567 
00573     DistributedVector GetSolutionDistributedVector();
00574 
00578     double GetCurrentTime();
00579 
00583     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & rGetMesh();
00584 
00588     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* GetTissue();
00589 
00599     void Solve();
00600 
00608     void CloseFilesAndPostProcess();
00609 
00617     virtual void WriteInfo(double time)=0;
00618 
00623     virtual void DefineWriterColumns(bool extending);
00624 
00629     void DefineExtraVariablesWriterColumns(bool extending);
00630 
00637     virtual void WriteOneStep(double time, Vec voltageVec) = 0;
00638 
00642     void WriteExtraVariablesOneStep();
00643 
00654     bool InitialiseWriter();
00655 
00665     void SetOutputNodes(std::vector<unsigned> & rNodesToOutput);
00666 
00670     Hdf5DataReader GetDataReader();
00671 
00679     virtual void AtBeginningOfTimestep(double time)
00680     {}
00681 
00689     virtual void OnEndOfTimestep(double time)
00690     {}
00691 
00699     virtual void SetUpAdditionalStoppingTimes(std::vector<double>& rAdditionalStoppingTimes)
00700     {}
00701 
00702 
00703 
00705     // and no controller, in which case the default is used.
00706 
00712     void SetUseTimeAdaptivityController(bool useAdaptivity,
00713                                         AbstractTimeAdaptivityController* pController = NULL);
00714 
00735     template<class Archive>
00736     void LoadExtraArchive(Archive & archive, unsigned version);
00737 
00741     virtual bool GetHasBath();
00742 
00747     virtual void SetElectrodes();
00748 
00754     void AddOutputModifier( boost::shared_ptr<AbstractOutputModifier> pOutputModifier)
00755     {
00756         mOutputModifiers.push_back(pOutputModifier);
00757     }
00758 };
00759 
00760 TEMPLATED_CLASS_IS_ABSTRACT_3_UNSIGNED(AbstractCardiacProblem)
00761 
00762 
00763 template<unsigned DIM>
00764 class BidomainProblem;
00765 
00766 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00767 template<class Archive>
00768 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::LoadExtraArchive(Archive & archive, unsigned version)
00769 {
00770     // The vector factory must be loaded, but isn't needed for anything.
00771     DistributedVectorFactory* p_mesh_factory;
00772     archive >> p_mesh_factory;
00773 
00774     // How many processes were used by the saving simulation?
00775     DistributedVectorFactory* p_original_factory = p_mesh_factory->GetOriginalFactory();
00776     unsigned orig_num_procs = 1;
00777     if (p_original_factory)
00778     {
00779         orig_num_procs = p_original_factory->GetNumProcs();
00780     }
00781 
00782     // The cardiac cells - load only the cells we actually own
00783     mpCardiacTissue->LoadCardiacCells(archive, version);
00784 
00785     {
00786         DistributedVectorFactory* p_pde_factory;
00787         archive >> p_pde_factory;
00788         assert(p_pde_factory == p_mesh_factory); // Paranoia...
00789     }
00790     // We no longer need this vector factory, since we already have our own.
00791     delete p_mesh_factory;
00792 
00793     // The boundary conditions
00794     BccType p_bcc;
00795     archive >> p_bcc;
00796     if (p_bcc)
00797     {
00798         if (!mpBoundaryConditionsContainer)
00799         {
00800             mpBoundaryConditionsContainer = p_bcc;
00801             mpBoundaryConditionsContainer->LoadFromArchive(archive, mpMesh);
00802         }
00803         else
00804         {
00805             // If the mesh which was archived was a TetrahedralMesh then we have all the boundary conditions
00806             // in every process-specific archive.  We no longer test for this.
00807 #define COVERAGE_IGNORE
00808             if(!dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(mpMesh) && orig_num_procs > 1)
00809             {
00810                 // The correct way to do this should be:
00811                 // p_bcc->LoadFromArchive(archive, mpMesh);
00812                 WARNING("Loading from a parallel archive which used a non-distributed mesh.  This scenario should work but is not fully tested.");
00813             }
00814 #undef COVERAGE_IGNORE
00815             mpBoundaryConditionsContainer->MergeFromArchive(archive, mpMesh);
00816         }
00817     }
00818     BccType p_default_bcc;
00819     archive >> p_default_bcc;
00820     if (p_default_bcc)
00821     {
00822         // This always holds, so we never need to load the default BCs
00823         assert(p_bcc == p_default_bcc);
00824     }
00825 
00826     // Are we a bidomain problem?
00827     BidomainProblem<ELEMENT_DIM>* p_bidomain_problem = dynamic_cast<BidomainProblem<ELEMENT_DIM>*>(this);
00828     if (p_bidomain_problem)
00829     {
00830         assert(ELEMENT_DIM == SPACE_DIM);
00831         p_bidomain_problem->LoadExtraArchiveForBidomain(archive, version);
00832     }
00833 }
00834 
00835 namespace boost {
00836 namespace serialization {
00843 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM,  unsigned PROBLEM_DIM>
00844 struct version<AbstractCardiacProblem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
00845 {
00847     CHASTE_VERSION_CONTENT(3);
00848 };
00849 } // namespace serialization
00850 } // namespace boost
00851 #endif /*ABSTRACTCARDIACPROBLEM_HPP_*/

Generated by  doxygen 1.6.2