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

Generated on Mon Apr 18 11:35:35 2011 for Chaste by  doxygen 1.5.5