Chaste Commit::6e4f5fe395bca70eb7641cf6e0e87f450383ca5a
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 auto p_original_mesh_reader = GenericMeshReader<ELEMENT_DIM, SPACE_DIM>(original_file, order_of_element, order_of_boundary_element);
150
151 if (p_original_mesh_reader->IsFileFormatBinary())
152 {
153 // Mesh is in binary format, we can just copy the files across ignoring the mesh reader
155 {
156 FileFinder mesh_base(this->GetMeshFileBaseName());
157 FileFinder mesh_folder = mesh_base.GetParent();
158 std::string mesh_leaf_name = mesh_base.GetLeafNameNoExtension();
159 std::vector<FileFinder> mesh_files = mesh_folder.FindMatches(mesh_leaf_name + ".*");
161 for (const FileFinder& r_mesh_file : mesh_files)
162 {
163 FileFinder dest_file(ArchiveLocationInfo::GetMeshFilename() + r_mesh_file.GetExtension(),
164 dest_dir);
165 ABORT_IF_THROWS(r_mesh_file.CopyTo(dest_file));
166 }
167 }
168 }
169 else
170 {
171 // Mesh in text format, use the mesh writer to "binarise" it
172 mesh_writer.WriteFilesUsingMeshReaderAndMesh(*p_original_mesh_reader,
174 }
175 }
176
177 // Make sure that the files are written before slave processes proceed
178 PetscTools::Barrier("AbstractTetrahedralMesh::save");
179 }
180
187 template<class Archive>
188 void load(Archive & archive, const unsigned int version)
189 {
190 archive & boost::serialization::base_object<AbstractMesh<ELEMENT_DIM,SPACE_DIM> >(*this);
191 archive & mMeshIsLinear;
192
193 bool permutation_available=false;
194 std::vector<unsigned> permutation;
195
196 if (version > 0)
197 {
198 archive & permutation_available;
199
200 if (permutation_available)
201 {
202 archive & permutation;
203 }
204 }
205
206 // Store the DistributedVectorFactory loaded from the archive
208 this->mpDistributedVectorFactory = nullptr;
209
210 // Check whether we're migrating, or if we can use the original partition for the mesh
211 DistributedVectorFactory* p_our_factory = nullptr;
212 if (p_factory)
213 {
214 p_our_factory = p_factory->GetOriginalFactory();
215 }
216 if (p_our_factory && p_our_factory->GetNumProcs() == p_factory->GetNumProcs())
217 {
218 // Specify the node distribution
219 this->SetDistributedVectorFactory(p_our_factory);
220 }
221 else
222 {
223 // Migrating; let the mesh re-partition if it likes
225 p_our_factory = nullptr;
226 }
227
228 if (mMeshIsLinear)
229 {
230 // I am a linear mesh
232
233 if (permutation_available)
234 {
235 mesh_reader.SetNodePermutation(permutation);
236 }
237
238 this->ConstructFromMeshReader(mesh_reader);
239 }
240 else
241 {
242 // I am a quadratic mesh and need quadratic information from the reader
244 this->ConstructFromMeshReader(mesh_reader);
245 }
246
247 // Make sure we're using the correct vector factory
248 if (p_factory)
249 {
251 {
252 // If we're not using a DistributedTetrahedralMesh, ConstructFromMeshReader won't set
253 // this->mpDistributedVectorFactory.
254 this->mpDistributedVectorFactory = p_factory;
255 }
256 else
257 {
258 // We need to update p_factory to match this->mpDistributedVectorFactory, and then use
259 // p_factory, since the rest of the code (e.g. AbstractCardiacPde) will be using p_factory.
261 if (p_our_factory != this->mpDistributedVectorFactory)
262 {
263 // Avoid memory leak
264 delete this->mpDistributedVectorFactory;
265 }
266 this->mpDistributedVectorFactory = p_factory;
267 }
268 }
269 }
270 BOOST_SERIALIZATION_SPLIT_MEMBER()
271
272protected: // Give access of these variables to subclasses
273
275 std::vector<Element<ELEMENT_DIM, SPACE_DIM> *> mElements;
276
278 std::vector<BoundaryElement<ELEMENT_DIM-1, SPACE_DIM> *> mBoundaryElements;
279
288
289public:
290
292 // Iterators //
294
296 typedef typename std::vector<BoundaryElement<ELEMENT_DIM-1, SPACE_DIM> *>::const_iterator BoundaryElementIterator;
297
299 class ElementIterator;
300
306 inline ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true);
307
311 inline ElementIterator GetElementIteratorEnd();
312
314 // Methods //
316
321
325 virtual ~AbstractTetrahedralMesh();
326
327
331 virtual unsigned GetNumElements() const;
332
336 virtual unsigned GetNumLocalElements() const;
337
341 virtual unsigned GetNumBoundaryElements() const;
342
346 virtual unsigned GetNumLocalBoundaryElements() const;
347
351 unsigned GetNumAllElements() const;
352
356 unsigned GetNumAllBoundaryElements() const;
357
363 virtual unsigned GetNumCableElements() const;
364
369 virtual unsigned GetNumVertices() const;
370
377 virtual unsigned GetMaximumNodeIndex();
378
385 Element<ELEMENT_DIM, SPACE_DIM>* GetElement(unsigned index) const;
386
393 BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* GetBoundaryElement(unsigned index) const;
394
395
402 virtual void ConstructFromMeshReader(AbstractMeshReader<ELEMENT_DIM, SPACE_DIM>& rMeshReader)=0;
403
412 void ConstructFromMesh(AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>& rOtherMesh);
413
414
419
425
434 virtual void GetInverseJacobianForElement(unsigned elementIndex, c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian,
435 double& rJacobianDeterminant,
436 c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian) const;
437
446 virtual void GetWeightedDirectionForBoundaryElement(unsigned elementIndex,
447 c_vector<double, SPACE_DIM>& rWeightedDirection,
448 double& rJacobianDeterminant) const;
449
457 void CheckOutwardNormals();
458
471 virtual void ConstructLinearMesh(unsigned width);
472
488 virtual void ConstructRectangularMesh(unsigned width, unsigned height, bool stagger=true);
489
501 virtual void ConstructCuboid(unsigned width, unsigned height, unsigned depth);
502
513 void ConstructRegularSlabMesh(double spaceStep, double width, double height=0, double depth=0);
514
531 void ConstructRegularSlabMeshWithDimensionSplit(unsigned dimension, double spaceStep, double width, double height=0, double depth=0);
532
533
541 virtual bool CalculateDesignatedOwnershipOfBoundaryElement( unsigned faceIndex );
542
550 virtual bool CalculateDesignatedOwnershipOfElement( unsigned elementIndex );
551
562
569 virtual void GetHaloNodeIndices(std::vector<unsigned>& rHaloIndices) const;
570
584 void CalculateNodeExchange( std::vector<std::vector<unsigned> >& rNodesToSendPerProcess,
585 std::vector<std::vector<unsigned> >& rNodesToReceivePerProcess);
586
587
596 virtual c_vector<double, 2> CalculateMinMaxEdgeLengths();
597
611 unsigned GetContainingElementIndex(const ChastePoint<SPACE_DIM>& rTestPoint,
612 bool strict=false,
613 std::set<unsigned> testElements=std::set<unsigned>(),
614 bool onlyTryWithTestElements = false);
615
621 unsigned GetNearestElementIndexFromTestElements(const ChastePoint<SPACE_DIM>& rTestPoint,
622 std::set<unsigned> testElements);
623
625 // Nested classes //
627
632 {
633 public:
640
646
652 inline bool operator!=(const typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator& rOther);
653
658 inline ElementIterator& operator++();
659
671 typename std::vector<Element<ELEMENT_DIM, SPACE_DIM> *>::iterator elementIter,
672 bool skipDeletedElements=true);
673
674 private:
677
679 typename std::vector<Element<ELEMENT_DIM, SPACE_DIM> *>::iterator mElementIter;
680
683
688 inline bool IsAtEnd();
689
694 inline bool IsAllowedElement();
695 };
696};
697
699
700namespace boost {
701namespace serialization {
708template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
709struct version<AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM> >
710{
713};
714} // namespace serialization
715} // namespace boost
716
717
719// ElementIterator class implementation - most methods are inlined //
721
722template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
724 bool skipDeletedElements)
725{
726 return ElementIterator(*this, mElements.begin(), skipDeletedElements);
727}
728
729template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
734
735template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
741
742template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
748
749template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
754
755template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
757{
758 do
759 {
760 ++mElementIter;
761 }
762 while (!IsAtEnd() && !IsAllowedElement());
763
764 return (*this);
765}
766
767template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
770 typename std::vector<Element<ELEMENT_DIM, SPACE_DIM> *>::iterator elementIter,
771 bool skipDeletedElements)
772 : mrMesh(rMesh),
773 mElementIter(elementIter),
774 mSkipDeletedElements(skipDeletedElements)
775{
776 if (mrMesh.mElements.size() == 0)
777 {
778 // Cope with empty meshes
780 }
781 else
782 {
783 // Make sure we start at an allowed element
784 if (mElementIter == mrMesh.mElements.begin() && !IsAllowedElement())
785 {
786 ++(*this);
787 }
788 }
789}
790
791template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
793{
794 return mElementIter == mrMesh.mElements.end();
795}
796
797template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
799{
800 return !(mSkipDeletedElements && (*this)->IsDeleted());
801}
802
803#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.