Chaste  Release::3.4
AbstractCardiacProblem.hpp
1 /*
2 
3 Copyright (c) 2005-2016, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 
37 #ifndef ABSTRACTCARDIACPROBLEM_HPP_
38 #define ABSTRACTCARDIACPROBLEM_HPP_
39 
40 
41 
42 #include <string>
43 #include <vector>
44 #include <cassert>
45 #include <climits>
46 #include <boost/shared_ptr.hpp>
47 
48 #include "ChasteSerialization.hpp"
49 #include <boost/serialization/vector.hpp>
50 #include <boost/serialization/string.hpp>
51 #include <boost/serialization/split_member.hpp>
52 #include <boost/serialization/shared_ptr.hpp>
53 #include "ClassIsAbstract.hpp"
55 
56 #include "AbstractTetrahedralMesh.hpp"
57 #include "AbstractCardiacCell.hpp"
58 #include "AbstractCardiacCellFactory.hpp"
59 #include "AbstractCardiacTissue.hpp"
60 #include "AbstractDynamicLinearPdeSolver.hpp"
61 #include "BoundaryConditionsContainer.hpp"
62 #include "DistributedVectorFactory.hpp"
63 #include "Hdf5DataReader.hpp"
64 #include "Hdf5DataWriter.hpp"
65 #include "Warnings.hpp"
66 #include "AbstractOutputModifier.hpp"
67 /*
68  * Archiving extravaganza:
69  *
70  * We archive mesh and tissue through a pointer to an abstract class. All the potential concrete
71  * classes need to be included here, so they are registered with boost. If not, boost won't be
72  * able to find the archiving methods of the concrete class and will throw the following
73  * exception:
74  *
75  * terminate called after throwing an instance of 'boost::archive::archive_exception'
76  * what(): unregistered class
77  *
78  * No member variable is defined to be of any of these clases, so removing them won't
79  * produce any compiler error. The exception above will occur at runtime.
80  *
81  * This might not be even necessary in certain cases, if the file is included implicitly by another
82  * header file or by the test itself. It's safer though.
83  */
84 #include "DistributedTetrahedralMesh.hpp"
85 #include "TetrahedralMesh.hpp" //May be needed for unarchiving a mesh
86 #include "MonodomainTissue.hpp"
87 #include "BidomainTissue.hpp"
88 
92 class AbstractUntemplatedCardiacProblem : private boost::noncopyable
93 {
94 public:
97  {}
98 };
99 
114 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
116 {
117  friend class TestBidomainWithBath;
118  friend class TestMonodomainProblem;
119  friend class TestCardiacSimulationArchiver;
120 
122  typedef typename boost::shared_ptr<BoundaryConditionsContainer<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
124 
125 private:
127  friend class boost::serialization::access;
128 
135  template<class Archive>
136  void save(Archive & archive, const unsigned int version) const
137  {
138  if (version >= 1)
139  {
140  const unsigned element_dim=ELEMENT_DIM;
141  archive & element_dim;
142  const unsigned space_dim=SPACE_DIM;
143  archive & space_dim;
144  const unsigned problem_dim=PROBLEM_DIM;
145  archive & problem_dim;
146  }
147  archive & mMeshFilename;
148  archive & mpMesh;
149  //archive & mAllocatedMemoryForMesh; // Mesh is deleted by AbstractCardiacTissue
150 
151  // We shouldn't ever have to save the old version
152  assert(version >= 2);
153 // {
154 // bool use_matrix_based_assembly = true;
155 // archive & use_matrix_based_assembly;
156 // }
157 
158  archive & mWriteInfo;
159  archive & mPrintOutput;
160  archive & mNodesToOutput;
161  //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
162  //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
163  //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
164  //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
165  //archive & mpWriter; // Created by InitialiseWriter, called from Solve
166  archive & mpCardiacTissue;
167  //archive & mpSolver; // Only exists during calls to the Solve method
168  bool has_solution = (mSolution != NULL);
169  archive & has_solution;
170  if (has_solution)
171  {
174  Hdf5DataWriter writer(*mpMesh->GetDistributedVectorFactory(), ArchiveLocationInfo::GetArchiveRelativePath(), "AbstractCardiacProblem_mSolution", false);
175  writer.DefineFixedDimension(mpMesh->GetDistributedVectorFactory()->GetProblemSize());
176  writer.DefineUnlimitedDimension("Time", "msec", 1);
177 
178  int vm_col = writer.DefineVariable("Vm","mV");
179 
180  if (PROBLEM_DIM==1)
181  {
182  writer.EndDefineMode();
183  writer.PutUnlimitedVariable(0.0);
184  writer.PutVector(vm_col, mSolution);
185  }
186 
187  if (PROBLEM_DIM==2)
188  {
189  int phie_col = writer.DefineVariable("Phie","mV");
190  std::vector<int> variable_ids;
191  variable_ids.push_back(vm_col);
192  variable_ids.push_back(phie_col);
193  writer.EndDefineMode();
194  writer.PutUnlimitedVariable(0.0);
195  writer.PutStripedVector(variable_ids, mSolution);
196  }
197 
198  writer.Close();
199 
200  }
201  archive & mCurrentTime;
202 
203  // Save boundary conditions
206 
207  if (version>= 3)
208  {
209  archive & mOutputModifiers;
210  }
211  }
212 
219  template<class Archive>
220  void load(Archive & archive, const unsigned int version)
221  {
222  if (version >= 1)
223  {
224  unsigned element_dim;
225  unsigned space_dim;
226  unsigned problem_dim;
227  archive & element_dim;
228  archive & space_dim;
229  archive & problem_dim;
230  if ( (element_dim != ELEMENT_DIM) ||(space_dim != SPACE_DIM) ||(problem_dim != PROBLEM_DIM) )
231  {
232  /*If we carry on from this point then the mesh produced by unarchiving from the
233  * archive is templated as AbstractTetrahedralMesh<element_dim, space_dim>
234  * which doesn't match AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>* mpMesh.
235  * Boost will through away the unarchived one, without deleting it properly and
236  * then set mpMesh=NULL. We need to avoid this happening by bailing out.
237  */
238  EXCEPTION("Failed to load from checkpoint because the dimensions of the archive do not match the object it's being read into.");
239  }
240  }
241  archive & mMeshFilename;
242  archive & mpMesh;
243  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.
244  //archive & mAllocatedMemoryForMesh; // Will always be true after a load
245 
246  if (version < 2)
247  {
248  bool use_matrix_based_assembly;
249  archive & use_matrix_based_assembly;
250  }
251 
252  archive & mWriteInfo;
253  archive & mPrintOutput;
254  archive & mNodesToOutput;
255  //archive & mVoltageColumnId; // Created by InitialiseWriter, called from Solve
256  //archive & mExtraVariablesId; // Created by InitialiseWriter, called from Solve
257  //archive & mTimeColumnId; // Created by InitialiseWriter, called from Solve
258  //archive & mNodeColumnId; // Created by InitialiseWriter, called from Solve
259  //archive & mpWriter; // Created by InitialiseWriter, called from Solve
260  archive & mpCardiacTissue;
261  //archive & mpSolver; // Only exists during calls to the Solve method
262  bool has_solution;
263  archive & has_solution;
264  if ((has_solution) && PROBLEM_DIM < 3)
265  {
268  mSolution = mpMesh->GetDistributedVectorFactory()->CreateVec(PROBLEM_DIM);
269  DistributedVector mSolution_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(mSolution);
270 
271  Vec vm = mpMesh->GetDistributedVectorFactory()->CreateVec();
272  Vec phie = mpMesh->GetDistributedVectorFactory()->CreateVec();
273 
274  std::string archive_dir = ArchiveLocationInfo::GetArchiveRelativePath();
275  Hdf5DataReader reader(archive_dir, "AbstractCardiacProblem_mSolution", !FileFinder::IsAbsolutePath(archive_dir));
276  reader.GetVariableOverNodes(vm, "Vm", 0);
277 
278  if (PROBLEM_DIM==1)
279  {
280  //reader.Close(); // no need to call close explicitly, done in the destructor
281 
282  DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
283 
284  DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
285 
286  for (DistributedVector::Iterator index = mSolution_distri.Begin();
287  index != mSolution_distri.End();
288  ++index)
289  {
290  mSolution_vm[index] = vm_distri[index];
291  }
292  }
293 
294  if (PROBLEM_DIM==2)
295  {
296  reader.GetVariableOverNodes(phie, "Phie", 0);
297  //reader.Close(); // no need to call close explicitly, done in the destructor
298 
299  DistributedVector vm_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(vm);
300  DistributedVector phie_distri = mpMesh->GetDistributedVectorFactory()->CreateDistributedVector(phie);
301 
302  DistributedVector::Stripe mSolution_vm(mSolution_distri,0);
303  DistributedVector::Stripe mSolution_phie(mSolution_distri,1);
304 
305  for (DistributedVector::Iterator index = mSolution_distri.Begin();
306  index != mSolution_distri.End();
307  ++index)
308  {
309  mSolution_vm[index] = vm_distri[index];
310  mSolution_phie[index] = phie_distri[index];
311  }
312  }
313 
314  mSolution_distri.Restore();
315 
317  PetscTools::Destroy(phie);
318 
319  }
320  archive & mCurrentTime;
321 
322  // Load boundary conditions
325 
326  if (version>= 3)
327  {
328  archive & mOutputModifiers;
329  }
330  }
331 
332  BOOST_SERIALIZATION_SPLIT_MEMBER()
333 
334 
341  template<class Archive>
342  void SaveBoundaryConditions(Archive & archive,
343  AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
344  BccType pBcc) const
345  {
347  }
348 
356  template<class Archive>
358  Archive & archive,
360  {
361  // Load pointer from archive
362  BccType p_bcc;
364 
365  // Fill in the conditions, if we have a container and it's not already full
366  if (p_bcc)
367  {
368  p_bcc->LoadFromArchive(*ProcessSpecificArchive<Archive>::Get(), pMesh);
369  }
370 
371  return p_bcc;
372  }
373 
374 protected:
377  std::string mMeshFilename;
378 
385 
387  std::vector<unsigned> mNodesToOutput;
388 
392  std::vector<unsigned> mExtraVariablesId;
394  unsigned mTimeColumnId;
396  unsigned mNodeColumnId;
397 
400 
411 
415 
423  double mCurrentTime;
424 
427 
428 
429 
437 
445 
453  virtual void CreateMeshFromHeartConfig();
454 
458  template<unsigned DIM, unsigned ELEC_PROB_DIM>
460 
465 
469  std::vector<boost::shared_ptr<AbstractOutputModifier> > mOutputModifiers;
470 
471 public:
478 
483 
487  virtual ~AbstractCardiacProblem();
488 
496  void Initialise();
497 
503  void SetNodesPerProcessorFilename(const std::string& rFilename);
504 
510 
518  virtual void PreSolveChecks();
519 
533  virtual Vec CreateInitialCondition();
534 
541 
547  void PrintOutput(bool rPrintOutput);
548 
554  void SetWriteInfo(bool writeInfo = true);
555 
566  Vec GetSolution();
567 
574 
578  double GetCurrentTime();
579 
584 
589 
599  void Solve();
600 
609 
617  virtual void WriteInfo(double time)=0;
618 
623  virtual void DefineWriterColumns(bool extending);
624 
629  void DefineExtraVariablesWriterColumns(bool extending);
630 
637  virtual void WriteOneStep(double time, Vec voltageVec) = 0;
638 
643 
654  bool InitialiseWriter();
655 
665  void SetOutputNodes(std::vector<unsigned> & rNodesToOutput);
666 
671 
679  virtual void AtBeginningOfTimestep(double time)
680  {}
681 
689  virtual void OnEndOfTimestep(double time)
690  {}
691 
699  virtual void SetUpAdditionalStoppingTimes(std::vector<double>& rAdditionalStoppingTimes)
700  {}
701 
702 
703 
705  // and no controller, in which case the default is used.
706 
712  void SetUseTimeAdaptivityController(bool useAdaptivity,
713  AbstractTimeAdaptivityController* pController = NULL);
714 
735  template<class Archive>
736  void LoadExtraArchive(Archive & archive, unsigned version);
737 
741  virtual bool GetHasBath();
742 
747  virtual void SetElectrodes();
748 
754  void AddOutputModifier( boost::shared_ptr<AbstractOutputModifier> pOutputModifier)
755  {
756  mOutputModifiers.push_back(pOutputModifier);
757  }
758 };
759 
761 
762 
763 template<unsigned DIM>
765 
766 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
767 template<class Archive>
768 void AbstractCardiacProblem<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::LoadExtraArchive(Archive & archive, unsigned version)
769 {
770  // The vector factory must be loaded, but isn't needed for anything.
771  DistributedVectorFactory* p_mesh_factory;
772  archive >> p_mesh_factory;
773 
774  // How many processes were used by the saving simulation?
775  DistributedVectorFactory* p_original_factory = p_mesh_factory->GetOriginalFactory();
776  unsigned orig_num_procs = 1;
777  if (p_original_factory)
778  {
779  orig_num_procs = p_original_factory->GetNumProcs();
780  }
781 
782  // The cardiac cells - load only the cells we actually own
783  mpCardiacTissue->LoadCardiacCells(archive, version);
784 
785  {
786  DistributedVectorFactory* p_pde_factory;
787  archive >> p_pde_factory;
788  assert(p_pde_factory == p_mesh_factory); // Paranoia...
789  }
790  // We no longer need this vector factory, since we already have our own.
791  delete p_mesh_factory;
792 
793  // The boundary conditions
794  BccType p_bcc;
795  archive >> p_bcc;
796  if (p_bcc)
797  {
798  if (!mpBoundaryConditionsContainer)
799  {
800  mpBoundaryConditionsContainer = p_bcc;
801  mpBoundaryConditionsContainer->LoadFromArchive(archive, mpMesh);
802  }
803  else
804  {
805  // If the mesh which was archived was a TetrahedralMesh then we have all the boundary conditions
806  // in every process-specific archive. We no longer test for this.
807 #define COVERAGE_IGNORE
808  if(!dynamic_cast<DistributedTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>*>(mpMesh) && orig_num_procs > 1)
809  {
810  // The correct way to do this should be:
811  // p_bcc->LoadFromArchive(archive, mpMesh);
812  WARNING("Loading from a parallel archive which used a non-distributed mesh. This scenario should work but is not fully tested.");
813  }
814 #undef COVERAGE_IGNORE
815  mpBoundaryConditionsContainer->MergeFromArchive(archive, mpMesh);
816  }
817  }
818  BccType p_default_bcc;
819  archive >> p_default_bcc;
820  if (p_default_bcc)
821  {
822  // This always holds, so we never need to load the default BCs
823  assert(p_bcc == p_default_bcc);
824  }
825 
826  // Are we a bidomain problem?
827  BidomainProblem<ELEMENT_DIM>* p_bidomain_problem = dynamic_cast<BidomainProblem<ELEMENT_DIM>*>(this);
828  if (p_bidomain_problem)
829  {
830  assert(ELEMENT_DIM == SPACE_DIM);
831  p_bidomain_problem->LoadExtraArchiveForBidomain(archive, version);
832  }
833 }
834 
835 namespace boost {
836 namespace serialization {
843 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
844 struct version<AbstractCardiacProblem<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM> >
845 {
848 };
849 } // namespace serialization
850 } // namespace boost
851 #endif /*ABSTRACTCARDIACPROBLEM_HPP_*/
#define TEMPLATED_CLASS_IS_ABSTRACT_3_UNSIGNED(T)
virtual void WriteOneStep(double time, Vec voltageVec)=0
std::vector< boost::shared_ptr< AbstractOutputModifier > > mOutputModifiers
void AddOutputModifier(boost::shared_ptr< AbstractOutputModifier > pOutputModifier)
void PrintOutput(bool rPrintOutput)
static bool IsAbsolutePath(const std::string &rPath)
Definition: FileFinder.cpp:528
#define EXCEPTION(message)
Definition: Exception.hpp:143
void save(Archive &archive, const unsigned int version) const
void LoadExtraArchiveForBidomain(Archive &archive, unsigned version)
AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > & rGetMesh()
std::vector< unsigned > mExtraVariablesId
void SetNodesPerProcessorFilename(const std::string &rFilename)
AbstractTimeAdaptivityController * mpTimeAdaptivityController
virtual void SetUpAdditionalStoppingTimes(std::vector< double > &rAdditionalStoppingTimes)
boost::shared_ptr< BoundaryConditionsContainer< ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM > > BccType
DistributedVectorFactory * GetOriginalFactory()
void GetVariableOverNodes(Vec data, const std::string &rVariableName, unsigned timestep=0)
static Archive * Get(void)
AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > * mpMesh
void SaveBoundaryConditions(Archive &archive, AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > *pMesh, BccType pBcc) const
void SetUseTimeAdaptivityController(bool useAdaptivity, AbstractTimeAdaptivityController *pController=NULL)
virtual void WriteInfo(double time)=0
AbstractCardiacTissue< ELEMENT_DIM, SPACE_DIM > * GetTissue()
#define CHASTE_VERSION_CONTENT(N)
std::vector< unsigned > mNodesToOutput
virtual void OnEndOfTimestep(double time)
void load(Archive &archive, const unsigned int version)
static void Destroy(Vec &rVec)
Definition: PetscTools.hpp:351
void SetMesh(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > *pMesh)
BccType LoadBoundaryConditions(Archive &archive, AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > *pMesh)
void LoadExtraArchive(Archive &archive, unsigned version)
AbstractCardiacCellFactory< ELEMENT_DIM, SPACE_DIM > * mpCellFactory
void DefineFixedDimension(long dimensionSize)
void SetOutputNodes(std::vector< unsigned > &rNodesToOutput)
AbstractDynamicLinearPdeSolver< ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM > * mpSolver
virtual void DefineWriterColumns(bool extending)
virtual AbstractCardiacTissue< ELEMENT_DIM, SPACE_DIM > * CreateCardiacTissue()=0
void SetBoundaryConditionsContainer(BccType pBcc)
AbstractCardiacTissue< ELEMENT_DIM, SPACE_DIM > * mpCardiacTissue
static std::string GetArchiveRelativePath()
void SetWriteInfo(bool writeInfo=true)
virtual AbstractDynamicLinearPdeSolver< ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM > * CreateSolver()=0
DistributedVector GetSolutionDistributedVector()
virtual void AtBeginningOfTimestep(double time)
void DefineExtraVariablesWriterColumns(bool extending)