00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "QuadraticMesh.hpp"
00030
00031 template<unsigned DIM>
00032 QuadraticMesh<DIM>::QuadraticMesh(const std::string& fileName)
00033 {
00034 LoadFromFile(fileName);
00035 }
00036
00037 template<unsigned DIM>
00038 QuadraticMesh<DIM>::QuadraticMesh(double xEnd, double yEnd, unsigned numElemX, unsigned numElemY)
00039 {
00040 assert(DIM==2);
00041
00042 assert(xEnd>0);
00043 assert(yEnd>0);
00044 assert(numElemX>0);
00045 assert(numElemY>0);
00046
00047 std::string tempfile_name_stem = "temp_quadmesh";
00048
00050
00052 OutputFileHandler handler("");
00053 out_stream p_file = handler.OpenOutputFile(tempfile_name_stem+".node");
00054
00055 *p_file << (numElemX+1)*(numElemY+1) << " 2 0 1\n";
00056 unsigned node_index = 0;
00057 for(unsigned j=0; j<=numElemY; j++)
00058 {
00059 for(unsigned i=0; i<=numElemX; i++)
00060 {
00061 double x = xEnd*i/numElemX;
00062 double y = yEnd*j/numElemY;
00063
00064 bool on_boundary = ( (i==0) || (i==numElemX) || (j==0) || (j==numElemX) );
00065 *p_file << node_index++ << " " << x << " " << y << " " << (on_boundary?1:0) << "\n";
00066 }
00067 }
00068 p_file->close();
00069
00071
00073
00074 RunMesherAndReadMesh("triangle", handler.GetOutputDirectoryFullPath(), tempfile_name_stem);
00075 }
00076
00077
00078 template<unsigned DIM>
00079 QuadraticMesh<DIM>::QuadraticMesh(double xEnd, double yEnd, double zEnd,
00080 unsigned numElemX, unsigned numElemY, unsigned numElemZ)
00081 {
00082 assert(DIM==3);
00083
00084 assert(xEnd>0);
00085 assert(yEnd>0);
00086 assert(zEnd>0);
00087 assert(numElemX>0);
00088 assert(numElemY>0);
00089 assert(numElemZ>0);
00090
00091 std::string tempfile_name_stem = "temp_quadmesh3d";
00092
00094
00096 OutputFileHandler handler("");
00097 out_stream p_file = handler.OpenOutputFile(tempfile_name_stem+".node");
00098
00099 *p_file << (numElemX+1)*(numElemY+1)*(numElemZ+1) << " 3 0 0\n";
00100 unsigned node_index = 0;
00101 for(unsigned k=0; k<=numElemZ; k++)
00102 {
00103 for(unsigned j=0; j<=numElemY; j++)
00104 {
00105 for(unsigned i=0; i<=numElemX; i++)
00106 {
00107 double x = xEnd*i/numElemX;
00108 double y = yEnd*j/numElemY;
00109 double z = zEnd*k/numElemZ;
00110
00111
00112 *p_file << node_index++ << " " << x << " " << y << " " << z << "\n";
00113 }
00114 }
00115 }
00116 p_file->close();
00117
00119
00121
00122
00123 RunMesherAndReadMesh("tetgen", handler.GetOutputDirectoryFullPath(), tempfile_name_stem);
00124 }
00125
00126
00127
00128 template<unsigned DIM>
00129 void QuadraticMesh<DIM>::RunMesherAndReadMesh(std::string binary,
00130 std::string outputDir,
00131 std::string fileStem)
00132 {
00133
00134 std::string args = "-Qeo2";
00135
00136
00137 if (DIM == 3)
00138 {
00139 args = "-Qo2";
00140 }
00141
00142 std::string command = binary + " " + args + " " + outputDir
00143 + "/" + fileStem + ".node";
00144
00145 if (DIM == 3)
00146 {
00147
00148 command += " > /dev/null";
00149 }
00150
00151 int return_value = system(command.c_str());
00152
00153 if(return_value != 0)
00154 {
00155 #define COVERAGE_IGNORE
00156 EXCEPTION("Remeshing (by calling " + binary + ") failed. Do you have it in your path?\n"+
00157 "The quadratic mesh relies on functionality from triangle (http://www.cs.cmu.edu/~quake/triangle.html) and tetgen (http://tetgen.berlios.de/).");
00158 #undef COVERAGE_IGNORE
00159 }
00160
00161
00162 command = "mv " + outputDir + "/"
00163 + fileStem + ".1.* .";
00164
00165
00166
00167
00168 return_value = system(command.c_str());
00169
00170
00171 LoadFromFile( fileStem + ".1");
00172
00173
00174 command = "rm -f " + outputDir + "/" + fileStem + ".node";
00175 EXPECT0(system, command);
00176 EXPECT0(system, "rm -f " + fileStem + ".1.node");
00177 EXPECT0(system, "rm -f " + fileStem + ".1.ele");
00178
00179 if (DIM==2)
00180 {
00181 EXPECT0(system, "rm -f " + fileStem + ".1.edge");
00182 }
00183 if (DIM==3)
00184 {
00185 EXPECT0(system, "rm -f " + fileStem + ".1.face");
00186 }
00187 }
00188
00189
00190 template<unsigned DIM>
00191 void QuadraticMesh<DIM>::LoadFromFile(const std::string& fileName)
00192 {
00193 TrianglesMeshReader<DIM,DIM> mesh_reader(fileName, 2);
00194
00195 ConstructFromMeshReader(mesh_reader);
00196
00197
00198
00199 mIsInternalNode.resize(this->GetNumNodes(), true);
00200 for(unsigned elem_index=0; elem_index<this->GetNumElements(); elem_index++)
00201 {
00202 for(unsigned i=0; i<DIM+1 ; i++)
00203 {
00204 unsigned node_index = this->GetElement(elem_index)->GetNodeGlobalIndex(i);
00205 mIsInternalNode[ node_index ] = false;
00206 }
00207 }
00208
00209
00210
00211 mNumVertices = 0;
00212 bool vertices_mode = true;
00213 for(unsigned i=0; i<this->GetNumNodes(); i++)
00214 {
00215 if(mIsInternalNode[i]==false)
00216 {
00217 mNumVertices++;
00218 }
00219 if((vertices_mode == false) && (mIsInternalNode[i]==false ) )
00220 {
00221 EXCEPTION("The quadratic mesh doesn't appear to have all vertices before the rest of the nodes");
00222 }
00223 if( (vertices_mode == true) && (mIsInternalNode[i]==true) )
00224 {
00225 vertices_mode = false;
00226 }
00227 }
00228
00229
00230 mesh_reader.Reset();
00231
00232
00233
00234 for(unsigned i=0; i<this->GetNumElements(); i++)
00235 {
00236 std::vector<unsigned> nodes = mesh_reader.GetNextElementData().NodeIndices;
00237 assert(nodes.size()==(DIM+1)*(DIM+2)/2);
00238 for(unsigned j=DIM+1; j<(DIM+1)*(DIM+2)/2; j++)
00239 {
00240 this->GetElement(i)->AddNode( this->GetNode(nodes[j]) );
00241 this->GetNode(nodes[j])->AddElement(this->GetElement(i)->GetIndex());
00242 }
00243 }
00244
00245
00246
00247 if(DIM>1)
00248 {
00249 for(typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00250 = this->GetBoundaryElementIteratorBegin();
00251 iter != this->GetBoundaryElementIteratorEnd();
00252 ++iter)
00253 {
00254
00255 std::set<unsigned> boundary_element_node_indices;
00256 for(unsigned i=0; i<DIM; i++)
00257 {
00258 boundary_element_node_indices.insert( (*iter)->GetNodeGlobalIndex(i) );
00259 }
00260
00261 bool found_this_boundary_element = false;
00262
00263
00264 for(unsigned i=0; i<this->GetNumElements(); i++)
00265 {
00266 Element<DIM,DIM>* p_element = this->GetElement(i);
00267
00268
00269 for(unsigned face=0; face<DIM+1; face++)
00270 {
00271
00272 std::set<unsigned> node_indices;
00273 for(unsigned local_node_index=0; local_node_index<DIM+1; local_node_index++)
00274 {
00275 if(local_node_index!=face)
00276 {
00277 node_indices.insert( p_element->GetNodeGlobalIndex(local_node_index) );
00278 }
00279 }
00280
00281 assert(node_indices.size()==DIM);
00282
00283
00284
00285 if(node_indices==boundary_element_node_indices)
00286 {
00287 AddExtraBoundaryNodes(*iter, p_element, face);
00288
00289 found_this_boundary_element = true;
00290 break;
00291 }
00292 }
00293
00294 if(found_this_boundary_element)
00295 {
00296 break;
00297 }
00298 }
00299
00300 if(!found_this_boundary_element)
00301 {
00302 #define COVERAGE_IGNORE
00303 EXCEPTION("Unable to find a face of an element which matches one of the boundary elements");
00304 #undef COVERAGE_IGNORE
00305 }
00306 }
00307 }
00308 }
00309
00310
00311 template<unsigned DIM>
00312 void QuadraticMesh<DIM>::AddNodeToBoundaryElement(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00313 Element<DIM,DIM>* pElement,
00314 unsigned internalNode)
00315 {
00316 assert(DIM>1);
00317 assert(internalNode >= DIM+1);
00318 assert(internalNode < (DIM+1)*(DIM+2)/2);
00319 Node<DIM>* p_internal_node = pElement->GetNode(internalNode);
00320
00321
00322 if(!p_internal_node->IsBoundaryNode())
00323 {
00324 p_internal_node->SetAsBoundaryNode();
00325 this->mBoundaryNodes.push_back(p_internal_node);
00326 }
00327
00328 pBoundaryElement->AddNode( p_internal_node );
00329 }
00330
00331
00332 template<unsigned DIM>
00333 void QuadraticMesh<DIM>::AddExtraBoundaryNodes(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00334 Element<DIM,DIM>* pElement,
00335 unsigned nodeIndexOppositeToFace)
00336 {
00337 assert(DIM!=1);
00338 if(DIM==2)
00339 {
00340 assert(nodeIndexOppositeToFace<3);
00341
00342 AddNodeToBoundaryElement(pBoundaryElement, pElement, nodeIndexOppositeToFace+3);
00343 }
00344 else
00345 {
00346 assert(DIM==3);
00347
00348 unsigned b_elem_n0 = pBoundaryElement->GetNodeGlobalIndex(0);
00349 unsigned b_elem_n1 = pBoundaryElement->GetNodeGlobalIndex(1);
00350
00351 unsigned offset;
00352 bool reverse;
00353
00354 if(nodeIndexOppositeToFace==0)
00355 {
00356
00357 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 1, 2, 3, offset, reverse);
00358 HelperMethod2(pBoundaryElement, pElement, 9, 8, 5, offset, reverse);
00359 }
00360 else if(nodeIndexOppositeToFace==1)
00361 {
00362
00363 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 2, 0, 3, offset, reverse);
00364 HelperMethod2(pBoundaryElement, pElement, 7, 9, 6, offset, reverse);
00365 }
00366 else if(nodeIndexOppositeToFace==2)
00367 {
00368
00369 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 3, offset, reverse);
00370 HelperMethod2(pBoundaryElement, pElement, 8, 7, 4, offset, reverse);
00371 }
00372 else
00373 {
00374 assert(nodeIndexOppositeToFace==3);
00375
00376 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 2, offset, reverse);
00377 HelperMethod2(pBoundaryElement, pElement, 5, 6, 4, offset, reverse);
00378 }
00379 }
00380 }
00381
00382
00384
00386
00396 #define COVERAGE_IGNORE
00397 template<unsigned DIM>
00398 void QuadraticMesh<DIM>::HelperMethod1(unsigned boundaryElemNode0, unsigned boundaryElemNode1,
00399 Element<DIM,DIM>* pElement,
00400 unsigned node0, unsigned node1, unsigned node2,
00401 unsigned& rOffset,
00402 bool& rReverse)
00403 {
00404 if(pElement->GetNodeGlobalIndex(node0)==boundaryElemNode0)
00405 {
00406 rOffset = 0;
00407 if(pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1)
00408 {
00409 rReverse = false;
00410 }
00411 else
00412 {
00413 assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1);
00414 rReverse = true;
00415 }
00416 }
00417 else if(pElement->GetNodeGlobalIndex(node1)==boundaryElemNode0)
00418 {
00419 rOffset = 1;
00420 if(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1)
00421 {
00422 rReverse = false;
00423 }
00424 else
00425 {
00426 assert(pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1);
00427 rReverse = true;
00428 }
00429 }
00430 else
00431 {
00432 assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode0);
00433 rOffset = 2;
00434 if(pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1)
00435 {
00436 rReverse = false;
00437 }
00438 else
00439 {
00440 assert(pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1);
00441 rReverse = true;
00442 }
00443 }
00444 }
00445 #undef COVERAGE_IGNORE
00446
00447
00448
00455 #define COVERAGE_IGNORE
00456 template<unsigned DIM>
00457 void QuadraticMesh<DIM>::HelperMethod2(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00458 Element<DIM,DIM>* pElement,
00459 unsigned internalNode0, unsigned internalNode1, unsigned internalNode2,
00460 unsigned offset,
00461 bool reverse)
00462 {
00463 if(offset==1)
00464 {
00465 unsigned temp = internalNode0;
00466 internalNode0 = internalNode1;
00467 internalNode1 = internalNode2;
00468 internalNode2 = temp;
00469 }
00470 else if(offset == 2)
00471 {
00472 unsigned temp = internalNode0;
00473 internalNode0 = internalNode2;
00474 internalNode2 = internalNode1;
00475 internalNode1 = temp;
00476 }
00477
00478 if(reverse)
00479 {
00480 unsigned temp = internalNode1;
00481 internalNode1 = internalNode2;
00482 internalNode2 = temp;
00483 }
00484
00485 AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode0);
00486 AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode1);
00487 AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode2);
00488 }
00489 #undef COVERAGE_IGNORE
00490
00491 template class QuadraticMesh<1>;
00492 template class QuadraticMesh<2>;
00493 template class QuadraticMesh<3>;