AbstractTetrahedralMesh.cpp

00001 /*
00002 
00003 Copyright (c) 2005-2015, 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 #include "AbstractTetrahedralMesh.hpp"
00037 
00038 #include <limits>
00039 
00041 // Implementation
00043 
00044 
00045 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00046 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::SetElementOwnerships()
00047 {
00048     unsigned lo=this->GetDistributedVectorFactory()->GetLow();
00049     unsigned hi=this->GetDistributedVectorFactory()->GetHigh();
00050     for (unsigned element_index=0; element_index<mElements.size(); element_index++)
00051     {
00052         Element<ELEMENT_DIM, SPACE_DIM>* p_element = mElements[element_index];
00053         p_element->SetOwnership(false);
00054         for (unsigned local_node_index=0; local_node_index< p_element->GetNumNodes(); local_node_index++)
00055         {
00056             unsigned global_node_index = p_element->GetNodeGlobalIndex(local_node_index);
00057             if (lo<=global_node_index && global_node_index<hi)
00058             {
00059                 p_element->SetOwnership(true);
00060                 break;
00061             }
00062         }
00063     }
00064 }
00065 
00066 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00067 AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::AbstractTetrahedralMesh()
00068     : mMeshIsLinear(true)
00069 {
00070 }
00071 
00072 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00073 AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::~AbstractTetrahedralMesh()
00074 {
00075     // Iterate over elements and free the memory
00076     for (unsigned i=0; i<mElements.size(); i++)
00077     {
00078         delete mElements[i];
00079     }
00080     // Iterate over boundary elements and free the memory
00081     for (unsigned i=0; i<mBoundaryElements.size(); i++)
00082     {
00083         delete mBoundaryElements[i];
00084     }
00085 }
00086 
00087 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00088 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNumElements() const
00089 {
00090     return mElements.size();
00091 }
00092 
00093 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00094 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNumLocalElements() const
00095 {
00096     return GetNumElements();
00097 }
00098 
00099 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00100 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNumAllElements() const
00101 {
00102     return mElements.size();
00103 }
00104 
00105 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00106 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNumBoundaryElements() const
00107 {
00108     return mBoundaryElements.size();
00109 }
00110 
00111 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00112 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNumLocalBoundaryElements() const
00113 {
00114     return GetNumBoundaryElements();
00115 }
00116 
00117 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00118 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNumAllBoundaryElements() const
00119 {
00120     return mBoundaryElements.size();
00121 }
00122 
00123 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00124 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNumCableElements() const
00125 {
00126     return 0u;
00127 }
00128 
00129 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00130 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNumVertices() const
00131 {
00132     return this->GetNumNodes();
00133 }
00134 
00135 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00136 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetMaximumNodeIndex()
00137 {
00138     return this->GetNumAllNodes();
00139 }
00140 
00141 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00142 Element<ELEMENT_DIM, SPACE_DIM>* AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetElement(unsigned index) const
00143 {
00144     unsigned local_index = SolveElementMapping(index);
00145     return mElements[local_index];
00146 }
00147 
00148 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00149 BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetBoundaryElement(unsigned index) const
00150 {
00151     unsigned local_index = SolveBoundaryElementMapping(index);
00152     return mBoundaryElements[local_index];
00153 }
00154 
00155 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00156 typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetBoundaryElementIteratorBegin() const
00157 {
00158     return mBoundaryElements.begin();
00159 }
00160 
00161 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00162 typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetBoundaryElementIteratorEnd() const
00163 {
00164     return mBoundaryElements.end();
00165 }
00166 
00167 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00168 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetInverseJacobianForElement(
00169         unsigned elementIndex,
00170         c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian,
00171         double& rJacobianDeterminant,
00172         c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian) const
00173 {
00174     mElements[SolveElementMapping(elementIndex)]->CalculateInverseJacobian(rJacobian, rJacobianDeterminant, rInverseJacobian);
00175 }
00176 
00177 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00178 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetWeightedDirectionForBoundaryElement(
00179         unsigned elementIndex,
00180         c_vector<double, SPACE_DIM>& rWeightedDirection,
00181         double& rJacobianDeterminant) const
00182 {
00183     mBoundaryElements[SolveBoundaryElementMapping(elementIndex)]->CalculateWeightedDirection(rWeightedDirection, rJacobianDeterminant );
00184 }
00185 
00186 
00187 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00188 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CheckOutwardNormals()
00189 {
00190     if (ELEMENT_DIM <= 1)
00191     {
00192         //If the ELEMENT_DIM of the mesh is 1 then the boundary will have ELEMENT_DIM = 0
00193         EXCEPTION("1-D mesh has no boundary normals");
00194     }
00195     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::BoundaryElementIterator face_iter = this->GetBoundaryElementIteratorBegin();
00196          face_iter != this->GetBoundaryElementIteratorEnd();
00197          ++face_iter)
00198     {
00199         //Form a set for the boundary element node indices
00200         std::set<unsigned> boundary_element_node_indices;
00201         for (unsigned i=0; i<ELEMENT_DIM; i++)
00202         {
00203             boundary_element_node_indices.insert( (*face_iter)->GetNodeGlobalIndex(i) );
00204         }
00205 
00206         Node<SPACE_DIM>* p_opposite_node = NULL;
00207         Node<SPACE_DIM>* p_representative_node = (*face_iter)->GetNode(0);
00208           for (typename Node<SPACE_DIM>::ContainingElementIterator element_iter = p_representative_node->ContainingElementsBegin();
00209              element_iter != p_representative_node->ContainingElementsEnd();
00210              ++element_iter)
00211         {
00212             Element<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(*element_iter);
00213             //Form a set for the element node indices
00214             std::set<unsigned> element_node_indices;
00215             for (unsigned i=0; i<=ELEMENT_DIM; i++)
00216             {
00217                 element_node_indices.insert( p_element->GetNodeGlobalIndex(i) );
00218             }
00219 
00220             std::vector<unsigned> difference(ELEMENT_DIM);
00221 
00222             std::vector<unsigned>::iterator set_iter = std::set_difference(
00223                     element_node_indices.begin(),element_node_indices.end(),
00224                     boundary_element_node_indices.begin(), boundary_element_node_indices.end(),
00225                     difference.begin());
00226             if (set_iter - difference.begin() == 1)
00227             {
00228                 p_opposite_node = this -> GetNodeOrHaloNode(difference[0]);
00229                 break;
00230             }
00231         }
00232         assert(p_opposite_node != NULL);
00233 
00234         // Vector from centroid of face to opposite node
00235         c_vector<double, SPACE_DIM> into_mesh = p_opposite_node->rGetLocation() - (*face_iter)->CalculateCentroid();
00236         c_vector<double, SPACE_DIM> normal = (*face_iter)->CalculateNormal();
00237 
00238         if (inner_prod(into_mesh, normal) > 0.0)
00239         {
00240             EXCEPTION("Inward facing normal in boundary element index "<<(*face_iter)->GetIndex());
00241         }
00242     }
00243 }
00244 
00245 
00246 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00247 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructLinearMesh(unsigned width)
00248 {
00249     assert(ELEMENT_DIM == 1);
00250 
00251     for (unsigned node_index=0; node_index<=width; node_index++)
00252     {
00253         Node<SPACE_DIM>* p_node = new Node<SPACE_DIM>(node_index, node_index==0 || node_index==width, node_index);
00254         this->mNodes.push_back(p_node); // create node
00255         if (node_index==0) // create left boundary node and boundary element
00256         {
00257             this->mBoundaryNodes.push_back(p_node);
00258             this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(0, p_node) );
00259         }
00260         if (node_index==width) // create right boundary node and boundary element
00261         {
00262             this->mBoundaryNodes.push_back(p_node);
00263             this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(1, p_node) );
00264         }
00265         if (node_index > 0) // create element
00266         {
00267             std::vector<Node<SPACE_DIM>*> nodes;
00268             nodes.push_back(this->mNodes[node_index-1]);
00269             nodes.push_back(this->mNodes[node_index]);
00270             this->mElements.push_back(new Element<ELEMENT_DIM,SPACE_DIM>(node_index-1, nodes) );
00271         }
00272     }
00273 
00274     this->RefreshMesh();
00275 }
00276 
00277 
00278 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00279 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructRectangularMesh(unsigned width, unsigned height, bool stagger)
00280 {
00281     assert(SPACE_DIM == 2);
00282     assert(ELEMENT_DIM == 2);
00283 
00284     //Construct the nodes
00285     unsigned node_index=0;
00286     for (unsigned j=0; j<height+1; j++)
00287     {
00288         for (unsigned i=0; i<width+1; i++)
00289         {
00290             bool is_boundary=false;
00291             if (i==0 || j==0 || i==width || j==height)
00292             {
00293                 is_boundary=true;
00294             }
00295             //Check in place for parallel
00296             assert(node_index==(width+1)*(j) + i);
00297             Node<SPACE_DIM>* p_node = new Node<SPACE_DIM>(node_index++, is_boundary, i, j);
00298             this->mNodes.push_back(p_node);
00299             if (is_boundary)
00300             {
00301                 this->mBoundaryNodes.push_back(p_node);
00302             }
00303         }
00304     }
00305 
00306     //Construct the boundary elements
00307     unsigned belem_index=0;
00308     //Top
00309     for (unsigned i=0; i<width; i++)
00310     {
00311         std::vector<Node<SPACE_DIM>*> nodes;
00312         nodes.push_back(this->mNodes[height*(width+1)+i+1]);
00313         nodes.push_back(this->mNodes[height*(width+1)+i]);
00314         assert(belem_index==i);
00315         this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,nodes));
00316     }
00317     //Right
00318     for (unsigned j=1; j<=height; j++)
00319     {
00320         std::vector<Node<SPACE_DIM>*> nodes;
00321         nodes.push_back(this->mNodes[(width+1)*j-1]);
00322         nodes.push_back(this->mNodes[(width+1)*(j+1)-1]);
00323         assert(belem_index==width+j-1);
00324         this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,nodes));
00325     }
00326     //Bottom
00327     for (unsigned i=0; i<width; i++)
00328     {
00329         std::vector<Node<SPACE_DIM>*> nodes;
00330         nodes.push_back(this->mNodes[i]);
00331         nodes.push_back(this->mNodes[i+1]);
00332         assert(belem_index==width+height+i);
00333         this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,nodes));
00334     }
00335     //Left
00336     for (unsigned j=0; j<height; j++)
00337     {
00338         std::vector<Node<SPACE_DIM>*> nodes;
00339         nodes.push_back(this->mNodes[(width+1)*(j+1)]);
00340         nodes.push_back(this->mNodes[(width+1)*(j)]);
00341         assert(belem_index==2*width+height+j);
00342         this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,nodes));
00343     }
00344 
00345     //Construct the elements
00346     unsigned elem_index = 0;
00347     for (unsigned j=0; j<height; j++)
00348     {
00349         for (unsigned i=0; i<width; i++)
00350         {
00351             unsigned parity=(i+(height-j))%2;//Note that parity is measured from the top-left (not bottom left) for historical reasons
00352             unsigned nw=(j+1)*(width+1)+i; //ne=nw+1
00353             unsigned sw=(j)*(width+1)+i;   //se=sw+1
00354             std::vector<Node<SPACE_DIM>*> upper_nodes;
00355             upper_nodes.push_back(this->mNodes[nw]);
00356             upper_nodes.push_back(this->mNodes[nw+1]);
00357             if (stagger==false  || parity == 1)
00358             {
00359                 upper_nodes.push_back(this->mNodes[sw+1]);
00360             }
00361             else
00362             {
00363                 upper_nodes.push_back(this->mNodes[sw]);
00364             }
00365             assert(elem_index==2*(j*width+i));
00366             this->mElements.push_back(new Element<ELEMENT_DIM,SPACE_DIM>(elem_index++,upper_nodes));
00367             std::vector<Node<SPACE_DIM>*> lower_nodes;
00368             lower_nodes.push_back(this->mNodes[sw+1]);
00369             lower_nodes.push_back(this->mNodes[sw]);
00370             if (stagger==false  ||parity == 1)
00371             {
00372                 lower_nodes.push_back(this->mNodes[nw]);
00373             }
00374             else
00375             {
00376                 lower_nodes.push_back(this->mNodes[nw+1]);
00377             }
00378             this->mElements.push_back(new Element<ELEMENT_DIM,SPACE_DIM>(elem_index++,lower_nodes));
00379         }
00380     }
00381 
00382     this->RefreshMesh();
00383 }
00384 
00385 
00386 
00387 
00388 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00389 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructCuboid(unsigned width,
00390         unsigned height,
00391         unsigned depth)
00392 {
00393     assert(SPACE_DIM == 3);
00394     assert(ELEMENT_DIM == 3);
00395     //Construct the nodes
00396 
00397     unsigned node_index = 0;
00398     for (unsigned k=0; k<depth+1; k++)
00399     {
00400         for (unsigned j=0; j<height+1; j++)
00401         {
00402             for (unsigned i=0; i<width+1; i++)
00403             {
00404                 bool is_boundary = false;
00405                 if (i==0 || j==0 || k==0 || i==width || j==height || k==depth)
00406                 {
00407                     is_boundary = true;
00408                 }
00409                 assert(node_index == (k*(height+1)+j)*(width+1)+i);
00410                 Node<SPACE_DIM>* p_node = new Node<SPACE_DIM>(node_index++, is_boundary, i, j, k);
00411 
00412                 this->mNodes.push_back(p_node);
00413                 if (is_boundary)
00414                 {
00415                     this->mBoundaryNodes.push_back(p_node);
00416                 }
00417             }
00418         }
00419     }
00420 
00421     // Construct the elements
00422 
00423     unsigned elem_index = 0;
00424     unsigned belem_index = 0;
00425     unsigned element_nodes[6][4] = {{0, 1, 5, 7}, {0, 1, 3, 7},
00426                                         {0, 2, 3, 7}, {0, 2, 6, 7},
00427                                         {0, 4, 6, 7}, {0, 4, 5, 7}};
00428 /* Alternative tessellation - (gerardus)
00429  * Note that our method (above) has a bias that all tetrahedra share a
00430  * common edge (the diagonal 0 - 7).  In the following method the cube is
00431  * split along the "face diagonal" 1-2-5-6 into two prisms.  This also has a bias.
00432  *
00433     unsigned element_nodes[6][4] = {{ 0, 6, 5, 4},
00434                                     { 0, 2, 6, 1},
00435                                     { 0, 1, 6, 5},
00436                                     { 1, 2, 3, 7},
00437                                     { 1, 2, 6, 7},
00438                                     { 1, 6, 7, 5 }};
00439 */
00440     std::vector<Node<SPACE_DIM>*> tetrahedra_nodes;
00441 
00442     for (unsigned k=0; k<depth; k++)
00443     {
00444         if (k!=0)
00445         {
00446             // height*width squares on upper face, k layers of 2*height+2*width square aroun
00447             assert(belem_index ==   2*(height*width+k*2*(height+width)) );
00448         }
00449         for (unsigned j=0; j<height; j++)
00450         {
00451             for (unsigned i=0; i<width; i++)
00452             {
00453                 // Compute the nodes' index
00454                 unsigned global_node_indices[8];
00455                 unsigned local_node_index = 0;
00456 
00457                 for (unsigned z = 0; z < 2; z++)
00458                 {
00459                     for (unsigned y = 0; y < 2; y++)
00460                     {
00461                         for (unsigned x = 0; x < 2; x++)
00462                         {
00463                             global_node_indices[local_node_index] = i+x+(width+1)*(j+y+(height+1)*(k+z));
00464 
00465                             local_node_index++;
00466                         }
00467                     }
00468                 }
00469 
00470                 for (unsigned m = 0; m < 6; m++)
00471                 {
00472                     // Tetrahedra #m
00473 
00474                     tetrahedra_nodes.clear();
00475 
00476                     for (unsigned n = 0; n < 4; n++)
00477                     {
00478                         tetrahedra_nodes.push_back(this->mNodes[global_node_indices[element_nodes[m][n]]]);
00479                     }
00480 
00481                     assert(elem_index == 6 * ((k*height+j)*width+i)+m );
00482                     this->mElements.push_back(new Element<ELEMENT_DIM,SPACE_DIM>(elem_index++, tetrahedra_nodes));
00483                 }
00484 
00485                 // Are we at a boundary?
00486                 std::vector<Node<SPACE_DIM>*> triangle_nodes;
00487 
00488                 if (i == 0) //low face at x==0
00489                 {
00490                     triangle_nodes.clear();
00491                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
00492                     triangle_nodes.push_back(this->mNodes[global_node_indices[2]]);
00493                     triangle_nodes.push_back(this->mNodes[global_node_indices[6]]);
00494                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00495                     triangle_nodes.clear();
00496                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
00497                     triangle_nodes.push_back(this->mNodes[global_node_indices[6]]);
00498                     triangle_nodes.push_back(this->mNodes[global_node_indices[4]]);
00499                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00500                 }
00501                 if (i == width-1) //high face at x=width
00502                 {
00503                     triangle_nodes.clear();
00504                     triangle_nodes.push_back(this->mNodes[global_node_indices[1]]);
00505                     triangle_nodes.push_back(this->mNodes[global_node_indices[5]]);
00506                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
00507                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00508                     triangle_nodes.clear();
00509                     triangle_nodes.push_back(this->mNodes[global_node_indices[1]]);
00510                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
00511                     triangle_nodes.push_back(this->mNodes[global_node_indices[3]]);
00512                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00513                 }
00514                 if (j == 0) //low face at y==0
00515                 {
00516                     triangle_nodes.clear();
00517                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
00518                     triangle_nodes.push_back(this->mNodes[global_node_indices[5]]);
00519                     triangle_nodes.push_back(this->mNodes[global_node_indices[1]]);
00520                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00521                     triangle_nodes.clear();
00522                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
00523                     triangle_nodes.push_back(this->mNodes[global_node_indices[4]]);
00524                     triangle_nodes.push_back(this->mNodes[global_node_indices[5]]);
00525                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00526                 }
00527                 if (j == height-1) //high face at y=height
00528                 {
00529                     triangle_nodes.clear();
00530                     triangle_nodes.push_back(this->mNodes[global_node_indices[2]]);
00531                     triangle_nodes.push_back(this->mNodes[global_node_indices[3]]);
00532                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
00533                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00534                     triangle_nodes.clear();
00535                     triangle_nodes.push_back(this->mNodes[global_node_indices[2]]);
00536                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
00537                     triangle_nodes.push_back(this->mNodes[global_node_indices[6]]);
00538                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00539                 }
00540                 if (k == 0) //low face at z==0
00541                 {
00542                     triangle_nodes.clear();
00543                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
00544                     triangle_nodes.push_back(this->mNodes[global_node_indices[3]]);
00545                     triangle_nodes.push_back(this->mNodes[global_node_indices[2]]);
00546                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00547                     triangle_nodes.clear();
00548                     triangle_nodes.push_back(this->mNodes[global_node_indices[0]]);
00549                     triangle_nodes.push_back(this->mNodes[global_node_indices[1]]);
00550                     triangle_nodes.push_back(this->mNodes[global_node_indices[3]]);
00551                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00552                 }
00553                 if (k == depth-1) //high face at z=depth
00554                 {
00555                     triangle_nodes.clear();
00556                     triangle_nodes.push_back(this->mNodes[global_node_indices[4]]);
00557                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
00558                     triangle_nodes.push_back(this->mNodes[global_node_indices[5]]);
00559                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00560                     triangle_nodes.clear();
00561                     triangle_nodes.push_back(this->mNodes[global_node_indices[4]]);
00562                     triangle_nodes.push_back(this->mNodes[global_node_indices[6]]);
00563                     triangle_nodes.push_back(this->mNodes[global_node_indices[7]]);
00564                     this->mBoundaryElements.push_back(new BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>(belem_index++,triangle_nodes));
00565                 }
00566             }//i
00567         }//j
00568     }//k
00569 
00570     this->RefreshMesh();
00571 }
00572 
00573 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00574 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructRegularSlabMesh(double spaceStep, double width, double height, double depth)
00575 {
00576     assert(spaceStep>0.0);
00577     assert(width>0.0);
00578     if (ELEMENT_DIM > 1)
00579     {
00580         assert(height>0.0);
00581     }
00582     if (ELEMENT_DIM > 2)
00583     {
00584         assert(depth>0.0);
00585     }
00586     unsigned num_elem_x=(unsigned)((width+0.5*spaceStep)/spaceStep); //0.5*spaceStep is to ensure that rounding down snaps to correct number
00587     unsigned num_elem_y=(unsigned)((height+0.5*spaceStep)/spaceStep);
00588     unsigned num_elem_z=(unsigned)((depth+0.5*spaceStep)/spaceStep);
00589 
00590     //Make it obvious that actual_width_x etc. are temporaries used in spotting for exception
00591     {
00592         double actual_width_x=num_elem_x*spaceStep;
00593         double actual_width_y=num_elem_y*spaceStep;
00594         double actual_width_z=num_elem_z*spaceStep;
00595 
00596         //Note here that in ELEMENT_DIM > 1 cases there may be a zero height or depth - in which case we don't need to use relative comparisons
00597         // Doing relative comparisons with zero is okay - if we avoid division by zero.
00598         // However, it's best not to test whether " fabs( 0.0 - 0.0) > DBL_EPSILON*0.0 "
00599         if (  fabs (actual_width_x - width) > DBL_EPSILON*width
00600             ||( height!= 0.0 &&  fabs (actual_width_y - height) > DBL_EPSILON*height)
00601             ||( depth != 0.0 &&  fabs (actual_width_z - depth) > DBL_EPSILON*depth ) )
00602         {
00603             EXCEPTION("Space step does not divide the size of the mesh");
00604         }
00605     }
00606     switch (ELEMENT_DIM)
00607     {
00608         case 1:
00609             this->ConstructLinearMesh(num_elem_x);
00610             break;
00611         case 2:
00612             this->ConstructRectangularMesh(num_elem_x, num_elem_y); // Stagger=default value
00613             break;
00614         default:
00615         case 3:
00616             this->ConstructCuboid(num_elem_x, num_elem_y, num_elem_z);
00617     }
00618     this->Scale(spaceStep, spaceStep, spaceStep);
00619 }
00620 
00621 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00622 bool AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CalculateDesignatedOwnershipOfBoundaryElement( unsigned faceIndex )
00623 {
00624     // This may throw in the distributed parallel case
00625     unsigned tie_break_index = this->GetBoundaryElement(faceIndex)->GetNodeGlobalIndex(0);
00626 
00627     // if it is in my range
00628     if (this->GetDistributedVectorFactory()->IsGlobalIndexLocal(tie_break_index))
00629     {
00630         return true;
00631     }
00632     else
00633     {
00634         return false;
00635     }
00636 }
00637 
00638 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00639 bool AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CalculateDesignatedOwnershipOfElement( unsigned elementIndex )
00640 {
00641     // This may throw in the distributed parallel case
00642     unsigned tie_break_index = this->GetElement(elementIndex)->GetNodeGlobalIndex(0);
00643 
00644     // if it is in my range
00645     if (this->GetDistributedVectorFactory()->IsGlobalIndexLocal(tie_break_index))
00646     {
00647         return true;
00648     }
00649     else
00650     {
00651         return false;
00652     }
00653 }
00654 
00655 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00656 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CalculateMaximumNodeConnectivityPerProcess() const
00657 {
00658 
00659     if (this->mNodes.size() == 0u)
00660     {
00661 #define COVERAGE_IGNORE
00662         /*
00663          * Coverage of this block requires a mesh regular slab mesh with the number of
00664          * elements in the primary dimension less than (num_procs - 1), e.g. a 1D mesh
00665          * one element wide with num_procs >=3.
00666          * Note that if a process owns no nodes, then it will still need to enter the
00667          * collective call to MatMPIAIJSetPreallocation. In PetscTools::SetupMat, the
00668          * rowPreallocation parameter uses the special value zero to indicate no preallocation.
00669          */
00670 
00671         // This process owns no nodes and thus owns none of the mesh
00672         return (1u);
00673 #undef COVERAGE_IGNORE
00674     }
00675 
00676     unsigned max_num = 0u;
00677     unsigned connected_node_index = 0u;
00678     unsigned boundary_max_num = 0u;
00679     unsigned boundary_connected_node_index = 0u;
00680     for (unsigned local_node_index=0; local_node_index<this->mNodes.size(); local_node_index++)
00681     {
00682         unsigned num = this->mNodes[local_node_index]->GetNumContainingElements();
00683         if (this->mNodes[local_node_index]->IsBoundaryNode()==false && num>max_num)
00684         {
00685             max_num = num;
00686             connected_node_index = local_node_index;
00687         }
00688         if (this->mNodes[local_node_index]->IsBoundaryNode() && num>boundary_max_num)
00689         {
00690             boundary_max_num = num;
00691             boundary_connected_node_index = local_node_index;
00692         }
00693     }
00694     assert (max_num != 0u || boundary_max_num != 0u);
00695     // connected_node_index now has the index of a maximally connected internal node
00696     // boundary_connected_node_index now has the index of a maximally connected boundary node
00697     std::set<unsigned> forward_star_nodes;
00698     unsigned nodes_per_element = this->mElements[0]->GetNumNodes(); //Usually ELEMENT_DIM+1, except in Quadratic case
00699 
00700     for (typename Node<SPACE_DIM>::ContainingElementIterator it = this->mNodes[connected_node_index]->ContainingElementsBegin();
00701         it != this->mNodes[connected_node_index]->ContainingElementsEnd();
00702         ++it)
00703     {
00704         Element<ELEMENT_DIM, SPACE_DIM>* p_elem = this->GetElement(*it);
00705         for (unsigned i=0; i<nodes_per_element; i++)
00706         {
00707             forward_star_nodes.insert(p_elem->GetNodeGlobalIndex(i));
00708         }
00709     }
00710 
00711     std::set<unsigned> boundary_forward_star_nodes;
00712     for (typename Node<SPACE_DIM>::ContainingElementIterator it = this->mNodes[boundary_connected_node_index]->ContainingElementsBegin();
00713         it != this->mNodes[boundary_connected_node_index]->ContainingElementsEnd();
00714         ++it)
00715     {
00716         Element<ELEMENT_DIM, SPACE_DIM>* p_elem = this->GetElement(*it);
00717         for (unsigned i=0; i<nodes_per_element; i++)
00718         {
00719             boundary_forward_star_nodes.insert(p_elem->GetNodeGlobalIndex(i));
00720         }
00721     }
00722 
00723     if (boundary_forward_star_nodes.size() > forward_star_nodes.size())
00724     {
00725         return boundary_forward_star_nodes.size();
00726     }
00727     return forward_star_nodes.size();
00728 }
00729 
00730 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00731 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetHaloNodeIndices(std::vector<unsigned>& rHaloIndices) const
00732 {
00733     // Make sure the output vector is empty
00734     rHaloIndices.clear();
00735 }
00736 
00737 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00738 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ConstructFromMesh(AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>& rOtherMesh)
00739 {
00740     for (unsigned i=0; i<rOtherMesh.GetNumNodes(); i++)
00741     {
00742         Node<SPACE_DIM>* p_node =  rOtherMesh.GetNode(i);
00743         assert(!p_node->IsDeleted());
00744         c_vector<double, SPACE_DIM> location=p_node->rGetLocation();
00745         bool is_boundary=p_node->IsBoundaryNode();
00746 
00747         Node<SPACE_DIM>* p_node_copy = new Node<SPACE_DIM>(i, location, is_boundary);
00748         this->mNodes.push_back( p_node_copy );
00749         if (is_boundary)
00750         {
00751             this->mBoundaryNodes.push_back( p_node_copy );
00752         }
00753     }
00754 
00755     for (unsigned i=0; i<rOtherMesh.GetNumElements(); i++)
00756     {
00757         Element<ELEMENT_DIM, SPACE_DIM>* p_elem = rOtherMesh.GetElement(i);
00758         assert(!p_elem->IsDeleted());
00759         std::vector<Node<SPACE_DIM>*> nodes_for_element;
00760         for (unsigned j=0; j<p_elem->GetNumNodes(); j++)
00761         {
00762             nodes_for_element.push_back(this->mNodes[ p_elem->GetNodeGlobalIndex(j) ]);
00763         }
00764         Element<ELEMENT_DIM, SPACE_DIM>* p_elem_copy = new Element<ELEMENT_DIM, SPACE_DIM>(i, nodes_for_element);
00765         p_elem_copy->RegisterWithNodes();
00766         this->mElements.push_back(p_elem_copy);
00767     }
00768 
00769     for (unsigned i=0; i<rOtherMesh.GetNumBoundaryElements(); i++)
00770     {
00771         BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* p_b_elem =  rOtherMesh.GetBoundaryElement(i);
00772         assert(!p_b_elem->IsDeleted());
00773         std::vector<Node<SPACE_DIM>*> nodes_for_element;
00774         for (unsigned j=0; j<p_b_elem->GetNumNodes(); j++)
00775         {
00776             nodes_for_element.push_back(this->mNodes[ p_b_elem->GetNodeGlobalIndex(j) ]);
00777         }
00778         BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* p_b_elem_copy = new BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>(i, nodes_for_element);
00779         p_b_elem_copy->RegisterWithNodes();
00780         this->mBoundaryElements.push_back(p_b_elem_copy);
00781     }
00782     this->RefreshMesh();
00783 
00784 }
00785 
00786 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00787 void AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CalculateNodeExchange(
00788                                      std::vector<std::vector<unsigned> >& rNodesToSendPerProcess,
00789                                      std::vector<std::vector<unsigned> >& rNodesToReceivePerProcess)
00790 {
00791     assert( rNodesToSendPerProcess.empty() );
00792     assert( rNodesToReceivePerProcess.empty() );
00793 
00794     //Initialise vectors of sets for the exchange data
00795     std::vector<std::set<unsigned> > node_sets_to_send_per_process;
00796     std::vector<std::set<unsigned> > node_sets_to_receive_per_process;
00797 
00798     node_sets_to_send_per_process.resize(PetscTools::GetNumProcs());
00799     node_sets_to_receive_per_process.resize(PetscTools::GetNumProcs());
00800     std::vector<unsigned> global_lows = this->GetDistributedVectorFactory()->rGetGlobalLows();
00801 
00802     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00803          iter != this->GetElementIteratorEnd();
00804          ++iter)
00805     {
00806         std::vector <unsigned> nodes_on_this_process;
00807         std::vector <unsigned> nodes_not_on_this_process;
00808         //Calculate local and non-local node indices
00809         for (unsigned i=0; i<ELEMENT_DIM+1; i++)
00810         {
00811             unsigned node_index=iter->GetNodeGlobalIndex(i);
00812             if (this->GetDistributedVectorFactory()->IsGlobalIndexLocal(node_index))
00813             {
00814                 nodes_on_this_process.push_back(node_index);
00815             }
00816             else
00817             {
00818                 nodes_not_on_this_process.push_back(node_index);
00819             }
00820         }
00821         /*
00822          * If this is a TetrahedralMesh (not distributed) then it's possible that we own none
00823          * of the nodes in this element.  In that case we must skip the element.
00824          */
00825         if (nodes_on_this_process.empty())
00826         {
00827             continue; //Move on to the next element.
00829         }
00830         // If there are any non-local nodes on this element then we need to add to the data exchange
00831         if (!nodes_not_on_this_process.empty())
00832         {
00833             for (unsigned i=0; i<nodes_not_on_this_process.size(); i++)
00834             {
00835                 // Calculate who owns this remote node
00836                 unsigned remote_process=global_lows.size()-1;
00837                 for (; global_lows[remote_process] > nodes_not_on_this_process[i]; remote_process--)
00838                 {
00839                 }
00840 
00841                 // Add this node to the correct receive set
00842                 node_sets_to_receive_per_process[remote_process].insert(nodes_not_on_this_process[i]);
00843 
00844                 // Add all local nodes to the send set
00845                 for (unsigned j=0; j<nodes_on_this_process.size(); j++)
00846                 {
00847                     node_sets_to_send_per_process[remote_process].insert(nodes_on_this_process[j]);
00848                 }
00849             }
00850         }
00851     }
00852 
00853     for (unsigned process_number = 0; process_number < PetscTools::GetNumProcs(); process_number++)
00854     {
00855         std::vector<unsigned> process_send_vector( node_sets_to_send_per_process[process_number].begin(),
00856                                                    node_sets_to_send_per_process[process_number].end()    );
00857         std::sort(process_send_vector.begin(), process_send_vector.end());
00858 
00859         rNodesToSendPerProcess.push_back(process_send_vector);
00860 
00861         std::vector<unsigned> process_receive_vector( node_sets_to_receive_per_process[process_number].begin(),
00862                                                       node_sets_to_receive_per_process[process_number].end()    );
00863         std::sort(process_receive_vector.begin(), process_receive_vector.end());
00864 
00865         rNodesToReceivePerProcess.push_back(process_receive_vector);
00866     }
00867 
00868 }
00869 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00870 c_vector<double, 2> AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::CalculateMinMaxEdgeLengths()
00871 {
00872     c_vector<double, 2> min_max;
00873     min_max[0] = DBL_MAX;
00874     min_max[1] = 0.0;
00875     for (typename AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::ElementIterator ele_iter = GetElementIteratorBegin();
00876             ele_iter != GetElementIteratorEnd();
00877             ++ele_iter)
00878     {
00879         c_vector<double, 2> ele_min_max = ele_iter->CalculateMinMaxEdgeLengths();
00880         if (ele_min_max[0] < min_max[0])
00881         {
00882             min_max[0] = ele_min_max[0];
00883         }
00884         if (ele_min_max[1] > min_max[1])
00885         {
00886             min_max[1] = ele_min_max[1];
00887         }
00888     }
00889     return min_max;
00890 }
00891 
00892 
00893 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00894 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetContainingElementIndex(const ChastePoint<SPACE_DIM>& rTestPoint,
00895                                                                             bool strict,
00896                                                                             std::set<unsigned> testElements,
00897                                                                             bool onlyTryWithTestElements)
00898 {
00899     for (std::set<unsigned>::iterator iter=testElements.begin(); iter!=testElements.end(); iter++)
00900     {
00901         assert(*iter<this->GetNumElements());
00902         if (this->mElements[*iter]->IncludesPoint(rTestPoint, strict))
00903         {
00904             assert(!this->mElements[*iter]->IsDeleted());
00905             return *iter;
00906         }
00907     }
00908 
00909     if (!onlyTryWithTestElements)
00910     {
00911         for (unsigned i=0; i<this->mElements.size(); i++)
00912         {
00913             if (this->mElements[i]->IncludesPoint(rTestPoint, strict))
00914             {
00915                 assert(!this->mElements[i]->IsDeleted());
00916                 return i;
00917             }
00918         }
00919     }
00920 
00921     // If it's in none of the elements, then throw
00922     std::stringstream ss;
00923     ss << "Point [";
00924     for (unsigned j=0; (int)j<(int)SPACE_DIM-1; j++)
00925     {
00926         ss << rTestPoint[j] << ",";
00927     }
00928     ss << rTestPoint[SPACE_DIM-1] << "] is not in ";
00929     if (!onlyTryWithTestElements)
00930     {
00931         ss << "mesh - all elements tested";
00932     }
00933     else
00934     {
00935         ss << "set of elements given";
00936     }
00937     EXCEPTION(ss.str());
00938 }
00939 
00940 
00941 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00942 unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNearestElementIndexFromTestElements(const ChastePoint<SPACE_DIM>& rTestPoint,
00943                                                                                          std::set<unsigned> testElements)
00944 {
00945     assert(testElements.size() > 0);
00946 
00947     double max_min_weight = -std::numeric_limits<double>::infinity();
00948     unsigned closest_index = 0;
00949     for (std::set<unsigned>::iterator iter = testElements.begin();
00950         iter != testElements.end();
00951         iter++)
00952     {
00953         c_vector<double, ELEMENT_DIM+1> weight=this->mElements[*iter]->CalculateInterpolationWeights(rTestPoint);
00954         double neg_weight_sum=0.0;
00955         for (unsigned j=0; j<=ELEMENT_DIM; j++)
00956         {
00957             if (weight[j] < 0.0)
00958             {
00959                 neg_weight_sum += weight[j];
00960             }
00961         }
00962         if (neg_weight_sum > max_min_weight)
00963         {
00964             max_min_weight = neg_weight_sum;
00965             closest_index = *iter;
00966         }
00967     }
00968     assert(!this->mElements[closest_index]->IsDeleted());
00969     return closest_index;
00970 }
00971 
00973 // Explicit instantiation
00975 
00976 template class AbstractTetrahedralMesh<1,1>;
00977 template class AbstractTetrahedralMesh<1,2>;
00978 template class AbstractTetrahedralMesh<1,3>;
00979 template class AbstractTetrahedralMesh<2,2>;
00980 template class AbstractTetrahedralMesh<2,3>;
00981 template class AbstractTetrahedralMesh<3,3>;

Generated by  doxygen 1.6.2