Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 00036 #ifndef ABSTRACTTETRAHEDRALMESH_HPP_ 00037 #define ABSTRACTTETRAHEDRALMESH_HPP_ 00038 00039 #include "ChasteSerialization.hpp" 00040 #include "ClassIsAbstract.hpp" 00041 #include "ChasteSerializationVersion.hpp" 00042 #include <boost/serialization/vector.hpp> 00043 #include <boost/serialization/base_object.hpp> 00044 #include <boost/serialization/split_member.hpp> 00045 00046 #include <vector> 00047 #include <string> 00048 #include <cassert> 00049 #include <boost/foreach.hpp> 00050 00051 #include "AbstractMesh.hpp" 00052 #include "BoundaryElement.hpp" 00053 #include "Element.hpp" 00054 #include "GenericMeshReader.hpp" 00055 #include "AbstractMeshReader.hpp" 00056 #include "TrianglesMeshReader.hpp" 00057 #include "TrianglesMeshWriter.hpp" 00058 #include "ArchiveLocationInfo.hpp" 00059 #include "FileFinder.hpp" 00060 00061 00063 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00064 class AbstractConductivityTensors; 00065 00070 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00071 class AbstractTetrahedralMesh : public AbstractMesh<ELEMENT_DIM, SPACE_DIM> 00072 { 00073 friend class AbstractConductivityTensors<ELEMENT_DIM, SPACE_DIM>; //A class which needs a global to local element mapping 00074 00075 protected: 00079 bool mMeshIsLinear; 00080 00081 private: 00089 virtual unsigned SolveElementMapping(unsigned index) const = 0; 00090 00098 virtual unsigned SolveBoundaryElementMapping(unsigned index) const = 0; 00099 00101 friend class boost::serialization::access; 00102 00114 template<class Archive> 00115 void save(Archive & archive, const unsigned int version) const 00116 { 00117 archive & boost::serialization::base_object<AbstractMesh<ELEMENT_DIM,SPACE_DIM> >(*this); 00118 archive & mMeshIsLinear; 00119 // Create a mesh writer pointing to the correct file and directory 00120 TrianglesMeshWriter<ELEMENT_DIM,SPACE_DIM> mesh_writer(ArchiveLocationInfo::GetArchiveRelativePath(), 00121 ArchiveLocationInfo::GetMeshFilename(), 00122 false); 00123 // Binary meshes have similar content to the original Triangle/Tetgen format, but take up less space on disk 00124 mesh_writer.SetWriteFilesAsBinary(); 00125 00126 // Archive the mesh permutation, so we can just copy the original mesh files whenever possible 00127 bool permutation_available = (this->rGetNodePermutation().size() != 0); 00128 archive & permutation_available; 00129 00130 if (permutation_available) 00131 { 00132 const std::vector<unsigned>& rPermutation = this->rGetNodePermutation(); 00133 archive & rPermutation; 00134 } 00135 00136 if (!this->IsMeshOnDisk()) 00137 { 00138 mesh_writer.WriteFilesUsingMesh(*(const_cast<AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>*>(this))); 00139 } 00140 else 00141 { 00142 unsigned order_of_element = (mMeshIsLinear?1:2); 00143 unsigned& order_of_boundary_element = order_of_element; 00144 00145 // Mesh in disc, copy it to the archiving folder 00146 std::string original_file=this->GetMeshFileBaseName(); 00147 std::auto_ptr<AbstractMeshReader<ELEMENT_DIM, SPACE_DIM> > p_original_mesh_reader 00148 = GenericMeshReader<ELEMENT_DIM, SPACE_DIM>(original_file, order_of_element, order_of_boundary_element); 00149 00150 if (p_original_mesh_reader->IsFileFormatBinary()) 00151 { 00152 // Mesh is in binary format, we can just copy the files across ignoring the mesh reader 00153 if (PetscTools::AmMaster()) 00154 { 00155 FileFinder mesh_base(this->GetMeshFileBaseName()); 00156 FileFinder mesh_folder = mesh_base.GetParent(); 00157 std::string mesh_leaf_name = mesh_base.GetLeafNameNoExtension(); 00158 std::vector<FileFinder> mesh_files = mesh_folder.FindMatches(mesh_leaf_name + ".*"); 00159 FileFinder dest_dir(ArchiveLocationInfo::GetArchiveDirectory()); 00160 BOOST_FOREACH(const FileFinder& r_mesh_file, mesh_files) 00161 { 00162 FileFinder dest_file(ArchiveLocationInfo::GetMeshFilename() + r_mesh_file.GetExtension(), 00163 dest_dir); 00164 ABORT_IF_THROWS(r_mesh_file.CopyTo(dest_file)); 00165 } 00166 } 00167 } 00168 else 00169 { 00170 // Mesh in text format, use the mesh writer to "binarise" it 00171 mesh_writer.WriteFilesUsingMeshReaderAndMesh(*p_original_mesh_reader, 00172 *(const_cast<AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>*>(this))); 00173 } 00174 } 00175 00176 // Make sure that the files are written before slave processes proceed 00177 PetscTools::Barrier("AbstractTetrahedralMesh::save"); 00178 } 00179 00186 template<class Archive> 00187 void load(Archive & archive, const unsigned int version) 00188 { 00189 archive & boost::serialization::base_object<AbstractMesh<ELEMENT_DIM,SPACE_DIM> >(*this); 00190 archive & mMeshIsLinear; 00191 00192 bool permutation_available=false; 00193 std::vector<unsigned> permutation; 00194 00195 if (version > 0) 00196 { 00197 archive & permutation_available; 00198 00199 if (permutation_available) 00200 { 00201 archive & permutation; 00202 } 00203 } 00204 00205 // Store the DistributedVectorFactory loaded from the archive 00206 DistributedVectorFactory* p_factory = this->mpDistributedVectorFactory; 00207 this->mpDistributedVectorFactory = NULL; 00208 00209 // Check whether we're migrating, or if we can use the original partition for the mesh 00210 DistributedVectorFactory* p_our_factory = NULL; 00211 if (p_factory) 00212 { 00213 p_our_factory = p_factory->GetOriginalFactory(); 00214 } 00215 if (p_our_factory && p_our_factory->GetNumProcs() == p_factory->GetNumProcs()) 00216 { 00217 // Specify the node distribution 00218 this->SetDistributedVectorFactory(p_our_factory); 00219 } 00220 else 00221 { 00222 // Migrating; let the mesh re-partition if it likes 00224 p_our_factory = NULL; 00225 } 00226 00227 if (mMeshIsLinear) 00228 { 00229 // I am a linear mesh 00230 TrianglesMeshReader<ELEMENT_DIM,SPACE_DIM> mesh_reader(ArchiveLocationInfo::GetArchiveDirectory() + ArchiveLocationInfo::GetMeshFilename()); 00231 00232 if (permutation_available) 00233 { 00234 mesh_reader.SetNodePermutation(permutation); 00235 } 00236 00237 this->ConstructFromMeshReader(mesh_reader); 00238 } 00239 else 00240 { 00241 // I am a quadratic mesh and need quadratic information from the reader 00242 TrianglesMeshReader<ELEMENT_DIM,SPACE_DIM> mesh_reader(ArchiveLocationInfo::GetArchiveDirectory() + ArchiveLocationInfo::GetMeshFilename(), 2, 2); 00243 this->ConstructFromMeshReader(mesh_reader); 00244 } 00245 00246 // Make sure we're using the correct vector factory 00247 if (p_factory) 00248 { 00249 if (!this->mpDistributedVectorFactory) 00250 { 00251 // If we're not using a DistributedTetrahedralMesh, ConstructFromMeshReader won't set 00252 // this->mpDistributedVectorFactory. 00253 this->mpDistributedVectorFactory = p_factory; 00254 } 00255 else 00256 { 00257 // We need to update p_factory to match this->mpDistributedVectorFactory, and then use 00258 // p_factory, since the rest of the code (e.g. AbstractCardiacPde) will be using p_factory. 00259 p_factory->SetFromFactory(this->mpDistributedVectorFactory); 00260 if (p_our_factory != this->mpDistributedVectorFactory) 00261 { 00262 // Avoid memory leak 00263 delete this->mpDistributedVectorFactory; 00264 } 00265 this->mpDistributedVectorFactory = p_factory; 00266 } 00267 } 00268 } 00269 BOOST_SERIALIZATION_SPLIT_MEMBER() 00270 00271 protected: // Give access of these variables to subclasses 00272 00274 std::vector<Element<ELEMENT_DIM, SPACE_DIM> *> mElements; 00275 00277 std::vector<BoundaryElement<ELEMENT_DIM-1, SPACE_DIM> *> mBoundaryElements; 00278 00286 void SetElementOwnerships(); 00287 00288 public: 00289 00291 // Iterators // 00293 00295 typedef typename std::vector<BoundaryElement<ELEMENT_DIM-1, SPACE_DIM> *>::const_iterator BoundaryElementIterator; 00296 00298 class ElementIterator; 00299 00305 inline ElementIterator GetElementIteratorBegin(bool skipDeletedElements=true); 00306 00310 inline ElementIterator GetElementIteratorEnd(); 00311 00313 // Methods // 00315 00319 AbstractTetrahedralMesh(); 00320 00324 virtual ~AbstractTetrahedralMesh(); 00325 00326 00330 virtual unsigned GetNumElements() const; 00331 00335 virtual unsigned GetNumLocalElements() const; 00336 00340 virtual unsigned GetNumBoundaryElements() const; 00341 00345 virtual unsigned GetNumLocalBoundaryElements() const; 00346 00350 unsigned GetNumAllElements() const; 00351 00355 unsigned GetNumAllBoundaryElements() const; 00356 00362 virtual unsigned GetNumCableElements() const; 00363 00368 virtual unsigned GetNumVertices() const; 00369 00376 Element<ELEMENT_DIM, SPACE_DIM>* GetElement(unsigned index) const; 00377 00384 BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* GetBoundaryElement(unsigned index) const; 00385 00386 00393 virtual void ConstructFromMeshReader(AbstractMeshReader<ELEMENT_DIM, SPACE_DIM>& rMeshReader)=0; 00394 00403 void ConstructFromMesh(AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>& rOtherMesh); 00404 00405 00409 BoundaryElementIterator GetBoundaryElementIteratorBegin() const; 00410 00415 BoundaryElementIterator GetBoundaryElementIteratorEnd() const; 00416 00425 virtual void GetInverseJacobianForElement(unsigned elementIndex, c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian, 00426 double& rJacobianDeterminant, 00427 c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian) const; 00428 00437 virtual void GetWeightedDirectionForBoundaryElement(unsigned elementIndex, 00438 c_vector<double, SPACE_DIM>& rWeightedDirection, 00439 double& rJacobianDeterminant) const; 00440 00448 void CheckOutwardNormals(); 00449 00462 virtual void ConstructLinearMesh(unsigned width); 00463 00464 00465 00481 virtual void ConstructRectangularMesh(unsigned width, unsigned height, bool stagger=true); 00482 00483 00484 00496 virtual void ConstructCuboid(unsigned width, unsigned height, unsigned depth); 00497 00498 00499 00510 void ConstructRegularSlabMesh(double spaceStep, double width, double height=0, double depth=0); 00511 00512 00513 00520 virtual bool CalculateDesignatedOwnershipOfBoundaryElement( unsigned faceIndex ); 00521 00528 virtual bool CalculateDesignatedOwnershipOfElement( unsigned elementIndex ); 00529 00537 unsigned CalculateMaximumNodeConnectivityPerProcess() const; 00538 00545 virtual void GetHaloNodeIndices(std::vector<unsigned>& rHaloIndices) const; 00546 00560 void CalculateNodeExchange( std::vector<std::vector<unsigned> >& rNodesToSendPerProcess, 00561 std::vector<std::vector<unsigned> >& rNodesToReceivePerProcess); 00562 00563 00572 virtual c_vector<double, 2> CalculateMinMaxEdgeLengths(); 00573 00575 // Nested classes // 00577 00578 00582 class ElementIterator 00583 { 00584 public: 00590 inline Element<ELEMENT_DIM, SPACE_DIM>& operator*(); 00591 00595 inline Element<ELEMENT_DIM, SPACE_DIM>* operator->(); 00596 00602 inline bool operator!=(const AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator& rOther); 00603 00607 inline ElementIterator& operator++(); 00608 00619 ElementIterator(AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>& rMesh, 00620 typename std::vector<Element<ELEMENT_DIM, SPACE_DIM> *>::iterator elementIter, 00621 bool skipDeletedElements=true); 00622 00623 private: 00625 AbstractTetrahedralMesh& mrMesh; 00626 00628 typename std::vector<Element<ELEMENT_DIM, SPACE_DIM> *>::iterator mElementIter; 00629 00631 bool mSkipDeletedElements; 00632 00636 inline bool IsAtEnd(); 00637 00641 inline bool IsAllowedElement(); 00642 }; 00643 00644 }; 00645 00646 TEMPLATED_CLASS_IS_ABSTRACT_2_UNSIGNED(AbstractTetrahedralMesh) 00647 00648 namespace boost { 00649 namespace serialization { 00656 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00657 struct version<AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM> > 00658 { 00660 CHASTE_VERSION_CONTENT(1); 00661 }; 00662 } // namespace serialization 00663 } // namespace boost 00664 00665 00667 // ElementIterator class implementation - most methods are inlined // 00669 00670 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00671 typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetElementIteratorBegin( 00672 bool skipDeletedElements) 00673 { 00674 return ElementIterator(*this, mElements.begin(), skipDeletedElements); 00675 } 00676 00677 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00678 typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetElementIteratorEnd() 00679 { 00680 return ElementIterator(*this, mElements.end()); 00681 } 00682 00683 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00684 Element<ELEMENT_DIM, SPACE_DIM>& AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator::operator*() 00685 { 00686 assert(!IsAtEnd()); 00687 return **mElementIter; 00688 } 00689 00690 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00691 Element<ELEMENT_DIM, SPACE_DIM>* AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator::operator->() 00692 { 00693 assert(!IsAtEnd()); 00694 return *mElementIter; 00695 } 00696 00697 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00698 bool AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator::operator!=(const AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator& rOther) 00699 { 00700 return mElementIter != rOther.mElementIter; 00701 } 00702 00703 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00704 typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator& AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator::operator++() 00705 { 00706 do 00707 { 00708 ++mElementIter; 00709 } 00710 while (!IsAtEnd() && !IsAllowedElement()); 00711 00712 return (*this); 00713 } 00714 00715 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00716 AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator::ElementIterator( 00717 AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>& rMesh, 00718 typename std::vector<Element<ELEMENT_DIM, SPACE_DIM> *>::iterator elementIter, 00719 bool skipDeletedElements) 00720 : mrMesh(rMesh), 00721 mElementIter(elementIter), 00722 mSkipDeletedElements(skipDeletedElements) 00723 { 00724 if (mrMesh.mElements.size() == 0) 00725 { 00726 // Cope with empty meshes 00727 mElementIter = mrMesh.mElements.end(); 00728 } 00729 else 00730 { 00731 // Make sure we start at an allowed element 00732 if (mElementIter == mrMesh.mElements.begin() && !IsAllowedElement()) 00733 { 00734 ++(*this); 00735 } 00736 } 00737 } 00738 00739 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00740 bool AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator::IsAtEnd() 00741 { 00742 return mElementIter == mrMesh.mElements.end(); 00743 } 00744 00745 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00746 bool AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator::IsAllowedElement() 00747 { 00748 return !(mSkipDeletedElements && (*this)->IsDeleted()); 00749 } 00750 00751 00752 00753 #endif /*ABSTRACTTETRAHEDRALMESH_HPP_*/