AbstractCardiacProblem.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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 
00040 #include "ChasteSerialization.hpp"
00041 #include <boost/serialization/vector.hpp>
00042 #include <boost/serialization/string.hpp>
00043 #include <boost/serialization/split_member.hpp>
00044 #include <boost/shared_ptr.hpp>
00045 #include <boost/serialization/shared_ptr.hpp>
00046 #include "ClassIsAbstract.hpp"
00047 
00048 #include "AbstractTetrahedralMesh.hpp"
00049 #include "AbstractCardiacCell.hpp"
00050 #include "AbstractCardiacCellFactory.hpp"
00051 #include "AbstractCardiacTissue.hpp"
00052 #include "AbstractDynamicLinearPdeSolver.hpp"
00053 #include "BoundaryConditionsContainer.hpp"
00054 #include "DistributedVectorFactory.hpp"
00055 #include "Hdf5DataReader.hpp"
00056 #include "Hdf5DataWriter.hpp"
00057 
00058 /*
00059  * Archiving extravaganza:
00060  *
00061  * We archive mesh and pde through a pointer to an abstract class. All the potential concrete
00062  * classes need to be included here, so they are registered with boost. If not, boost won't be
00063  * able to find the archiving methods of the concrete class and will throw the following
00064  * exception:
00065  *
00066  *       terminate called after throwing an instance of 'boost::archive::archive_exception'
00067  *       what():  unregistered class
00068  *
00069  * No member variable is defined to be of any of these clases, removing them won't
00070  * produce any compiler error. The exception above will occur at runtime.
00071  *
00072  * This might not be even necessary in certain cases, if the file is included implicitely by another header file
00073  * or by the test itself. It's safer though.
00074  *
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");
00154             int vm_col = writer.DefineVariable("Vm","mV");
00155 
00157             assert(HeartConfig::Instance()->GetOutputUsingOriginalNodeOrdering() == false );
00158             
00159             if (PROBLEM_DIM==1)
00160             {
00161                 writer.EndDefineMode();
00162                 writer.PutUnlimitedVariable(0.0);
00163                 writer.PutVector(vm_col, mSolution);
00164             }
00165 
00166             if (PROBLEM_DIM==2)
00167             {
00168                 int phie_col = writer.DefineVariable("Phie","mV");
00169                 std::vector<int> variable_ids;
00170                 variable_ids.push_back(vm_col);
00171                 variable_ids.push_back(phie_col);
00172                 writer.EndDefineMode();
00173                 writer.PutUnlimitedVariable(0.0);
00174                 writer.PutStripedVector(variable_ids, mSolution);
00175             }
00176 
00177             writer.Close();
00178 
00179         }
00180         archive & mCurrentTime;
00181 
00182         // Save boundary conditions
00183         SaveBoundaryConditions(archive, mpMesh, mpBoundaryConditionsContainer);
00184         SaveBoundaryConditions(archive, mpMesh, mpDefaultBoundaryConditionsContainer);
00185     }
00186 
00193     template<class Archive>
00194     void load(Archive & archive, const unsigned int version)
00195     {
00196         if (version == 1)
00197         {
00198             unsigned element_dim;
00199             unsigned space_dim;
00200             unsigned problem_dim;
00201             archive & element_dim;
00202             archive & space_dim;
00203             archive & problem_dim;
00204             if ( (element_dim != ELEMENT_DIM) ||(space_dim != SPACE_DIM) ||(problem_dim != PROBLEM_DIM) )
00205             {
00206                 /*If we carry on from this point then the mesh produced by unarchiving from the
00207                  * archive is templated as AbstractTetrahedralMesh<element_dim, space_dim>
00208                  * which doesn't match AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>*  mpMesh.
00209                  * Boost will through away the unarchived one, without deleting it properly and
00210                  * then set mpMesh=NULL.  We need to avoid this happening by bailing out.
00211                  */
00212                 EXCEPTION("Failed to load from checkpoint because the dimensions of the archive do not match the object it's being read into.");
00213             }
00214         }
00215         archive & mMeshFilename;
00216         archive & mpMesh;
00217         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.
00218         //archive & mAllocatedMemoryForMesh; // Will always be true after a load
00219         archive & mUseMatrixBasedRhsAssembly;
00220         archive & mWriteInfo;
00221         archive & mPrintOutput;
00222         archive & mNodesToOutput;
00223         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00224         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00225         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00226         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00227         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00228         archive & mpCardiacTissue;
00229         //archive & mpSolver; // Only exists during calls to the Solve method
00230         bool has_solution;
00231         archive & has_solution;
00232         if (has_solution)
00233         {
00236             std::string filename = ArchiveLocationInfo::GetArchiveDirectory() + "AbstractCardiacProblem_mSolution.vec";
00237 
00238             mSolution = mpMesh->GetDistributedVectorFactory()->CreateVec(PROBLEM_DIM);
00239             DistributedVector mSolution_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
00240 
00241             Vec vm = mpMesh->GetDistributedVectorFactory()->CreateVec();
00242             Vec phie = mpMesh->GetDistributedVectorFactory()->CreateVec();
00243 
00244             std::string archive_dir = ArchiveLocationInfo::GetArchiveRelativePath();
00245             Hdf5DataReader reader(archive_dir, "AbstractCardiacProblem_mSolution", !FileFinder::IsAbsolutePath(archive_dir));
00246             reader.GetVariableOverNodes(vm, "Vm", 0);
00247 
00248             if (PROBLEM_DIM==1)
00249             {
00250                 //reader.Close(); // no need to call close explicitly, done in the destructor
00251 
00252                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00253 
00254                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00255 
00256                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00257                      index != mSolution_distri.End();
00258                      ++index)
00259                 {
00260                     mSolution_vm[index] = vm_distri[index];
00261                 }
00262             }
00263 
00264             if (PROBLEM_DIM==2)
00265             {
00266                 reader.GetVariableOverNodes(phie, "Phie", 0);
00267                 //reader.Close(); // no need to call close explicitly, done in the destructor
00268 
00269                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00270                 DistributedVector phie_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(phie);
00271 
00272                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00273                 DistributedVector::Stripe mSolution_phie(mSolution_distri,1);
00274 
00275                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00276                      index != mSolution_distri.End();
00277                      ++index)
00278                 {
00279                     mSolution_vm[index] = vm_distri[index];
00280                     mSolution_phie[index] = phie_distri[index];
00281                 }
00282             }
00283 
00284             mSolution_distri.Restore();
00285 
00286             VecDestroy(vm);
00287             VecDestroy(phie);
00288 
00289         }
00290         archive & mCurrentTime;
00291 
00292         // Load boundary conditions
00293         mpBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00294         mpDefaultBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00295     }
00296 
00297     BOOST_SERIALIZATION_SPLIT_MEMBER()
00298 
00299     
00306     template<class Archive>
00307     void SaveBoundaryConditions(Archive & archive,
00308                                 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00309                                 BccType pBcc) const
00310     {
00311         (*ProcessSpecificArchive<Archive>::Get()) & pBcc;
00312     }
00313 
00321     template<class Archive>
00322     BccType LoadBoundaryConditions(
00323             Archive & archive,
00324             AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00325     {
00326         // Load pointer from archive
00327         BccType p_bcc;
00328         (*ProcessSpecificArchive<Archive>::Get()) & p_bcc;
00329 
00330         // Fill in the conditions, if we have a container and it's not already full
00331         if (p_bcc)
00332         {
00333             p_bcc->LoadFromArchive(*ProcessSpecificArchive<Archive>::Get(), pMesh);
00334         }
00335 
00336         return p_bcc;
00337     }
00338 
00339 protected:
00342     std::string mMeshFilename;
00343 
00348     bool mUseMatrixBasedRhsAssembly;
00350     bool mAllocatedMemoryForMesh;
00352     bool mWriteInfo;
00354     bool mPrintOutput;
00355 
00357     std::vector<unsigned> mNodesToOutput;
00358 
00360     unsigned mVoltageColumnId;
00362     std::vector<unsigned> mExtraVariablesId;
00364     unsigned mTimeColumnId;
00366     unsigned mNodeColumnId;
00367 
00369     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* mpCardiacTissue;
00370 
00372     BccType mpBoundaryConditionsContainer;
00374     BccType mpDefaultBoundaryConditionsContainer;
00376     AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* mpSolver;
00378     AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* mpCellFactory;
00380     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* mpMesh;
00381 
00384     Vec mSolution;
00385 
00393     double mCurrentTime;
00394 
00400     virtual AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* CreateCardiacTissue() =0;
00401 
00407     virtual AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* CreateSolver() =0;
00408 
00409 protected:
00413     template<unsigned DIM>
00414     friend class CardiacElectroMechanicsProblem;
00418     Hdf5DataWriter* mpWriter;
00425     virtual void SetElectrodes();
00426     
00427 public:
00433     AbstractCardiacProblem(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory);
00434 
00438     AbstractCardiacProblem();
00439 
00443     virtual ~AbstractCardiacProblem();
00444 
00452     void Initialise();
00453 
00459     void SetNodesPerProcessorFilename(const std::string& rFilename);
00460 
00465     void SetBoundaryConditionsContainer(BccType pBcc);
00466 
00474     virtual void PreSolveChecks();
00475 
00481     virtual Vec CreateInitialCondition();
00482 
00488     void SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00489 
00495     void PrintOutput(bool rPrintOutput);
00496 
00502     void SetWriteInfo(bool writeInfo = true);
00503 
00514     Vec GetSolution();
00515 
00521     DistributedVector GetSolutionDistributedVector();
00522 
00526     double GetCurrentTime();
00527 
00531     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & rGetMesh();
00532 
00536     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>* GetTissue();
00537 
00547     void Solve();
00548 
00556     void CloseFilesAndPostProcess();
00557 
00565     virtual void WriteInfo(double time)=0;
00566 
00571     virtual void DefineWriterColumns(bool extending);
00572 
00577     void DefineExtraVariablesWriterColumns(bool extending);
00578 
00585     virtual void WriteOneStep(double time, Vec voltageVec) = 0;
00586 
00590     void WriteExtraVariablesOneStep();
00591 
00597     void InitialiseWriter();
00598 
00606     void SetOutputNodes(std::vector<unsigned> & rNodesToOutput);
00607 
00611     Hdf5DataReader GetDataReader();
00612 
00618     void UseMatrixBasedRhsAssembly(bool usematrix=true);
00619 
00627     virtual void AtBeginningOfTimestep(double time)
00628     {}
00629 
00637     virtual void OnEndOfTimestep(double time)
00638     {}
00639 
00647     virtual void SetUpAdditionalStoppingTimes(std::vector<double>& rAdditionalStoppingTimes)
00648     {}
00649 
00670     template<class Archive>
00671     void LoadExtraArchive(Archive & archive, unsigned version);
00672 
00676     virtual bool GetHasBath();
00677   
00678 };
00679 
00680 TEMPLATED_CLASS_IS_ABSTRACT_3_UNSIGNED(AbstractCardiacProblem)
00681 
00682 
00683 template<unsigned DIM>
00684 class BidomainProblem;
00685 
00686 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00687 template<class Archive>
00688 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::LoadExtraArchive(Archive & archive, unsigned version)
00689 {
00690     // The vector factory must be loaded, but isn't needed for anything.
00691     DistributedVectorFactory* p_mesh_factory;
00692     archive >> p_mesh_factory;
00693 
00694     // The cardiac cells
00695     std::vector<AbstractCardiacCell*> cells;
00696     // Load only the cells we actually own
00697     AbstractCardiacTissue<ELEMENT_DIM,SPACE_DIM>::LoadCardiacCells(archive, version, cells, this->mpMesh);
00698     mpCardiacTissue->MergeCells(cells);
00699 
00700     {
00701         DistributedVectorFactory* p_pde_factory;
00702         archive >> p_pde_factory;
00703         assert(p_pde_factory == p_mesh_factory); // Paranoia...
00704     }
00705     // We no longer need this vector factory, since we already have our own.
00706     delete p_mesh_factory;
00707 
00708     // The boundary conditions
00709     BccType p_bcc;
00710     archive >> p_bcc;
00711     if (p_bcc)
00712     {
00713         if (!mpBoundaryConditionsContainer)
00714         {
00715             mpBoundaryConditionsContainer = p_bcc;
00716             mpBoundaryConditionsContainer->LoadFromArchive(archive, mpMesh);
00717         }
00718         else
00719         {
00720             // The BCs will only actually be different if using a distributed tetrahedral mesh
00721             DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* p_dist_mesh = dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(mpMesh);
00722             if (p_dist_mesh)
00723             {
00724                 mpBoundaryConditionsContainer->MergeFromArchive(archive, mpMesh);
00725             }
00726             else
00727             {
00728                 // Load into the temporary container, which will get thrown away shortly
00729                 p_bcc->LoadFromArchive(archive, mpMesh);
00731             }
00732         }
00733     }
00734     BccType p_default_bcc;
00735     archive >> p_default_bcc;
00736     if (p_default_bcc)
00737     {
00738         // This always holds, so we never need to load the default BCs
00739         assert(p_bcc == p_default_bcc);
00740     }
00741 
00742     // Are we a bidomain problem?
00743     if (PROBLEM_DIM == 2)
00744     {
00745         assert(ELEMENT_DIM == SPACE_DIM);
00746         BidomainProblem<ELEMENT_DIM>* p_problem = dynamic_cast<BidomainProblem<ELEMENT_DIM>*>(this);
00747         assert(p_problem);
00748         p_problem->LoadExtraArchiveForBidomain(archive, version);
00749     }
00750 }
00751 
00752 namespace boost {
00753 namespace serialization {
00760 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM,  unsigned PROBLEM_DIM>
00761 struct version<AbstractCardiacProblem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
00762 {
00764     BOOST_STATIC_CONSTANT(unsigned, value = 1);
00765 };
00766 } // namespace serialization
00767 } // namespace boost
00768 #endif /*ABSTRACTCARDIACPROBLEM_HPP_*/

Generated on Mon Nov 1 12:35:16 2010 for Chaste by  doxygen 1.5.5