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
00030
00031
00032
00033
00034
00035
00036 #include "QuadraticMesh.hpp"
00037 #include "OutputFileHandler.hpp"
00038 #include "TrianglesMeshReader.hpp"
00039 #include "Warnings.hpp"
00040 #include "QuadraticMeshHelper.hpp"
00041
00042
00043 #define REAL double
00044 #define VOID void
00045 #include "triangle.h"
00046 #include "tetgen.h"
00047 #undef REAL
00048 #undef VOID
00049
00050 template<unsigned DIM>
00051 void QuadraticMesh<DIM>::CountVertices()
00052 {
00053 mNumVertices = 0;
00054 for (unsigned i=0; i<this->GetNumNodes(); i++)
00055 {
00056 bool is_internal = this->GetNode(i)->IsInternal();
00057 if (is_internal==false)
00058 {
00059 mNumVertices++;
00060 }
00061 }
00062 }
00063
00064 template<unsigned DIM>
00065 QuadraticMesh<DIM>::QuadraticMesh(double spaceStep, double width, double height, double depth)
00066 {
00067 this->ConstructRegularSlabMesh(spaceStep, width, height, depth);
00068 }
00069
00071
00072
00073
00075 template<unsigned DIM>
00076 void QuadraticMesh<DIM>::ConstructLinearMesh(unsigned numElemX)
00077 {
00078 assert(DIM==1);
00079
00080 AbstractTetrahedralMesh<DIM,DIM>::ConstructLinearMesh(numElemX);
00081 assert (this->mNodes.size() == numElemX+1);
00082 mNumVertices = numElemX+1;
00083 c_vector<double, DIM> top;
00084 top[0] = numElemX;
00085
00086 unsigned mid_node_index=mNumVertices;
00087 for (unsigned element_index=0; element_index<numElemX; element_index++)
00088 {
00089 c_vector<double, DIM> x_value_mid_node;
00090 x_value_mid_node[0] = element_index+0.5;
00091
00092 Node<DIM>* p_mid_node = MakeNewInternalNode(mid_node_index, x_value_mid_node, top);
00093
00094
00095 this->mElements[element_index]->AddNode(p_mid_node);
00096 p_mid_node->AddElement(element_index);
00097 }
00098
00099 this->RefreshMesh();
00100 }
00101
00102
00103
00104
00105
00106 template<unsigned DIM>
00107 void QuadraticMesh<DIM>::ConstructRectangularMesh(unsigned numElemX, unsigned numElemY, bool stagger)
00108 {
00109 assert(DIM==2);
00110 assert(numElemX > 0);
00111 assert(numElemY > 0);
00112
00113 AbstractTetrahedralMesh<DIM,DIM>::ConstructRectangularMesh(numElemX, numElemY, stagger);
00114
00115 this->mMeshIsLinear=false;
00116
00117
00118 std::map<std::pair<unsigned, unsigned>, unsigned> edge_to_internal_map;
00119
00120 unsigned node_index = this->GetNumNodes();
00121 c_vector<double, DIM> top;
00122 top[0]=numElemX;
00123 top[1]=numElemY;
00124 c_vector<double, DIM> node_pos;
00125
00126 for (unsigned j=0; j<numElemY+1; j++)
00127 {
00128 node_pos[1]=j;
00129
00130 for (unsigned i=0; i<numElemX; i++)
00131 {
00132 unsigned left_index = j*(numElemX+1) + i;
00133 std::pair<unsigned,unsigned> edge(left_index, left_index+1 ) ;
00134 edge_to_internal_map[edge] = node_index;
00135 node_pos[0]=i+0.5;
00136 MakeNewInternalNode(node_index, node_pos, top);
00137 }
00138
00139
00140 node_pos[1] = j+0.5;
00141 for (unsigned i=0; i<numElemX+1; i++)
00142 {
00143 node_pos[0] = i;
00144 unsigned left_index = j*(numElemX+1) + i;
00145 std::pair<unsigned,unsigned> edge(left_index, left_index+(numElemX+1) ) ;
00146 edge_to_internal_map[edge] = node_index;
00147 MakeNewInternalNode(node_index, node_pos, top);
00148 unsigned parity=(i+(numElemY-j))%2;
00149 if (stagger==false || parity==1)
00150 {
00151
00152 std::pair<unsigned,unsigned> back_edge(left_index+1, left_index+(numElemX+1) ) ;
00153 edge_to_internal_map[back_edge] = node_index;
00154 }
00155 else
00156 {
00157
00158 std::pair<unsigned,unsigned> forward_edge(left_index, left_index+(numElemX+1)+1 ) ;
00159 edge_to_internal_map[forward_edge] = node_index;
00160 }
00161 node_pos[0] = i+0.5;
00162 MakeNewInternalNode(node_index, node_pos, top);
00163 }
00164 }
00165 CountVertices();
00166
00167
00168 for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00169 iter != this->GetElementIteratorEnd();
00170 ++iter)
00171 {
00172 unsigned local_index1=0;
00173 for (unsigned index=0; index<=DIM; index++)
00174 {
00175 local_index1 = (local_index1+1)%(DIM+1);
00176 unsigned local_index2 = (local_index1+1)%(DIM+1);
00177 unsigned global_index1 = iter->GetNodeGlobalIndex(local_index1);
00178 unsigned global_index2 = iter->GetNodeGlobalIndex(local_index2);
00179 unsigned new_node_index = LookupInternalNode(global_index1, global_index2, edge_to_internal_map);
00180 iter->AddNode(this->mNodes[new_node_index]);
00181 this->mNodes[new_node_index]->AddElement(iter->GetIndex());
00182 }
00183 }
00184
00185 for (typename AbstractTetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter = this->GetBoundaryElementIteratorBegin();
00186 iter != this->GetBoundaryElementIteratorEnd();
00187 ++iter)
00188 {
00189 unsigned global_index1 = (*iter)->GetNodeGlobalIndex(0);
00190 unsigned global_index2 = (*iter)->GetNodeGlobalIndex(1);
00191 unsigned new_node_index = LookupInternalNode(global_index1, global_index2, edge_to_internal_map);
00192 (*iter)->AddNode(this->mNodes[new_node_index]);
00193 this->mNodes[new_node_index]->AddBoundaryElement((*iter)->GetIndex());
00194 }
00195
00196 this->RefreshMesh();
00197 }
00198
00199 template<unsigned DIM>
00200 Node<DIM>* QuadraticMesh<DIM>::MakeNewInternalNode(unsigned& rIndex, c_vector<double, DIM>& rLocation, c_vector<double, DIM>& rTop)
00201 {
00202 bool boundary = false;
00203 for (unsigned dim=0; dim<DIM; dim++)
00204 {
00205 if (rLocation[dim] > rTop[dim])
00206 {
00207
00208 return NULL;
00209 }
00210 if ( (rLocation[dim] == 0.0) || (rLocation[dim] == rTop[dim]) )
00211 {
00212 boundary = true;
00213 }
00214 }
00215
00216 assert(rIndex == this->mNodes.size());
00217 Node<DIM>* p_node = new Node<DIM>(rIndex++, rLocation, boundary);
00218 p_node->MarkAsInternal();
00219
00220 this->mNodes.push_back(p_node);
00221 if (boundary)
00222 {
00223 this->mBoundaryNodes.push_back(p_node);
00224 }
00225 return p_node;
00226 }
00227
00228 template<unsigned DIM>
00229 unsigned QuadraticMesh<DIM>::LookupInternalNode(unsigned globalIndex1, unsigned globalIndex2, std::map<std::pair<unsigned, unsigned>, unsigned>& rEdgeMap)
00230 {
00231 unsigned node_index = 0u;
00232 assert(globalIndex1 != globalIndex2);
00233 if (globalIndex1 < globalIndex2)
00234 {
00235 node_index = rEdgeMap[std::pair<unsigned,unsigned>(globalIndex1, globalIndex2)];
00236 }
00237 else
00238 {
00239 node_index = rEdgeMap[std::pair<unsigned,unsigned>(globalIndex2, globalIndex1)];
00240 }
00241
00242 assert(node_index != 0u);
00243 return node_index;
00244 }
00245
00246 template<unsigned DIM>
00247 void QuadraticMesh<DIM>::ConstructCuboid(unsigned numElemX, unsigned numElemY, unsigned numElemZ)
00248 {
00249 assert(DIM==3);
00250
00251 assert(numElemX > 0);
00252 assert(numElemY > 0);
00253 assert(numElemZ > 0);
00254
00255 AbstractTetrahedralMesh<DIM,DIM>::ConstructCuboid(numElemX, numElemY, numElemZ);
00256 c_vector<double, DIM> top;
00257 top[0]=numElemX;
00258 top[1]=numElemY;
00259 top[2]=numElemZ;
00260 c_vector<double, DIM> node_pos;
00261 this->mMeshIsLinear=false;
00262
00263
00264 std::map<std::pair<unsigned, unsigned>, unsigned> edge_to_internal_map;
00265 unsigned node_index = this->GetNumNodes();
00266 for (unsigned k=0; k<numElemZ+1; k++)
00267 {
00268
00269 node_pos[2] = k;
00270 for (unsigned j=0; j<numElemY+1; j++)
00271 {
00272 unsigned lo_z_lo_y = (numElemX+1)*((numElemY+1)*k + j);
00273 unsigned lo_z_hi_y = (numElemX+1)*((numElemY+1)*k + j + 1);
00274
00275 node_pos[1] = j;
00276
00277
00278 for (unsigned i=0; i<numElemX+1; i++)
00279 {
00280
00281 std::pair<unsigned,unsigned> edge(lo_z_lo_y+i, lo_z_lo_y+i+1);
00282 edge_to_internal_map[edge] = node_index;
00283 node_pos[0] = i+0.5;
00284 MakeNewInternalNode(node_index, node_pos, top);
00285 }
00286
00287 node_pos[1] = j+0.5;
00288 for (unsigned i=0; i<numElemX+1; i++)
00289 {
00290
00291 std::pair<unsigned,unsigned> edge(lo_z_lo_y+i, lo_z_hi_y+i);
00292 edge_to_internal_map[edge] = node_index;
00293 node_pos[0] = i;
00294 MakeNewInternalNode(node_index, node_pos, top);
00295
00296
00297 std::pair<unsigned,unsigned> edge2(lo_z_lo_y+i, lo_z_hi_y+i+1);
00298 edge_to_internal_map[edge2] = node_index;
00299 node_pos[0] = i+0.5;
00300 MakeNewInternalNode(node_index, node_pos, top);
00301 }
00302 }
00303
00304 node_pos[2] = k+0.5;
00305 for (unsigned j=0; j<numElemY+1; j++)
00306 {
00307 node_pos[1] = j;
00308 unsigned lo_z_lo_y = (numElemX+1)*((numElemY+1)*k + j);
00309 unsigned hi_z_lo_y = (numElemX+1)*((numElemY+1)*(k+1) + j);
00310 unsigned hi_z_hi_y = (numElemX+1)*((numElemY+1)*(k+1) + j + 1);
00311
00312
00313 for (unsigned i=0; i<numElemX+1; i++)
00314 {
00315
00316 std::pair<unsigned,unsigned> edge(lo_z_lo_y+i, hi_z_lo_y+i);
00317 edge_to_internal_map[edge] = node_index;
00318 node_pos[0] = i;
00319 MakeNewInternalNode(node_index, node_pos, top);
00320
00321
00322 node_pos[0] = i+0.5;
00323 std::pair<unsigned,unsigned> edge2(lo_z_lo_y+i, hi_z_lo_y+i+1);
00324 edge_to_internal_map[edge2] = node_index;
00325 MakeNewInternalNode(node_index, node_pos, top);
00326 }
00327
00328 node_pos[1] = j+0.5;
00329 for (unsigned i=0; i<numElemX+1; i++)
00330 {
00331
00332 std::pair<unsigned,unsigned> edge(lo_z_lo_y+i, hi_z_hi_y+i);
00333 edge_to_internal_map[edge] = node_index;
00334 node_pos[0] = i;
00335 MakeNewInternalNode(node_index, node_pos, top);
00336
00337
00338 std::pair<unsigned,unsigned> edge2(lo_z_lo_y+i, hi_z_hi_y+i+1);
00339 edge_to_internal_map[edge2] = node_index;
00340 node_pos[0] = i+0.5;
00341 MakeNewInternalNode(node_index, node_pos, top);
00342 }
00343 }
00344
00345 }
00346 CountVertices();
00347 for (typename AbstractTetrahedralMesh<DIM,DIM>::ElementIterator iter = this->GetElementIteratorBegin();
00348 iter != this->GetElementIteratorEnd();
00349 ++iter)
00350 {
00351
00352
00353
00354
00355
00356
00357 unsigned v0=iter->GetNodeGlobalIndex(0);
00358 unsigned v1=iter->GetNodeGlobalIndex(1);
00359 unsigned v2=iter->GetNodeGlobalIndex(2);
00360 unsigned v3=iter->GetNodeGlobalIndex(3);
00361 unsigned internal_index;
00362
00363
00364 internal_index=LookupInternalNode(v0, v1, edge_to_internal_map);
00365 iter->AddNode(this->mNodes[internal_index]);
00366 this->mNodes[internal_index]->AddElement(iter->GetIndex());
00367
00368 internal_index=LookupInternalNode(v1, v2, edge_to_internal_map);
00369 iter->AddNode(this->mNodes[internal_index]);
00370 this->mNodes[internal_index]->AddElement(iter->GetIndex());
00371
00372 internal_index=LookupInternalNode(v0, v2, edge_to_internal_map);
00373 iter->AddNode(this->mNodes[internal_index]);
00374 this->mNodes[internal_index]->AddElement(iter->GetIndex());
00375
00376 internal_index=LookupInternalNode(v0, v3, edge_to_internal_map);
00377 iter->AddNode(this->mNodes[internal_index]);
00378 this->mNodes[internal_index]->AddElement(iter->GetIndex());
00379
00380 internal_index=LookupInternalNode(v1, v3, edge_to_internal_map);
00381 iter->AddNode(this->mNodes[internal_index]);
00382 this->mNodes[internal_index]->AddElement(iter->GetIndex());
00383
00384 internal_index=LookupInternalNode(v2, v3, edge_to_internal_map);
00385 iter->AddNode(this->mNodes[internal_index]);
00386 this->mNodes[internal_index]->AddElement(iter->GetIndex());
00387
00388 }
00389 for (typename AbstractTetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter = this->GetBoundaryElementIteratorBegin();
00390 iter != this->GetBoundaryElementIteratorEnd();
00391 ++iter)
00392 {
00393 unsigned local_index1=0;
00394 for (unsigned index=0; index<DIM; index++)
00395 {
00396 local_index1 = (local_index1+1)%(DIM);
00397 unsigned local_index2 = (local_index1+1)%(DIM);
00398 unsigned global_index1 = (*iter)->GetNodeGlobalIndex(local_index1);
00399 unsigned global_index2 = (*iter)->GetNodeGlobalIndex(local_index2);
00400 unsigned new_node_index = LookupInternalNode(global_index1, global_index2, edge_to_internal_map);
00401 (*iter)->AddNode(this->mNodes[new_node_index]);
00402 this->mNodes[new_node_index]->AddBoundaryElement((*iter)->GetIndex());
00403 }
00404
00405 }
00406 this->RefreshMesh();
00407 }
00408
00409
00410
00411 template<unsigned DIM>
00412 unsigned QuadraticMesh<DIM>::GetNumVertices() const
00413 {
00414 return mNumVertices;
00415 }
00416
00417
00418 template<unsigned DIM>
00419 void QuadraticMesh<DIM>::ConstructFromLinearMeshReader(AbstractMeshReader<DIM, DIM>& rMeshReader)
00420 {
00421 assert(DIM != 1);
00422
00423
00424 TetrahedralMesh<DIM,DIM>::ConstructFromMeshReader(rMeshReader);
00425
00426 NodeMap unused_map(this->GetNumNodes());
00427
00428 if (DIM==2)
00429 {
00430 struct triangulateio mesher_input, mesher_output;
00431 this->InitialiseTriangulateIo(mesher_input);
00432 this->InitialiseTriangulateIo(mesher_output);
00433
00434 mesher_input.numberoftriangles = this->GetNumElements();
00435 mesher_input.trianglelist = (int *) malloc(this->GetNumElements() * (DIM+1) * sizeof(int));
00436 this->ExportToMesher(unused_map, mesher_input, mesher_input.trianglelist);
00437
00438
00439 triangulate((char*)"Qzero2", &mesher_input, &mesher_output, NULL);
00440
00441 this->ImportFromMesher(mesher_output, mesher_output.numberoftriangles, mesher_output.trianglelist, mesher_output.numberofedges, mesher_output.edgelist, mesher_output.edgemarkerlist);
00442 CountVertices();
00443 QuadraticMeshHelper<DIM>::AddNodesToBoundaryElements(this, NULL);
00444
00445
00446 this->FreeTriangulateIo(mesher_input);
00447 this->FreeTriangulateIo(mesher_output);
00448 }
00449 else
00450 {
00451
00452 class tetgen::tetgenio mesher_input, mesher_output;
00453
00454 mesher_input.numberoftetrahedra = this->GetNumElements();
00455 mesher_input.tetrahedronlist = new int[this->GetNumElements() * (DIM+1)];
00456 this->ExportToMesher(unused_map, mesher_input, mesher_input.tetrahedronlist);
00457
00458
00459 tetgen::tetrahedralize((char*)"Qzro2", &mesher_input, &mesher_output);
00460
00461 this->ImportFromMesher(mesher_output, mesher_output.numberoftetrahedra, mesher_output.tetrahedronlist, mesher_output.numberoftrifaces, mesher_output.trifacelist, NULL);
00462 CountVertices();
00463 QuadraticMeshHelper<DIM>::AddNodesToBoundaryElements(this, NULL);
00464 }
00465 }
00466
00467
00468 template<unsigned DIM>
00469 void QuadraticMesh<DIM>::ConstructFromMeshReader(AbstractMeshReader<DIM, DIM>& rAbsMeshReader)
00470 {
00471
00472 unsigned order_of_elements = rAbsMeshReader.GetOrderOfElements();
00473
00474
00475 if (order_of_elements == 1)
00476 {
00477 WARNING("Reading a (linear) tetrahedral mesh and converting it to a QuadraticMesh. This involves making an external library call to Triangle/Tetgen in order to compute internal nodes");
00478 ConstructFromLinearMeshReader(rAbsMeshReader);
00479 return;
00480 }
00481
00482 TetrahedralMesh<DIM,DIM>::ConstructFromMeshReader(rAbsMeshReader);
00483 assert(this->GetNumBoundaryElements() > 0);
00484
00485 QuadraticMeshHelper<DIM>::AddInternalNodesToElements(this, &rAbsMeshReader);
00486 CountVertices();
00487 QuadraticMeshHelper<DIM>::AddInternalNodesToBoundaryElements(this, &rAbsMeshReader);
00488 QuadraticMeshHelper<DIM>::CheckBoundaryElements(this);
00489 }
00490
00492
00494
00495
00496 template class QuadraticMesh<1>;
00497 template class QuadraticMesh<2>;
00498 template class QuadraticMesh<3>;
00499
00500
00501
00502 #include "SerializationExportWrapperForCpp.hpp"
00503 EXPORT_TEMPLATE_CLASS_SAME_DIMS(QuadraticMesh)