Chaste Release::3.1
AbstractTetrahedralMesh.hpp
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_*/