Chaste Commit::a9c8bf7350f67d7cf086e6fe3cf5461521554546
AbstractTetrahedralMesh.hpp
1/*
2
3Copyright (c) 2005-2026, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, 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
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#ifndef ABSTRACTTETRAHEDRALMESH_HPP_
37#define ABSTRACTTETRAHEDRALMESH_HPP_
38
40#include "ClassIsAbstract.hpp"
42#include <boost/serialization/vector.hpp>
43#include <boost/serialization/base_object.hpp>
44#include <boost/serialization/split_member.hpp>
45
46#include <vector>
47#include <string>
48#include <cassert>
49
50#include "AbstractMesh.hpp"
51#include "BoundaryElement.hpp"
52#include "Element.hpp"
53#include "GenericMeshReader.hpp"
54#include "AbstractMeshReader.hpp"
55#include "TrianglesMeshReader.hpp"
56#include "TrianglesMeshWriter.hpp"
57#include "ArchiveLocationInfo.hpp"
58#include "FileFinder.hpp"
59
60
62template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
64
69template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
70class AbstractTetrahedralMesh : public AbstractMesh<ELEMENT_DIM, SPACE_DIM>
71{
72 friend class AbstractConductivityTensors<ELEMENT_DIM, SPACE_DIM>; //A class which needs a global to local element mapping
73 friend class CentroidWriter; //A test class which needs access to mElements in order to check that local/global indices match
74protected:
79
80private:
90 virtual unsigned SolveElementMapping(unsigned index) const = 0;
91
100 virtual unsigned SolveBoundaryElementMapping(unsigned index) const = 0;
101
104
116 template<class Archive>
117 void save(Archive & archive, const unsigned int version) const
118 {
119 archive & boost::serialization::base_object<AbstractMesh<ELEMENT_DIM,SPACE_DIM> >(*this);
120 archive & mMeshIsLinear;
121 // Create a mesh writer pointing to the correct file and directory
124 false);
125 // Binary meshes have similar content to the original Triangle/Tetgen format, but take up less space on disk
126 mesh_writer.SetWriteFilesAsBinary();
127
128 // Archive the mesh permutation, so we can just copy the original mesh files whenever possible
129 bool permutation_available = (this->rGetNodePermutation().size() != 0);
130 archive & permutation_available;
131
132 if (permutation_available)
133 {
134 const std::vector<unsigned>& rPermutation = this->rGetNodePermutation();
135 archive & rPermutation;
136 }
137
138 if (!this->IsMeshOnDisk() || this->mMeshChangesDuringSimulation)
139 {
141 }
142 else
143 {
144 unsigned order_of_element = (mMeshIsLinear?1:2);
145 unsigned& order_of_boundary_element = order_of_element;
146
147 // Mesh in disc, copy it to the archiving folder
148 std::string original_file=this->GetMeshFileBaseName();
149 std::shared_ptr<AbstractMeshReader<ELEMENT_DIM, SPACE_DIM> > p_original_mesh_reader
150 = GenericMeshReader<ELEMENT_DIM, SPACE_DIM>(original_file, order_of_element, order_of_boundary_element);
151
152 if (p_original_mesh_reader->IsFileFormatBinary())
153 {
154 // Mesh is in binary format, we can just copy the files across ignoring the mesh reader
156 {
157 FileFinder mesh_base(this->GetMeshFileBaseName());
158 FileFinder mesh_folder = mesh_base.GetParent();
159 std::string mesh_leaf_name = mesh_base.GetLeafNameNoExtension();
160 std::vector<FileFinder> mesh_files = mesh_folder.FindMatches(mesh_leaf_name + ".*");
162 for (const FileFinder& r_mesh_file : mesh_files)
163 {
164 FileFinder dest_file(ArchiveLocationInfo::GetMeshFilename() + r_mesh_file.GetExtension(),
165 dest_dir);
166 ABORT_IF_THROWS(r_mesh_file.CopyTo(dest_file));
167 }
168 }
169 }
170 else
171 {
172 // Mesh in text format, use the mesh writer to "binarise" it
173 mesh_writer.WriteFilesUsingMeshReaderAndMesh(*p_original_mesh_reader,
175 }
176 }
177
178 // Make sure that the files are written before slave processes proceed
179 PetscTools::Barrier("AbstractTetrahedralMesh::save");
180 }
181
188 template<class Archive>
189 void load(Archive & archive, const unsigned int version)
190 {
191 archive & boost::serialization::base_object<AbstractMesh<ELEMENT_DIM,SPACE_DIM> >(*this);
192 archive & mMeshIsLinear;
193
194 bool permutation_available=false;
195 std::vector<unsigned> permutation;
196
197 if (version > 0)
198 {
199 archive & permutation_available;
200
201 if (permutation_available)
202 {
203 archive & permutation;
204 }
205 }
206
207 // Store the DistributedVectorFactory loaded from the archive
209 this->mpDistributedVectorFactory = nullptr;
210
211 // Check whether we're migrating, or if we can use the original partition for the mesh
212 DistributedVectorFactory* p_our_factory = nullptr;
213 if (p_factory)
214 {
215 p_our_factory = p_factory->GetOriginalFactory();
216 }
217 if (p_our_factory && p_our_factory->GetNumProcs() == p_factory->GetNumProcs())
218 {
219 // Specify the node distribution
220 this->SetDistributedVectorFactory(p_our_factory);
221 }
222 else
223 {
224 // Migrating; let the mesh re-partition if it likes
226 p_our_factory = nullptr;
227 }
228
229 if (mMeshIsLinear)
230 {
231 // I am a linear mesh
233
234 if (permutation_available)
235 {
236 mesh_reader.SetNodePermutation(permutation);
237 }
238
239 this->ConstructFromMeshReader(mesh_reader);
240 }
241 else
242 {
243 // I am a quadratic mesh and need quadratic information from the reader
245 this->ConstructFromMeshReader(mesh_reader);
246 }
247
248 // Make sure we're using the correct vector factory
249 if (p_factory)
250 {
252 {
253 // If we're not using a DistributedTetrahedralMesh, ConstructFromMeshReader won't set
254 // this->mpDistributedVectorFactory.
255 this->mpDistributedVectorFactory = p_factory;
256 }
257 else
258 {
259 // We need to update p_factory to match this->mpDistributedVectorFactory, and then use
260 // p_factory, since the rest of the code (e.g. AbstractCardiacPde) will be using p_factory.
262 if (p_our_factory != this->mpDistributedVectorFactory)
263 {
264 // Avoid memory leak
265 delete this->mpDistributedVectorFactory;
266 }
267 this->mpDistributedVectorFactory = p_factory;
268 }
269 }
270 }
271 BOOST_SERIALIZATION_SPLIT_MEMBER()
272
273protected: // Give access of these variables to subclasses
274
276 std::vector<Element<ELEMENT_DIM, SPACE_DIM> *> mElements;
277
279 std::vector<BoundaryElement<ELEMENT_DIM-1, SPACE_DIM> *> mBoundaryElements;
280
289
290public:
291
293 // Iterators //
295
297 typedef typename std::vector<BoundaryElement<ELEMENT_DIM-1, SPACE_DIM> *>::const_iterator BoundaryElementIterator;
298
300 class ElementIterator;
301
307 inline ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true);
308
312 inline ElementIterator GetElementIteratorEnd();
313
315 // Methods //
317
322
326 virtual ~AbstractTetrahedralMesh();
327
328
332 virtual unsigned GetNumElements() const;
333
337 virtual unsigned GetNumLocalElements() const;
338
342 virtual unsigned GetNumBoundaryElements() const;
343
347 virtual unsigned GetNumLocalBoundaryElements() const;
348
352 unsigned GetNumAllElements() const;
353
357 unsigned GetNumAllBoundaryElements() const;
358
364 virtual unsigned GetNumCableElements() const;
365
370 virtual unsigned GetNumVertices() const;
371
378 virtual unsigned GetMaximumNodeIndex();
379
386 Element<ELEMENT_DIM, SPACE_DIM>* GetElement(unsigned index) const;
387
394 BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* GetBoundaryElement(unsigned index) const;
395
396
403 virtual void ConstructFromMeshReader(AbstractMeshReader<ELEMENT_DIM, SPACE_DIM>& rMeshReader)=0;
404
413 void ConstructFromMesh(AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>& rOtherMesh);
414
415
420
426
435 virtual void GetInverseJacobianForElement(unsigned elementIndex, c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian,
436 double& rJacobianDeterminant,
437 c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian) const;
438
447 virtual void GetWeightedDirectionForBoundaryElement(unsigned elementIndex,
448 c_vector<double, SPACE_DIM>& rWeightedDirection,
449 double& rJacobianDeterminant) const;
450
458 void CheckOutwardNormals();
459
472 virtual void ConstructLinearMesh(unsigned width);
473
489 virtual void ConstructRectangularMesh(unsigned width, unsigned height, bool stagger=true);
490
502 virtual void ConstructCuboid(unsigned width, unsigned height, unsigned depth);
503
514 void ConstructRegularSlabMesh(double spaceStep, double width, double height=0, double depth=0);
515
532 void ConstructRegularSlabMeshWithDimensionSplit(unsigned dimension, double spaceStep, double width, double height=0, double depth=0);
533
534
542 virtual bool CalculateDesignatedOwnershipOfBoundaryElement( unsigned faceIndex );
543
551 virtual bool CalculateDesignatedOwnershipOfElement( unsigned elementIndex );
552
563
570 virtual void GetHaloNodeIndices(std::vector<unsigned>& rHaloIndices) const;
571
585 void CalculateNodeExchange( std::vector<std::vector<unsigned> >& rNodesToSendPerProcess,
586 std::vector<std::vector<unsigned> >& rNodesToReceivePerProcess);
587
588
597 virtual c_vector<double, 2> CalculateMinMaxEdgeLengths();
598
612 unsigned GetContainingElementIndex(const ChastePoint<SPACE_DIM>& rTestPoint,
613 bool strict=false,
614 std::set<unsigned> testElements=std::set<unsigned>(),
615 bool onlyTryWithTestElements = false);
616
622 unsigned GetNearestElementIndexFromTestElements(const ChastePoint<SPACE_DIM>& rTestPoint,
623 std::set<unsigned> testElements);
624
626 // Nested classes //
628
633 {
634 public:
641
647
653 inline bool operator!=(const typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator& rOther);
654
659 inline ElementIterator& operator++();
660
672 typename std::vector<Element<ELEMENT_DIM, SPACE_DIM> *>::iterator elementIter,
673 bool skipDeletedElements=true);
674
675 private:
678
680 typename std::vector<Element<ELEMENT_DIM, SPACE_DIM> *>::iterator mElementIter;
681
684
689 inline bool IsAtEnd();
690
695 inline bool IsAllowedElement();
696 };
697};
698
700
701namespace boost {
702namespace serialization {
709template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
710struct version<AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM> >
711{
714};
715} // namespace serialization
716} // namespace boost
717
718
720// ElementIterator class implementation - most methods are inlined //
722
723template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
725 bool skipDeletedElements)
726{
727 return ElementIterator(*this, mElements.begin(), skipDeletedElements);
728}
729
730template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
735
736template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
742
743template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
749
750template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
755
756template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
758{
759 do
760 {
761 ++mElementIter;
762 }
763 while (!IsAtEnd() && !IsAllowedElement());
764
765 return (*this);
766}
767
768template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
771 typename std::vector<Element<ELEMENT_DIM, SPACE_DIM> *>::iterator elementIter,
772 bool skipDeletedElements)
773 : mrMesh(rMesh),
774 mElementIter(elementIter),
775 mSkipDeletedElements(skipDeletedElements)
776{
777 if (mrMesh.mElements.size() == 0)
778 {
779 // Cope with empty meshes
781 }
782 else
783 {
784 // Make sure we start at an allowed element
785 if (mElementIter == mrMesh.mElements.begin() && !IsAllowedElement())
786 {
787 ++(*this);
788 }
789 }
790}
791
792template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
794{
795 return mElementIter == mrMesh.mElements.end();
796}
797
798template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
800{
801 return !(mSkipDeletedElements && (*this)->IsDeleted());
802}
803
804#endif /*ABSTRACTTETRAHEDRALMESH_HPP_*/
gcov doesn't like this file...
#define TEMPLATED_CLASS_IS_ABSTRACT_2_UNSIGNED(T)
#define ABORT_IF_THROWS(block)
Forward declaration which is going to be used for friendship.
bool mMeshChangesDuringSimulation
virtual void SetDistributedVectorFactory(DistributedVectorFactory *pFactory)
std::string GetMeshFileBaseName() const
bool IsMeshOnDisk() const
const std::vector< unsigned > & rGetNodePermutation() const
DistributedVectorFactory * mpDistributedVectorFactory
virtual void WriteFilesUsingMesh(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, bool keepOriginalElementIndexing=true)
void WriteFilesUsingMeshReaderAndMesh(AbstractMeshReader< ELEMENT_DIM, SPACE_DIM > &rMeshReader, AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
Element< ELEMENT_DIM, SPACE_DIM > & operator*()
std::vector< Element< ELEMENT_DIM, SPACE_DIM > * >::iterator mElementIter
Element< ELEMENT_DIM, SPACE_DIM > * operator->()
ElementIterator(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, typename std::vector< Element< ELEMENT_DIM, SPACE_DIM > * >::iterator elementIter, bool skipDeletedElements=true)
bool operator!=(const typename AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM >::ElementIterator &rOther)
void load(Archive &archive, const unsigned int version)
void ConstructRegularSlabMesh(double spaceStep, double width, double height=0, double depth=0)
virtual unsigned SolveBoundaryElementMapping(unsigned index) const =0
virtual unsigned GetNumLocalBoundaryElements() const
virtual bool CalculateDesignatedOwnershipOfElement(unsigned elementIndex)
void CalculateNodeExchange(std::vector< std::vector< unsigned > > &rNodesToSendPerProcess, std::vector< std::vector< unsigned > > &rNodesToReceivePerProcess)
unsigned GetContainingElementIndex(const ChastePoint< SPACE_DIM > &rTestPoint, bool strict=false, std::set< unsigned > testElements=std::set< unsigned >(), bool onlyTryWithTestElements=false)
virtual void ConstructFromMeshReader(AbstractMeshReader< ELEMENT_DIM, SPACE_DIM > &rMeshReader)=0
virtual void GetWeightedDirectionForBoundaryElement(unsigned elementIndex, c_vector< double, SPACE_DIM > &rWeightedDirection, double &rJacobianDeterminant) const
virtual unsigned GetNumBoundaryElements() const
virtual unsigned SolveElementMapping(unsigned index) const =0
virtual void GetInverseJacobianForElement(unsigned elementIndex, c_matrix< double, SPACE_DIM, ELEMENT_DIM > &rJacobian, double &rJacobianDeterminant, c_matrix< double, ELEMENT_DIM, SPACE_DIM > &rInverseJacobian) const
virtual bool CalculateDesignatedOwnershipOfBoundaryElement(unsigned faceIndex)
void ConstructFromMesh(AbstractTetrahedralMesh< ELEMENT_DIM, SPACE_DIM > &rOtherMesh)
virtual unsigned GetNumVertices() const
ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
void ConstructRegularSlabMeshWithDimensionSplit(unsigned dimension, double spaceStep, double width, double height=0, double depth=0)
virtual void GetHaloNodeIndices(std::vector< unsigned > &rHaloIndices) const
std::vector< BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * >::const_iterator BoundaryElementIterator
virtual unsigned GetNumLocalElements() const
unsigned GetNearestElementIndexFromTestElements(const ChastePoint< SPACE_DIM > &rTestPoint, std::set< unsigned > testElements)
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
unsigned CalculateMaximumNodeConnectivityPerProcess() const
virtual c_vector< double, 2 > CalculateMinMaxEdgeLengths()
std::vector< Element< ELEMENT_DIM, SPACE_DIM > * > mElements
void save(Archive &archive, const unsigned int version) const
virtual void ConstructRectangularMesh(unsigned width, unsigned height, bool stagger=true)
BoundaryElementIterator GetBoundaryElementIteratorBegin() const
BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * GetBoundaryElement(unsigned index) const
friend class boost::serialization::access
virtual unsigned GetNumCableElements() const
virtual void ConstructCuboid(unsigned width, unsigned height, unsigned depth)
virtual unsigned GetNumElements() const
virtual void ConstructLinearMesh(unsigned width)
BoundaryElementIterator GetBoundaryElementIteratorEnd() const
std::vector< BoundaryElement< ELEMENT_DIM-1, SPACE_DIM > * > mBoundaryElements
static std::string GetMeshFilename()
static std::string GetArchiveDirectory()
static std::string GetArchiveRelativePath()
DistributedVectorFactory * GetOriginalFactory()
void SetFromFactory(DistributedVectorFactory *pFactory)
std::string GetLeafNameNoExtension() const
std::vector< FileFinder > FindMatches(const std::string &rPattern) const
FileFinder GetParent() const
static bool AmMaster()
static void Barrier(const std::string callerId="")
void SetNodePermutation(std::vector< unsigned > &rPermutationVector)
CHASTE_VERSION_CONTENT(1)
Macro to set the version number of templated archive in known versions of Boost.