AbstractTetrahedralMesh.cpp

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