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 #include "OutputFileHandler.hpp"
00031 #include "TrianglesMeshReader.hpp"
00032
00033
00034 #define REAL double
00035 #define VOID void
00036 #include "triangle.h"
00037 #undef REAL
00038 #undef VOID
00039
00040
00041 template<unsigned DIM>
00042 QuadraticMesh<DIM>::QuadraticMesh(double xEnd, double yEnd, unsigned numElemX, unsigned numElemY)
00043 {
00044 assert(DIM==2);
00045
00046 assert(xEnd>0);
00047 assert(yEnd>0);
00048 assert(numElemX>0);
00049 assert(numElemY>0);
00050
00051 this->mMeshIsLinear=false;
00052 unsigned num_nodes=(numElemX+1)*(numElemY+1);
00053 struct triangulateio triangle_input;
00054 triangle_input.pointlist = (double *) malloc( num_nodes * 2 * sizeof(double));
00055 triangle_input.numberofpoints = num_nodes;
00056 triangle_input.numberofpointattributes = 0;
00057 triangle_input.pointmarkerlist = NULL;
00058 triangle_input.numberofsegments = 0;
00059 triangle_input.numberofholes = 0;
00060 triangle_input.numberofregions = 0;
00061
00062 unsigned new_index = 0;
00063 for (unsigned j=0; j<=numElemY; j++)
00064 {
00065 double y = yEnd*j/numElemY;
00066 for (unsigned i=0; i<=numElemX; i++)
00067 {
00068 double x = xEnd*i/numElemX;
00069
00070 triangle_input.pointlist[2*new_index] = x;
00071 triangle_input.pointlist[2*new_index + 1] = y;
00072 new_index++;
00073 }
00074 }
00075
00076
00077 struct triangulateio triangle_output;
00078 triangle_output.pointlist = NULL;
00079 triangle_output.pointattributelist = (double *) NULL;
00080 triangle_output.pointmarkerlist = (int *) NULL;
00081 triangle_output.trianglelist = (int *) NULL;
00082 triangle_output.triangleattributelist = (double *) NULL;
00083 triangle_output.edgelist = (int *) NULL;
00084 triangle_output.edgemarkerlist = (int *) NULL;
00085
00086
00087 triangulate((char*)"Qzeo2", &triangle_input, &triangle_output, NULL);
00088
00089 assert(triangle_output.numberofcorners == 6);
00090
00091
00092 for (unsigned node_index=0; node_index<(unsigned)triangle_output.numberofpoints; node_index++)
00093 {
00094 if (triangle_output.pointmarkerlist[node_index] == 1)
00095 {
00096
00097 Node<DIM>* p_node = new Node<DIM>(node_index, true,
00098 triangle_output.pointlist[node_index * 2],
00099 triangle_output.pointlist[node_index * 2+1]);
00100 this->mNodes.push_back(p_node);
00101 this->mBoundaryNodes.push_back(p_node);
00102 }
00103 else
00104 {
00105 this->mNodes.push_back(new Node<DIM>(node_index, false,
00106 triangle_output.pointlist[node_index * 2],
00107 triangle_output.pointlist[node_index * 2+1]));
00108 }
00109 }
00110
00111 mIsInternalNode.resize(this->GetNumNodes(), true);
00112
00113
00114 this->mElements.reserve(triangle_output.numberoftriangles);
00115 for (unsigned element_index=0; element_index<(unsigned)triangle_output.numberoftriangles; element_index++)
00116 {
00117 std::vector<Node<DIM>*> nodes;
00118
00119 for (unsigned j=0; j<3; j++)
00120 {
00121 unsigned global_node_index = triangle_output.trianglelist[element_index*6 + j];
00122 assert(global_node_index < this->mNodes.size());
00123 nodes.push_back(this->mNodes[global_node_index]);
00124 mIsInternalNode[global_node_index]=false;
00125 }
00126
00127 this->mElements.push_back(new Element<DIM, DIM>(element_index, nodes));
00128
00129 for (unsigned j=3; j<6; j++)
00130 {
00131 unsigned global_node_index = triangle_output.trianglelist[element_index*6 + j];
00132 assert(global_node_index < this->mNodes.size());
00133 this->mElements[element_index]->AddNode( this->mNodes[global_node_index] );
00134 this->mNodes[j]->AddElement(element_index);
00135 }
00136 }
00137 bool vertices_mode = true;
00138 mNumVertices = 0u;
00139 for (unsigned i=0; i<this->GetNumNodes(); i++)
00140 {
00141 if (mIsInternalNode[i]==false)
00142 {
00143 mNumVertices++;
00144 assert(vertices_mode);
00145 }
00146 if ( (vertices_mode == true) && (mIsInternalNode[i]==true) )
00147 {
00148 vertices_mode = false;
00149 }
00150 }
00151 unsigned next_boundary_element_index = 0;
00152 for (unsigned boundary_element_index=0; boundary_element_index<(unsigned)triangle_output.numberofedges; boundary_element_index++)
00153 {
00154 if (triangle_output.edgemarkerlist[boundary_element_index] == 1)
00155 {
00156 std::vector<Node<DIM>*> nodes;
00157 for (unsigned j=0; j<2; j++)
00158 {
00159 unsigned global_node_index=triangle_output.edgelist[boundary_element_index*2 + j];
00160 assert(global_node_index < this->mNodes.size());
00161 nodes.push_back(this->mNodes[global_node_index]);
00162 }
00163 this->mBoundaryElements.push_back(new BoundaryElement<DIM-1, DIM>(next_boundary_element_index++, nodes));
00164 }
00165 }
00166
00167 this->RefreshJacobianCachedData();
00168
00169 AddNodesToBoundaryElements(NULL);
00170
00171 free(triangle_input.pointlist);
00172
00173 free(triangle_output.pointlist);
00174 free(triangle_output.pointattributelist);
00175 free(triangle_output.pointmarkerlist);
00176 free(triangle_output.trianglelist);
00177 free(triangle_output.triangleattributelist);
00178 free(triangle_output.edgelist);
00179 free(triangle_output.edgemarkerlist);
00180 }
00181
00182
00183 template<unsigned DIM>
00184 QuadraticMesh<DIM>::QuadraticMesh(double xEnd, double yEnd, double zEnd,
00185 unsigned numElemX, unsigned numElemY, unsigned numElemZ)
00186 {
00187 assert(DIM==3);
00188
00189 assert(xEnd>0);
00190 assert(yEnd>0);
00191 assert(zEnd>0);
00192 assert(numElemX>0);
00193 assert(numElemY>0);
00194 assert(numElemZ>0);
00195
00196 this->mMeshIsLinear=false;
00197 std::string tempfile_name_stem = "temp_quadmesh3d";
00198
00200
00202 OutputFileHandler handler("");
00203 out_stream p_file = handler.OpenOutputFile(tempfile_name_stem+".node");
00204
00205 *p_file << (numElemX+1)*(numElemY+1)*(numElemZ+1) << " 3 0 0\n";
00206 unsigned node_index = 0;
00207 for (unsigned k=0; k<=numElemZ; k++)
00208 {
00209 for (unsigned j=0; j<=numElemY; j++)
00210 {
00211 for (unsigned i=0; i<=numElemX; i++)
00212 {
00213 double x = xEnd*i/numElemX;
00214 double y = yEnd*j/numElemY;
00215 double z = zEnd*k/numElemZ;
00216
00217
00218 *p_file << node_index++ << " " << x << " " << y << " " << z << "\n";
00219 }
00220 }
00221 }
00222 p_file->close();
00223
00225
00227
00228
00229 RunMesherAndReadMesh("tetgen", handler.GetOutputDirectoryFullPath(), tempfile_name_stem);
00230 }
00231
00232
00233 template<unsigned DIM>
00234 unsigned QuadraticMesh<DIM>::GetNumVertices()
00235 {
00236 return mNumVertices;
00237 }
00238
00239
00240 template<unsigned DIM>
00241 void QuadraticMesh<DIM>::RunMesherAndReadMesh(std::string binary,
00242 std::string outputDir,
00243 std::string fileStem)
00244 {
00245 assert(DIM == 3);
00246
00247 if(PetscTools::AmMaster())
00248 {
00249 std::string args = "-Qo2";
00250
00251 std::string command = binary + " " + args + " " + outputDir
00252 + "/" + fileStem + ".node" + " > /dev/null";
00253
00254 int return_value = system(command.c_str());
00255
00256 if (return_value != 0)
00257 {
00258 #define COVERAGE_IGNORE
00259 EXCEPTION("Remeshing (by calling " + binary + ") failed. Do you have it in your path?\n"+
00260 "The quadratic mesh relies on functionality from tetgen (http://tetgen.berlios.de/).");
00261 #undef COVERAGE_IGNORE
00262 }
00263
00264
00265 command = "mv " + outputDir + "/"
00266 + fileStem + ".1.* .";
00267
00268
00269
00270
00271 return_value = system(command.c_str());
00272 }
00273 PetscTools::Barrier();
00274
00275
00276 TrianglesMeshReader<DIM,DIM> mesh_reader(fileStem + ".1", 2, 1, false);
00277 ConstructFromMeshReader(mesh_reader);
00279
00280
00281
00282 if(PetscTools::AmMaster())
00283 {
00284
00285 std::string command = "rm -f " + outputDir + "/" + fileStem + ".node";
00286 EXPECT0(system, command);
00287 EXPECT0(system, "rm -f " + fileStem + ".1.node");
00288 EXPECT0(system, "rm -f " + fileStem + ".1.ele");
00289 EXPECT0(system, "rm -f " + fileStem + ".1.face");
00290 }
00291 }
00292
00293
00294 template<unsigned DIM>
00295 void QuadraticMesh<DIM>::ConstructFromMeshReader(AbstractMeshReader<DIM, DIM>& rAbsMeshReader)
00296 {
00297 TrianglesMeshReader<DIM, DIM>* p_mesh_reader=dynamic_cast<TrianglesMeshReader<DIM, DIM>*>(&rAbsMeshReader);
00298 assert(p_mesh_reader != NULL);
00299
00300
00301 if (p_mesh_reader->GetOrderOfElements() == 1)
00302 {
00303 EXCEPTION("Supplied mesh reader is reading a linear mesh into quadratic mesh");
00304 }
00305
00306 TetrahedralMesh<DIM,DIM>::ConstructFromMeshReader(*p_mesh_reader);
00307 assert(this->GetNumBoundaryElements()>0);
00308
00309
00310
00311 mIsInternalNode.resize(this->GetNumNodes(), true);
00312 for (unsigned elem_index=0; elem_index<this->GetNumElements(); elem_index++)
00313 {
00314 for (unsigned i=0; i<DIM+1 ; i++)
00315 {
00316 unsigned node_index = this->GetElement(elem_index)->GetNodeGlobalIndex(i);
00317 mIsInternalNode[ node_index ] = false;
00318 }
00319 }
00320
00321
00322 mNumVertices = 0;
00323 bool vertices_mode = true;
00324 for (unsigned i=0; i<this->GetNumNodes(); i++)
00325 {
00326 if (mIsInternalNode[i]==false)
00327 {
00328 mNumVertices++;
00329 }
00330 if ((vertices_mode == false) && (mIsInternalNode[i]==false ) )
00331 {
00332
00333 EXCEPTION("The quadratic mesh doesn't appear to have all vertices before the rest of the nodes");
00334 }
00335 if ( (vertices_mode == true) && (mIsInternalNode[i]==true) )
00336 {
00337 vertices_mode = false;
00338 }
00339 }
00340
00341 p_mesh_reader->Reset();
00342
00343
00344
00345
00346 for (unsigned i=0; i<this->GetNumElements(); i++)
00347 {
00348 std::vector<unsigned> nodes = p_mesh_reader->GetNextElementData().NodeIndices;
00349 assert(nodes.size()==(DIM+1)*(DIM+2)/2);
00350 assert(this->GetElement(i)->GetNumNodes()==DIM+1);
00351
00352 for (unsigned j=DIM+1; j<(DIM+1)*(DIM+2)/2; j++)
00353 {
00354 this->GetElement(i)->AddNode( this->GetNode(nodes[j]) );
00355 this->GetNode(nodes[j])->AddElement(this->GetElement(i)->GetIndex());
00356 }
00357 }
00358 if (DIM > 1)
00359 {
00360
00361 if (p_mesh_reader->GetOrderOfBoundaryElements() == 2u)
00362 {
00363 p_mesh_reader->Reset();
00364 for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00365 = this->GetBoundaryElementIteratorBegin();
00366 iter != this->GetBoundaryElementIteratorEnd();
00367 ++iter)
00368 {
00369 std::vector<unsigned> nodes = p_mesh_reader->GetNextFaceData().NodeIndices;
00370
00371 assert((*iter)->GetNumNodes()==DIM);
00372 assert(nodes.size()==DIM*(DIM+1)/2);
00373
00374 for (unsigned j=DIM; j<DIM*(DIM+1)/2; j++)
00375 {
00376 (*iter)->AddNode( this->GetNode(nodes[j]) );
00377 }
00378 }
00379 }
00380 else
00381 {
00382 AddNodesToBoundaryElements(p_mesh_reader);
00383 }
00384 }
00385
00386
00387 #ifndef NDEBUG
00388 unsigned expected_num_nodes = DIM*(DIM+1)/2;
00389 for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00390 = this->GetBoundaryElementIteratorBegin();
00391 iter != this->GetBoundaryElementIteratorEnd();
00392 ++iter)
00393 {
00394 assert((*iter)->GetNumNodes()==expected_num_nodes);
00395 }
00396 #endif
00397 }
00398
00399 template<unsigned DIM>
00400 void QuadraticMesh<DIM>::AddNodesToBoundaryElements(TrianglesMeshReader<DIM,DIM>* pMeshReader)
00401 {
00402
00403
00404 bool boundary_element_file_has_containing_element_info=false;
00405
00406 if (pMeshReader)
00407 {
00408 boundary_element_file_has_containing_element_info=pMeshReader->GetReadContainingElementOfBoundaryElement();
00409 }
00410
00411 if (DIM>1)
00412 {
00413 if(boundary_element_file_has_containing_element_info)
00414 {
00415 pMeshReader->Reset();
00416 }
00417
00418
00419 for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00420 = this->GetBoundaryElementIteratorBegin();
00421 iter != this->GetBoundaryElementIteratorEnd();
00422 ++iter)
00423 {
00424
00425
00426
00427 std::set<unsigned> boundary_element_node_indices;
00428 for (unsigned i=0; i<DIM; i++)
00429 {
00430 boundary_element_node_indices.insert( (*iter)->GetNodeGlobalIndex(i) );
00431 }
00432
00433 bool found_this_boundary_element = false;
00434
00435
00436
00437
00438
00439 for (unsigned elem_index=0; elem_index<this->GetNumElements(); elem_index++)
00440 {
00441
00442 if(boundary_element_file_has_containing_element_info)
00443 {
00444 elem_index = pMeshReader->GetNextFaceData().ContainingElement;
00445 }
00446
00447 Element<DIM,DIM>* p_element = this->GetElement(elem_index);
00448
00449
00450 for (unsigned face=0; face<DIM+1; face++)
00451 {
00452
00453 std::set<unsigned> node_indices;
00454 for (unsigned local_node_index=0; local_node_index<DIM+1; local_node_index++)
00455 {
00456 if (local_node_index!=face)
00457 {
00458 node_indices.insert( p_element->GetNodeGlobalIndex(local_node_index) );
00459 }
00460 }
00461
00462 assert(node_indices.size()==DIM);
00463
00464
00465
00466 if (node_indices==boundary_element_node_indices)
00467 {
00468 AddExtraBoundaryNodes(*iter, p_element, face);
00469
00470 found_this_boundary_element = true;
00471 break;
00472 }
00473 }
00474
00475
00476
00477 if(boundary_element_file_has_containing_element_info && !found_this_boundary_element)
00478 {
00479 #define COVERAGE_IGNORE
00480 std::cout << (*iter)->GetIndex() << " " << pMeshReader->GetNextFaceData().ContainingElement << "\n";
00481 std::stringstream ss;
00482 ss << "Boundary element " << (*iter)->GetIndex()
00483 << "wasn't found in the containing element given for it "
00484 << elem_index;
00485
00486 EXCEPTION(ss.str());
00487 #undef COVERAGE_IGNORE
00488 }
00489
00490 if (found_this_boundary_element)
00491 {
00492 break;
00493 }
00494 }
00495
00496 if (!found_this_boundary_element)
00497 {
00498 #define COVERAGE_IGNORE
00499 EXCEPTION("Unable to find a face of an element which matches one of the boundary elements");
00500 #undef COVERAGE_IGNORE
00501 }
00502 }
00503 }
00504 }
00505
00506
00507 template<unsigned DIM>
00508 void QuadraticMesh<DIM>::AddNodeToBoundaryElement(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00509 Element<DIM,DIM>* pElement,
00510 unsigned internalNode)
00511 {
00512 assert(DIM>1);
00513 assert(internalNode >= DIM+1);
00514 assert(internalNode < (DIM+1)*(DIM+2)/2);
00515 Node<DIM>* p_internal_node = pElement->GetNode(internalNode);
00516
00517
00518 if (!p_internal_node->IsBoundaryNode())
00519 {
00520 p_internal_node->SetAsBoundaryNode();
00521 this->mBoundaryNodes.push_back(p_internal_node);
00522 }
00523
00524 pBoundaryElement->AddNode( p_internal_node );
00525 }
00526
00527
00528 template<unsigned DIM>
00529 void QuadraticMesh<DIM>::AddExtraBoundaryNodes(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00530 Element<DIM,DIM>* pElement,
00531 unsigned nodeIndexOppositeToFace)
00532 {
00533 assert(DIM!=1);
00534 if (DIM==2)
00535 {
00536 assert(nodeIndexOppositeToFace<3);
00537
00538 AddNodeToBoundaryElement(pBoundaryElement, pElement, nodeIndexOppositeToFace+3);
00539 }
00540 else
00541 {
00542 assert(DIM==3);
00543
00544 unsigned b_elem_n0 = pBoundaryElement->GetNodeGlobalIndex(0);
00545 unsigned b_elem_n1 = pBoundaryElement->GetNodeGlobalIndex(1);
00546
00547 unsigned offset;
00548 bool reverse;
00549
00550 if (nodeIndexOppositeToFace==0)
00551 {
00552
00553 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 1, 2, 3, offset, reverse);
00554 HelperMethod2(pBoundaryElement, pElement, 9, 8, 5, offset, reverse);
00555 }
00556 else if (nodeIndexOppositeToFace==1)
00557 {
00558
00559 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 2, 0, 3, offset, reverse);
00560 HelperMethod2(pBoundaryElement, pElement, 7, 9, 6, offset, reverse);
00561 }
00562 else if (nodeIndexOppositeToFace==2)
00563 {
00564
00565 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 3, offset, reverse);
00566 HelperMethod2(pBoundaryElement, pElement, 8, 7, 4, offset, reverse);
00567 }
00568 else
00569 {
00570 assert(nodeIndexOppositeToFace==3);
00571
00572 HelperMethod1(b_elem_n0, b_elem_n1, pElement, 0, 1, 2, offset, reverse);
00573 HelperMethod2(pBoundaryElement, pElement, 5, 6, 4, offset, reverse);
00574 }
00575 }
00576 }
00577
00578 template<unsigned DIM>
00579 void QuadraticMesh<DIM>::WriteBoundaryElementFile(std::string directory, std::string fileName)
00580 {
00581 OutputFileHandler handler(directory, false);
00582 out_stream p_file = handler.OpenOutputFile(fileName);
00583
00584 unsigned expected_num_nodes;
00585 assert(DIM > 1);
00586 if (DIM == 2)
00587 {
00588 expected_num_nodes = 3;
00589 }
00590 else if (DIM == 3)
00591 {
00592 expected_num_nodes = 6;
00593 }
00594
00595 unsigned num_elements = 0;
00596
00597 for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00598 = this->GetBoundaryElementIteratorBegin();
00599 iter != this->GetBoundaryElementIteratorEnd();
00600 ++iter)
00601 {
00602 assert((*iter)->GetNumNodes()==expected_num_nodes);
00603 num_elements++;
00604 }
00605
00606 *p_file << num_elements << " 0\n";
00607
00608 unsigned counter = 0;
00609 for (typename TetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00610 = this->GetBoundaryElementIteratorBegin();
00611 iter != this->GetBoundaryElementIteratorEnd();
00612 ++iter)
00613 {
00614 *p_file << counter++ << " ";
00615 for (unsigned i=0; i<(*iter)->GetNumNodes(); i++)
00616 {
00617 *p_file << (*iter)->GetNodeGlobalIndex(i) << " ";
00618 }
00619 *p_file << "\n";
00620 }
00621
00622 p_file->close();
00623 }
00624
00626
00628
00629 #define COVERAGE_IGNORE
00630 template<unsigned DIM>
00631 void QuadraticMesh<DIM>::HelperMethod1(unsigned boundaryElemNode0, unsigned boundaryElemNode1,
00632 Element<DIM,DIM>* pElement,
00633 unsigned node0, unsigned node1, unsigned node2,
00634 unsigned& rOffset,
00635 bool& rReverse)
00636 {
00637 if (pElement->GetNodeGlobalIndex(node0)==boundaryElemNode0)
00638 {
00639 rOffset = 0;
00640 if (pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1)
00641 {
00642 rReverse = false;
00643 }
00644 else
00645 {
00646 assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1);
00647 rReverse = true;
00648 }
00649 }
00650 else if (pElement->GetNodeGlobalIndex(node1)==boundaryElemNode0)
00651 {
00652 rOffset = 1;
00653 if (pElement->GetNodeGlobalIndex(node2)==boundaryElemNode1)
00654 {
00655 rReverse = false;
00656 }
00657 else
00658 {
00659 assert(pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1);
00660 rReverse = true;
00661 }
00662 }
00663 else
00664 {
00665 assert(pElement->GetNodeGlobalIndex(node2)==boundaryElemNode0);
00666 rOffset = 2;
00667 if (pElement->GetNodeGlobalIndex(node0)==boundaryElemNode1)
00668 {
00669 rReverse = false;
00670 }
00671 else
00672 {
00673 assert(pElement->GetNodeGlobalIndex(node1)==boundaryElemNode1);
00674 rReverse = true;
00675 }
00676 }
00677 }
00678 #undef COVERAGE_IGNORE
00679
00680
00681 #define COVERAGE_IGNORE
00682 template<unsigned DIM>
00683 void QuadraticMesh<DIM>::HelperMethod2(BoundaryElement<DIM-1,DIM>* pBoundaryElement,
00684 Element<DIM,DIM>* pElement,
00685 unsigned internalNode0, unsigned internalNode1, unsigned internalNode2,
00686 unsigned offset,
00687 bool reverse)
00688 {
00689 if (offset==1)
00690 {
00691 unsigned temp = internalNode0;
00692 internalNode0 = internalNode1;
00693 internalNode1 = internalNode2;
00694 internalNode2 = temp;
00695 }
00696 else if (offset == 2)
00697 {
00698 unsigned temp = internalNode0;
00699 internalNode0 = internalNode2;
00700 internalNode2 = internalNode1;
00701 internalNode1 = temp;
00702 }
00703
00704 if (reverse)
00705 {
00706 unsigned temp = internalNode1;
00707 internalNode1 = internalNode2;
00708 internalNode2 = temp;
00709 }
00710
00711 AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode0);
00712 AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode1);
00713 AddNodeToBoundaryElement(pBoundaryElement, pElement, internalNode2);
00714 }
00715 #undef COVERAGE_IGNORE
00716
00717
00719
00721
00722
00723 template class QuadraticMesh<1>;
00724 template class QuadraticMesh<2>;
00725 template class QuadraticMesh<3>;
00726
00727
00728
00729 #include "SerializationExportWrapperForCpp.hpp"
00730 EXPORT_TEMPLATE_CLASS_SAME_DIMS(QuadraticMesh);