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 #include <string>
00034 #include <vector>
00035 #include <cassert>
00036 #include <climits> // Work around a boost bug - see #1024.
00037 #include <boost/serialization/vector.hpp>
00038 #include <boost/serialization/string.hpp>
00039 #include "ChasteSerialization.hpp"
00040 #include <boost/serialization/split_member.hpp>
00041 #include <boost/shared_ptr.hpp>
00042 #include <boost/serialization/shared_ptr.hpp>
00043 #include "ClassIsAbstract.hpp"
00044 #include "AbstractCardiacCell.hpp"
00045 #include "AbstractCardiacCellFactory.hpp"
00046 #include "AbstractCardiacPde.hpp"
00047 #include "AbstractDynamicAssemblerMixin.hpp"
00048 #include "AbstractTetrahedralMesh.hpp"
00049 #include "BoundaryConditionsContainer.hpp"
00050 #include "DistributedVectorFactory.hpp"
00051 #include "Hdf5DataReader.hpp"
00052 #include "Hdf5DataWriter.hpp"
00053 
00054 /*
00055  * Archiving extravaganza:
00056  *
00057  * We archive mesh and pde through a pointer to an abstract class. All the potential concrete
00058  * classes need to be included here, so they are registered with boost. If not, boost won't be
00059  * able to find the archiving methods of the concrete class and will throw the following
00060  * exception:
00061  *
00062  *       terminate called after throwing an instance of 'boost::archive::archive_exception'
00063  *       what():  unregistered class
00064  *
00065  * No member variable is defined to be of any of these clases, removing them won't
00066  * produce any compiler error. The exception above will occur at runtime.
00067  *
00068  * This might not be even necessary in certain cases, if the file is included implicitely by another header file
00069  * or by the test itself. It's safer though.
00070  *
00071  */
00072 #include "DistributedTetrahedralMesh.hpp"
00073 #include "TetrahedralMesh.hpp" //May be needed for unarchiving a mesh
00074 #include "MonodomainPde.hpp"
00075 #include "BidomainPde.hpp"
00076 
00077 
00083 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00084 class AbstractCardiacProblem
00085 {
00086     friend class TestBidomainWithBathAssembler;
00087     friend class TestCardiacSimulationArchiver;
00088 
00090     typedef typename boost::shared_ptr<BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
00091         BccType;
00092 
00093 private:
00095     friend class boost::serialization::access;
00096 
00103     template<class Archive>
00104     void save(Archive & archive, const unsigned int version) const
00105     {
00106         archive & mMeshFilename;
00107         archive & mpMesh;
00108         //archive & mAllocatedMemoryForMesh; // Mesh is deleted by AbstractCardiacPde
00109         archive & mUseMatrixBasedRhsAssembly;
00110         archive & mWriteInfo;
00111         archive & mPrintOutput;
00112         archive & mNodesToOutput;
00113         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00114         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00115         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00116         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00117         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00118         archive & mpCardiacPde;
00119         //archive & mpAssembler; // Only exists during calls to the Solve method
00120         bool has_solution = (mSolution != NULL);
00121         archive & has_solution;
00122         if (has_solution)
00123         {
00125             std::string filename = ArchiveLocationInfo::GetArchiveDirectory() + "AbstractCardiacProblem_mSolution.vec";
00126 
00127             Hdf5DataWriter writer(*mpMesh->GetDistributedVectorFactory(), ArchiveLocationInfo::GetArchiveRelativePath(), "AbstractCardiacProblem_mSolution", false);
00128             writer.DefineFixedDimension(mpMesh->GetDistributedVectorFactory()->GetProblemSize());
00129 
00130             writer.DefineUnlimitedDimension("Time", "msec");
00131             int vm_col = writer.DefineVariable("Vm","mV");
00132 
00133             if (PROBLEM_DIM==1)
00134             {
00135                 writer.EndDefineMode();
00136                 writer.PutUnlimitedVariable(0.0);
00137                 writer.PutVector(vm_col, mSolution);
00138             }
00139 
00140             if (PROBLEM_DIM==2)
00141             {
00142                 int phie_col = writer.DefineVariable("Phie","mV");
00143                 writer.EndDefineMode();
00144                 writer.PutUnlimitedVariable(0.0);
00145                 writer.PutStripedVector(vm_col, phie_col, mSolution);
00146             }
00147 
00148             writer.Close();
00149 
00150         }
00151         archive & mCurrentTime;
00152 
00153         // Save boundary conditions
00154         SaveBoundaryConditions(archive, mpMesh, mpBoundaryConditionsContainer);
00155         SaveBoundaryConditions(archive, mpMesh, mpDefaultBoundaryConditionsContainer);
00156     }
00157 
00164     template<class Archive>
00165     void load(Archive & archive, const unsigned int version)
00166     {
00167         archive & mMeshFilename;
00168         archive & mpMesh;
00169         //archive & mAllocatedMemoryForMesh; // Will always be true after a load
00170         archive & mUseMatrixBasedRhsAssembly;
00171         archive & mWriteInfo;
00172         archive & mPrintOutput;
00173         archive & mNodesToOutput;
00174         //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
00175         //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
00176         //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
00177         //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
00178         //archive & mpWriter; // Created by InitialiseWriter, called from Solve
00179         archive & mpCardiacPde;
00180         //archive & mpAssembler; // Only exists during calls to the Solve method
00181         bool has_solution;
00182         archive & has_solution;
00183         if (has_solution)
00184         {
00187             std::string filename = ArchiveLocationInfo::GetArchiveDirectory() + "AbstractCardiacProblem_mSolution.vec";
00188 
00189             mSolution = mpMesh->GetDistributedVectorFactory()->CreateVec(PROBLEM_DIM);
00190             DistributedVector mSolution_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
00191 
00192             Vec vm = mpMesh->GetDistributedVectorFactory()->CreateVec();
00193             Vec phie = mpMesh->GetDistributedVectorFactory()->CreateVec();
00194 
00195             Hdf5DataReader reader(ArchiveLocationInfo::GetArchiveRelativePath(), "AbstractCardiacProblem_mSolution", ArchiveLocationInfo::GetIsDirRelativeToChasteTestOutput());
00196             reader.GetVariableOverNodes(vm, "Vm", 0);
00197 
00198             if (PROBLEM_DIM==1)
00199             {
00200                 //reader.Close(); // no need to call close explicitly, done in the destructor
00201 
00202                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00203 
00204                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00205 
00206                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00207                      index != mSolution_distri.End();
00208                      ++index)
00209                 {
00210                     mSolution_vm[index] = vm_distri[index];
00211                 }
00212             }
00213 
00214             if (PROBLEM_DIM==2)
00215             {
00216                 reader.GetVariableOverNodes(phie, "Phie", 0);
00217                 //reader.Close(); // no need to call close explicitly, done in the destructor
00218 
00219                 DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
00220                 DistributedVector phie_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(phie);
00221 
00222                 DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
00223                 DistributedVector::Stripe mSolution_phie(mSolution_distri,1);
00224 
00225                 for (DistributedVector::Iterator index = mSolution_distri.Begin();
00226                      index != mSolution_distri.End();
00227                      ++index)
00228                 {
00229                     mSolution_vm[index] = vm_distri[index];
00230                     mSolution_phie[index] = phie_distri[index];
00231                 }
00232             }
00233 
00234             mSolution_distri.Restore();
00235 
00236             VecDestroy(vm);
00237             VecDestroy(phie);
00238 
00239         }
00240         archive & mCurrentTime;
00241 
00242         // Load boundary conditions
00243         mpBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00244         mpDefaultBoundaryConditionsContainer = LoadBoundaryConditions(archive, mpMesh);
00245     }
00246 
00247     BOOST_SERIALIZATION_SPLIT_MEMBER()
00248 
00249     
00256     template<class Archive>
00257     void SaveBoundaryConditions(Archive & archive,
00258                                 AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00259                                 BccType pBcc) const
00260     {
00261         (*ProcessSpecificArchive<Archive>::Get()) & pBcc;
00262     }
00263 
00271     template<class Archive>
00272     BccType LoadBoundaryConditions(
00273             Archive & archive,
00274             AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00275     {
00276         // Load pointer from archive
00277         BccType p_bcc;
00278         (*ProcessSpecificArchive<Archive>::Get()) & p_bcc;
00279 
00280         // Fill in the conditions, if we have a container and it's not already full
00281         if (p_bcc)
00282         {
00283             p_bcc->LoadFromArchive(*ProcessSpecificArchive<Archive>::Get(), pMesh);
00284         }
00285 
00286         return p_bcc;
00287     }
00288 
00289 protected:
00292     std::string mMeshFilename;
00293 
00298     bool mUseMatrixBasedRhsAssembly;
00300     bool mAllocatedMemoryForMesh;
00302     bool mWriteInfo;
00304     bool mPrintOutput;
00305 
00307     std::vector<unsigned> mNodesToOutput;
00308 
00310     unsigned mVoltageColumnId;
00312     std::vector<unsigned> mExtraVariablesId;
00314     unsigned mTimeColumnId;
00316     unsigned mNodeColumnId;
00317 
00319     AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>* mpCardiacPde;
00320 
00322     BccType mpBoundaryConditionsContainer;
00324     BccType mpDefaultBoundaryConditionsContainer;
00326     AbstractDynamicAssemblerMixin<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* mpAssembler;
00328     AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* mpCellFactory;
00330     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* mpMesh;
00331 
00334     Vec mSolution;
00335 
00343     double mCurrentTime;
00344 
00350     virtual AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>* CreateCardiacPde() =0;
00351 
00357     virtual AbstractDynamicAssemblerMixin<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>* CreateAssembler() =0;
00358 
00359 protected:
00363     template<unsigned DIM>
00364     friend class CardiacElectroMechanicsProblem;
00368     Hdf5DataWriter* mpWriter;
00369 
00370 public:
00376     AbstractCardiacProblem(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory);
00377 
00381     AbstractCardiacProblem();
00382 
00386     virtual ~AbstractCardiacProblem();
00387 
00395     void Initialise();
00396 
00402     void SetNodesPerProcessorFilename(const std::string& rFilename);
00403 
00408     void SetBoundaryConditionsContainer(BccType pBcc);
00409 
00417     virtual void PreSolveChecks();
00418 
00424     virtual Vec CreateInitialCondition();
00425 
00431     void SetMesh(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00432 
00438     void PrintOutput(bool rPrintOutput);
00439 
00445     void SetWriteInfo(bool writeInfo = true);
00446 
00457     Vec GetSolution();
00458 
00464     DistributedVector GetSolutionDistributedVector();
00465     
00469     double GetCurrentTime();
00470 
00474     AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM> & rGetMesh();
00475 
00479     AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>* GetPde();
00480 
00490     void Solve();
00491 
00499     void CloseFilesAndPostProcess();
00500 
00508     virtual void WriteInfo(double time)=0;
00509 
00514     virtual void DefineWriterColumns(bool extending);
00515 
00520     void DefineExtraVariablesWriterColumns(bool extending);
00521 
00528     virtual void WriteOneStep(double time, Vec voltageVec) = 0;
00529 
00533     void WriteExtraVariablesOneStep();
00534 
00540     void InitialiseWriter();
00541 
00549     void SetOutputNodes(std::vector<unsigned> & rNodesToOutput);
00550 
00554     Hdf5DataReader GetDataReader();
00555 
00561     void UseMatrixBasedRhsAssembly(bool usematrix=true);
00562 
00570     virtual void AtBeginningOfTimestep(double time)
00571     {}
00572 
00580     virtual void OnEndOfTimestep(double time)
00581     {}
00582     
00590     virtual void SetUpAdditionalStoppingTimes(std::vector<double>& rAdditionalStoppingTimes)
00591     {}
00592 
00613     template<class Archive>
00614     void LoadExtraArchive(Archive & archive, unsigned version);
00615 };
00616 
00617 TEMPLATED_CLASS_IS_ABSTRACT_3_UNSIGNED(AbstractCardiacProblem);
00618 
00619 
00620 template<unsigned DIM>
00621 class BidomainProblem;
00622 
00623 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00624 template<class Archive>
00625 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::LoadExtraArchive(Archive & archive, unsigned version)
00626 {
00627     // The vector factory must be loaded, but isn't needed for anything.
00628     DistributedVectorFactory* p_mesh_factory;
00629     archive >> p_mesh_factory;
00630 
00631     // The cardiac cells
00632     std::vector<AbstractCardiacCell*> cells;
00633     // Load only the cells we actually own
00634     AbstractCardiacPde<ELEMENT_DIM,SPACE_DIM>::LoadCardiacCells(archive, version, cells, this->mpMesh);
00635     mpCardiacPde->MergeCells(cells);
00636 
00637     {
00638         DistributedVectorFactory* p_pde_factory;
00639         archive >> p_pde_factory;
00640         assert(p_pde_factory == p_mesh_factory); // Paranoia...
00641     }
00642     // We no longer need this vector factory, since we already have our own.
00643     delete p_mesh_factory;
00644 
00645     // The boundary conditions
00646     BccType p_bcc;
00647     archive >> p_bcc;
00648     if (p_bcc)
00649     {
00650         if (!mpBoundaryConditionsContainer)
00651         {
00652             mpBoundaryConditionsContainer = p_bcc;
00653             mpBoundaryConditionsContainer->LoadFromArchive(archive, mpMesh);
00654         }
00655         else
00656         {
00657             // The BCs will only actually be different if using a distributed tetrahedral mesh
00658             DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* p_dist_mesh = dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(mpMesh);
00659             if (p_dist_mesh)
00660             {
00661                 mpBoundaryConditionsContainer->MergeFromArchive(archive, mpMesh);
00662             }
00663             else
00664             {
00665                 // Load into the temporary container, which will get thrown away shortly
00666                 p_bcc->LoadFromArchive(archive, mpMesh);
00668             }
00669         }
00670     }
00671     BccType p_default_bcc;
00672     archive >> p_default_bcc;
00673     if (p_default_bcc)
00674     {
00675         // This always holds, so we never need to load the default BCs
00676         assert(p_bcc == p_default_bcc);
00677     }
00678 
00679     // Are we a bidomain problem?
00680     if (PROBLEM_DIM == 2)
00681     {
00682         assert(ELEMENT_DIM == SPACE_DIM);
00683         BidomainProblem<ELEMENT_DIM>* p_problem = dynamic_cast<BidomainProblem<ELEMENT_DIM>*>(this);
00684         assert(p_problem);
00685         p_problem->LoadExtraArchiveForBidomain(archive, version);
00686     }
00687 }
00688 
00689 
00690 #endif /*ABSTRACTCARDIACPROBLEM_HPP_*/

Generated by  doxygen 1.6.2