Chaste Release::3.1
|
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>;