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