MFEM v2.0
|
00001 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at 00002 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights 00003 // reserved. See file COPYRIGHT for details. 00004 // 00005 // This file is part of the MFEM library. For more information and source code 00006 // availability see http://mfem.googlecode.com. 00007 // 00008 // MFEM is free software; you can redistribute it and/or modify it under the 00009 // terms of the GNU Lesser General Public License (as published by the Free 00010 // Software Foundation) version 2.1 dated February 1999. 00011 00012 // Implementation of data type mesh 00013 00014 #include <iostream> 00015 #include <fstream> 00016 #include <limits> 00017 #include <math.h> 00018 #include <string.h> 00019 #include <time.h> 00020 00021 #include "mesh_headers.hpp" 00022 #include "../fem/fem.hpp" 00023 #include "../general/sort_pairs.hpp" 00024 00025 void Mesh::GetElementJacobian(int i, DenseMatrix &J) 00026 { 00027 int geom = GetElementBaseGeometry(i); 00028 ElementTransformation *eltransf = GetElementTransformation(i); 00029 eltransf->SetIntPoint(&Geometries.GetCenter(geom)); 00030 Geometries.JacToPerfJac(geom, eltransf->Jacobian(), J); 00031 } 00032 00033 double Mesh::GetElementSize(int i, int type) 00034 { 00035 DenseMatrix J(Dim); 00036 GetElementJacobian(i, J); 00037 if (type == 0) 00038 return pow(fabs(J.Det()), 1./Dim); 00039 else if (type == 1) 00040 return J.CalcSingularvalue(Dim-1); // h_min 00041 else 00042 return J.CalcSingularvalue(0); // h_max 00043 } 00044 00045 double Mesh::GetElementSize(int i, const Vector &dir) 00046 { 00047 DenseMatrix J(Dim); 00048 Vector d_hat(Dim); 00049 GetElementJacobian(i, J); 00050 J.MultTranspose(dir, d_hat); 00051 return sqrt((d_hat * d_hat) / (dir * dir)); 00052 } 00053 00054 double Mesh::GetElementVolume(int i) 00055 { 00056 ElementTransformation *et = GetElementTransformation(i); 00057 const IntegrationRule &ir = IntRules.Get(GetElementBaseGeometry(i), 00058 et->OrderJ()); 00059 double volume = 0.0; 00060 for (int j = 0; j < ir.GetNPoints(); j++) 00061 { 00062 const IntegrationPoint &ip = ir.IntPoint(j); 00063 et->SetIntPoint(&ip); 00064 volume += ip.weight * et->Weight(); 00065 } 00066 00067 return volume; 00068 } 00069 00070 void Mesh::PrintCharacteristics(Vector *Vh, Vector *Vk) 00071 { 00072 int i, dim; 00073 DenseMatrix J; 00074 double h_min, h_max, kappa_min, kappa_max, h, kappa; 00075 00076 cout << "Mesh Characteristics:" << flush; 00077 00078 dim = Dimension(); 00079 J.SetSize(dim); 00080 00081 if (Vh) Vh->SetSize(NumOfElements); 00082 if (Vk) Vk->SetSize(NumOfElements); 00083 00084 for (i = 0; i < NumOfElements; i++) 00085 { 00086 GetElementJacobian(i, J); 00087 h = pow(fabs(J.Det()), 1.0/double(dim)); 00088 kappa = J.CalcSingularvalue(0) / J.CalcSingularvalue(dim-1); 00089 if (Vh) (*Vh)(i) = h; 00090 if (Vk) (*Vk)(i) = kappa; 00091 if (i == 0) 00092 { 00093 h_min = h_max = h; 00094 kappa_min = kappa_max = kappa; 00095 } 00096 else 00097 { 00098 if (h < h_min) h_min = h; 00099 if (h > h_max) h_max = h; 00100 if (kappa < kappa_min) kappa_min = kappa; 00101 if (kappa > kappa_max) kappa_max = kappa; 00102 } 00103 } 00104 00105 if (dim == 2) 00106 cout << endl 00107 << "Number of vertices : " << GetNV() << endl 00108 << "Number of edges : " << GetNEdges() << endl 00109 << "Number of elements : " << GetNE() << endl 00110 << "Number of bdr elem : " << GetNBE() << endl 00111 << "Euler Number : " << EulerNumber2D() << endl 00112 << "h_min : " << h_min << endl 00113 << "h_max : " << h_max << endl 00114 << "kappa_min : " << kappa_min << endl 00115 << "kappa_max : " << kappa_max << endl 00116 << endl; 00117 else 00118 cout << endl 00119 << "Number of vertices : " << GetNV() << endl 00120 << "Number of edges : " << GetNEdges() << endl 00121 << "Number of faces : " << GetNFaces() << endl 00122 << "Number of elements : " << GetNE() << endl 00123 << "Number of bdr elem : " << GetNBE() << endl 00124 << "Euler Number : " << EulerNumber() << endl 00125 << "h_min : " << h_min << endl 00126 << "h_max : " << h_max << endl 00127 << "kappa_min : " << kappa_min << endl 00128 << "kappa_max : " << kappa_max << endl 00129 << endl; 00130 } 00131 00132 FiniteElement *Mesh::GetTransformationFEforElementType(int ElemType) 00133 { 00134 switch (ElemType) 00135 { 00136 case Element::POINT : return &PointFE; 00137 case Element::SEGMENT : return &SegmentFE; 00138 case Element::TRIANGLE : return &TriangleFE; 00139 case Element::QUADRILATERAL : return &QuadrilateralFE; 00140 case Element::TETRAHEDRON : return &TetrahedronFE; 00141 case Element::HEXAHEDRON : return &HexahedronFE; 00142 } 00143 mfem_error("Mesh::GetTransformationFEforElement - unknown ElementType"); 00144 return &TriangleFE; 00145 } 00146 00147 00148 void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr) 00149 { 00150 ElTr->Attribute = GetAttribute(i); 00151 ElTr->ElementNo = i; 00152 if (Nodes == NULL) 00153 { 00154 GetPointMatrix(i, ElTr->GetPointMat()); 00155 ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i))); 00156 } 00157 else 00158 { 00159 DenseMatrix &pm = ElTr->GetPointMat(); 00160 Array<int> vdofs; 00161 Nodes->FESpace()->GetElementVDofs(i, vdofs); 00162 int n = vdofs.Size()/Dim; 00163 pm.SetSize(Dim, n); 00164 for (int k = 0; k < Dim; k++) 00165 for (int j = 0; j < n; j++) 00166 pm(k,j) = (*Nodes)(vdofs[n*k+j]); 00167 ElTr->SetFE(Nodes->FESpace()->GetFE(i)); 00168 } 00169 } 00170 00171 void Mesh::GetElementTransformation(int i, const Vector &nodes, 00172 IsoparametricTransformation *ElTr) 00173 { 00174 ElTr->Attribute = GetAttribute(i); 00175 ElTr->ElementNo = i; 00176 DenseMatrix &pm = ElTr->GetPointMat(); 00177 if (Nodes == NULL) 00178 { 00179 int nv = elements[i]->GetNVertices(); 00180 const int *v = elements[i]->GetVertices(); 00181 int n = vertices.Size(); 00182 pm.SetSize(Dim, nv); 00183 for (int k = 0; k < Dim; k++) 00184 for (int j = 0; j < nv; j++) 00185 pm(k, j) = nodes(k*n+v[j]); 00186 ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i))); 00187 } 00188 else 00189 { 00190 Array<int> vdofs; 00191 Nodes->FESpace()->GetElementVDofs(i, vdofs); 00192 int n = vdofs.Size()/Dim; 00193 pm.SetSize(Dim, n); 00194 for (int k = 0; k < Dim; k++) 00195 for (int j = 0; j < n; j++) 00196 pm(k,j) = nodes(vdofs[n*k+j]); 00197 ElTr->SetFE(Nodes->FESpace()->GetFE(i)); 00198 } 00199 } 00200 00201 ElementTransformation *Mesh::GetElementTransformation(int i) 00202 { 00203 GetElementTransformation(i, &Transformation); 00204 00205 return &Transformation; 00206 } 00207 00208 ElementTransformation *Mesh::GetBdrElementTransformation(int i) 00209 { 00210 FaceTransformation.Attribute = GetBdrAttribute(i); 00211 FaceTransformation.ElementNo = i; // boundary element number 00212 if (Nodes == NULL) 00213 { 00214 GetBdrPointMatrix(i, FaceTransformation.GetPointMat()); 00215 FaceTransformation.SetFE( 00216 GetTransformationFEforElementType(GetBdrElementType(i))); 00217 } 00218 else 00219 { 00220 DenseMatrix &pm = FaceTransformation.GetPointMat(); 00221 Array<int> vdofs; 00222 Nodes->FESpace()->GetBdrElementVDofs(i, vdofs); 00223 int n = vdofs.Size()/Dim; 00224 pm.SetSize(Dim, n); 00225 for (int k = 0; k < Dim; k++) 00226 for (int j = 0; j < n; j++) 00227 pm(k,j) = (*Nodes)(vdofs[n*k+j]); 00228 FaceTransformation.SetFE(Nodes->FESpace()->GetBE(i)); 00229 } 00230 00231 return &FaceTransformation; 00232 } 00233 00234 void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr) 00235 { 00236 FTr->Attribute = faces[FaceNo]->GetAttribute(); 00237 FTr->ElementNo = FaceNo; 00238 const int *v = faces[FaceNo]->GetVertices(); 00239 const int nv = faces[FaceNo]->GetNVertices(); 00240 DenseMatrix &pm = FTr->GetPointMat(); 00241 pm.SetSize(Dim, nv); 00242 for (int i = 0; i < Dim; i++) 00243 for (int j = 0; j < nv; j++) 00244 pm(i, j) = vertices[v[j]](i); 00245 FTr->SetFE(GetTransformationFEforElementType(faces[FaceNo]->GetType())); 00246 } 00247 00248 ElementTransformation *Mesh::GetFaceTransformation(int FaceNo) 00249 { 00250 GetFaceTransformation(FaceNo, &FaceTransformation); 00251 return &FaceTransformation; 00252 } 00253 00254 void Mesh::GetLocalSegToTriTransformation( 00255 IsoparametricTransformation &Transf, int i) 00256 { 00257 static const int tri_faces[3][2] = {{1, 0}, {2, 1}, {0, 2}}; 00258 static const int seg_inv_orient[2][2] = {{0, 1}, {1, 0}}; 00259 int j; 00260 const int *tv, *so; 00261 const IntegrationRule *TriVert; 00262 DenseMatrix &locpm = Transf.GetPointMat(); 00263 00264 Transf.SetFE(&SegmentFE); 00265 tv = tri_faces[i/64]; // (i/64) is the local face no. in the triangle 00266 so = seg_inv_orient[i%64]; // (i%64) is the orientation of the segment 00267 TriVert = Geometries.GetVertices(Geometry::TRIANGLE); 00268 locpm.SetSize(2, 2); 00269 for (j = 0; j < 2; j++) 00270 { 00271 locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x; 00272 locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y; 00273 } 00274 } 00275 00276 void Mesh::GetLocalSegToQuadTransformation( 00277 IsoparametricTransformation &Transf, int i) 00278 { 00279 static const int quad_faces[4][2] = {{1, 0}, {2, 1}, {3, 2}, {0, 3}}; 00280 static const int seg_inv_orient[2][2] = {{0, 1}, {1, 0}}; 00281 int j; 00282 const int *qv, *so; 00283 const IntegrationRule *QuadVert; 00284 DenseMatrix &locpm = Transf.GetPointMat(); 00285 00286 Transf.SetFE(&SegmentFE); 00287 qv = quad_faces[i/64]; // (i/64) is the local face no. in the quad 00288 so = seg_inv_orient[i%64]; // (i%64) is the orientation of the segment 00289 QuadVert = Geometries.GetVertices(Geometry::SQUARE); 00290 locpm.SetSize(2, 2); 00291 for (j = 0; j < 2; j++) 00292 { 00293 locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x; 00294 locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y; 00295 } 00296 } 00297 00298 void Mesh::GetLocalTriToTetTransformation( 00299 IsoparametricTransformation &Transf, int i) 00300 { 00301 static const int tet_faces[4][3] = {{1, 2, 3}, {0, 3, 2}, 00302 {0, 1, 3}, {0, 2, 1}}; 00303 static const int tri_inv_orient[6][3] = {{0, 1, 2}, {1, 0, 2}, 00304 {1, 2, 0}, {2, 1, 0}, 00305 {2, 0, 1}, {0, 2, 1}}; 00306 int j; 00307 const int *tv, *to; 00308 const IntegrationRule *TetVert; 00309 DenseMatrix &locpm = Transf.GetPointMat(); 00310 00311 Transf.SetFE(&TriangleFE); 00312 tv = tet_faces[i/64]; // (i/64) is the local face no. in the tet 00313 // (i%64) is the orientation of the tetrahedron face 00314 // w.r.t. the face element 00315 to = tri_inv_orient[i%64]; 00316 TetVert = Geometries.GetVertices(Geometry::TETRAHEDRON); 00317 locpm.SetSize(3, 3); 00318 for (j = 0; j < 3; j++) 00319 { 00320 locpm(0, to[j]) = TetVert->IntPoint(tv[j]).x; 00321 locpm(1, to[j]) = TetVert->IntPoint(tv[j]).y; 00322 locpm(2, to[j]) = TetVert->IntPoint(tv[j]).z; 00323 } 00324 } 00325 00326 void Mesh::GetLocalQuadToHexTransformation( 00327 IsoparametricTransformation &Transf, int i) 00328 { 00329 static const int hex_faces[6][4] = {{3, 2, 1, 0}, {0, 1, 5, 4}, 00330 {1, 2, 6, 5}, {2, 3, 7, 6}, 00331 {3, 0, 4, 7}, {4, 5, 6, 7}}; 00332 // must be 'quad_inv_or' ... fix me 00333 static const int quad_orient[8][4] = {{0, 1, 2, 3}, {0, 3, 2, 1}, 00334 {1, 2, 3, 0}, {1, 0, 3, 2}, 00335 {2, 3, 0, 1}, {2, 1, 0, 3}, 00336 {3, 0, 1, 2}, {3, 2, 1, 0}}; 00337 int j; 00338 const int *hv, *qo; 00339 const IntegrationRule *HexVert; 00340 DenseMatrix &locpm = Transf.GetPointMat(); 00341 00342 Transf.SetFE(&QuadrilateralFE); 00343 hv = hex_faces[i/64]; // (i/64) is the local face no. in the hex 00344 qo = quad_orient[i%64]; // (i%64) is the orientation of the quad 00345 HexVert = Geometries.GetVertices(Geometry::CUBE); 00346 locpm.SetSize(3, 4); 00347 for (j = 0; j < 4; j++) 00348 { 00349 locpm(0, qo[j]) = HexVert->IntPoint(hv[j]).x; 00350 locpm(1, qo[j]) = HexVert->IntPoint(hv[j]).y; 00351 locpm(2, qo[j]) = HexVert->IntPoint(hv[j]).z; 00352 } 00353 } 00354 00355 FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo, 00356 int mask) 00357 { 00358 // setup the transformation for the first element 00359 FaceElemTr.Elem1No = faces_info[FaceNo].Elem1No; 00360 if (mask & 1) 00361 { 00362 GetElementTransformation(FaceElemTr.Elem1No, &Transformation); 00363 FaceElemTr.Elem1 = &Transformation; 00364 } 00365 else 00366 FaceElemTr.Elem1 = NULL; 00367 00368 // setup the transformation for the second element 00369 // return NULL in the Elem2 field if there's no second element, i.e. 00370 // the face is on the "boundary" 00371 if ( (FaceElemTr.Elem2No = faces_info[FaceNo].Elem2No) >= 0 && (mask & 2)) 00372 { 00373 #ifdef MFEM_DEBUG 00374 if (NURBSext && (mask & 1)) 00375 mfem_error("Mesh::GetFaceElementTransformations :" 00376 " NURBS mesh is not supported!"); 00377 #endif 00378 GetElementTransformation(FaceElemTr.Elem2No, &Transformation2); 00379 FaceElemTr.Elem2 = &Transformation2; 00380 } 00381 else 00382 FaceElemTr.Elem2 = NULL; 00383 00384 FaceElemTr.FaceGeom = faces[FaceNo]->GetGeometryType(); 00385 00386 // setup the face transformation 00387 if (mask & 16) 00388 FaceElemTr.Face = GetFaceTransformation(FaceNo); 00389 else 00390 FaceElemTr.Face = NULL; 00391 00392 // setup Loc1 & Loc2 00393 switch (faces[FaceNo]->GetType()) 00394 { 00395 case Element::SEGMENT: 00396 if (mask & 4) 00397 { 00398 if (GetElementType(faces_info[FaceNo].Elem1No) == Element::TRIANGLE) 00399 GetLocalSegToTriTransformation(FaceElemTr.Loc1.Transf, 00400 faces_info[FaceNo].Elem1Inf); 00401 else // assume the element is a quad 00402 GetLocalSegToQuadTransformation(FaceElemTr.Loc1.Transf, 00403 faces_info[FaceNo].Elem1Inf); 00404 } 00405 00406 if (FaceElemTr.Elem2No >= 0 && (mask & 8)) 00407 { 00408 if (GetElementType(faces_info[FaceNo].Elem2No) 00409 == Element::TRIANGLE) 00410 GetLocalSegToTriTransformation(FaceElemTr.Loc2.Transf, 00411 faces_info[FaceNo].Elem2Inf); 00412 else // assume the element is a quad 00413 GetLocalSegToQuadTransformation(FaceElemTr.Loc2.Transf, 00414 faces_info[FaceNo].Elem2Inf); 00415 } 00416 break; 00417 case Element::TRIANGLE: 00418 // --------- assumes the face is a triangle -- face of a tetrahedron 00419 if (mask & 4) 00420 GetLocalTriToTetTransformation(FaceElemTr.Loc1.Transf, 00421 faces_info[FaceNo].Elem1Inf); 00422 if (FaceElemTr.Elem2No >= 0 && (mask & 8)) 00423 GetLocalTriToTetTransformation(FaceElemTr.Loc2.Transf, 00424 faces_info[FaceNo].Elem2Inf); 00425 break; 00426 case Element::QUADRILATERAL: 00427 // --------- assumes the face is a quad -- face of a hexahedron 00428 if (mask & 4) 00429 GetLocalQuadToHexTransformation(FaceElemTr.Loc1.Transf, 00430 faces_info[FaceNo].Elem1Inf); 00431 if (FaceElemTr.Elem2No >= 0 && (mask & 8)) 00432 GetLocalQuadToHexTransformation(FaceElemTr.Loc2.Transf, 00433 faces_info[FaceNo].Elem2Inf); 00434 break; 00435 } 00436 00437 return &FaceElemTr; 00438 } 00439 00440 FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo) 00441 { 00442 FaceElementTransformations *tr; 00443 int fn; 00444 if (Dim == 3) 00445 fn = be_to_face[BdrElemNo]; 00446 else 00447 fn = be_to_edge[BdrElemNo]; 00448 if (faces_info[fn].Elem2No >= 0) 00449 return NULL; 00450 tr = GetFaceElementTransformations(fn); 00451 tr->Face->Attribute = boundary[BdrElemNo]->GetAttribute(); 00452 return tr; 00453 } 00454 00455 void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2) 00456 { 00457 *Elem1 = faces_info[Face].Elem1No; 00458 *Elem2 = faces_info[Face].Elem2No; 00459 } 00460 00461 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) 00462 { 00463 *Inf1 = faces_info[Face].Elem1Inf; 00464 *Inf2 = faces_info[Face].Elem2Inf; 00465 } 00466 00467 void Mesh::Init() 00468 { 00469 NumOfVertices = NumOfElements = NumOfBdrElements = NumOfEdges = -1; 00470 WantTwoLevelState = 0; 00471 State = Mesh::NORMAL; 00472 Nodes = NULL; 00473 own_nodes = 1; 00474 NURBSext = NULL; 00475 } 00476 00477 void Mesh::InitTables() 00478 { 00479 el_to_edge = el_to_face = el_to_el = 00480 bel_to_edge = face_edge = edge_vertex = NULL; 00481 } 00482 00483 void Mesh::DeleteTables() 00484 { 00485 if (el_to_edge != NULL) 00486 delete el_to_edge; 00487 00488 if (el_to_face != NULL) 00489 delete el_to_face; 00490 00491 if (el_to_el != NULL) 00492 delete el_to_el; 00493 00494 if (Dim == 3 && bel_to_edge != NULL) 00495 delete bel_to_edge; 00496 00497 if (face_edge != NULL) 00498 delete face_edge; 00499 00500 if (edge_vertex != NULL) 00501 delete edge_vertex; 00502 00503 InitTables(); 00504 } 00505 00506 void Mesh::DeleteCoarseTables() 00507 { 00508 delete el_to_el; 00509 delete face_edge; 00510 delete edge_vertex; 00511 00512 el_to_el = face_edge = edge_vertex = NULL; 00513 } 00514 00515 void Mesh::SetAttributes() 00516 { 00517 int i, j, nattr; 00518 Array<int> attribs; 00519 00520 attribs.SetSize(GetNBE()); 00521 for (i = 0; i < attribs.Size(); i++) 00522 attribs[i] = GetBdrAttribute(i); 00523 attribs.Sort(); 00524 00525 if (attribs.Size() > 0) 00526 nattr = 1; 00527 else 00528 nattr = 0; 00529 for (i = 1; i < attribs.Size(); i++) 00530 if (attribs[i] != attribs[i-1]) 00531 nattr++; 00532 00533 bdr_attributes.SetSize(nattr); 00534 if (nattr > 0) 00535 { 00536 bdr_attributes[0] = attribs[0]; 00537 for (i = j = 1; i < attribs.Size(); i++) 00538 if (attribs[i] != attribs[i-1]) 00539 bdr_attributes[j++] = attribs[i]; 00540 if (attribs[0] <= 0) 00541 cout << "Mesh::SetAttributes(): " 00542 "Non-positive attributes on the boundary!" 00543 << endl; 00544 } 00545 00546 00547 attribs.SetSize(GetNE()); 00548 for (i = 0; i < attribs.Size(); i++) 00549 attribs[i] = GetAttribute(i); 00550 attribs.Sort(); 00551 00552 if (attribs.Size() > 0) 00553 nattr = 1; 00554 else 00555 nattr = 0; 00556 for (i = 1; i < attribs.Size(); i++) 00557 if (attribs[i] != attribs[i-1]) 00558 nattr++; 00559 00560 attributes.SetSize(nattr); 00561 if (nattr > 0) 00562 { 00563 attributes[0] = attribs[0]; 00564 for (i = j = 1; i < attribs.Size(); i++) 00565 if (attribs[i] != attribs[i-1]) 00566 attributes[j++] = attribs[i]; 00567 if (attribs[0] <= 0) 00568 cout << "Mesh::SetAttributes(): " 00569 "Non-positive attributes in the domain!" 00570 << endl; 00571 } 00572 } 00573 00574 Mesh::Mesh(int _Dim, int NVert, int NElem, int NBdrElem) 00575 { 00576 Dim = _Dim; 00577 00578 Init(); 00579 InitTables(); 00580 00581 NumOfVertices = 0; 00582 vertices.SetSize(NVert); // just allocate space for vertices 00583 00584 NumOfElements = 0; 00585 elements.SetSize(NElem); // just allocate space for Element * 00586 00587 NumOfBdrElements = 0; 00588 boundary.SetSize(NBdrElem); // just allocate space for Element * 00589 } 00590 00591 void Mesh::AddVertex(double *x) 00592 { 00593 double *y = vertices[NumOfVertices](); 00594 00595 for (int i = 0; i < Dim; i++) 00596 y[i] = x[i]; 00597 NumOfVertices++; 00598 } 00599 00600 void Mesh::AddTri(int *vi, int attr) 00601 { 00602 elements[NumOfElements++] = new Triangle(vi, attr); 00603 } 00604 00605 void Mesh::AddTriangle(int *vi, int attr) 00606 { 00607 elements[NumOfElements++] = new Triangle(vi, attr); 00608 } 00609 00610 void Mesh::AddQuad(int *vi, int attr) 00611 { 00612 elements[NumOfElements++] = new Quadrilateral(vi, attr); 00613 } 00614 00615 void Mesh::AddTet(int *vi, int attr) 00616 { 00617 #ifdef MFEM_USE_MEMALLOC 00618 Tetrahedron *tet; 00619 tet = TetMemory.Alloc(); 00620 tet->SetVertices(vi); 00621 tet->SetAttribute(attr); 00622 elements[NumOfElements++] = tet; 00623 #else 00624 elements[NumOfElements++] = new Tetrahedron(vi, attr); 00625 #endif 00626 } 00627 00628 void Mesh::AddHex(int *vi, int attr) 00629 { 00630 elements[NumOfElements++] = new Hexahedron(vi, attr); 00631 } 00632 00633 void Mesh::AddBdrSegment(int *vi, int attr) 00634 { 00635 boundary[NumOfBdrElements++] = new Segment(vi, attr); 00636 } 00637 00638 void Mesh::AddBdrTriangle(int *vi, int attr) 00639 { 00640 boundary[NumOfBdrElements++] = new Triangle(vi, attr); 00641 } 00642 00643 void Mesh::AddBdrQuad(int *vi, int attr) 00644 { 00645 boundary[NumOfBdrElements++] = new Quadrilateral(vi, attr); 00646 } 00647 00648 void Mesh::GenerateBoundaryElements() 00649 { 00650 int i, j; 00651 Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face; 00652 00653 // GenerateFaces(); 00654 00655 for (i = 0; i < boundary.Size(); i++) 00656 FreeElement(boundary[i]); 00657 00658 if (Dim == 3) 00659 { 00660 delete bel_to_edge; 00661 bel_to_edge = NULL; 00662 } 00663 00664 // count the 'NumOfBdrElements' 00665 NumOfBdrElements = 0; 00666 for (i = 0; i < faces_info.Size(); i++) 00667 if (faces_info[i].Elem2No == -1) 00668 NumOfBdrElements++; 00669 00670 boundary.SetSize(NumOfBdrElements); 00671 be2face.SetSize(NumOfBdrElements); 00672 for (j = i = 0; i < faces_info.Size(); i++) 00673 if (faces_info[i].Elem2No == -1) 00674 { 00675 boundary[j] = faces[i]->Duplicate(this); 00676 be2face[j++] = i; 00677 } 00678 // In 3D, 'bel_to_edge' is destroyed but it's not updated. 00679 } 00680 00681 typedef struct { 00682 int edge; 00683 double length; 00684 } edge_length; 00685 00686 // Used by qsort to sort edges in increasing (according their length) order. 00687 static int edge_compare(const void *ii, const void *jj) 00688 { 00689 edge_length *i = (edge_length *)ii, *j = (edge_length *)jj; 00690 if (i->length > j->length) return (1); 00691 if (i->length < j->length) return (-1); 00692 return (0); 00693 } 00694 00695 void Mesh::FinalizeTriMesh(int generate_edges, int refine) 00696 { 00697 CheckElementOrientation(); 00698 00699 if (refine) 00700 MarkTriMeshForRefinement(); 00701 00702 if (generate_edges) 00703 { 00704 el_to_edge = new Table; 00705 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 00706 GenerateFaces(); 00707 CheckBdrElementOrientation(); 00708 } 00709 else 00710 NumOfEdges = 0; 00711 00712 NumOfFaces = 0; 00713 00714 SetAttributes(); 00715 00716 meshgen = 1; 00717 } 00718 00719 void Mesh::FinalizeQuadMesh(int generate_edges, int refine) 00720 { 00721 CheckElementOrientation(); 00722 00723 if (generate_edges) 00724 { 00725 el_to_edge = new Table; 00726 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 00727 GenerateFaces(); 00728 CheckBdrElementOrientation(); 00729 } 00730 else 00731 NumOfEdges = 0; 00732 00733 NumOfFaces = 0; 00734 00735 SetAttributes(); 00736 00737 meshgen = 2; 00738 } 00739 00740 void Mesh::MarkForRefinement() 00741 { 00742 if (meshgen & 1) 00743 { 00744 if (Dim == 2) 00745 MarkTriMeshForRefinement(); 00746 else if (Dim == 3) 00747 MarkTetMeshForRefinement(); 00748 } 00749 } 00750 00751 void Mesh::MarkTriMeshForRefinement() 00752 { 00753 // Mark the longest triangle edge by rotating the indeces so that 00754 // vertex 0 - vertex 1 to be the longest element's edge. 00755 DenseMatrix pmat; 00756 for (int i = 0; i < NumOfElements; i++) 00757 if (elements[i]->GetType() == Element::TRIANGLE) 00758 { 00759 GetPointMatrix(i, pmat); 00760 elements[i]->MarkEdge(pmat); 00761 } 00762 } 00763 00764 void Mesh::MarkTetMeshForRefinement() 00765 { 00766 // Mark the longest tetrahedral edge by rotating the indices so that 00767 // vertex 0 - vertex 1 is the longest edge in the element. 00768 DSTable v_to_v(NumOfVertices); 00769 GetVertexToVertexTable(v_to_v); 00770 NumOfEdges = v_to_v.NumberOfEntries(); 00771 edge_length *length = new edge_length[NumOfEdges]; 00772 for (int i = 0; i < NumOfVertices; i++) 00773 { 00774 for (DSTable::RowIterator it(v_to_v, i); !it; ++it) 00775 { 00776 int j = it.Index(); 00777 length[j].length = GetLength(i, it.Column()); 00778 length[j].edge = j; 00779 } 00780 } 00781 00782 // sort in increasing order 00783 qsort(length, NumOfEdges, sizeof(edge_length), edge_compare); 00784 00785 int *order = new int [NumOfEdges]; 00786 for (int i = 0; i < NumOfEdges; i++) 00787 order[length[i].edge] = i; 00788 00789 for (int i = 0; i < NumOfElements; i++) 00790 if (elements[i]->GetType() == Element::TETRAHEDRON) 00791 elements[i]->MarkEdge(v_to_v, order); 00792 00793 for (int i = 0; i < NumOfBdrElements; i++) 00794 if (boundary[i]->GetType() == Element::TRIANGLE) 00795 boundary[i]->MarkEdge(v_to_v, order); 00796 00797 delete [] order; 00798 delete [] length; 00799 } 00800 00801 void Mesh::FinalizeTetMesh(int generate_edges, int refine) 00802 { 00803 CheckElementOrientation(); 00804 00805 if (NumOfBdrElements == 0) 00806 { 00807 GetElementToFaceTable(); 00808 GenerateFaces(); 00809 GenerateBoundaryElements(); 00810 } 00811 00812 if (refine) 00813 { 00814 MarkTetMeshForRefinement(); 00815 } 00816 00817 GetElementToFaceTable(); 00818 GenerateFaces(); 00819 00820 CheckBdrElementOrientation(); 00821 00822 if (generate_edges == 1) 00823 { 00824 el_to_edge = new Table; 00825 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 00826 } 00827 else 00828 { 00829 el_to_edge = NULL; // Not really necessary -- InitTables was called 00830 bel_to_edge = NULL; 00831 NumOfEdges = 0; 00832 } 00833 00834 SetAttributes(); 00835 00836 meshgen = 1; 00837 } 00838 00839 void Mesh::FinalizeHexMesh(int generate_edges, int refine) 00840 { 00841 CheckElementOrientation(); 00842 00843 GetElementToFaceTable(); 00844 GenerateFaces(); 00845 00846 if (NumOfBdrElements == 0) 00847 GenerateBoundaryElements(); 00848 00849 CheckBdrElementOrientation(); 00850 00851 if (generate_edges) 00852 { 00853 el_to_edge = new Table; 00854 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 00855 } 00856 else 00857 NumOfEdges = 0; 00858 00859 SetAttributes(); 00860 00861 meshgen = 2; 00862 } 00863 00864 Mesh::Mesh(int nx, int ny, Element::Type type, int generate_edges, 00865 double sx, double sy) 00866 { 00867 int i, j, k; 00868 00869 Dim = 2; 00870 00871 Init(); 00872 InitTables(); 00873 00874 // Creates quadrilateral mesh 00875 if (type == Element::QUADRILATERAL) 00876 { 00877 meshgen = 2; 00878 NumOfVertices = (nx+1) * (ny+1); 00879 NumOfElements = nx * ny; 00880 NumOfBdrElements = 2 * nx + 2 * ny; 00881 vertices.SetSize(NumOfVertices); 00882 elements.SetSize(NumOfElements); 00883 boundary.SetSize(NumOfBdrElements); 00884 double cx, cy; 00885 int ind[4]; 00886 00887 // Sets vertices and the corresponding coordinates 00888 k = 0; 00889 for (j = 0; j < ny+1; j++) 00890 { 00891 cy = ((double) j / ny) * sy; 00892 for (i = 0; i < nx+1; i++) 00893 { 00894 cx = ((double) i / nx) * sx; 00895 vertices[k](0) = cx; 00896 vertices[k](1) = cy; 00897 k++; 00898 } 00899 } 00900 00901 // Sets elements and the corresponding indices of vertices 00902 k = 0; 00903 for (j = 0; j < ny; j++) 00904 { 00905 for (i = 0; i < nx; i++) 00906 { 00907 ind[0] = i + j*(nx+1); 00908 ind[1] = i + 1 +j*(nx+1); 00909 ind[2] = i + 1 + (j+1)*(nx+1); 00910 ind[3] = i + (j+1)*(nx+1); 00911 elements[k] = new Quadrilateral(ind); 00912 k++; 00913 } 00914 } 00915 00916 // Sets boundary elements and the corresponding indices of vertices 00917 int m = (nx+1)*ny; 00918 for (i = 0; i < nx; i++) 00919 { 00920 boundary[i] = new Segment(i, i+1, 1); 00921 boundary[nx+i] = new Segment(m+i, m+i+1, 3); 00922 } 00923 m = nx+1; 00924 for (j = 0; j < ny; j++) 00925 { 00926 boundary[2*nx+j] = new Segment(j*m, (j+1)*m, 4); 00927 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2); 00928 } 00929 } 00930 00931 // Creates triangular mesh 00932 if (type == Element::TRIANGLE) 00933 { 00934 meshgen = 1; 00935 NumOfVertices = (nx+1) * (ny+1); 00936 NumOfElements = 2 * nx * ny; 00937 NumOfBdrElements = 2 * nx + 2 * ny; 00938 vertices.SetSize(NumOfVertices); 00939 elements.SetSize(NumOfElements); 00940 boundary.SetSize(NumOfBdrElements); 00941 double cx, cy; 00942 int ind[3]; 00943 00944 // Sets vertices and the corresponding coordinates 00945 k = 0; 00946 for (j = 0; j < ny+1; j++) 00947 { 00948 cy = ((double) j / ny) * sy; 00949 for (i = 0; i < nx+1; i++) 00950 { 00951 cx = ((double) i / nx) * sx; 00952 vertices[k](0) = cx; 00953 vertices[k](1) = cy; 00954 k++; 00955 } 00956 } 00957 00958 // Sets the elements and the corresponding indices of vertices 00959 k = 0; 00960 for (j = 0; j < ny; j++) 00961 { 00962 for (i = 0; i < nx; i++) 00963 { 00964 ind[0] = i + j*(nx+1); 00965 ind[1] = i + 1 + (j+1)*(nx+1); 00966 ind[2] = i + (j+1)*(nx+1); 00967 elements[k] = new Triangle(ind); 00968 k++; 00969 ind[1] = i + 1 + j*(nx+1); 00970 ind[2] = i + 1 + (j+1)*(nx+1); 00971 elements[k] = new Triangle(ind); 00972 k++; 00973 } 00974 } 00975 00976 // Sets boundary elements and the corresponding indices of vertices 00977 int m = (nx+1)*ny; 00978 for (i = 0; i < nx; i++) 00979 { 00980 boundary[i] = new Segment(i, i+1, 1); 00981 boundary[nx+i] = new Segment(m+i, m+i+1, 3); 00982 } 00983 m = nx+1; 00984 for (j = 0; j < ny; j++) 00985 { 00986 boundary[2*nx+j] = new Segment(j*m, (j+1)*m, 4); 00987 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2); 00988 } 00989 00990 MarkTriMeshForRefinement(); 00991 } 00992 00993 CheckElementOrientation(); 00994 00995 if (generate_edges == 1) 00996 { 00997 el_to_edge = new Table; 00998 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 00999 GenerateFaces(); 01000 CheckBdrElementOrientation(); 01001 } 01002 else 01003 NumOfEdges = 0; 01004 01005 NumOfFaces = 0; 01006 01007 attributes.Append(1); 01008 bdr_attributes.Append(1); bdr_attributes.Append(2); 01009 bdr_attributes.Append(3); bdr_attributes.Append(4); 01010 } 01011 01012 Mesh::Mesh(int n) 01013 { 01014 int j, ind[1]; 01015 01016 Dim = 1; 01017 01018 Init(); 01019 InitTables(); 01020 01021 meshgen = 1; 01022 01023 NumOfVertices = n + 1; 01024 NumOfElements = n; 01025 NumOfBdrElements = 2; 01026 vertices.SetSize(NumOfVertices); 01027 elements.SetSize(NumOfElements); 01028 boundary.SetSize(NumOfBdrElements); 01029 01030 // Sets vertices and the corresponding coordinates 01031 for (j = 0; j < n+1; j++) 01032 vertices[j](0) = (double) j / n; 01033 01034 // Sets elements and the corresponding indices of vertices 01035 for (j = 0; j < n; j++) 01036 elements[j] = new Segment(j, j+1, 1); 01037 01038 // Sets the boundary elements 01039 ind[0] = 0; 01040 boundary[0] = new Point(ind, 1); 01041 ind[0] = n; 01042 boundary[1] = new Point(ind, 2); 01043 01044 NumOfEdges = 0; 01045 NumOfFaces = 0; 01046 } 01047 01048 Mesh::Mesh(istream &input, int generate_edges, int refine) 01049 { 01050 Init(); 01051 InitTables(); 01052 Load(input, generate_edges, refine); 01053 } 01054 01055 Element *Mesh::NewElement(int geom) 01056 { 01057 switch (geom) 01058 { 01059 case Geometry::SEGMENT: return (new Segment); 01060 case Geometry::TRIANGLE: return (new Triangle); 01061 case Geometry::SQUARE: return (new Quadrilateral); 01062 case Geometry::CUBE: return (new Hexahedron); 01063 case Geometry::TETRAHEDRON: 01064 #ifdef MFEM_USE_MEMALLOC 01065 return TetMemory.Alloc(); 01066 #else 01067 return (new Tetrahedron); 01068 #endif 01069 } 01070 01071 return NULL; 01072 } 01073 01074 Element *Mesh::ReadElement(istream &input) 01075 { 01076 int attr, geom, nv, *v; 01077 Element *el; 01078 01079 input >> attr >> geom; 01080 el = NewElement(geom); 01081 el->SetAttribute(attr); 01082 nv = el->GetNVertices(); 01083 v = el->GetVertices(); 01084 for (int i = 0; i < nv; i++) 01085 input >> v[i]; 01086 01087 return el; 01088 } 01089 01090 void Mesh::PrintElement(Element *el, ostream &out) 01091 { 01092 out << el->GetAttribute() << ' ' << el->GetGeometryType(); 01093 const int nv = el->GetNVertices(); 01094 const int *v = el->GetVertices(); 01095 for (int j = 0; j < nv; j++) 01096 out << ' ' << v[j]; 01097 out << '\n'; 01098 } 01099 01100 // see Tetrahedron::edges 01101 static const int vtk_quadratic_tet[10] = 01102 { 0, 1, 2, 3, 4, 7, 5, 6, 8, 9 }; 01103 01104 // see Hexahedron::edges & Mesh::GenerateFaces 01105 static const int vtk_quadratic_hex[27] = 01106 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 01107 24, 22, 21, 23, 20, 25, 26 }; 01108 01109 void skip_comment_lines(istream &is, const char comment_char) 01110 { 01111 while(1) 01112 { 01113 is >> ws; 01114 if (is.peek() != comment_char) 01115 break; 01116 is.ignore(numeric_limits<streamsize>::max(), '\n'); 01117 } 01118 } 01119 01120 void Mesh::Load(istream &input, int generate_edges, int refine) 01121 { 01122 int i, j, ints[32], n, attr, curved = 0, read_gf = 1; 01123 const int buflen = 1024; 01124 char buf[buflen]; 01125 01126 #ifdef MFEM_DEBUG 01127 if (!input) 01128 mfem_error("Input file stream not opened : Mesh::Load"); 01129 #endif 01130 01131 if (NumOfVertices != -1) 01132 { 01133 // Delete the elements. 01134 for (i = 0; i < NumOfElements; i++) 01135 // delete elements[i]; 01136 FreeElement(elements[i]); 01137 elements.DeleteAll(); 01138 01139 // Delete the vertices. 01140 vertices.DeleteAll(); 01141 01142 // Delete the boundary elements. 01143 for (i = 0; i < NumOfBdrElements; i++) 01144 // delete boundary[i]; 01145 FreeElement(boundary[i]); 01146 boundary.DeleteAll(); 01147 01148 // Delete interior faces (if generated) 01149 for (i = 0; i < faces.Size(); i++) 01150 FreeElement(faces[i]); 01151 faces.DeleteAll(); 01152 01153 faces_info.DeleteAll(); 01154 01155 // Delete the edges (if generated). 01156 DeleteTables(); 01157 be_to_edge.DeleteAll(); 01158 be_to_face.DeleteAll(); 01159 01160 } 01161 01162 InitTables(); 01163 if (own_nodes) delete Nodes; 01164 Nodes = NULL; 01165 01166 string mesh_type; 01167 input >> ws; 01168 getline(input, mesh_type); 01169 01170 if (mesh_type == "MFEM mesh v1.0") 01171 { 01172 // Read MFEM mesh v1.0 format 01173 string ident; 01174 01175 // read lines begining with '#' (comments) 01176 skip_comment_lines(input, '#'); 01177 01178 input >> ident; // 'dimension' 01179 input >> Dim; 01180 01181 skip_comment_lines(input, '#'); 01182 01183 input >> ident; // 'elements' 01184 input >> NumOfElements; 01185 elements.SetSize(NumOfElements); 01186 for (j = 0; j < NumOfElements; j++) 01187 elements[j] = ReadElement(input); 01188 01189 skip_comment_lines(input, '#'); 01190 01191 input >> ident; // 'boundary' 01192 input >> NumOfBdrElements; 01193 boundary.SetSize(NumOfBdrElements); 01194 for (j = 0; j < NumOfBdrElements; j++) 01195 boundary[j] = ReadElement(input); 01196 01197 skip_comment_lines(input, '#'); 01198 01199 input >> ident; // 'vertices' 01200 input >> NumOfVertices; 01201 vertices.SetSize(NumOfVertices); 01202 01203 input >> ws >> ident; 01204 if (ident != "nodes") 01205 { 01206 // read the vertices 01207 int vdim = atoi(ident.c_str()); 01208 for (j = 0; j < NumOfVertices; j++) 01209 for (i = 0; i < vdim; i++) 01210 input >> vertices[j](i); 01211 } 01212 else 01213 { 01214 // prepare to read the nodes 01215 input >> ws; 01216 curved = 1; 01217 } 01218 } 01219 else if (mesh_type == "linemesh") 01220 { 01221 int j,p1,p2,a; 01222 01223 Dim = 1; 01224 01225 input >> NumOfVertices; 01226 vertices.SetSize(NumOfVertices); 01227 // Sets vertices and the corresponding coordinates 01228 for (j = 0; j < NumOfVertices; j++) 01229 input >> vertices[j](0); 01230 01231 input >> NumOfElements; 01232 elements.SetSize(NumOfElements); 01233 // Sets elements and the corresponding indices of vertices 01234 for (j = 0; j < NumOfElements; j++) 01235 { 01236 input >> a >> p1 >> p2; 01237 elements[j] = new Segment(p1-1, p2-1, a); 01238 } 01239 01240 int ind[1]; 01241 input >> NumOfBdrElements; 01242 boundary.SetSize(NumOfBdrElements); 01243 for (j = 0; j < NumOfBdrElements; j++) 01244 { 01245 input >> a >> ind[0]; 01246 ind[0]--; 01247 boundary[j] = new Point(ind,a); 01248 } 01249 } 01250 else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2") 01251 { 01252 // Read planar mesh in Netgen format. 01253 Dim = 2; 01254 01255 if (mesh_type == "curved_areamesh2") 01256 curved = 1; 01257 01258 // Read the boundary elements. 01259 input >> NumOfBdrElements; 01260 boundary.SetSize(NumOfBdrElements); 01261 for (i = 0; i < NumOfBdrElements; i++) 01262 { 01263 input >> attr 01264 >> ints[0] >> ints[1]; 01265 ints[0]--; ints[1]--; 01266 boundary[i] = new Segment(ints, attr); 01267 } 01268 01269 // Read the elements. 01270 input >> NumOfElements; 01271 elements.SetSize(NumOfElements); 01272 for (i = 0; i < NumOfElements; i++) 01273 { 01274 input >> attr >> n; 01275 for (j = 0; j < n; j++) 01276 { 01277 input >> ints[j]; 01278 ints[j]--; 01279 } 01280 switch (n) 01281 { 01282 case 2: 01283 elements[i] = new Segment(ints, attr); 01284 break; 01285 case 3: 01286 elements[i] = new Triangle(ints, attr); 01287 break; 01288 case 4: 01289 elements[i] = new Quadrilateral(ints, attr); 01290 break; 01291 } 01292 } 01293 01294 if (!curved) 01295 { 01296 // Read the vertices. 01297 input >> NumOfVertices; 01298 vertices.SetSize(NumOfVertices); 01299 for (i = 0; i < NumOfVertices; i++) 01300 for (j = 0; j < Dim; j++) 01301 input >> vertices[i](j); 01302 } 01303 else 01304 { 01305 input >> NumOfVertices; 01306 vertices.SetSize(NumOfVertices); 01307 input >> ws; 01308 } 01309 } 01310 else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format") 01311 { 01312 // Read a netgen format mesh of tetrahedra. 01313 Dim = 3; 01314 01315 // Read the vertices 01316 input >> NumOfVertices; 01317 01318 vertices.SetSize(NumOfVertices); 01319 for (i = 0; i < NumOfVertices; i++) 01320 for (j = 0; j < Dim; j++) 01321 input >> vertices[i](j); 01322 01323 // Read the elements 01324 input >> NumOfElements; 01325 elements.SetSize(NumOfElements); 01326 for (i = 0; i < NumOfElements; i++) 01327 { 01328 input >> attr; 01329 for (j = 0; j < 4; j++) 01330 { 01331 input >> ints[j]; 01332 ints[j]--; 01333 } 01334 #ifdef MFEM_USE_MEMALLOC 01335 Tetrahedron *tet; 01336 tet = TetMemory.Alloc(); 01337 tet->SetVertices(ints); 01338 tet->SetAttribute(attr); 01339 elements[i] = tet; 01340 #else 01341 elements[i] = new Tetrahedron(ints, attr); 01342 #endif 01343 } 01344 01345 // Read the boundary information. 01346 input >> NumOfBdrElements; 01347 boundary.SetSize(NumOfBdrElements); 01348 for (i = 0; i < NumOfBdrElements; i++) 01349 { 01350 input >> attr; 01351 for (j = 0; j < 3; j++) 01352 { 01353 input >> ints[j]; 01354 ints[j]--; 01355 } 01356 boundary[i] = new Triangle(ints, attr); 01357 } 01358 } 01359 else if (mesh_type == "TrueGrid") 01360 { 01361 // Reading TrueGrid mesh. 01362 01363 // TODO: find the actual dimension 01364 Dim = 3; 01365 01366 if (Dim == 2) 01367 { 01368 int vari; 01369 double varf; 01370 01371 input >> vari >> NumOfVertices >> vari >> vari >> NumOfElements; 01372 input.getline(buf, buflen); 01373 input.getline(buf, buflen); 01374 input >> vari; 01375 input.getline(buf, buflen); 01376 input.getline(buf, buflen); 01377 input.getline(buf, buflen); 01378 01379 // Read the vertices. 01380 vertices.SetSize(NumOfVertices); 01381 for (i = 0; i < NumOfVertices; i++) 01382 { 01383 input >> vari >> varf >> vertices[i](0) >> vertices[i](1); 01384 input.getline(buf, buflen); 01385 } 01386 01387 // Read the elements. 01388 elements.SetSize(NumOfElements); 01389 for (i = 0; i < NumOfElements; i++) 01390 { 01391 input >> vari >> attr; 01392 for (j = 0; j < 4; j++) 01393 { 01394 input >> ints[j]; 01395 ints[j]--; 01396 } 01397 input.getline(buf, buflen); 01398 input.getline(buf, buflen); 01399 elements[i] = new Quadrilateral(ints, attr); 01400 } 01401 } 01402 else if (Dim == 3) 01403 { 01404 int vari; 01405 double varf; 01406 input >> vari >> NumOfVertices >> NumOfElements; 01407 input.getline(buf, buflen); 01408 input.getline(buf, buflen); 01409 input >> vari >> vari >> NumOfBdrElements; 01410 input.getline(buf, buflen); 01411 input.getline(buf, buflen); 01412 input.getline(buf, buflen); 01413 // Read the vertices. 01414 vertices.SetSize(NumOfVertices); 01415 for (i = 0; i < NumOfVertices; i++) 01416 { 01417 input >> vari >> varf >> vertices[i](0) >> vertices[i](1) 01418 >> vertices[i](2); 01419 input.getline(buf, buflen); 01420 } 01421 // Read the elements. 01422 elements.SetSize(NumOfElements); 01423 for (i = 0; i < NumOfElements; i++) 01424 { 01425 input >> vari >> attr; 01426 for (j = 0; j < 8; j++) 01427 { 01428 input >> ints[j]; 01429 ints[j]--; 01430 } 01431 input.getline(buf, buflen); 01432 elements[i] = new Hexahedron(ints, attr); 01433 } 01434 // Read the boundary elements. 01435 boundary.SetSize(NumOfBdrElements); 01436 for (i = 0; i < NumOfBdrElements; i++) 01437 { 01438 input >> attr; 01439 for (j = 0; j < 4; j++) 01440 { 01441 input >> ints[j]; 01442 ints[j]--; 01443 } 01444 input.getline(buf, buflen); 01445 boundary[i] = new Quadrilateral(ints, attr); 01446 } 01447 } 01448 } 01449 else if (mesh_type == "# vtk DataFile Version 3.0" || 01450 mesh_type == "# vtk DataFile Version 2.0") 01451 { 01452 // Reading VTK mesh 01453 01454 string buff; 01455 getline(input, buff); // comment line 01456 getline(input, buff); 01457 if (buff != "ASCII") 01458 { 01459 mfem_error("Mesh::Load : VTK mesh is not in ASCII format!"); 01460 return; 01461 } 01462 getline(input, buff); 01463 if (buff != "DATASET UNSTRUCTURED_GRID") 01464 { 01465 mfem_error("Mesh::Load : VTK mesh is not UNSTRUCTURED_GRID!"); 01466 return; 01467 } 01468 01469 // Read the points, skipping optional sections such as the FIELD data from 01470 // VisIt's VTK export (or from Mesh::PrintVTK with field_data==1). 01471 do 01472 { 01473 input >> buff; 01474 if (!input.good()) 01475 mfem_error("Mesh::Load : VTK mesh does not have POINTS data!"); 01476 } 01477 while (buff != "POINTS"); 01478 int np = 0; 01479 Vector points; 01480 { 01481 input >> np >> ws; 01482 points.SetSize(3*np); 01483 getline(input, buff); // "double" 01484 for (i = 0; i < points.Size(); i++) 01485 input >> points(i); 01486 } 01487 01488 // Read the cells 01489 NumOfElements = n = 0; 01490 Array<int> cells_data; 01491 input >> ws >> buff; 01492 if (buff == "CELLS") 01493 { 01494 input >> NumOfElements >> n >> ws; 01495 cells_data.SetSize(n); 01496 for (i = 0; i < n; i++) 01497 input >> cells_data[i]; 01498 } 01499 01500 // Read the cell types 01501 Dim = 0; 01502 int order = 1; 01503 input >> ws >> buff; 01504 if (buff == "CELL_TYPES") 01505 { 01506 input >> NumOfElements; 01507 elements.SetSize(NumOfElements); 01508 for (j = i = 0; i < NumOfElements; i++) 01509 { 01510 int ct; 01511 input >> ct; 01512 switch (ct) 01513 { 01514 case 5: // triangle 01515 Dim = 2; 01516 elements[i] = new Triangle(&cells_data[j+1]); 01517 break; 01518 case 9: // quadrilateral 01519 Dim = 2; 01520 elements[i] = new Quadrilateral(&cells_data[j+1]); 01521 break; 01522 case 10: // tetrahedron 01523 Dim = 3; 01524 #ifdef MFEM_USE_MEMALLOC 01525 elements[i] = TetMemory.Alloc(); 01526 elements[i]->SetVertices(&cells_data[j+1]); 01527 #else 01528 elements[i] = new Tetrahedron(&cells_data[j+1]); 01529 #endif 01530 break; 01531 case 12: // hexahedron 01532 Dim = 3; 01533 elements[i] = new Hexahedron(&cells_data[j+1]); 01534 break; 01535 01536 case 22: // quadratic triangle 01537 Dim = 2; 01538 order = 2; 01539 elements[i] = new Triangle(&cells_data[j+1]); 01540 break; 01541 case 28: // biquadratic quadrilateral 01542 Dim = 2; 01543 order = 2; 01544 elements[i] = new Quadrilateral(&cells_data[j+1]); 01545 break; 01546 case 24: // quadratic tetrahedron 01547 Dim = 3; 01548 order = 2; 01549 #ifdef MFEM_USE_MEMALLOC 01550 elements[i] = TetMemory.Alloc(); 01551 elements[i]->SetVertices(&cells_data[j+1]); 01552 #else 01553 elements[i] = new Tetrahedron(&cells_data[j+1]); 01554 #endif 01555 break; 01556 case 29: // triquadratic hexahedron 01557 Dim = 3; 01558 order = 2; 01559 elements[i] = new Hexahedron(&cells_data[j+1]); 01560 break; 01561 default: 01562 cerr << "Mesh::Load : VTK mesh : cell type " << ct 01563 << " is not supported!" << endl; 01564 mfem_error(); 01565 return; 01566 } 01567 j += cells_data[j] + 1; 01568 } 01569 } 01570 01571 // Read attributes 01572 streampos sp = input.tellg(); 01573 input >> ws >> buff; 01574 if (buff == "CELL_DATA") 01575 { 01576 input >> n >> ws; 01577 getline(input, buff); 01578 if (buff == "SCALARS material int" || buff == "SCALARS material float") 01579 { 01580 getline(input, buff); // "LOOKUP_TABLE default" 01581 for (i = 0; i < NumOfElements; i++) 01582 { 01583 input >> attr; 01584 elements[i]->SetAttribute(attr); 01585 } 01586 } 01587 else 01588 input.seekg(sp); 01589 } 01590 else 01591 input.seekg(sp); 01592 01593 if (order == 1) 01594 { 01595 cells_data.DeleteAll(); 01596 NumOfVertices = np; 01597 vertices.SetSize(np); 01598 for (i = 0; i < np; i++) 01599 { 01600 vertices[i](0) = points(3*i+0); 01601 vertices[i](1) = points(3*i+1); 01602 vertices[i](2) = points(3*i+2); 01603 } 01604 points.Destroy(); 01605 01606 // No boundary is defined in a VTK mesh 01607 NumOfBdrElements = 0; 01608 } 01609 else if (order == 2) 01610 { 01611 curved = 1; 01612 01613 // generate new enumeration for the vertices 01614 Array<int> pts_dof(np); 01615 pts_dof = -1; 01616 for (n = i = 0; i < NumOfElements; i++) 01617 { 01618 int *v = elements[i]->GetVertices(); 01619 int nv = elements[i]->GetNVertices(); 01620 for (j = 0; j < nv; j++) 01621 if (pts_dof[v[j]] == -1) 01622 pts_dof[v[j]] = n++; 01623 } 01624 // keep the original ordering of the vertices 01625 for (n = i = 0; i < np; i++) 01626 if (pts_dof[i] != -1) 01627 pts_dof[i] = n++; 01628 // update the element vertices 01629 for (i = 0; i < NumOfElements; i++) 01630 { 01631 int *v = elements[i]->GetVertices(); 01632 int nv = elements[i]->GetNVertices(); 01633 for (j = 0; j < nv; j++) 01634 v[j] = pts_dof[v[j]]; 01635 } 01636 // Define the 'vertices' from the 'points' through the 'pts_dof' map 01637 NumOfVertices = n; 01638 vertices.SetSize(n); 01639 for (i = 0; i < np; i++) 01640 { 01641 if ((j = pts_dof[i]) != -1) 01642 { 01643 vertices[j](0) = points(3*i+0); 01644 vertices[j](1) = points(3*i+1); 01645 vertices[j](2) = points(3*i+2); 01646 } 01647 } 01648 01649 // No boundary is defined in a VTK mesh 01650 NumOfBdrElements = 0; 01651 01652 // Generate faces and edges so that we can define quadratic 01653 // FE space on the mesh 01654 01655 // Generate faces 01656 if (Dim > 2) 01657 { 01658 GetElementToFaceTable(); 01659 GenerateFaces(); 01660 } 01661 else 01662 NumOfFaces = 0; 01663 01664 // Generate edges 01665 el_to_edge = new Table; 01666 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 01667 if (Dim == 2) 01668 GenerateFaces(); // 'Faces' in 2D refers to the edges 01669 01670 // Define quadratic FE space 01671 FiniteElementCollection *fec = new QuadraticFECollection; 01672 FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim); 01673 Nodes = new GridFunction(fes); 01674 Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes' 01675 own_nodes = 1; 01676 01677 // Map vtk points to edge/face/element dofs 01678 Array<int> dofs; 01679 for (n = i = 0; i < NumOfElements; i++) 01680 { 01681 fes->GetElementDofs(i, dofs); 01682 const int *vtk_mfem; 01683 switch (elements[i]->GetGeometryType()) 01684 { 01685 case Geometry::TRIANGLE: 01686 case Geometry::SQUARE: 01687 vtk_mfem = vtk_quadratic_hex; break; // identity map 01688 case Geometry::TETRAHEDRON: 01689 vtk_mfem = vtk_quadratic_tet; break; 01690 case Geometry::CUBE: 01691 vtk_mfem = vtk_quadratic_hex; break; 01692 } 01693 01694 for (n++, j = 0; j < dofs.Size(); j++, n++) 01695 { 01696 if (pts_dof[cells_data[n]] == -1) 01697 { 01698 pts_dof[cells_data[n]] = dofs[vtk_mfem[j]]; 01699 } 01700 else 01701 { 01702 if (pts_dof[cells_data[n]] != dofs[vtk_mfem[j]]) 01703 mfem_error("Mesh::Load : VTK mesh : " 01704 "inconsistent quadratic mesh!"); 01705 } 01706 } 01707 } 01708 01709 // Define the 'Nodes' from the 'points' through the 'pts_dof' map 01710 for (i = 0; i < np; i++) 01711 { 01712 dofs.SetSize(1); 01713 if ((dofs[0] = pts_dof[i]) != -1) 01714 { 01715 fes->DofsToVDofs(dofs); 01716 for (j = 0; j < dofs.Size(); j++) 01717 (*Nodes)(dofs[j]) = points(3*i+j); 01718 } 01719 } 01720 01721 read_gf = 0; 01722 } 01723 } 01724 else if (mesh_type == "MFEM NURBS mesh v1.0") 01725 { 01726 NURBSext = new NURBSExtension(input); 01727 01728 Dim = NURBSext->Dimension(); 01729 NumOfVertices = NURBSext->GetNV(); 01730 NumOfElements = NURBSext->GetNE(); 01731 NumOfBdrElements = NURBSext->GetNBE(); 01732 01733 NURBSext->GetElementTopo(elements); 01734 NURBSext->GetBdrElementTopo(boundary); 01735 01736 vertices.SetSize(NumOfVertices); 01737 curved = 1; 01738 if (NURBSext->HavePatches()) 01739 { 01740 NURBSFECollection *fec = new NURBSFECollection(NURBSext->GetOrder()); 01741 FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim, 01742 Ordering::byVDIM); 01743 Nodes = new GridFunction(fes); 01744 Nodes->MakeOwner(fec); 01745 NURBSext->SetCoordsFromPatches(*Nodes); 01746 own_nodes = 1; 01747 read_gf = 0; 01748 int vd = Nodes->VectorDim(); 01749 for (i = 0; i < vd; i++) 01750 { 01751 Vector vert_val; 01752 Nodes->GetNodalValues(vert_val, i+1); 01753 for (j = 0; j < NumOfVertices; j++) 01754 vertices[j](i) = vert_val(j); 01755 } 01756 } 01757 else 01758 read_gf = 1; 01759 } 01760 else 01761 { 01762 mfem_error("Mesh::Load : Unknown input mesh format!"); 01763 return; 01764 } 01765 01766 // at this point the following should be defined: 01767 // 1) Dim 01768 // 2) NumOfElements, elements 01769 // 3) NumOfBdrElements, boundary 01770 // 4) NumOfVertices, with allocated space in vertices 01771 // 5) curved 01772 // 5a) if curved == 0, vertices must be defined 01773 // 5b) if curved != 0 and read_gf != 0, 01774 // 'input' must point to a GridFunction 01775 // 5c) if curved != 0 and read_gf == 0, 01776 // vertices and Nodes must be defined 01777 01778 // set the mesh type ('meshgen') 01779 meshgen = 0; 01780 for (i = 0; i < NumOfElements; i++) 01781 { 01782 switch (elements[i]->GetType()) 01783 { 01784 case Element::SEGMENT: 01785 case Element::TRIANGLE: 01786 case Element::TETRAHEDRON: 01787 meshgen |= 1; break; 01788 01789 case Element::QUADRILATERAL: 01790 case Element::HEXAHEDRON: 01791 meshgen |= 2; 01792 } 01793 } 01794 01795 if (NumOfBdrElements == 0 && Dim > 2) 01796 { 01797 // in 3D, generate boundary elements before we 'MarkForRefinement' 01798 GetElementToFaceTable(); 01799 GenerateFaces(); 01800 GenerateBoundaryElements(); 01801 } 01802 01803 if (!curved) 01804 { 01805 // check and fix element orientation 01806 CheckElementOrientation(); 01807 01808 if (refine) 01809 MarkForRefinement(); 01810 } 01811 01812 // generate the faces 01813 if (Dim > 2) 01814 { 01815 GetElementToFaceTable(); 01816 GenerateFaces(); 01817 // check and fix boundary element orientation 01818 if ( !(curved && (meshgen & 1)) ) 01819 CheckBdrElementOrientation(); 01820 } 01821 else 01822 NumOfFaces = 0; 01823 01824 // generate edges if requested 01825 if (Dim > 1 && generate_edges == 1) 01826 { 01827 el_to_edge = new Table; 01828 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 01829 if (Dim == 2) 01830 { 01831 GenerateFaces(); // 'Faces' in 2D refers to the edges 01832 if (NumOfBdrElements == 0) 01833 GenerateBoundaryElements(); 01834 // check and fix boundary element orientation 01835 if ( !(curved && (meshgen & 1)) ) 01836 CheckBdrElementOrientation(); 01837 } 01838 c_el_to_edge = NULL; 01839 } 01840 else 01841 NumOfEdges = 0; 01842 01843 // generate the arrays 'attributes' and ' bdr_attributes' 01844 SetAttributes(); 01845 01846 if (curved) 01847 { 01848 if (read_gf) 01849 { 01850 Nodes = new GridFunction(this, input); 01851 own_nodes = 1; 01852 int vd = Nodes->VectorDim(); 01853 for (i = 0; i < vd; i++) 01854 { 01855 Vector vert_val; 01856 Nodes->GetNodalValues(vert_val, i+1); 01857 for (j = 0; j < NumOfVertices; j++) 01858 vertices[j](i) = vert_val(j); 01859 } 01860 } 01861 01862 // Check orientation and mark edges; only for triangles / tets 01863 if (meshgen & 1) 01864 { 01865 FiniteElementSpace *fes = Nodes->FESpace(); 01866 const FiniteElementCollection *fec = fes->FEColl(); 01867 int num_edge_dofs = fec->DofForGeometry(Geometry::SEGMENT); 01868 DSTable *old_v_to_v = NULL; 01869 if (num_edge_dofs) 01870 { 01871 old_v_to_v = new DSTable(NumOfVertices); 01872 GetVertexToVertexTable(*old_v_to_v); 01873 } 01874 // assuming all faces have the same geometry 01875 int num_face_dofs = 01876 (Dim < 3) ? 0 : fec->DofForGeometry(GetFaceBaseGeometry(0)); 01877 // assuming all elements have the same geometry 01878 int num_elem_dofs = fec->DofForGeometry(GetElementBaseGeometry(0)); 01879 01880 // check orientation and mark for refinement using just vertices 01881 // (i.e. higher order curvature is not used) 01882 CheckElementOrientation(); 01883 if (refine) 01884 MarkForRefinement(); // changes topology! 01885 01886 // reorder the Nodes 01887 Vector onodes = *Nodes; 01888 01889 Array<int> old_dofs, new_dofs; 01890 int offset; 01891 #ifdef MFEM_DEBUG 01892 int redges = 0; 01893 #endif 01894 01895 // vertex dofs do not need to be moved 01896 offset = NumOfVertices * fec->DofForGeometry(Geometry::POINT); 01897 01898 // edge dofs: 01899 // edge enumeration may be different but edge orientation is 01900 // the same 01901 if (num_edge_dofs > 0) 01902 { 01903 DSTable new_v_to_v(NumOfVertices); 01904 GetVertexToVertexTable(new_v_to_v); 01905 01906 for (i = 0; i < NumOfVertices; i++) 01907 { 01908 for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it) 01909 { 01910 int old_i = (*old_v_to_v)(i, it.Column()); 01911 int new_i = it.Index(); 01912 #ifdef MFEM_DEBUG 01913 if (old_i != new_i) 01914 redges++; 01915 #endif 01916 old_dofs.SetSize(num_edge_dofs); 01917 new_dofs.SetSize(num_edge_dofs); 01918 for (j = 0; j < num_edge_dofs; j++) 01919 { 01920 old_dofs[j] = offset + old_i * num_edge_dofs + j; 01921 new_dofs[j] = offset + new_i * num_edge_dofs + j; 01922 } 01923 fes->DofsToVDofs(old_dofs); 01924 fes->DofsToVDofs(new_dofs); 01925 for (j = 0; j < old_dofs.Size(); j++) 01926 (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]); 01927 } 01928 } 01929 offset += NumOfEdges * num_edge_dofs; 01930 delete old_v_to_v; 01931 } 01932 #ifdef MFEM_DEBUG 01933 cout << "Mesh::Load : redges = " << redges << endl; 01934 #endif 01935 01936 // face dofs: 01937 // both enumeration and orientation of the faces 01938 // may be different 01939 if (num_face_dofs > 0) 01940 { 01941 // generate the old face-vertex table 01942 Table old_face_vertex; 01943 old_face_vertex.MakeI(NumOfFaces); 01944 for (i = 0; i < NumOfFaces; i++) 01945 old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices()); 01946 old_face_vertex.MakeJ(); 01947 for (i = 0; i < NumOfFaces; i++) 01948 old_face_vertex.AddConnections(i, faces[i]->GetVertices(), 01949 faces[i]->GetNVertices()); 01950 old_face_vertex.ShiftUpI(); 01951 01952 // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info' 01953 STable3D *faces_tbl = GetElementToFaceTable(1); 01954 GenerateFaces(); 01955 01956 // loop over the old face numbers 01957 for (i = 0; i < NumOfFaces; i++) 01958 { 01959 int *old_v = old_face_vertex.GetRow(i), *new_v; 01960 int new_i, new_or, *dof_ord; 01961 switch (old_face_vertex.RowSize(i)) 01962 { 01963 case 3: 01964 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]); 01965 new_v = faces[new_i]->GetVertices(); 01966 new_or = GetTriOrientation(old_v, new_v); 01967 dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, 01968 new_or); 01969 break; 01970 case 4: 01971 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]); 01972 new_v = faces[new_i]->GetVertices(); 01973 new_or = GetQuadOrientation(old_v, new_v); 01974 dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, 01975 new_or); 01976 break; 01977 } 01978 01979 old_dofs.SetSize(num_face_dofs); 01980 new_dofs.SetSize(num_face_dofs); 01981 for (j = 0; j < num_face_dofs; j++) 01982 { 01983 old_dofs[j] = offset + i * num_face_dofs + j; 01984 new_dofs[j] = offset + new_i * num_face_dofs + dof_ord[j]; 01985 // we assumed the dofs are non-directional 01986 // i.e. dof_ord[j] is >= 0 01987 } 01988 fes->DofsToVDofs(old_dofs); 01989 fes->DofsToVDofs(new_dofs); 01990 for (j = 0; j < old_dofs.Size(); j++) 01991 (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]); 01992 } 01993 01994 offset += NumOfFaces * num_face_dofs; 01995 delete faces_tbl; 01996 } 01997 01998 // element dofs: 01999 // element orientation may be different 02000 if (num_elem_dofs > 0) 02001 { 02002 // matters when the 'fec' is 02003 // (this code is executed only for triangles/tets) 02004 // - Pk on triangles, k >= 4 02005 // - Qk on quads, k >= 3 02006 // - Pk on tets, k >= 5 02007 // - Qk on hexes, k >= 3 02008 // - ... 02009 } 02010 02011 // Update Tables, faces, etc 02012 if (Dim > 2) 02013 { 02014 if (num_face_dofs == 0) 02015 { 02016 // needed for FE spaces that have face dofs, even if 02017 // the 'Nodes' do not have face dofs. 02018 GetElementToFaceTable(); 02019 GenerateFaces(); 02020 } 02021 CheckBdrElementOrientation(); 02022 } 02023 if (el_to_edge) 02024 { 02025 // update 'el_to_edge', 'be_to_edge' (2D), 'bel_to_edge' (3D) 02026 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 02027 if (Dim == 2) 02028 { 02029 // update 'faces' and 'faces_info' 02030 GenerateFaces(); 02031 CheckBdrElementOrientation(); 02032 } 02033 } 02034 } 02035 } 02036 } 02037 02038 Mesh::Mesh(Mesh *mesh_array[], int num_pieces) 02039 { 02040 int i, j, ie, ib, iv, *v, nv; 02041 Element *el; 02042 Mesh *m; 02043 02044 Init(); 02045 InitTables(); 02046 02047 Dim = mesh_array[0]->Dimension(); 02048 02049 if (mesh_array[0]->NURBSext) 02050 { 02051 // assuming the pieces form a partition of a NURBS mesh 02052 NURBSext = new NURBSExtension(mesh_array, num_pieces); 02053 02054 NumOfVertices = NURBSext->GetNV(); 02055 NumOfElements = NURBSext->GetNE(); 02056 02057 NURBSext->GetElementTopo(elements); 02058 02059 // NumOfBdrElements = NURBSext->GetNBE(); 02060 // NURBSext->GetBdrElementTopo(boundary); 02061 02062 Array<int> lvert_vert, lelem_elem; 02063 02064 NumOfBdrElements = 0; 02065 for (i = 0; i < num_pieces; i++) 02066 NumOfBdrElements += mesh_array[i]->GetNBE(); 02067 boundary.SetSize(NumOfBdrElements); 02068 vertices.SetSize(NumOfVertices); 02069 ib = 0; 02070 for (i = 0; i < num_pieces; i++) 02071 { 02072 m = mesh_array[i]; 02073 m->NURBSext->GetVertexLocalToGlobal(lvert_vert); 02074 m->NURBSext->GetElementLocalToGlobal(lelem_elem); 02075 // copy the element attributes 02076 for (j = 0; j < m->GetNE(); j++) 02077 elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j)); 02078 // copy the boundary 02079 for (j = 0; j < m->GetNBE(); j++) 02080 { 02081 el = m->GetBdrElement(j)->Duplicate(this); 02082 v = el->GetVertices(); 02083 nv = el->GetNVertices(); 02084 for (int k = 0; k < nv; k++) 02085 v[k] = lvert_vert[v[k]]; 02086 boundary[ib++] = el; 02087 } 02088 // copy the vertices 02089 for (j = 0; j < m->GetNV(); j++) 02090 vertices[lvert_vert[j]].SetCoords(m->GetVertex(j)); 02091 } 02092 } 02093 else // not a NURBS mesh 02094 { 02095 NumOfElements = 0; 02096 NumOfBdrElements = 0; 02097 NumOfVertices = 0; 02098 for (i = 0; i < num_pieces; i++) 02099 { 02100 m = mesh_array[i]; 02101 NumOfElements += m->GetNE(); 02102 NumOfBdrElements += m->GetNBE(); 02103 NumOfVertices += m->GetNV(); 02104 } 02105 elements.SetSize(NumOfElements); 02106 boundary.SetSize(NumOfBdrElements); 02107 vertices.SetSize(NumOfVertices); 02108 ie = ib = iv = 0; 02109 for (i = 0; i < num_pieces; i++) 02110 { 02111 m = mesh_array[i]; 02112 // copy the elements 02113 for (j = 0; j < m->GetNE(); j++) 02114 { 02115 el = m->GetElement(j)->Duplicate(this); 02116 v = el->GetVertices(); 02117 nv = el->GetNVertices(); 02118 for (int k = 0; k < nv; k++) 02119 v[k] += iv; 02120 elements[ie++] = el; 02121 } 02122 // copy the boundary elements 02123 for (j = 0; j < m->GetNBE(); j++) 02124 { 02125 el = m->GetBdrElement(j)->Duplicate(this); 02126 v = el->GetVertices(); 02127 nv = el->GetNVertices(); 02128 for (int k = 0; k < nv; k++) 02129 v[k] += iv; 02130 boundary[ib++] = el; 02131 } 02132 // copy the vertices 02133 for (j = 0; j < m->GetNV(); j++) 02134 vertices[iv++].SetCoords(m->GetVertex(j)); 02135 } 02136 } 02137 02138 // set the mesh type ('meshgen') 02139 meshgen = 0; 02140 for (i = 0; i < num_pieces; i++) 02141 meshgen |= mesh_array[i]->MeshGenerator(); 02142 02143 // generate faces 02144 if (Dim > 2) 02145 { 02146 GetElementToFaceTable(); 02147 GenerateFaces(); 02148 } 02149 else 02150 NumOfFaces = 0; 02151 02152 // generate edges 02153 if (Dim > 1) 02154 { 02155 el_to_edge = new Table; 02156 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 02157 if (Dim == 2) 02158 GenerateFaces(); // 'Faces' in 2D refers to the edges 02159 } 02160 else 02161 NumOfEdges = 0; 02162 02163 // generate the arrays 'attributes' and ' bdr_attributes' 02164 SetAttributes(); 02165 02166 // copy the nodes (curvilinear meshes) 02167 GridFunction *g = mesh_array[0]->GetNodes(); 02168 if (g) 02169 { 02170 Array<GridFunction *> gf_array(num_pieces); 02171 for (i = 0; i < num_pieces; i++) 02172 gf_array[i] = mesh_array[i]->GetNodes(); 02173 Nodes = new GridFunction(this, gf_array, num_pieces); 02174 own_nodes = 1; 02175 } 02176 } 02177 02178 void Mesh::KnotInsert(Array<KnotVector *> &kv) 02179 { 02180 if (NURBSext == NULL) 02181 mfem_error("Mesh::KnotInsert : Not a NURBS mesh!"); 02182 02183 if (kv.Size() != NURBSext->GetNKV()) 02184 mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!"); 02185 02186 NURBSext->ConvertToPatches(*Nodes); 02187 02188 NURBSext->KnotInsert(kv); 02189 02190 UpdateNURBS(); 02191 } 02192 02193 void Mesh::NURBSUniformRefinement() 02194 { 02195 // do not check for NURBSext since this method is protected 02196 NURBSext->ConvertToPatches(*Nodes); 02197 02198 NURBSext->UniformRefinement(); 02199 02200 UpdateNURBS(); 02201 } 02202 02203 void Mesh::DegreeElevate(int t) 02204 { 02205 if (NURBSext == NULL) 02206 mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!"); 02207 02208 NURBSext->ConvertToPatches(*Nodes); 02209 02210 NURBSext->DegreeElevate(t); 02211 02212 NURBSFECollection *nurbs_fec = 02213 dynamic_cast<NURBSFECollection *>(Nodes->OwnFEC()); 02214 if (!nurbs_fec) 02215 mfem_error("Mesh::DegreeElevate"); 02216 nurbs_fec->UpdateOrder(nurbs_fec->GetOrder() + t); 02217 02218 UpdateNURBS(); 02219 } 02220 02221 void Mesh::UpdateNURBS() 02222 { 02223 NURBSext->SetKnotsFromPatches(); 02224 02225 Dim = NURBSext->Dimension(); 02226 02227 if (NumOfElements != NURBSext->GetNE()) 02228 { 02229 for (int i = 0; i < elements.Size(); i++) 02230 FreeElement(elements[i]); 02231 NumOfElements = NURBSext->GetNE(); 02232 NURBSext->GetElementTopo(elements); 02233 } 02234 02235 if (NumOfBdrElements != NURBSext->GetNBE()) 02236 { 02237 for (int i = 0; i < boundary.Size(); i++) 02238 FreeElement(boundary[i]); 02239 NumOfBdrElements = NURBSext->GetNBE(); 02240 NURBSext->GetBdrElementTopo(boundary); 02241 } 02242 02243 Nodes->FESpace()->Update(); 02244 Nodes->Update(); 02245 NURBSext->SetCoordsFromPatches(*Nodes); 02246 02247 if (NumOfVertices != NURBSext->GetNV()) 02248 { 02249 NumOfVertices = NURBSext->GetNV(); 02250 vertices.SetSize(NumOfVertices); 02251 int vd = Nodes->VectorDim(); 02252 for (int i = 0; i < vd; i++) 02253 { 02254 Vector vert_val; 02255 Nodes->GetNodalValues(vert_val, i+1); 02256 for (int j = 0; j < NumOfVertices; j++) 02257 vertices[j](i) = vert_val(j); 02258 } 02259 } 02260 02261 if (el_to_edge) 02262 { 02263 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 02264 if (Dim == 2) 02265 GenerateFaces(); 02266 } 02267 02268 if (el_to_face) 02269 { 02270 GetElementToFaceTable(); 02271 GenerateFaces(); 02272 } 02273 } 02274 02275 void Mesh::LoadPatchTopo(istream &input, Array<int> &edge_to_knot) 02276 { 02277 Init(); 02278 InitTables(); 02279 02280 int j; 02281 02282 // Read MFEM NURBS mesh v1.0 format 02283 string ident; 02284 02285 skip_comment_lines(input, '#'); 02286 02287 input >> ident; // 'dimension' 02288 input >> Dim; 02289 02290 skip_comment_lines(input, '#'); 02291 02292 input >> ident; // 'elements' 02293 input >> NumOfElements; 02294 elements.SetSize(NumOfElements); 02295 for (j = 0; j < NumOfElements; j++) 02296 elements[j] = ReadElement(input); 02297 02298 skip_comment_lines(input, '#'); 02299 02300 input >> ident; // 'boundary' 02301 input >> NumOfBdrElements; 02302 boundary.SetSize(NumOfBdrElements); 02303 for (j = 0; j < NumOfBdrElements; j++) 02304 boundary[j] = ReadElement(input); 02305 02306 skip_comment_lines(input, '#'); 02307 02308 input >> ident; // 'edges' 02309 input >> NumOfEdges; 02310 edge_vertex = new Table(NumOfEdges, 2); 02311 edge_to_knot.SetSize(NumOfEdges); 02312 for (j = 0; j < NumOfEdges; j++) 02313 { 02314 int *v = edge_vertex->GetRow(j); 02315 input >> edge_to_knot[j] >> v[0] >> v[1]; 02316 if (v[0] > v[1]) 02317 edge_to_knot[j] = -1 - edge_to_knot[j]; 02318 } 02319 02320 skip_comment_lines(input, '#'); 02321 02322 input >> ident; // 'vertices' 02323 input >> NumOfVertices; 02324 vertices.SetSize(0); 02325 02326 meshgen = 2; 02327 02328 // generate the faces 02329 if (Dim > 2) 02330 { 02331 GetElementToFaceTable(); 02332 GenerateFaces(); 02333 if (NumOfBdrElements == 0) 02334 GenerateBoundaryElements(); 02335 CheckBdrElementOrientation(); 02336 } 02337 else 02338 NumOfFaces = 0; 02339 02340 // generate edges 02341 if (Dim > 1) 02342 { 02343 el_to_edge = new Table; 02344 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 02345 if (Dim < 3) 02346 { 02347 GenerateFaces(); 02348 if (NumOfBdrElements == 0) 02349 GenerateBoundaryElements(); 02350 CheckBdrElementOrientation(); 02351 } 02352 } 02353 else 02354 NumOfEdges = 0; 02355 02356 // generate the arrays 'attributes' and ' bdr_attributes' 02357 SetAttributes(); 02358 } 02359 02360 void XYZ_VectorFunction(const Vector &p, Vector &v) 02361 { 02362 v = p; 02363 } 02364 02365 void Mesh::SetNodalFESpace(FiniteElementSpace *nfes) 02366 { 02367 GridFunction *nodes = new GridFunction(nfes); 02368 VectorFunctionCoefficient xyz(Dim, XYZ_VectorFunction); 02369 nodes->ProjectCoefficient(xyz); 02370 02371 if (own_nodes) delete Nodes; 02372 Nodes = nodes; 02373 own_nodes = 1; 02374 } 02375 02376 void Mesh::SetNodalGridFunction(GridFunction *nodes) 02377 { 02378 if (Nodes == NULL || Nodes->FESpace() != nodes->FESpace()) 02379 { 02380 VectorFunctionCoefficient xyz(Dim, XYZ_VectorFunction); 02381 nodes->ProjectCoefficient(xyz); 02382 } 02383 else 02384 *nodes = *Nodes; 02385 02386 if (own_nodes) delete Nodes; 02387 Nodes = nodes; 02388 own_nodes = 0; 02389 } 02390 02391 const FiniteElementSpace *Mesh::GetNodalFESpace() 02392 { 02393 return ((Nodes) ? Nodes->FESpace() : NULL); 02394 } 02395 02396 void Mesh::CheckElementOrientation() 02397 { 02398 int i, j, k, wo = 0, *vi; 02399 double *v[4]; 02400 02401 if (Dim == 2) 02402 { 02403 DenseMatrix tri(2, 2); 02404 02405 for (i = 0; i < NumOfElements; i++) 02406 { 02407 vi = elements[i]->GetVertices(); 02408 for (j = 0; j < 3; j++) 02409 v[j] = vertices[vi[j]](); 02410 for (j = 0; j < 2; j++) 02411 for (k = 0; k < 2; k++) 02412 tri(j, k) = v[j+1][k] - v[0][k]; 02413 if (tri.Det() < 0.0) 02414 switch (GetElementType(i)) 02415 { 02416 case Element::TRIANGLE: 02417 k = vi[0], vi[0] = vi[1], vi[1] = k, wo++; 02418 break; 02419 case Element::QUADRILATERAL: 02420 k = vi[1], vi[1] = vi[3], vi[3] = k, wo++; 02421 break; 02422 } 02423 } 02424 } 02425 02426 if (Dim == 3) 02427 { 02428 DenseMatrix tet(3, 3); 02429 02430 for (i = 0; i < NumOfElements; i++) 02431 { 02432 vi = elements[i]->GetVertices(); 02433 switch (GetElementType(i)) 02434 { 02435 case Element::TETRAHEDRON: 02436 for (j = 0; j < 4; j++) 02437 v[j] = vertices[vi[j]](); 02438 for (j = 0; j < 3; j++) 02439 for (k = 0; k < 3; k++) 02440 tet(j, k) = v[j+1][k] - v[0][k]; 02441 if (tet.Det() < 0.0) 02442 k = vi[0], vi[0] = vi[1], vi[1] = k, wo++; 02443 break; 02444 case Element::HEXAHEDRON: 02445 // to do ... 02446 break; 02447 } 02448 } 02449 } 02450 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG)) 02451 if (wo > 0) 02452 cout << "Orientation fixed in " << wo << " of "<< NumOfElements 02453 << " elements" << endl; 02454 #endif 02455 } 02456 02457 int Mesh::GetTriOrientation(const int *base, const int *test) 02458 { 02459 int orient; 02460 02461 if (test[0] == base[0]) 02462 if (test[1] == base[1]) 02463 orient = 0; // (0, 1, 2) 02464 else 02465 orient = 5; // (0, 2, 1) 02466 else if (test[0] == base[1]) 02467 if (test[1] == base[0]) 02468 orient = 1; // (1, 0, 2) 02469 else 02470 orient = 2; // (1, 2, 0) 02471 else // test[0] == base[2] 02472 if (test[1] == base[0]) 02473 orient = 4; // (2, 0, 1) 02474 else 02475 orient = 3; // (2, 1, 0) 02476 02477 #ifdef MFEM_DEBUG 02478 static const int tri_orient[6][3] = {{0, 1, 2}, {1, 0, 2}, 02479 {2, 0, 1}, {2, 1, 0}, 02480 {1, 2, 0}, {0, 2, 1}}; 02481 const int *aor = tri_orient[orient]; 02482 for (int j = 0; j < 3; j++) 02483 if (test[aor[j]] != base[j]) 02484 mfem_error("Mesh::GetTriOrientation(...)"); 02485 #endif 02486 02487 return orient; 02488 } 02489 02490 int Mesh::GetQuadOrientation(const int *base, const int *test) 02491 { 02492 int i; 02493 02494 for (i = 0; i < 4; i++) 02495 if (test[i] == base[0]) 02496 break; 02497 02498 #ifdef MFEM_DEBUG 02499 static const int quad_orient[8][4] = {{0, 1, 2, 3}, {0, 3, 2, 1}, 02500 {1, 2, 3, 0}, {1, 0, 3, 2}, 02501 {2, 3, 0, 1}, {2, 1, 0, 3}, 02502 {3, 0, 1, 2}, {3, 2, 1, 0}}; 02503 int orient; 02504 if (test[(i+1)%4] == base[1]) 02505 orient = 2*i; 02506 else 02507 orient = 2*i+1; 02508 const int *aor = quad_orient[orient]; 02509 for (int j = 0; j < 4; j++) 02510 if (test[aor[j]] != base[j]) 02511 { 02512 cerr << "Mesh::GetQuadOrientation(...)" << endl; 02513 cerr << " base = ["; 02514 for (int k = 0; k < 4; k++) 02515 cerr << " " << base[k]; 02516 cerr << " ]\n test = ["; 02517 for (int k = 0; k < 4; k++) 02518 cerr << " " << test[k]; 02519 cerr << " ]" << endl; 02520 mfem_error(); 02521 } 02522 #endif 02523 02524 if (test[(i+1)%4] == base[1]) 02525 return 2*i; 02526 02527 return 2*i+1; 02528 } 02529 02530 void Mesh::CheckBdrElementOrientation() 02531 { 02532 int i, j, wo = 0; 02533 02534 if (Dim == 2) 02535 { 02536 for (i = 0; i < NumOfBdrElements; i++) 02537 { 02538 if (faces_info[be_to_edge[i]].Elem2No < 0) // boundary face 02539 { 02540 int *bv = boundary[i]->GetVertices(); 02541 int *fv = faces[be_to_edge[i]]->GetVertices(); 02542 if (bv[0] != fv[0]) 02543 { 02544 j = bv[0]; bv[0] = bv[1]; bv[1] = j; 02545 wo++; 02546 } 02547 } 02548 } 02549 } 02550 02551 if (Dim == 3) 02552 { 02553 int el, *bv, *ev; 02554 int v[4]; 02555 02556 for (i = 0; i < NumOfBdrElements; i++) 02557 { 02558 if (faces_info[be_to_face[i]].Elem2No < 0) 02559 { // boundary face 02560 bv = boundary[i]->GetVertices(); 02561 el = faces_info[be_to_face[i]].Elem1No; 02562 ev = elements[el]->GetVertices(); 02563 switch (GetElementType(el)) 02564 { 02565 case Element::TETRAHEDRON: 02566 { 02567 int *fv = faces[be_to_face[i]]->GetVertices(); 02568 int orientation; // orientation of the bdr. elem. w.r.t. the 02569 // corresponding face element (that's the base) 02570 orientation = GetTriOrientation(fv, bv); 02571 if (orientation % 2) 02572 { 02573 // wrong orientation -- swap vertices 0 and 1 so that 02574 // we don't change the marked edge: (0,1,2) -> (1,0,2) 02575 Swap<int>(bv[0], bv[1]); 02576 wo++; 02577 } 02578 } 02579 break; 02580 02581 case Element::HEXAHEDRON: 02582 switch (faces_info[be_to_face[i]].Elem1Inf/64) 02583 { 02584 case 0: 02585 v[0] = ev[3]; v[1] = ev[2]; v[2] = ev[1]; v[3] = ev[0]; 02586 break; 02587 case 1: 02588 v[0] = ev[0]; v[1] = ev[1]; v[2] = ev[5]; v[3] = ev[4]; 02589 break; 02590 case 2: 02591 v[0] = ev[1]; v[1] = ev[2]; v[2] = ev[6]; v[3] = ev[5]; 02592 break; 02593 case 3: 02594 v[0] = ev[2]; v[1] = ev[3]; v[2] = ev[7]; v[3] = ev[6]; 02595 break; 02596 case 4: 02597 v[0] = ev[3]; v[1] = ev[0]; v[2] = ev[4]; v[3] = ev[7]; 02598 break; 02599 case 5: 02600 v[0] = ev[4]; v[1] = ev[5]; v[2] = ev[6]; v[3] = ev[7]; 02601 break; 02602 } 02603 if (GetQuadOrientation(v, bv) % 2) 02604 { 02605 j = bv[0]; bv[0] = bv[2]; bv[2] = j; 02606 wo++; 02607 } 02608 break; 02609 } 02610 } 02611 } 02612 } 02613 // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG)) 02614 #ifdef MFEM_DEBUG 02615 if (wo > 0) 02616 cout << "Orientation fixed in " << wo << " of "<< NumOfBdrElements 02617 << " boundary elements" << endl; 02618 #endif 02619 } 02620 02621 void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) 02622 const 02623 { 02624 if (el_to_edge) 02625 el_to_edge->GetRow(i, edges); 02626 else 02627 mfem_error("Mesh::GetElementEdges(...) element to edge table " 02628 "is not generated."); 02629 02630 const int *v = elements[i]->GetVertices(); 02631 const int ne = elements[i]->GetNEdges(); 02632 cor.SetSize(ne); 02633 for (int j = 0; j < ne; j++) 02634 { 02635 const int *e = elements[i]->GetEdgeVertices(j); 02636 cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1); 02637 } 02638 } 02639 02640 void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) 02641 const 02642 { 02643 if (Dim == 2) 02644 { 02645 edges.SetSize(1); 02646 cor.SetSize(1); 02647 edges[0] = be_to_edge[i]; 02648 const int *v = boundary[i]->GetVertices(); 02649 cor[0] = (v[0] < v[1]) ? (1) : (-1); 02650 } 02651 else if (Dim == 3) 02652 { 02653 if (bel_to_edge) 02654 bel_to_edge->GetRow(i, edges); 02655 else 02656 mfem_error("Mesh::GetBdrElementEdges(...)"); 02657 02658 const int *v = boundary[i]->GetVertices(); 02659 const int ne = boundary[i]->GetNEdges(); 02660 cor.SetSize(ne); 02661 for (int j = 0; j < ne; j++) 02662 { 02663 const int *e = boundary[i]->GetEdgeVertices(j); 02664 cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1); 02665 } 02666 } 02667 } 02668 02669 void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const 02670 { 02671 if (Dim != 3) 02672 return; 02673 02674 GetFaceEdgeTable(); // generate face_edge Table (if not generated) 02675 02676 face_edge->GetRow(i, edges); 02677 02678 const int *v = faces[i]->GetVertices(); 02679 const int ne = faces[i]->GetNEdges(); 02680 o.SetSize(ne); 02681 for (int j = 0; j < ne; j++) 02682 { 02683 const int *e = faces[i]->GetEdgeVertices(j); 02684 o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1); 02685 } 02686 } 02687 02688 void Mesh::GetEdgeVertices(int i, Array<int> &vert) const 02689 { 02690 if (Dim == 2 && faces.Size() == NumOfEdges) 02691 { 02692 faces[i]->GetVertices(vert); 02693 } 02694 else 02695 { 02696 GetEdgeVertexTable(); // generate edge_vertex Table (if not generated) 02697 02698 edge_vertex->GetRow(i, vert); 02699 } 02700 } 02701 02702 Table *Mesh::GetFaceEdgeTable() const 02703 { 02704 if (face_edge) 02705 return face_edge; 02706 02707 if (Dim != 3) 02708 return NULL; 02709 02710 #ifdef MFEM_DEBUG 02711 if (faces.Size() != NumOfFaces) 02712 mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!"); 02713 #endif 02714 02715 DSTable v_to_v(NumOfVertices); 02716 GetVertexToVertexTable(v_to_v); 02717 02718 face_edge = new Table; 02719 GetElementArrayEdgeTable(faces, v_to_v, *face_edge); 02720 02721 return(face_edge); 02722 } 02723 02724 Table *Mesh::GetEdgeVertexTable() const 02725 { 02726 if (edge_vertex) 02727 return edge_vertex; 02728 02729 DSTable v_to_v(NumOfVertices); 02730 GetVertexToVertexTable(v_to_v); 02731 02732 int nedges = v_to_v.NumberOfEntries(); 02733 edge_vertex = new Table(nedges, 2); 02734 for (int i = 0; i < NumOfVertices; i++) 02735 { 02736 for (DSTable::RowIterator it(v_to_v, i); !it; ++it) 02737 { 02738 int j = it.Index(); 02739 edge_vertex->Push(j, i); 02740 edge_vertex->Push(j, it.Column()); 02741 } 02742 } 02743 edge_vertex->Finalize(); 02744 02745 return edge_vertex; 02746 } 02747 02748 Table *Mesh::GetVertexToElementTable() 02749 { 02750 int i, j, nv, *v; 02751 02752 Table *vert_elem = new Table; 02753 02754 vert_elem->MakeI(NumOfVertices); 02755 02756 for (i = 0; i < NumOfElements; i++) 02757 { 02758 nv = elements[i]->GetNVertices(); 02759 v = elements[i]->GetVertices(); 02760 for (j = 0; j < nv; j++) 02761 vert_elem->AddAColumnInRow(v[j]); 02762 } 02763 02764 vert_elem->MakeJ(); 02765 02766 for (i = 0; i < NumOfElements; i++) 02767 { 02768 nv = elements[i]->GetNVertices(); 02769 v = elements[i]->GetVertices(); 02770 for (j = 0; j < nv; j++) 02771 vert_elem->AddConnection(v[j], i); 02772 } 02773 02774 vert_elem->ShiftUpI(); 02775 02776 return vert_elem; 02777 } 02778 02779 void Mesh::GetElementFaces(int i, Array<int> &fcs, Array<int> &cor) 02780 const 02781 { 02782 int n, j; 02783 02784 if (el_to_face) 02785 el_to_face->GetRow(i, fcs); 02786 else 02787 mfem_error("Mesh::GetElementFaces(...) : el_to_face not generated."); 02788 02789 n = fcs.Size(); 02790 cor.SetSize(n); 02791 for (j = 0; j < n; j++) 02792 if (faces_info[fcs[j]].Elem1No == i) 02793 cor[j] = faces_info[fcs[j]].Elem1Inf % 64; 02794 #ifdef MFEM_DEBUG 02795 else if (faces_info[fcs[j]].Elem2No == i) 02796 cor[j] = faces_info[fcs[j]].Elem2Inf % 64; 02797 else 02798 mfem_error("Mesh::GetElementFaces(...) : 2"); 02799 #else 02800 else 02801 cor[j] = faces_info[fcs[j]].Elem2Inf % 64; 02802 #endif 02803 } 02804 02805 void Mesh::GetBdrElementFace(int i, int *f, int *o) const 02806 { 02807 const int *bv, *fv; 02808 02809 if (State == Mesh::TWO_LEVEL_COARSE) 02810 { 02811 // the coarse level 'be_to_face' and 'faces' are destroyed 02812 mfem_error("Mesh::GetBdrElementFace (...)"); 02813 } 02814 02815 *f = be_to_face[i]; 02816 bv = boundary[i]->GetVertices(); 02817 fv = faces[be_to_face[i]]->GetVertices(); 02818 02819 // find the orientation of the bdr. elem. w.r.t. 02820 // the corresponding face element (that's the base) 02821 switch (GetBdrElementType(i)) 02822 { 02823 case Element::TRIANGLE: 02824 *o = GetTriOrientation(fv, bv); 02825 break; 02826 case Element::QUADRILATERAL: 02827 *o = GetQuadOrientation(fv, bv); 02828 break; 02829 default: 02830 mfem_error("Mesh::GetBdrElementFace(...) 2"); 02831 } 02832 } 02833 02834 int Mesh::GetFaceBaseGeometry(int i) const 02835 { 02836 // Here, we assume all faces are of the same type 02837 switch (GetElementType(0)) 02838 { 02839 case Element::TRIANGLE: 02840 case Element::QUADRILATERAL: 02841 return Geometry::SEGMENT; // in 2D 'face' is an edge 02842 02843 case Element::TETRAHEDRON: 02844 return Geometry::TRIANGLE; 02845 case Element::HEXAHEDRON: 02846 return Geometry::SQUARE; 02847 default: 02848 mfem_error("Mesh::GetFaceBaseGeometry(...) #1"); 02849 } 02850 return(-1); 02851 #if 0 02852 if (faces[i] == NULL) 02853 switch (GetElementType(faces_info[i].Elem1No)) 02854 { 02855 case Element::TETRAHEDRON: 02856 return Geometry::TRIANGLE; 02857 case Element::HEXAHEDRON: 02858 return Geometry::SQUARE; 02859 default: 02860 mfem_error("Mesh::GetFaceBaseGeometry(...) #2"); 02861 } 02862 else 02863 return faces[i]->GetGeometryType(); 02864 #endif 02865 } 02866 02867 int Mesh::GetBdrElementEdgeIndex(int i) const 02868 { 02869 if (Dim == 2) 02870 return be_to_edge[i]; 02871 return be_to_face[i]; 02872 } 02873 02874 int Mesh::GetElementType(int i) const 02875 { 02876 Element *El = elements[i]; 02877 int t = El->GetType(); 02878 02879 while (1) 02880 if (t == Element::BISECTED || 02881 t == Element::QUADRISECTED || 02882 t == Element::OCTASECTED) 02883 t = (El = ((RefinedElement *) El)->IAm())->GetType(); 02884 else 02885 break; 02886 return t; 02887 } 02888 02889 int Mesh::GetBdrElementType(int i) const 02890 { 02891 Element *El = boundary[i]; 02892 int t = El->GetType(); 02893 02894 while (1) 02895 if (t == Element::BISECTED || t == Element::QUADRISECTED) 02896 t = (El = ((RefinedElement *) El)->IAm())->GetType(); 02897 else 02898 break; 02899 return t; 02900 } 02901 02902 void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const 02903 { 02904 int k, j, nv; 02905 const int *v; 02906 02907 v = elements[i]->GetVertices(); 02908 nv = elements[i]->GetNVertices(); 02909 02910 pointmat.SetSize(Dim, nv); 02911 for (k = 0; k < Dim; k++) 02912 for (j = 0; j < nv; j++) 02913 pointmat(k, j) = vertices[v[j]](k); 02914 } 02915 02916 void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const 02917 { 02918 int k, j, nv; 02919 const int *v; 02920 02921 v = boundary[i]->GetVertices(); 02922 nv = boundary[i]->GetNVertices(); 02923 02924 pointmat.SetSize(Dim, nv); 02925 for (k = 0; k < Dim; k++) 02926 for (j = 0; j < nv; j++) 02927 pointmat(k, j) = vertices[v[j]](k); 02928 } 02929 02930 double Mesh::GetLength(int i, int j) const 02931 { 02932 const double *vi = vertices[i](); 02933 const double *vj = vertices[j](); 02934 double length = 0.; 02935 02936 for (int k = 0; k < Dim; k++) 02937 length += (vi[k]-vj[k])*(vi[k]-vj[k]); 02938 02939 return sqrt(length); 02940 } 02941 02942 // static method 02943 void Mesh::GetElementArrayEdgeTable(const Array<Element*> &elem_array, 02944 const DSTable &v_to_v, Table &el_to_edge) 02945 { 02946 el_to_edge.MakeI(elem_array.Size()); 02947 for (int i = 0; i < elem_array.Size(); i++) 02948 { 02949 el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges()); 02950 } 02951 el_to_edge.MakeJ(); 02952 for (int i = 0; i < elem_array.Size(); i++) 02953 { 02954 const int *v = elem_array[i]->GetVertices(); 02955 const int ne = elem_array[i]->GetNEdges(); 02956 for (int j = 0; j < ne; j++) 02957 { 02958 const int *e = elem_array[i]->GetEdgeVertices(j); 02959 el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]])); 02960 } 02961 } 02962 el_to_edge.ShiftUpI(); 02963 } 02964 02965 void Mesh::GetVertexToVertexTable(DSTable &v_to_v) const 02966 { 02967 if (edge_vertex) 02968 { 02969 for (int i = 0; i < edge_vertex->Size(); i++) 02970 { 02971 const int *v = edge_vertex->GetRow(i); 02972 v_to_v.Push(v[0], v[1]); 02973 } 02974 } 02975 else 02976 { 02977 for (int i = 0; i < NumOfElements; i++) 02978 { 02979 const int *v = elements[i]->GetVertices(); 02980 const int ne = elements[i]->GetNEdges(); 02981 for (int j = 0; j < ne; j++) 02982 { 02983 const int *e = elements[i]->GetEdgeVertices(j); 02984 v_to_v.Push(v[e[0]], v[e[1]]); 02985 } 02986 } 02987 } 02988 } 02989 02990 int Mesh::GetElementToEdgeTable(Table & e_to_f, Array<int> &be_to_f) 02991 { 02992 int i, NumberOfEdges; 02993 02994 DSTable v_to_v(NumOfVertices); 02995 GetVertexToVertexTable(v_to_v); 02996 02997 NumberOfEdges = v_to_v.NumberOfEntries(); 02998 02999 // Fill the element to edge table 03000 GetElementArrayEdgeTable(elements, v_to_v, e_to_f); 03001 03002 if (Dim == 2) 03003 { 03004 // Initialize the indeces for the boundary elements. 03005 be_to_f.SetSize(NumOfBdrElements); 03006 for (i = 0; i < NumOfBdrElements; i++) 03007 { 03008 const int *v = boundary[i]->GetVertices(); 03009 be_to_f[i] = v_to_v(v[0], v[1]); 03010 } 03011 } 03012 else if (Dim == 3) 03013 { 03014 if (bel_to_edge == NULL) 03015 bel_to_edge = new Table; 03016 GetElementArrayEdgeTable(boundary, v_to_v, *bel_to_edge); 03017 } 03018 else 03019 mfem_error("1D GetElementToEdgeTable is not yet implemented."); 03020 03021 // Return the number of edges 03022 return NumberOfEdges; 03023 } 03024 03025 const Table & Mesh::ElementToElementTable() 03026 { 03027 if (el_to_el) 03028 return *el_to_el; 03029 03030 if (Dim == 2) 03031 { 03032 Table edge_el; 03033 03034 Transpose(ElementToEdgeTable(), edge_el); 03035 el_to_el = new Table(NumOfElements, 4); // 4 is the max. # of edges 03036 03037 for (int i = 0; i < edge_el.Size(); i++) 03038 if (edge_el.RowSize(i) > 1) 03039 { 03040 const int *el = edge_el.GetRow(i); 03041 el_to_el->Push(el[0], el[1]); 03042 el_to_el->Push(el[1], el[0]); 03043 } 03044 03045 el_to_el->Finalize(); 03046 } 03047 else if (Dim == 3) 03048 { 03049 el_to_el = new Table(NumOfElements, 6); // 6 is the max. # of faces 03050 03051 #ifdef MFEM_DEBUG 03052 if (faces_info.Size() != NumOfFaces) 03053 mfem_error("Mesh::ElementToElementTable : faces were not generated!"); 03054 #endif 03055 03056 for (int i = 0; i < faces_info.Size(); i++) 03057 if (faces_info[i].Elem2No >= 0) 03058 { 03059 el_to_el->Push(faces_info[i].Elem1No, faces_info[i].Elem2No); 03060 el_to_el->Push(faces_info[i].Elem2No, faces_info[i].Elem1No); 03061 } 03062 03063 el_to_el->Finalize(); 03064 } 03065 else 03066 mfem_error("Mesh::ElementToElementTable() in 1D is not implemented!"); 03067 03068 return *el_to_el; 03069 } 03070 03071 const Table & Mesh::ElementToFaceTable() const 03072 { 03073 if (el_to_face == NULL) 03074 mfem_error("Mesh::ElementToFaceTable()"); 03075 return *el_to_face; 03076 } 03077 03078 const Table & Mesh::ElementToEdgeTable() const 03079 { 03080 if (el_to_edge == NULL) 03081 mfem_error("Mesh::ElementToEdgeTable()"); 03082 return *el_to_edge; 03083 } 03084 03085 void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1) 03086 { 03087 if (faces[gf] == NULL) // this will be elem1 03088 { 03089 faces[gf] = new Segment(v0, v1); 03090 faces_info[gf].Elem1No = el; 03091 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0 03092 faces_info[gf].Elem2No = -1; // in case there's no other side 03093 } 03094 else // this will be elem2 03095 { 03096 #ifdef MFEM_DEBUG 03097 int *v = faces[gf]->GetVertices(); 03098 if (v[1] != v0 || v[0] != v1) 03099 mfem_error("Mesh::AddSegmentFaceElement(...)"); 03100 #endif 03101 faces_info[gf].Elem2No = el; 03102 faces_info[gf].Elem2Inf = 64 * lf + 1; 03103 } 03104 } 03105 03106 void Mesh::AddTriangleFaceElement(int lf, int gf, int el, 03107 int v0, int v1, int v2) 03108 { 03109 if (faces[gf] == NULL) // this will be elem1 03110 { 03111 faces[gf] = new Triangle(v0, v1, v2); 03112 faces_info[gf].Elem1No = el; 03113 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0 03114 faces_info[gf].Elem2No = -1; // in case there's no other side 03115 } 03116 else // this will be elem2 03117 { 03118 int orientation, vv[3] = { v0, v1, v2 }; 03119 orientation = GetTriOrientation(faces[gf]->GetVertices(), vv); 03120 #ifdef MFEM_DEBUG 03121 if (orientation % 2 == 0) 03122 mfem_error("Mesh::AddTriangleFaceElement(...)"); 03123 #endif 03124 faces_info[gf].Elem2No = el; 03125 faces_info[gf].Elem2Inf = 64 * lf + orientation; 03126 } 03127 } 03128 03129 void Mesh::AddQuadFaceElement(int lf, int gf, int el, 03130 int v0, int v1, int v2, int v3) 03131 { 03132 if (faces_info[gf].Elem1No < 0) // this will be elem1 03133 { 03134 faces[gf] = new Quadrilateral(v0, v1, v2, v3); 03135 faces_info[gf].Elem1No = el; 03136 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0 03137 faces_info[gf].Elem2No = -1; // in case there's no other side 03138 } 03139 else // this will be elem2 03140 { 03141 int vv[4] = { v0, v1, v2, v3 }; 03142 int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv); 03143 #ifdef MFEM_DEBUG 03144 if (oo % 2 == 0) 03145 mfem_error("Mesh::AddQuadFaceElement(...)"); 03146 #endif 03147 faces_info[gf].Elem2No = el; 03148 faces_info[gf].Elem2Inf = 64 * lf + oo; 03149 } 03150 } 03151 03152 void Mesh::GenerateFaces() 03153 { 03154 int i, nfaces; 03155 03156 nfaces = (Dim == 2) ? NumOfEdges : NumOfFaces; 03157 03158 for (i = 0; i < faces.Size(); i++) 03159 FreeElement(faces[i]); 03160 03161 // (re)generate the interior faces and the info for them 03162 faces.SetSize(nfaces); 03163 faces_info.SetSize(nfaces); 03164 for (i = 0; i < nfaces; i++) 03165 { 03166 faces[i] = NULL; 03167 faces_info[i].Elem1No = -1; 03168 } 03169 for (i = 0; i < NumOfElements; i++) 03170 { 03171 const int *v = elements[i]->GetVertices(); 03172 const int *ef; 03173 if (Dim == 2) 03174 { 03175 ef = el_to_edge->GetRow(i); 03176 const int ne = elements[i]->GetNEdges(); 03177 for (int j = 0; j < ne; j++) 03178 { 03179 const int *e = elements[i]->GetEdgeVertices(j); 03180 AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]); 03181 } 03182 } 03183 else 03184 { 03185 ef = el_to_face->GetRow(i); 03186 switch (GetElementType(i)) 03187 { 03188 case Element::TETRAHEDRON: 03189 AddTriangleFaceElement(0, ef[0], i, v[1], v[2], v[3]); 03190 AddTriangleFaceElement(1, ef[1], i, v[0], v[3], v[2]); 03191 AddTriangleFaceElement(2, ef[2], i, v[0], v[1], v[3]); 03192 AddTriangleFaceElement(3, ef[3], i, v[0], v[2], v[1]); 03193 break; 03194 case Element::HEXAHEDRON: 03195 AddQuadFaceElement(0, ef[0], i, v[3], v[2], v[1], v[0]); 03196 AddQuadFaceElement(1, ef[1], i, v[0], v[1], v[5], v[4]); 03197 AddQuadFaceElement(2, ef[2], i, v[1], v[2], v[6], v[5]); 03198 AddQuadFaceElement(3, ef[3], i, v[2], v[3], v[7], v[6]); 03199 AddQuadFaceElement(4, ef[4], i, v[3], v[0], v[4], v[7]); 03200 AddQuadFaceElement(5, ef[5], i, v[4], v[5], v[6], v[7]); 03201 break; 03202 } 03203 } 03204 } 03205 } 03206 03207 STable3D *Mesh::GetFacesTable() 03208 { 03209 STable3D *faces_tbl = new STable3D(NumOfVertices); 03210 for (int i = 0; i < NumOfElements; i++) 03211 { 03212 const int *v = elements[i]->GetVertices(); 03213 switch (GetElementType(i)) 03214 { 03215 case Element::TETRAHEDRON: 03216 faces_tbl->Push(v[1], v[2], v[3]); 03217 faces_tbl->Push(v[0], v[3], v[2]); 03218 faces_tbl->Push(v[0], v[1], v[3]); 03219 faces_tbl->Push(v[0], v[2], v[1]); 03220 break; 03221 case Element::HEXAHEDRON: 03222 // find the face by the vertices with the smallest 3 numbers 03223 // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1 03224 faces_tbl->Push4(v[3], v[2], v[1], v[0]); 03225 faces_tbl->Push4(v[0], v[1], v[5], v[4]); 03226 faces_tbl->Push4(v[1], v[2], v[6], v[5]); 03227 faces_tbl->Push4(v[2], v[3], v[7], v[6]); 03228 faces_tbl->Push4(v[3], v[0], v[4], v[7]); 03229 faces_tbl->Push4(v[4], v[5], v[6], v[7]); 03230 break; 03231 } 03232 } 03233 return faces_tbl; 03234 } 03235 03236 STable3D *Mesh::GetElementToFaceTable(int ret_ftbl) 03237 { 03238 int i, *v; 03239 STable3D *faces_tbl; 03240 03241 if (el_to_face != NULL) 03242 delete el_to_face; 03243 el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra 03244 faces_tbl = new STable3D(NumOfVertices); 03245 for (i = 0; i < NumOfElements; i++) 03246 { 03247 v = elements[i]->GetVertices(); 03248 switch (GetElementType(i)) 03249 { 03250 case Element::TETRAHEDRON: 03251 el_to_face->Push(i, faces_tbl->Push(v[1], v[2], v[3])); 03252 el_to_face->Push(i, faces_tbl->Push(v[0], v[3], v[2])); 03253 el_to_face->Push(i, faces_tbl->Push(v[0], v[1], v[3])); 03254 el_to_face->Push(i, faces_tbl->Push(v[0], v[2], v[1])); 03255 break; 03256 case Element::HEXAHEDRON: 03257 // find the face by the vertices with the smallest 3 numbers 03258 // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1 03259 el_to_face->Push(i, faces_tbl->Push4(v[3], v[2], v[1], v[0])); 03260 el_to_face->Push(i, faces_tbl->Push4(v[0], v[1], v[5], v[4])); 03261 el_to_face->Push(i, faces_tbl->Push4(v[1], v[2], v[6], v[5])); 03262 el_to_face->Push(i, faces_tbl->Push4(v[2], v[3], v[7], v[6])); 03263 el_to_face->Push(i, faces_tbl->Push4(v[3], v[0], v[4], v[7])); 03264 el_to_face->Push(i, faces_tbl->Push4(v[4], v[5], v[6], v[7])); 03265 break; 03266 } 03267 } 03268 el_to_face->Finalize(); 03269 NumOfFaces = faces_tbl->NumberOfElements(); 03270 be_to_face.SetSize(NumOfBdrElements); 03271 for (i = 0; i < NumOfBdrElements; i++) 03272 { 03273 v = boundary[i]->GetVertices(); 03274 switch (GetBdrElementType(i)) 03275 { 03276 case Element::TRIANGLE: 03277 be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]); 03278 break; 03279 case Element::QUADRILATERAL: 03280 be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]); 03281 break; 03282 } 03283 } 03284 03285 if (ret_ftbl) 03286 return faces_tbl; 03287 delete faces_tbl; 03288 return NULL; 03289 } 03290 03291 void Mesh::ReorientTetMesh() 03292 { 03293 int *v; 03294 03295 if (Dim != 3 || !(meshgen & 1)) 03296 return; 03297 03298 DeleteCoarseTables(); 03299 03300 for (int i = 0; i < NumOfElements; i++) 03301 if (GetElementType(i) == Element::TETRAHEDRON) 03302 { 03303 v = elements[i]->GetVertices(); 03304 03305 Rotate3(v[0], v[1], v[2]); 03306 if (v[0] < v[3]) 03307 Rotate3(v[1], v[2], v[3]); 03308 else 03309 ShiftL2R(v[0], v[1], v[3]); 03310 } 03311 03312 for (int i = 0; i < NumOfBdrElements; i++) 03313 if (GetBdrElementType(i) == Element::TRIANGLE) 03314 { 03315 v = boundary[i]->GetVertices(); 03316 03317 Rotate3(v[0], v[1], v[2]); 03318 } 03319 03320 GetElementToFaceTable(); 03321 GenerateFaces(); 03322 if (el_to_edge) 03323 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 03324 } 03325 03326 #ifdef MFEM_USE_MPI 03327 // auxiliary function for qsort 03328 static int mfem_less(const void *x, const void *y) 03329 { 03330 if (*(int*)x < *(int*)y) 03331 return 1; 03332 if (*(int*)x > *(int*)y) 03333 return -1; 03334 return 0; 03335 } 03336 #ifndef MFEM_USE_METIS_5 03337 // METIS 4 prototypes 03338 typedef int idxtype; 03339 extern "C" { 03340 void METIS_PartGraphRecursive(int*, idxtype*, idxtype*, idxtype*, idxtype*, 03341 int*, int*, int*, int*, int*, idxtype*); 03342 void METIS_PartGraphKway(int*, idxtype*, idxtype*, idxtype*, idxtype*, 03343 int*, int*, int*, int*, int*, idxtype*); 03344 void METIS_PartGraphVKway(int*, idxtype*, idxtype*, idxtype*, idxtype*, 03345 int*, int*, int*, int*, int*, idxtype*); 03346 } 03347 #else 03348 // METIS 5 prototypes 03349 typedef int idx_t; 03350 typedef float real_t; 03351 extern "C" { 03352 int METIS_PartGraphRecursive( 03353 idx_t *nvtxs, idx_t *ncon, idx_t *xadj, 03354 idx_t *adjncy, idx_t *vwgt, idx_t *vsize, idx_t *adjwgt, 03355 idx_t *nparts, real_t *tpwgts, real_t *ubvec, idx_t *options, 03356 idx_t *edgecut, idx_t *part); 03357 int METIS_PartGraphKway( 03358 idx_t *nvtxs, idx_t *ncon, idx_t *xadj, 03359 idx_t *adjncy, idx_t *vwgt, idx_t *vsize, idx_t *adjwgt, 03360 idx_t *nparts, real_t *tpwgts, real_t *ubvec, idx_t *options, 03361 idx_t *edgecut, idx_t *part); 03362 int METIS_SetDefaultOptions(idx_t *options); 03363 } 03364 #endif 03365 #endif 03366 03367 int *Mesh::CartesianPartitioning(int nxyz[]) 03368 { 03369 int *partitioning; 03370 double pmin[3], pmax[3]; 03371 for (int i = 0; i < Dim; i++) 03372 { 03373 pmin[i] = numeric_limits<double>::infinity(); 03374 pmax[i] = -pmin[i]; 03375 } 03376 // find a bounding box using the vertices 03377 for (int vi = 0; vi < NumOfVertices; vi++) 03378 { 03379 const double *p = vertices[vi](); 03380 for (int i = 0; i < Dim; i++) 03381 { 03382 if (p[i] < pmin[i]) pmin[i] = p[i]; 03383 if (p[i] > pmax[i]) pmax[i] = p[i]; 03384 } 03385 } 03386 03387 partitioning = new int[NumOfElements]; 03388 03389 // determine the partitioning using the centers of the elements 03390 double ppt[3]; 03391 Vector pt(ppt, Dim); 03392 for (int el = 0; el < NumOfElements; el++) 03393 { 03394 GetElementTransformation(el)->Transform( 03395 Geometries.GetCenter(GetElementBaseGeometry(el)), pt); 03396 int part = 0; 03397 for (int i = Dim-1; i >= 0; i--) 03398 { 03399 int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i]))); 03400 if (idx < 0) idx = 0; 03401 if (idx >= nxyz[i]) idx = nxyz[i]-1; 03402 part = part * nxyz[i] + idx; 03403 } 03404 partitioning[el] = part; 03405 } 03406 03407 return partitioning; 03408 } 03409 03410 int *Mesh::GeneratePartitioning(int nparts, int part_method) 03411 { 03412 #ifdef MFEM_USE_MPI 03413 int i, *partitioning; 03414 03415 ElementToElementTable(); 03416 03417 partitioning = new int[NumOfElements]; 03418 03419 if (nparts == 1) 03420 { 03421 for (i = 0; i < NumOfElements; i++) 03422 partitioning[i] = 0; 03423 } 03424 else 03425 { 03426 int *I, *J, n; 03427 #ifndef MFEM_USE_METIS_5 03428 int wgtflag = 0; 03429 int numflag = 0; 03430 int options[5]; 03431 #else 03432 int ncon = 1; 03433 int err; 03434 int options[40]; 03435 #endif 03436 int edgecut; 03437 03438 n = NumOfElements; 03439 I = el_to_el->GetI(); 03440 J = el_to_el->GetJ(); 03441 #ifndef MFEM_USE_METIS_5 03442 options[0] = 0; 03443 #else 03444 METIS_SetDefaultOptions(options); 03445 options[10] = 1; // set METIS_OPTION_CONTIG 03446 #endif 03447 03448 // Sort the neighbor lists 03449 if (part_method >= 0 && part_method <= 2) 03450 for (i = 0; i < n; i++) 03451 qsort(&J[I[i]], I[i+1]-I[i], sizeof(int), &mfem_less); 03452 03453 // This function should be used to partition a graph into a small 03454 // number of partitions (less than 8). 03455 if (part_method == 0 || part_method == 3) 03456 { 03457 #ifndef MFEM_USE_METIS_5 03458 METIS_PartGraphRecursive(&n, 03459 (idxtype *) I, 03460 (idxtype *) J, 03461 (idxtype *) NULL, 03462 (idxtype *) NULL, 03463 &wgtflag, 03464 &numflag, 03465 &nparts, 03466 options, 03467 &edgecut, 03468 (idxtype *) partitioning); 03469 #else 03470 err = METIS_PartGraphRecursive(&n, 03471 &ncon, 03472 I, 03473 J, 03474 (idx_t *) NULL, 03475 (idx_t *) NULL, 03476 (idx_t *) NULL, 03477 &nparts, 03478 (real_t *) NULL, 03479 (real_t *) NULL, 03480 options, 03481 &edgecut, 03482 partitioning); 03483 if (err != 1) 03484 mfem_error("Mesh::GeneratePartitioning: " 03485 " error in METIS_PartGraphRecursive!"); 03486 #endif 03487 } 03488 03489 // This function should be used to partition a graph into a large 03490 // number of partitions (greater than 8). 03491 if (part_method == 1 || part_method == 4) 03492 { 03493 #ifndef MFEM_USE_METIS_5 03494 METIS_PartGraphKway(&n, 03495 (idxtype *) I, 03496 (idxtype *) J, 03497 (idxtype *) NULL, 03498 (idxtype *) NULL, 03499 &wgtflag, 03500 &numflag, 03501 &nparts, 03502 options, 03503 &edgecut, 03504 (idxtype *) partitioning); 03505 #else 03506 err = METIS_PartGraphKway(&n, 03507 &ncon, 03508 I, 03509 J, 03510 (idx_t *) NULL, 03511 (idx_t *) NULL, 03512 (idx_t *) NULL, 03513 &nparts, 03514 (real_t *) NULL, 03515 (real_t *) NULL, 03516 options, 03517 &edgecut, 03518 partitioning); 03519 if (err != 1) 03520 mfem_error("Mesh::GeneratePartitioning: " 03521 " error in METIS_PartGraphKway!"); 03522 #endif 03523 } 03524 03525 // The objective of this partitioning is to minimize the total 03526 // communication volume 03527 if (part_method == 2 || part_method == 5) 03528 { 03529 #ifndef MFEM_USE_METIS_5 03530 METIS_PartGraphVKway(&n, 03531 (idxtype *) I, 03532 (idxtype *) J, 03533 (idxtype *) NULL, 03534 (idxtype *) NULL, 03535 &wgtflag, 03536 &numflag, 03537 &nparts, 03538 options, 03539 &edgecut, 03540 (idxtype *) partitioning); 03541 #else 03542 options[1] = 1; // set METIS_OPTION_OBJTYPE to METIS_OBJTYPE_VOL 03543 err = METIS_PartGraphKway(&n, 03544 &ncon, 03545 I, 03546 J, 03547 (idx_t *) NULL, 03548 (idx_t *) NULL, 03549 (idx_t *) NULL, 03550 &nparts, 03551 (real_t *) NULL, 03552 (real_t *) NULL, 03553 options, 03554 &edgecut, 03555 partitioning); 03556 if (err != 1) 03557 mfem_error("Mesh::GeneratePartitioning: " 03558 " error in METIS_PartGraphKway!"); 03559 #endif 03560 } 03561 03562 #ifdef MFEM_DEBUG 03563 cout << "Mesh::GeneratePartitioning(...): edgecut = " 03564 << edgecut << endl; 03565 #endif 03566 } 03567 03568 if (el_to_el) 03569 delete el_to_el; 03570 el_to_el = NULL; 03571 03572 // Check for empty partitionings (a "feature" in METIS) 03573 { 03574 Array< Pair<int,int> > psize(nparts); 03575 for (i = 0; i < nparts; i++) 03576 { 03577 psize[i].one = 0; 03578 psize[i].two = i; 03579 } 03580 03581 for (i = 0; i < NumOfElements; i++) 03582 psize[partitioning[i]].one++; 03583 03584 int empty_parts = 0; 03585 for (i = 0; i < nparts; i++) 03586 if (psize[i].one == 0) 03587 empty_parts++; 03588 03589 // This code just split the largest partitionings in two. 03590 // Do we need to replace it with something better? 03591 if (empty_parts) 03592 { 03593 cerr << "Mesh::GeneratePartitioning returned " << empty_parts 03594 << " empty parts!" << endl; 03595 03596 SortPairs<int,int>(psize, nparts); 03597 03598 for (i = nparts-1; i > nparts-1-empty_parts; i--) 03599 psize[i].one /= 2; 03600 03601 for (int j = 0; j < NumOfElements; j++) 03602 for (i = nparts-1; i > nparts-1-empty_parts; i--) 03603 if (psize[i].one == 0 || partitioning[j] != psize[i].two) 03604 continue; 03605 else 03606 { 03607 partitioning[j] = psize[nparts-1-i].two; 03608 psize[i].one--; 03609 } 03610 } 03611 } 03612 03613 return partitioning; 03614 03615 #else 03616 03617 mfem_error("Mesh::GeneratePartitioning(...): " 03618 "MFEM was compiled without Metis."); 03619 03620 return NULL; 03621 03622 #endif 03623 } 03624 03625 /* required: 0 <= partitioning[i] < num_part */ 03626 void FindPartitioningComponents(Table &elem_elem, 03627 const Array<int> &partitioning, 03628 Array<int> &component, 03629 Array<int> &num_comp) 03630 { 03631 int i, j, k; 03632 int num_elem, *i_elem_elem, *j_elem_elem; 03633 03634 num_elem = elem_elem.Size(); 03635 i_elem_elem = elem_elem.GetI(); 03636 j_elem_elem = elem_elem.GetJ(); 03637 03638 component.SetSize(num_elem); 03639 03640 Array<int> elem_stack(num_elem); 03641 int stack_p, stack_top_p, elem; 03642 int num_part; 03643 03644 num_part = -1; 03645 for (i = 0; i < num_elem; i++) 03646 { 03647 if (partitioning[i] > num_part) 03648 num_part = partitioning[i]; 03649 component[i] = -1; 03650 } 03651 num_part++; 03652 03653 num_comp.SetSize(num_part); 03654 for (i = 0; i < num_part; i++) 03655 num_comp[i] = 0; 03656 03657 stack_p = 0; 03658 stack_top_p = 0; // points to the first unused element in the stack 03659 for (elem = 0; elem < num_elem; elem++) 03660 { 03661 if (component[elem] >= 0) 03662 continue; 03663 03664 component[elem] = num_comp[partitioning[elem]]++; 03665 03666 elem_stack[stack_top_p++] = elem; 03667 03668 for ( ; stack_p < stack_top_p; stack_p++) 03669 { 03670 i = elem_stack[stack_p]; 03671 for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++) 03672 { 03673 k = j_elem_elem[j]; 03674 if (partitioning[k] == partitioning[i]) 03675 { 03676 if (component[k] < 0) 03677 { 03678 component[k] = component[i]; 03679 elem_stack[stack_top_p++] = k; 03680 } 03681 else if (component[k] != component[i]) 03682 { 03683 mfem_error("FindPartitioningComponents"); 03684 } 03685 } 03686 } 03687 } 03688 } 03689 } 03690 03691 void Mesh::CheckPartitioning(int *partitioning) 03692 { 03693 int i, n_empty, n_mcomp; 03694 Array<int> component, num_comp; 03695 const Array<int> _partitioning(partitioning, GetNE()); 03696 03697 ElementToElementTable(); 03698 03699 FindPartitioningComponents(*el_to_el, _partitioning, component, num_comp); 03700 03701 n_empty = n_mcomp = 0; 03702 for (i = 0; i < num_comp.Size(); i++) 03703 if (num_comp[i] == 0) 03704 n_empty++; 03705 else if (num_comp[i] > 1) 03706 n_mcomp++; 03707 03708 if (n_empty > 0) 03709 { 03710 cout << "Mesh::CheckPartitioning(...) :\n" 03711 << "The following subdomains are empty :\n"; 03712 for (i = 0; i < num_comp.Size(); i++) 03713 if (num_comp[i] == 0) 03714 cout << ' ' << i; 03715 cout << endl; 03716 } 03717 if (n_mcomp > 0) 03718 { 03719 cout << "Mesh::CheckPartitioning(...) :\n" 03720 << "The following subdomains are NOT connected :\n"; 03721 for (i = 0; i < num_comp.Size(); i++) 03722 if (num_comp[i] > 1) 03723 cout << ' ' << i; 03724 cout << endl; 03725 } 03726 if (n_empty == 0 && n_mcomp == 0) 03727 cout << "Mesh::CheckPartitioning(...) : " 03728 "All subdomains are connected." << endl; 03729 03730 if (el_to_el) 03731 delete el_to_el; 03732 el_to_el = NULL; 03733 } 03734 03735 // compute the coefficients of the polynomial in t: 03736 // c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B) 03737 // where A, B are (d x d), d=2,3 03738 void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c) 03739 { 03740 const double *a = A.Data(); 03741 const double *b = B.Data(); 03742 03743 c.SetSize(A.Size()+1); 03744 switch (A.Size()) 03745 { 03746 case 2: 03747 { 03748 // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ 03749 // |a1 a3| + \ |a1 b3| |b1 a3| / * t + 03750 // |b0 b2| 03751 // |b1 b3| * t^2 03752 c(0) = a[0]*a[3]-a[1]*a[2]; 03753 c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2]; 03754 c(2) = b[0]*b[3]-b[1]*b[2]; 03755 } 03756 break; 03757 03758 case 3: 03759 { 03760 // |a0 a3 a6| 03761 // det(A+t*B) = |a1 a4 a7| + 03762 // |a2 a5 a8| 03763 03764 // / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \ 03765 // | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t + 03766 // \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| / 03767 03768 // / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \ 03769 // | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 + 03770 // \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| / 03771 03772 // |b0 b3 b6| 03773 // |b1 b4 b7| * t^3 03774 // |b2 b5 b8| 03775 c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) + 03776 a[1] * (a[5] * a[6] - a[3] * a[8]) + 03777 a[2] * (a[3] * a[7] - a[4] * a[6])); 03778 03779 c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) + 03780 b[1] * (a[5] * a[6] - a[3] * a[8]) + 03781 b[2] * (a[3] * a[7] - a[4] * a[6]) + 03782 03783 a[0] * (b[4] * a[8] - b[5] * a[7]) + 03784 a[1] * (b[5] * a[6] - b[3] * a[8]) + 03785 a[2] * (b[3] * a[7] - b[4] * a[6]) + 03786 03787 a[0] * (a[4] * b[8] - a[5] * b[7]) + 03788 a[1] * (a[5] * b[6] - a[3] * b[8]) + 03789 a[2] * (a[3] * b[7] - a[4] * b[6])); 03790 03791 c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) + 03792 a[1] * (b[5] * b[6] - b[3] * b[8]) + 03793 a[2] * (b[3] * b[7] - b[4] * b[6]) + 03794 03795 b[0] * (a[4] * b[8] - a[5] * b[7]) + 03796 b[1] * (a[5] * b[6] - a[3] * b[8]) + 03797 b[2] * (a[3] * b[7] - a[4] * b[6]) + 03798 03799 b[0] * (b[4] * a[8] - b[5] * a[7]) + 03800 b[1] * (b[5] * a[6] - b[3] * a[8]) + 03801 b[2] * (b[3] * a[7] - b[4] * a[6])); 03802 03803 c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) + 03804 b[1] * (b[5] * b[6] - b[3] * b[8]) + 03805 b[2] * (b[3] * b[7] - b[4] * b[6])); 03806 } 03807 break; 03808 03809 default: 03810 mfem_error("DetOfLinComb(...)"); 03811 } 03812 } 03813 03814 // compute the real roots of 03815 // z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3; 03816 // the roots are returned in x, sorted in increasing order; 03817 // it is assumed that x is at least of size d; 03818 // return the number of roots counting multiplicity; 03819 // return -1 if all z(i) are 0. 03820 int FindRoots(const Vector &z, Vector &x) 03821 { 03822 int d = z.Size()-1; 03823 if (d > 3 || d < 0) 03824 mfem_error("FindRoots(...)"); 03825 03826 while (z(d) == 0.0) 03827 { 03828 if (d == 0) 03829 return(-1); 03830 d--; 03831 } 03832 switch (d) 03833 { 03834 case 0: 03835 { 03836 return 0; 03837 } 03838 03839 case 1: 03840 { 03841 x(0) = -z(0)/z(1); 03842 return 1; 03843 } 03844 03845 case 2: 03846 { 03847 double a = z(2), b = z(1), c = z(0); 03848 double D = b*b-4*a*c; 03849 if (D < 0.0) 03850 { 03851 return 0; 03852 } 03853 if (D == 0.0) 03854 { 03855 x(0) = x(1) = -0.5 * b / a; 03856 return 2; // root with multiplicity 2 03857 } 03858 if (b == 0.0) 03859 { 03860 x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a)); 03861 return 2; 03862 } 03863 else 03864 { 03865 double t; 03866 if (b > 0.0) 03867 t = -0.5 * (b + sqrt(D)); 03868 else 03869 t = -0.5 * (b - sqrt(D)); 03870 x(0) = t / a; 03871 x(1) = c / t; 03872 if (x(0) > x(1)) 03873 Swap<double>(x(0), x(1)); 03874 return 2; 03875 } 03876 } 03877 03878 case 3: 03879 { 03880 double a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3); 03881 03882 // find the real roots of x^3 + a x^2 + b x + c = 0 03883 double Q = (a * a - 3 * b) / 9; 03884 double R = (2 * a * a * a - 9 * a * b + 27 * c) / 54; 03885 double Q3 = Q * Q * Q; 03886 double R2 = R * R; 03887 03888 if (R2 == Q3) 03889 { 03890 if (Q == 0) 03891 { 03892 x(0) = x(1) = x(2) = - a / 3; 03893 } 03894 else 03895 { 03896 double sqrtQ = sqrt(Q); 03897 03898 if (R > 0) 03899 { 03900 x(0) = -2 * sqrtQ - a / 3; 03901 x(1) = x(2) = sqrtQ - a / 3; 03902 } 03903 else 03904 { 03905 x(0) = x(1) = - sqrtQ - a / 3; 03906 x(2) = 2 * sqrtQ - a / 3; 03907 } 03908 } 03909 return 3; 03910 } 03911 else if (R2 < Q3) 03912 { 03913 double theta = acos(R / sqrt(Q3)); 03914 double A = -2 * sqrt(Q); 03915 double x0, x1, x2; 03916 x0 = A * cos(theta / 3) - a / 3; 03917 x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3; 03918 x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3; 03919 03920 /* Sort x0, x1, x2 */ 03921 if (x0 > x1) 03922 Swap<double>(x0, x1); 03923 if (x1 > x2) 03924 { 03925 Swap<double>(x1, x2); 03926 if (x0 > x1) 03927 Swap<double>(x0, x1); 03928 } 03929 x(0) = x0; 03930 x(1) = x1; 03931 x(2) = x2; 03932 return 3; 03933 } 03934 else 03935 { 03936 double A; 03937 if (R >= 0.0) 03938 A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0); 03939 else 03940 A = pow(sqrt(R2 - Q3) - R, 1.0/3.0); 03941 x(0) = A + Q / A - a / 3; 03942 return 1; 03943 } 03944 } 03945 } 03946 return 0; 03947 } 03948 03949 void FindTMax(Vector &c, Vector &x, double &tmax, 03950 const double factor, const int Dim) 03951 { 03952 const double c0 = c(0); 03953 c(0) = c0 * (1.0 - pow(factor, -Dim)); 03954 int nr = FindRoots(c, x); 03955 for (int j = 0; j < nr; j++) 03956 { 03957 if (x(j) > tmax) 03958 break; 03959 if (x(j) >= 0.0) 03960 { 03961 tmax = x(j); 03962 break; 03963 } 03964 } 03965 c(0) = c0 * (1.0 - pow(factor, Dim)); 03966 nr = FindRoots(c, x); 03967 for (int j = 0; j < nr; j++) 03968 { 03969 if (x(j) > tmax) 03970 break; 03971 if (x(j) >= 0.0) 03972 { 03973 tmax = x(j); 03974 break; 03975 } 03976 } 03977 } 03978 03979 void Mesh::CheckDisplacements(const Vector &displacements, double &tmax) 03980 { 03981 int nvs = vertices.Size(); 03982 DenseMatrix P, V, DS, PDS(Dim), VDS(Dim); 03983 Vector c(Dim+1), x(Dim); 03984 const double factor = 2.0; 03985 03986 // check for tangling assuming constant speed 03987 if (tmax < 1.0) 03988 tmax = 1.0; 03989 for (int i = 0; i < NumOfElements; i++) 03990 { 03991 Element *el = elements[i]; 03992 int nv = el->GetNVertices(); 03993 int *v = el->GetVertices(); 03994 P.SetSize(Dim, nv); 03995 V.SetSize(Dim, nv); 03996 for (int j = 0; j < Dim; j++) 03997 for (int k = 0; k < nv; k++) 03998 { 03999 P(j, k) = vertices[v[k]](j); 04000 V(j, k) = displacements(v[k]+j*nvs); 04001 } 04002 DS.SetSize(nv, Dim); 04003 const FiniteElement *fe = 04004 GetTransformationFEforElementType(el->GetType()); 04005 // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1 04006 switch (el->GetType()) 04007 { 04008 case Element::TRIANGLE: 04009 case Element::TETRAHEDRON: 04010 { 04011 // DS is constant 04012 fe->CalcDShape(Geometries.GetCenter(fe->GetGeomType()), DS); 04013 Mult(P, DS, PDS); 04014 Mult(V, DS, VDS); 04015 DetOfLinComb(PDS, VDS, c); 04016 if (c(0) <= 0.0) 04017 tmax = 0.0; 04018 else 04019 FindTMax(c, x, tmax, factor, Dim); 04020 } 04021 break; 04022 04023 case Element::QUADRILATERAL: 04024 { 04025 const IntegrationRule &ir = fe->GetNodes(); 04026 for (int j = 0; j < nv; j++) 04027 { 04028 fe->CalcDShape(ir.IntPoint(j), DS); 04029 Mult(P, DS, PDS); 04030 Mult(V, DS, VDS); 04031 DetOfLinComb(PDS, VDS, c); 04032 if (c(0) <= 0.0) 04033 tmax = 0.0; 04034 else 04035 FindTMax(c, x, tmax, factor, Dim); 04036 } 04037 } 04038 break; 04039 04040 default: 04041 mfem_error("Mesh::CheckDisplacements(...)"); 04042 } 04043 } 04044 } 04045 04046 void Mesh::MoveVertices(const Vector &displacements) 04047 { 04048 for (int i = 0, nv = vertices.Size(); i < nv; i++) 04049 for (int j = 0; j < Dim; j++) 04050 vertices[i](j) += displacements(j*nv+i); 04051 } 04052 04053 void Mesh::GetVertices(Vector &vert_coord) const 04054 { 04055 int nv = vertices.Size(); 04056 vert_coord.SetSize(nv*Dim); 04057 for (int i = 0; i < nv; i++) 04058 for (int j = 0; j < Dim; j++) 04059 vert_coord(j*nv+i) = vertices[i](j); 04060 } 04061 04062 void Mesh::SetVertices(const Vector &vert_coord) 04063 { 04064 for (int i = 0, nv = vertices.Size(); i < nv; i++) 04065 for (int j = 0; j < Dim; j++) 04066 vertices[i](j) = vert_coord(j*nv+i); 04067 } 04068 04069 void Mesh::MoveNodes(const Vector &displacements) 04070 { 04071 if (Nodes) 04072 (*Nodes) += displacements; 04073 else 04074 MoveVertices(displacements); 04075 } 04076 04077 void Mesh::GetNodes(Vector &node_coord) const 04078 { 04079 if (Nodes) 04080 node_coord = (*Nodes); 04081 else 04082 GetVertices(node_coord); 04083 } 04084 04085 void Mesh::SetNodes(const Vector &node_coord) 04086 { 04087 if (Nodes) 04088 (*Nodes) = node_coord; 04089 else 04090 SetVertices(node_coord); 04091 } 04092 04093 void Mesh::NewNodes(GridFunction &nodes) 04094 { 04095 if (own_nodes) delete Nodes; 04096 Nodes = &nodes; 04097 own_nodes = 0; 04098 } 04099 04100 void Mesh::AverageVertices(int * indexes, int n, int result) 04101 { 04102 int j, k; 04103 04104 for (k = 0; k < Dim; k++) 04105 vertices[result](k) = vertices[indexes[0]](k); 04106 04107 for (j = 1; j < n; j++) 04108 for (k = 0; k < Dim; k++) 04109 vertices[result](k) += vertices[indexes[j]](k); 04110 04111 for (k = 0; k < Dim; k++) 04112 vertices[result](k) *= (1.0 / n); 04113 } 04114 04115 void Mesh::UpdateNodes() 04116 { 04117 FiniteElementSpace *cfes = Nodes->FESpace()->SaveUpdate(); 04118 SparseMatrix *R = 04119 Nodes->FESpace()->GlobalRestrictionMatrix(cfes, 0); 04120 delete cfes; 04121 { 04122 Vector cNodes = *Nodes; 04123 Nodes->Update(); 04124 R->MultTranspose(cNodes, *Nodes); 04125 } 04126 delete R; 04127 04128 SetState(Mesh::TWO_LEVEL_FINE); 04129 04130 // update the vertices? 04131 } 04132 04133 void Mesh::QuadUniformRefinement() 04134 { 04135 int i, j, *v, vv[2], attr, wtls = WantTwoLevelState; 04136 const int *e; 04137 04138 if (Nodes) // curved mesh 04139 { 04140 UseTwoLevelState(1); 04141 } 04142 04143 SetState(Mesh::NORMAL); 04144 04145 if (el_to_edge == NULL) 04146 { 04147 el_to_edge = new Table; 04148 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 04149 } 04150 04151 int oedge = NumOfVertices; 04152 int oelem = oedge + NumOfEdges; 04153 04154 DeleteCoarseTables(); 04155 04156 vertices.SetSize(oelem + NumOfElements); 04157 04158 for (i = 0; i < NumOfElements; i++) 04159 { 04160 v = elements[i]->GetVertices(); 04161 04162 AverageVertices(v, 4, oelem+i); 04163 04164 e = el_to_edge->GetRow(i); 04165 04166 vv[0] = v[0], vv[1] = v[1]; AverageVertices(vv, 2, oedge+e[0]); 04167 vv[0] = v[1], vv[1] = v[2]; AverageVertices(vv, 2, oedge+e[1]); 04168 vv[0] = v[2], vv[1] = v[3]; AverageVertices(vv, 2, oedge+e[2]); 04169 vv[0] = v[3], vv[1] = v[0]; AverageVertices(vv, 2, oedge+e[3]); 04170 } 04171 04172 elements.SetSize(4 * NumOfElements); 04173 for (i = 0; i < NumOfElements; i++) 04174 { 04175 attr = elements[i]->GetAttribute(); 04176 v = elements[i]->GetVertices(); 04177 e = el_to_edge->GetRow(i); 04178 j = NumOfElements + 3 * i; 04179 04180 elements[j+0] = new Quadrilateral(oedge+e[0], v[1], oedge+e[1], 04181 oelem+i, attr); 04182 elements[j+1] = new Quadrilateral(oelem+i, oedge+e[1], v[2], 04183 oedge+e[2], attr); 04184 elements[j+2] = new Quadrilateral(oedge+e[3], oelem+i, oedge+e[2], 04185 v[3], attr); 04186 04187 if (WantTwoLevelState) 04188 { 04189 QuadrisectedElement *qe; 04190 04191 qe = new QuadrisectedElement(elements[i]->Duplicate(this)); 04192 qe->FirstChild = elements[i]; 04193 qe->Child2 = j; 04194 qe->Child3 = j+1; 04195 qe->Child4 = j+2; 04196 elements[i] = qe; 04197 } 04198 04199 v[1] = oedge+e[0]; 04200 v[2] = oelem+i; 04201 v[3] = oedge+e[3]; 04202 } 04203 04204 boundary.SetSize(2 * NumOfBdrElements); 04205 for (i = 0; i < NumOfBdrElements; i++) 04206 { 04207 attr = boundary[i]->GetAttribute(); 04208 v = boundary[i]->GetVertices(); 04209 j = NumOfBdrElements + i; 04210 04211 boundary[j] = new Segment(oedge+be_to_edge[i], v[1], attr); 04212 04213 if (WantTwoLevelState) 04214 { 04215 #ifdef MFEM_USE_MEMALLOC 04216 BisectedElement *be = BEMemory.Alloc(); 04217 #else 04218 BisectedElement *be = new BisectedElement; 04219 #endif 04220 be->SetCoarseElem(boundary[i]->Duplicate(this)); 04221 be->FirstChild = boundary[i]; 04222 be->SecondChild = j; 04223 boundary[i] = be; 04224 } 04225 04226 v[1] = oedge+be_to_edge[i]; 04227 } 04228 04229 if (WantTwoLevelState) 04230 { 04231 c_NumOfVertices = NumOfVertices; 04232 c_NumOfEdges = NumOfEdges; 04233 c_NumOfElements = NumOfElements; 04234 c_NumOfBdrElements = NumOfBdrElements; 04235 04236 RefinedElement::State = RefinedElement::FINE; 04237 State = Mesh::TWO_LEVEL_FINE; 04238 } 04239 04240 NumOfVertices = oelem + NumOfElements; 04241 NumOfElements = 4 * NumOfElements; 04242 NumOfBdrElements = 2 * NumOfBdrElements; 04243 NumOfFaces = 0; 04244 04245 if (WantTwoLevelState) 04246 { 04247 f_NumOfVertices = NumOfVertices; 04248 f_NumOfElements = NumOfElements; 04249 f_NumOfBdrElements = NumOfBdrElements; 04250 } 04251 04252 if (el_to_edge != NULL) 04253 { 04254 if (WantTwoLevelState) 04255 { 04256 c_el_to_edge = el_to_edge; 04257 Swap(be_to_edge, fc_be_to_edge); // save coarse be_to_edge 04258 f_el_to_edge = new Table; 04259 NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge); 04260 el_to_edge = f_el_to_edge; 04261 f_NumOfEdges = NumOfEdges; 04262 } 04263 else 04264 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 04265 GenerateFaces(); 04266 } 04267 04268 #ifdef MFEM_DEBUG 04269 CheckElementOrientation(); 04270 CheckBdrElementOrientation(); 04271 #endif 04272 04273 if (Nodes) // curved mesh 04274 { 04275 UpdateNodes(); 04276 UseTwoLevelState(wtls); 04277 } 04278 } 04279 04280 void Mesh::HexUniformRefinement() 04281 { 04282 int i, wtls = WantTwoLevelState; 04283 int * v; 04284 const int *e, *f; 04285 int vv[4]; 04286 04287 if (Nodes) // curved mesh 04288 { 04289 UseTwoLevelState(1); 04290 } 04291 04292 SetState(Mesh::NORMAL); 04293 04294 if (el_to_edge == NULL) 04295 { 04296 el_to_edge = new Table; 04297 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 04298 } 04299 if (el_to_face == NULL) 04300 GetElementToFaceTable(); 04301 04302 int oedge = NumOfVertices; 04303 int oface = oedge + NumOfEdges; 04304 int oelem = oface + NumOfFaces; 04305 04306 DeleteCoarseTables(); 04307 04308 vertices.SetSize(oelem + NumOfElements); 04309 for (i = 0; i < NumOfElements; i++) 04310 { 04311 v = elements[i]->GetVertices(); 04312 04313 AverageVertices(v, 8, oelem+i); 04314 04315 f = el_to_face->GetRow(i); 04316 04317 vv[0] = v[3], vv[1] = v[2], vv[2] = v[1], vv[3] = v[0]; 04318 AverageVertices(vv, 4, oface+f[0]); 04319 vv[0] = v[0], vv[1] = v[1], vv[2] = v[5], vv[3] = v[4]; 04320 AverageVertices(vv, 4, oface+f[1]); 04321 vv[0] = v[1], vv[1] = v[2], vv[2] = v[6], vv[3] = v[5]; 04322 AverageVertices(vv, 4, oface+f[2]); 04323 vv[0] = v[2], vv[1] = v[3], vv[2] = v[7], vv[3] = v[6]; 04324 AverageVertices(vv, 4, oface+f[3]); 04325 vv[0] = v[3], vv[1] = v[0], vv[2] = v[4], vv[3] = v[7]; 04326 AverageVertices(vv, 4, oface+f[4]); 04327 vv[0] = v[4], vv[1] = v[5], vv[2] = v[6], vv[3] = v[7]; 04328 AverageVertices(vv, 4, oface+f[5]); 04329 04330 e = el_to_edge->GetRow(i); 04331 04332 vv[0] = v[0], vv[1] = v[1]; AverageVertices(vv, 2, oedge+e[0]); 04333 vv[0] = v[1], vv[1] = v[2]; AverageVertices(vv, 2, oedge+e[1]); 04334 vv[0] = v[2], vv[1] = v[3]; AverageVertices(vv, 2, oedge+e[2]); 04335 vv[0] = v[3], vv[1] = v[0]; AverageVertices(vv, 2, oedge+e[3]); 04336 vv[0] = v[4], vv[1] = v[5]; AverageVertices(vv, 2, oedge+e[4]); 04337 vv[0] = v[5], vv[1] = v[6]; AverageVertices(vv, 2, oedge+e[5]); 04338 vv[0] = v[6], vv[1] = v[7]; AverageVertices(vv, 2, oedge+e[6]); 04339 vv[0] = v[7], vv[1] = v[4]; AverageVertices(vv, 2, oedge+e[7]); 04340 vv[0] = v[0], vv[1] = v[4]; AverageVertices(vv, 2, oedge+e[8]); 04341 vv[0] = v[1], vv[1] = v[5]; AverageVertices(vv, 2, oedge+e[9]); 04342 vv[0] = v[2], vv[1] = v[6]; AverageVertices(vv, 2, oedge+e[10]); 04343 vv[0] = v[3], vv[1] = v[7]; AverageVertices(vv, 2, oedge+e[11]); 04344 } 04345 04346 int attr, j, k; 04347 elements.SetSize(8 * NumOfElements); 04348 for (i = 0; i < NumOfElements; i++) 04349 { 04350 attr = elements[i]->GetAttribute(); 04351 v = elements[i]->GetVertices(); 04352 e = el_to_edge->GetRow(i); 04353 f = el_to_face->GetRow(i); 04354 j = NumOfElements + 7 * i; 04355 04356 elements[j+0] = new Hexahedron(oedge+e[0], v[1], oedge+e[1], oface+f[0], 04357 oface+f[1], oedge+e[9], oface+f[2], 04358 oelem+i, attr); 04359 elements[j+1] = new Hexahedron(oface+f[0], oedge+e[1], v[2], oedge+e[2], 04360 oelem+i, oface+f[2], oedge+e[10], 04361 oface+f[3], attr); 04362 elements[j+2] = new Hexahedron(oedge+e[3], oface+f[0], oedge+e[2], v[3], 04363 oface+f[4], oelem+i, oface+f[3], 04364 oedge+e[11], attr); 04365 elements[j+3] = new Hexahedron(oedge+e[8], oface+f[1], oelem+i, 04366 oface+f[4], v[4], oedge+e[4], oface+f[5], 04367 oedge+e[7], attr); 04368 elements[j+4] = new Hexahedron(oface+f[1], oedge+e[9], oface+f[2], 04369 oelem+i, oedge+e[4], v[5], oedge+e[5], 04370 oface+f[5], attr); 04371 elements[j+5] = new Hexahedron(oelem+i, oface+f[2], oedge+e[10], 04372 oface+f[3], oface+f[5], oedge+e[5], v[6], 04373 oedge+e[6], attr); 04374 elements[j+6] = new Hexahedron(oface+f[4], oelem+i, oface+f[3], 04375 oedge+e[11], oedge+e[7], oface+f[5], 04376 oedge+e[6], v[7], attr); 04377 04378 if (WantTwoLevelState) 04379 { 04380 OctasectedElement *oe; 04381 04382 oe = new OctasectedElement(elements[i]->Duplicate(this)); 04383 oe->FirstChild = elements[i]; 04384 for (k = 0; k < 7; k++) 04385 oe->Child[k] = j + k; 04386 elements[i] = oe; 04387 } 04388 04389 v[1] = oedge+e[0]; 04390 v[2] = oface+f[0]; 04391 v[3] = oedge+e[3]; 04392 v[4] = oedge+e[8]; 04393 v[5] = oface+f[1]; 04394 v[6] = oelem+i; 04395 v[7] = oface+f[4]; 04396 } 04397 04398 boundary.SetSize(4 * NumOfBdrElements); 04399 for (i = 0; i < NumOfBdrElements; i++) 04400 { 04401 attr = boundary[i]->GetAttribute(); 04402 v = boundary[i]->GetVertices(); 04403 e = bel_to_edge->GetRow(i); 04404 f = & be_to_face[i]; 04405 j = NumOfBdrElements + 3 * i; 04406 04407 boundary[j+0] = new Quadrilateral(oedge+e[0], v[1], oedge+e[1], 04408 oface+f[0], attr); 04409 boundary[j+1] = new Quadrilateral(oface+f[0], oedge+e[1], v[2], 04410 oedge+e[2], attr); 04411 boundary[j+2] = new Quadrilateral(oedge+e[3], oface+f[0], oedge+e[2], 04412 v[3], attr); 04413 04414 if (WantTwoLevelState) 04415 { 04416 QuadrisectedElement *qe; 04417 04418 qe = new QuadrisectedElement(boundary[i]->Duplicate(this)); 04419 qe->FirstChild = boundary[i]; 04420 qe->Child2 = j; 04421 qe->Child3 = j+1; 04422 qe->Child4 = j+2; 04423 boundary[i] = qe; 04424 } 04425 04426 v[1] = oedge+e[0]; 04427 v[2] = oface+f[0]; 04428 v[3] = oedge+e[3]; 04429 } 04430 04431 if (WantTwoLevelState) 04432 { 04433 c_NumOfVertices = NumOfVertices; 04434 c_NumOfEdges = NumOfEdges; 04435 c_NumOfFaces = NumOfFaces; 04436 c_NumOfElements = NumOfElements; 04437 c_NumOfBdrElements = NumOfBdrElements; 04438 04439 RefinedElement::State = RefinedElement::FINE; 04440 State = Mesh::TWO_LEVEL_FINE; 04441 } 04442 04443 NumOfVertices = oelem + NumOfElements; 04444 NumOfElements = 8 * NumOfElements; 04445 NumOfBdrElements = 4 * NumOfBdrElements; 04446 04447 if (WantTwoLevelState) 04448 { 04449 f_NumOfVertices = NumOfVertices; 04450 f_NumOfElements = NumOfElements; 04451 f_NumOfBdrElements = NumOfBdrElements; 04452 } 04453 04454 if (el_to_edge != NULL) 04455 { 04456 if (WantTwoLevelState) 04457 { 04458 c_el_to_edge = el_to_edge; 04459 f_el_to_edge = new Table; 04460 c_bel_to_edge = bel_to_edge; 04461 bel_to_edge = NULL; 04462 NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge); 04463 el_to_edge = f_el_to_edge; 04464 f_bel_to_edge = bel_to_edge; 04465 f_NumOfEdges = NumOfEdges; 04466 } 04467 else 04468 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 04469 } 04470 if (el_to_face != NULL) 04471 { 04472 if (WantTwoLevelState) 04473 { 04474 c_el_to_face = el_to_face; 04475 el_to_face = NULL; 04476 Swap(faces_info, fc_faces_info); 04477 } 04478 GetElementToFaceTable(); 04479 GenerateFaces(); 04480 if (WantTwoLevelState) 04481 { 04482 f_el_to_face = el_to_face; 04483 f_NumOfFaces = NumOfFaces; 04484 } 04485 } 04486 04487 #ifdef MFEM_DEBUG 04488 CheckBdrElementOrientation(); 04489 #endif 04490 04491 if (Nodes) // curved mesh 04492 { 04493 UpdateNodes(); 04494 UseTwoLevelState(wtls); 04495 } 04496 04497 // When 'WantTwoLevelState' is true the coarse level 04498 // 'be_to_face' and 'faces' 04499 // are destroyed !!! 04500 } 04501 04502 void Mesh::LocalRefinement(const Array<int> &marked_el, int type) 04503 { 04504 int i, j, ind, nedges, wtls = WantTwoLevelState; 04505 Array<int> v; 04506 04507 if (Nodes) // curved mesh 04508 { 04509 UseTwoLevelState(1); 04510 } 04511 04512 SetState(Mesh::NORMAL); 04513 DeleteCoarseTables(); 04514 04515 if (Dim == 1) // -------------------------------------------------------- 04516 { 04517 int cne = NumOfElements, cnv = NumOfVertices; 04518 NumOfVertices += marked_el.Size(); 04519 NumOfElements += marked_el.Size(); 04520 vertices.SetSize(NumOfVertices); 04521 elements.SetSize(NumOfElements); 04522 for (j = 0; j < marked_el.Size(); j++) 04523 { 04524 i = marked_el[j]; 04525 int *vert = elements[i]->GetVertices(); 04526 vertices[cnv+j](0) = 0.5 * ( vertices[vert[0]](0) + 04527 vertices[vert[1]](0) ); 04528 elements[cne+j] = new Segment(cnv+j, vert[1], 04529 elements[i]->GetAttribute()); 04530 vert[1] = cnv+j; 04531 } 04532 } // end of 'if (Dim == 1)' 04533 else if (Dim == 2) // --------------------------------------------------- 04534 { 04535 if (WantTwoLevelState) 04536 { 04537 c_NumOfVertices = NumOfVertices; 04538 c_NumOfEdges = NumOfEdges; 04539 c_NumOfElements = NumOfElements; 04540 c_NumOfBdrElements = NumOfBdrElements; 04541 } 04542 04543 // 1. Get table of vertex to vertex connections. 04544 DSTable v_to_v(NumOfVertices); 04545 GetVertexToVertexTable(v_to_v); 04546 04547 // 2. Get edge to element connections in arrays edge1 and edge2 04548 nedges = v_to_v.NumberOfEntries(); 04549 int *edge1 = new int[nedges]; 04550 int *edge2 = new int[nedges]; 04551 int *middle = new int[nedges]; 04552 04553 for (i = 0; i < nedges; i++) 04554 edge1[i] = edge2[i] = middle[i] = -1; 04555 04556 for (i = 0; i < NumOfElements; i++) 04557 { 04558 elements[i]->GetVertices(v); 04559 for (j = 1; j < v.Size(); j++) 04560 { 04561 ind = v_to_v(v[j-1], v[j]); 04562 (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i); 04563 } 04564 ind = v_to_v(v[0], v[v.Size()-1]); 04565 (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i); 04566 } 04567 04568 // 3. Do the red refinement. 04569 for (i = 0; i < marked_el.Size(); i++) 04570 RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle); 04571 04572 // 4. Do the green refinement (to get conforming mesh). 04573 int need_refinement; 04574 do 04575 { 04576 need_refinement = 0; 04577 for (i = 0; i < nedges; i++) 04578 if (middle[i] != -1 && edge1[i] != -1) 04579 { 04580 need_refinement = 1; 04581 GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle); 04582 } 04583 } 04584 while (need_refinement == 1); 04585 04586 // 5. Update the boundary elements. 04587 int v1[2], v2[2], bisect, temp; 04588 temp = NumOfBdrElements; 04589 for (i = 0; i < temp; i++) 04590 { 04591 boundary[i]->GetVertices(v); 04592 bisect = v_to_v(v[0], v[1]); 04593 if (middle[bisect] != -1) // the element was refined (needs updating) 04594 { 04595 if (boundary[i]->GetType() == Element::SEGMENT) 04596 { 04597 v1[0] = v[0]; v1[1] = middle[bisect]; 04598 v2[0] = middle[bisect]; v2[1] = v[1]; 04599 04600 if (WantTwoLevelState) 04601 { 04602 boundary.Append(new Segment(v2, boundary[i]->GetAttribute())); 04603 #ifdef MFEM_USE_MEMALLOC 04604 BisectedElement *aux = BEMemory.Alloc(); 04605 aux->SetCoarseElem(boundary[i]); 04606 #else 04607 BisectedElement *aux = new BisectedElement(boundary[i]); 04608 #endif 04609 aux->FirstChild = 04610 new Segment(v1, boundary[i]->GetAttribute()); 04611 aux->SecondChild = NumOfBdrElements; 04612 boundary[i] = aux; 04613 NumOfBdrElements++; 04614 } 04615 else 04616 { 04617 boundary[i]->SetVertices(v1); 04618 boundary.Append(new Segment(v2, boundary[i]->GetAttribute())); 04619 } 04620 } 04621 else 04622 mfem_error("Only bisection of segment is implemented" 04623 " for bdr elem."); 04624 } 04625 } 04626 NumOfBdrElements = boundary.Size(); 04627 04628 // 6. Free the allocated memory. 04629 delete [] edge1; 04630 delete [] edge2; 04631 delete [] middle; 04632 04633 #ifdef MFEM_DEBUG 04634 CheckElementOrientation(); 04635 #endif 04636 04637 if (WantTwoLevelState) 04638 { 04639 f_NumOfVertices = NumOfVertices; 04640 f_NumOfElements = NumOfElements; 04641 f_NumOfBdrElements = NumOfBdrElements; 04642 RefinedElement::State = RefinedElement::FINE; 04643 State = Mesh::TWO_LEVEL_FINE; 04644 } 04645 04646 if (el_to_edge != NULL) 04647 { 04648 if (WantTwoLevelState) 04649 { 04650 c_el_to_edge = el_to_edge; 04651 Swap(be_to_edge, fc_be_to_edge); // save coarse be_to_edge 04652 f_el_to_edge = new Table; 04653 NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge); 04654 el_to_edge = f_el_to_edge; 04655 f_NumOfEdges = NumOfEdges; 04656 } 04657 else 04658 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 04659 GenerateFaces(); 04660 } 04661 04662 } 04663 else if (Dim == 3) // --------------------------------------------------- 04664 { 04665 if (WantTwoLevelState) 04666 { 04667 c_NumOfVertices = NumOfVertices; 04668 c_NumOfEdges = NumOfEdges; 04669 c_NumOfFaces = NumOfFaces; 04670 c_NumOfElements = NumOfElements; 04671 c_NumOfBdrElements = NumOfBdrElements; 04672 } 04673 04674 // 1. Get table of vertex to vertex connections. 04675 DSTable v_to_v(NumOfVertices); 04676 GetVertexToVertexTable(v_to_v); 04677 04678 // 2. Get edge to element connections in arrays edge1 and edge2 04679 nedges = v_to_v.NumberOfEntries(); 04680 int *middle = new int[nedges]; 04681 04682 for (i = 0; i < nedges; i++) 04683 middle[i] = -1; 04684 04685 // 3. Do the red refinement. 04686 int ii; 04687 switch (type) 04688 { 04689 case 1: 04690 for (i = 0; i < marked_el.Size(); i++) 04691 Bisection(marked_el[i], v_to_v, NULL, NULL, middle); 04692 break; 04693 case 2: 04694 for (i = 0; i < marked_el.Size(); i++) 04695 { 04696 Bisection(marked_el[i], v_to_v, NULL, NULL, middle); 04697 04698 Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle); 04699 Bisection(marked_el[i], v_to_v, NULL, NULL, middle); 04700 } 04701 break; 04702 case 3: 04703 for (i = 0; i < marked_el.Size(); i++) 04704 { 04705 Bisection(marked_el[i], v_to_v, NULL, NULL, middle); 04706 04707 ii = NumOfElements - 1; 04708 Bisection(ii, v_to_v, NULL, NULL, middle); 04709 Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle); 04710 Bisection(ii, v_to_v, NULL, NULL, middle); 04711 04712 Bisection(marked_el[i], v_to_v, NULL, NULL, middle); 04713 Bisection(NumOfElements-1, v_to_v, NULL, NULL, middle); 04714 Bisection(marked_el[i], v_to_v, NULL, NULL, middle); 04715 } 04716 break; 04717 } 04718 04719 if (WantTwoLevelState) 04720 { 04721 RefinedElement::State = RefinedElement::FINE; 04722 State = Mesh::TWO_LEVEL_FINE; 04723 } 04724 04725 // 4. Do the green refinement (to get conforming mesh). 04726 int need_refinement; 04727 // int need_refinement, onoe, max_gen = 0; 04728 do 04729 { 04730 // int redges[2], type, flag; 04731 need_refinement = 0; 04732 // onoe = NumOfElements; 04733 // for (i = 0; i < onoe; i++) 04734 for (i = 0; i < NumOfElements; i++) 04735 { 04736 // ((Tetrahedron *)elements[i])->ParseRefinementFlag(redges, type, flag); 04737 // if (flag > max_gen) max_gen = flag; 04738 if (elements[i]->NeedRefinement(v_to_v, middle)) 04739 { 04740 need_refinement = 1; 04741 Bisection(i, v_to_v, NULL, NULL, middle); 04742 } 04743 } 04744 } 04745 while (need_refinement == 1); 04746 04747 // cout << "Maximum generation: " << max_gen << endl; 04748 04749 // 5. Update the boundary elements. 04750 do 04751 { 04752 need_refinement = 0; 04753 for (i = 0; i < NumOfBdrElements; i++) 04754 if (boundary[i]->NeedRefinement(v_to_v, middle)) 04755 { 04756 need_refinement = 1; 04757 Bisection(i, v_to_v, middle); 04758 } 04759 } 04760 while (need_refinement == 1); 04761 04762 // 6. Un-mark the Pf elements. 04763 int refinement_edges[2], type, flag; 04764 for (i = 0; i < NumOfElements; i++) 04765 { 04766 Element *El = elements[i]; 04767 while (El->GetType() == Element::BISECTED) 04768 El = ((BisectedElement *) El)->FirstChild; 04769 ((Tetrahedron *)El)->ParseRefinementFlag(refinement_edges, type, 04770 flag); 04771 if (type == Tetrahedron::TYPE_PF) 04772 ((Tetrahedron *)El)->CreateRefinementFlag(refinement_edges, 04773 Tetrahedron::TYPE_PU, 04774 flag); 04775 } 04776 04777 NumOfBdrElements = boundary.Size(); 04778 04779 // 7. Free the allocated memory. 04780 delete [] middle; 04781 04782 #ifdef MFEM_DEBUG 04783 CheckElementOrientation(); 04784 #endif 04785 04786 if (el_to_edge != NULL) 04787 { 04788 if (WantTwoLevelState) 04789 { 04790 c_el_to_edge = el_to_edge; 04791 f_el_to_edge = new Table; 04792 c_bel_to_edge = bel_to_edge; 04793 bel_to_edge = NULL; 04794 NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge); 04795 el_to_edge = f_el_to_edge; 04796 f_bel_to_edge = bel_to_edge; 04797 } 04798 else 04799 NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge); 04800 } 04801 if (el_to_face != NULL) 04802 { 04803 if (WantTwoLevelState) 04804 { 04805 c_el_to_face = el_to_face; 04806 el_to_face = NULL; 04807 Swap(faces_info, fc_faces_info); 04808 } 04809 GetElementToFaceTable(); 04810 GenerateFaces(); 04811 if (WantTwoLevelState) 04812 { 04813 f_el_to_face = el_to_face; 04814 } 04815 } 04816 04817 if (WantTwoLevelState) 04818 { 04819 f_NumOfVertices = NumOfVertices; 04820 f_NumOfEdges = NumOfEdges; 04821 f_NumOfFaces = NumOfFaces; 04822 f_NumOfElements = NumOfElements; 04823 f_NumOfBdrElements = NumOfBdrElements; 04824 } 04825 04826 } // end 'if (Dim == 3)' 04827 04828 if (Nodes) // curved mesh 04829 { 04830 UpdateNodes(); 04831 UseTwoLevelState(wtls); 04832 } 04833 } 04834 04835 void Mesh::UniformRefinement() 04836 { 04837 if (NURBSext) 04838 NURBSUniformRefinement(); 04839 else if (meshgen == 1) 04840 { 04841 Array<int> elem_to_refine(GetNE()); 04842 04843 for (int i = 0; i < elem_to_refine.Size(); i++) 04844 elem_to_refine[i] = i; 04845 LocalRefinement(elem_to_refine); 04846 } 04847 else if (Dim == 2) 04848 QuadUniformRefinement(); 04849 else if (Dim == 3) 04850 HexUniformRefinement(); 04851 else 04852 mfem_error("Mesh::UniformRefinement()"); 04853 } 04854 04855 void Mesh::Bisection(int i, const DSTable &v_to_v, 04856 int *edge1, int *edge2, int *middle) 04857 { 04858 int *vert; 04859 int v[2][4], v_new, bisect, t; 04860 Element **pce; 04861 Vertex V; 04862 04863 if (WantTwoLevelState) 04864 { 04865 pce = &(elements[i]); 04866 while (1) 04867 { 04868 t = pce[0]->GetType(); 04869 if (t == Element::BISECTED) 04870 pce = & ( ((BisectedElement *) pce[0])->FirstChild ); 04871 else if (t == Element::QUADRISECTED) 04872 pce = & ( ((QuadrisectedElement *) pce[0])->FirstChild ); 04873 else 04874 break; 04875 } 04876 } 04877 else 04878 t = elements[i]->GetType(); 04879 04880 04881 if (t == Element::TRIANGLE) 04882 { 04883 Triangle *tri; 04884 04885 if (WantTwoLevelState) 04886 tri = (Triangle *) pce[0]; 04887 else 04888 tri = (Triangle *) elements[i]; 04889 04890 vert = tri->GetVertices(); 04891 04892 // 1. Get the index for the new vertex in v_new. 04893 bisect = v_to_v(vert[0], vert[1]); 04894 #ifdef MFEM_DEBUG 04895 if (bisect < 0) 04896 mfem_error("Mesh::Bisection(...): ERROR"); 04897 #endif 04898 if (middle[bisect] == -1) 04899 { 04900 v_new = NumOfVertices++; 04901 V(0) = 0.5 * (vertices[vert[0]](0) + vertices[vert[1]](0)); 04902 V(1) = 0.5 * (vertices[vert[0]](1) + vertices[vert[1]](1)); 04903 V(2) = 0.0; 04904 vertices.Append(V); 04905 04906 // Put the element that may need refinement (because of this 04907 // bisection) in edge1, or -1 if no more refinement is needed. 04908 if (edge1[bisect] == i) 04909 edge1[bisect] = edge2[bisect]; 04910 04911 middle[bisect] = v_new; 04912 } 04913 else 04914 { 04915 v_new = middle[bisect]; 04916 04917 // This edge will require no more refinement. 04918 edge1[bisect] = -1; 04919 } 04920 04921 // 2. Set the node indices for the new elements in v[0] and v[1] so that 04922 // the edge marked for refinement is between the first two nodes. 04923 v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new; 04924 v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new; 04925 04926 if (WantTwoLevelState) 04927 { 04928 #ifdef MFEM_USE_MEMALLOC 04929 BisectedElement *aux = BEMemory.Alloc(); 04930 aux->SetCoarseElem(tri); 04931 #else 04932 BisectedElement *aux = new BisectedElement(tri); 04933 #endif 04934 aux->FirstChild = tri = new Triangle(v[0], tri->GetAttribute()); 04935 aux->SecondChild = NumOfElements; 04936 pce[0] = aux; 04937 } 04938 else 04939 tri->SetVertices(v[0]); // changes vert[0..2] !!! 04940 elements.Append(new Triangle(v[1], tri->GetAttribute())); 04941 04942 // 3. edge1 and edge2 may have to be changed for the second triangle. 04943 if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows()) 04944 { 04945 bisect = v_to_v(v[1][0], v[1][1]); 04946 #ifdef MFEM_DEBUG 04947 if (bisect < 0) 04948 mfem_error("Mesh::Bisection(...): ERROR 2"); 04949 #endif 04950 if (edge1[bisect] == i) 04951 edge1[bisect] = NumOfElements; 04952 else if (edge2[bisect] == i) 04953 edge2[bisect] = NumOfElements; 04954 } 04955 NumOfElements++; 04956 } 04957 else if (t == Element::TETRAHEDRON) 04958 { 04959 int j, type, new_type, old_redges[2], new_redges[2][2], flag; 04960 Tetrahedron *tet; 04961 04962 if (WantTwoLevelState) 04963 tet = (Tetrahedron *) pce[0]; 04964 else 04965 tet = (Tetrahedron *) elements[i]; 04966 04967 if (tet->GetRefinementFlag() == 0) 04968 mfem_error("Mesh::Bisection : TETRAHEDRON element is not marked for " 04969 "refinement."); 04970 04971 vert = tet->GetVertices(); 04972 04973 // 1. Get the index for the new vertex in v_new. 04974 bisect = v_to_v(vert[0], vert[1]); 04975 if (bisect == -1) 04976 { 04977 tet->ParseRefinementFlag(old_redges, type, flag); 04978 cerr << "Error in Bisection(...) of tetrahedron!" << endl 04979 << " redge[0] = " << old_redges[0] 04980 << " redge[1] = " << old_redges[1] 04981 << " type = " << type 04982 << " flag = " << flag << endl; 04983 mfem_error(); 04984 } 04985 04986 if (middle[bisect] == -1) 04987 { 04988 v_new = NumOfVertices++; 04989 for (j = 0; j < 3; j++) 04990 V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j)); 04991 vertices.Append(V); 04992 04993 middle[bisect] = v_new; 04994 } 04995 else 04996 v_new = middle[bisect]; 04997 04998 // 2. Set the node indices for the new elements in v[2][4] so that 04999 // the edge marked for refinement is between the first two nodes. 05000 tet->ParseRefinementFlag(old_redges, type, flag); 05001 05002 v[0][3] = v_new; 05003 v[1][3] = v_new; 05004 new_redges[0][0] = 2; 05005 new_redges[0][1] = 1; 05006 new_redges[1][0] = 2; 05007 new_redges[1][1] = 1; 05008 switch (old_redges[0]) 05009 { 05010 case 2: 05011 v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3]; 05012 if (type == Tetrahedron::TYPE_PF) new_redges[0][1] = 4; 05013 break; 05014 case 3: 05015 v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2]; 05016 break; 05017 case 5: 05018 v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0]; 05019 } 05020 switch (old_redges[1]) 05021 { 05022 case 1: 05023 v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3]; 05024 if (type == Tetrahedron::TYPE_PF) new_redges[1][0] = 3; 05025 break; 05026 case 4: 05027 v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2]; 05028 break; 05029 case 5: 05030 v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1]; 05031 } 05032 05033 int attr = tet->GetAttribute(); 05034 if (WantTwoLevelState) 05035 { 05036 #ifdef MFEM_USE_MEMALLOC 05037 BisectedElement *aux = BEMemory.Alloc(); 05038 aux->SetCoarseElem(tet); 05039 tet = TetMemory.Alloc(); 05040 tet->SetVertices(v[0]); 05041 tet->SetAttribute(attr); 05042 #else 05043 BisectedElement *aux = new BisectedElement(tet); 05044 tet = new Tetrahedron(v[0], attr); 05045 #endif 05046 aux->FirstChild = tet; 05047 aux->SecondChild = NumOfElements; 05048 pce[0] = aux; 05049 } 05050 else 05051 tet->SetVertices(v[0]); 05052 // 'tet' now points to the first child 05053 { 05054 #ifdef MFEM_USE_MEMALLOC 05055 Tetrahedron *tet2 = TetMemory.Alloc(); 05056 tet2->SetVertices(v[1]); 05057 tet2->SetAttribute(attr); 05058 elements.Append(tet2); 05059 #else 05060 elements.Append(new Tetrahedron(v[1], attr)); 05061 #endif 05062 } 05063 05064 // 3. Set the bisection flag 05065 switch (type) 05066 { 05067 case Tetrahedron::TYPE_PU: 05068 new_type = Tetrahedron::TYPE_PF; break; 05069 case Tetrahedron::TYPE_PF: 05070 new_type = Tetrahedron::TYPE_A; break; 05071 default: 05072 new_type = Tetrahedron::TYPE_PU; 05073 } 05074 05075 tet->CreateRefinementFlag(new_redges[0], new_type, flag+1); 05076 ((Tetrahedron *)elements[NumOfElements])-> 05077 CreateRefinementFlag(new_redges[1], new_type, flag+1); 05078 05079 NumOfElements++; 05080 } 05081 else 05082 mfem_error("Bisection for now works only for triangles & tetrahedra."); 05083 } 05084 05085 void Mesh::Bisection(int i, const DSTable &v_to_v, int *middle) 05086 { 05087 int *vert; 05088 int v[2][3], v_new, bisect, t; 05089 Element **pce; 05090 05091 if (WantTwoLevelState) 05092 { 05093 pce = &(boundary[i]); 05094 while (1) 05095 { 05096 t = pce[0]->GetType(); 05097 if (t == Element::BISECTED) 05098 pce = & ( ((BisectedElement *) pce[0])->FirstChild ); 05099 else if (t == Element::QUADRISECTED) 05100 pce = & ( ((QuadrisectedElement *) pce[0])->FirstChild ); 05101 else 05102 break; 05103 } 05104 } 05105 else 05106 t = boundary[i]->GetType(); 05107 05108 if (t == Element::TRIANGLE) 05109 { 05110 Triangle *tri; 05111 if (WantTwoLevelState) 05112 tri = (Triangle *) pce[0]; 05113 else 05114 tri = (Triangle *) boundary[i]; 05115 05116 vert = tri->GetVertices(); 05117 05118 // 1. Get the index for the new vertex in v_new. 05119 bisect = v_to_v(vert[0], vert[1]); 05120 if (middle[bisect] == -1) 05121 mfem_error("Error in Bisection(...) of boundary triangle!"); 05122 else 05123 v_new = middle[bisect]; 05124 05125 // 2. Set the node indices for the new elements in v[0] and v[1] so that 05126 // the edge marked for refinement is between the first two nodes. 05127 v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new; 05128 v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new; 05129 if (WantTwoLevelState) 05130 { 05131 #ifdef MFEM_USE_MEMALLOC 05132 BisectedElement *aux = BEMemory.Alloc(); 05133 aux->SetCoarseElem(tri); 05134 #else 05135 BisectedElement *aux = new BisectedElement(tri); 05136 #endif 05137 aux->FirstChild = tri = new Triangle(v[0], tri->GetAttribute()); 05138 aux->SecondChild = NumOfBdrElements; 05139 pce[0] = aux; 05140 } 05141 else 05142 boundary[i]->SetVertices(v[0]); 05143 // 'tri' now points to the first child 05144 boundary.Append(new Triangle(v[1], tri->GetAttribute())); 05145 05146 NumOfBdrElements++; 05147 } 05148 else 05149 mfem_error("Bisection of boundary elements works only for triangles!"); 05150 } 05151 05152 void Mesh::UniformRefinement(int i, const DSTable &v_to_v, 05153 int *edge1, int *edge2, int *middle) 05154 { 05155 Array<int> v; 05156 int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3]; 05157 double coord[2]; 05158 05159 if (elements[i]->GetType() == Element::TRIANGLE) 05160 { 05161 elements[i]->GetVertices(v); 05162 05163 // 1. Get the indeces for the new vertices in array v_new 05164 bisect[0] = v_to_v(v[0],v[1]); 05165 bisect[1] = v_to_v(v[1],v[2]); 05166 bisect[2] = v_to_v(v[0],v[2]); 05167 #ifdef MFEM_DEBUG 05168 if (bisect[0] < 0 || bisect[1] < 0 || bisect[2] < 0) 05169 mfem_error("Mesh::UniformRefinement(...): ERROR"); 05170 #endif 05171 05172 for (j = 0; j < 3; j++) // for the 3 edges fix v_new 05173 if (middle[bisect[j]] == -1) 05174 { 05175 v_new[j] = NumOfVertices++; 05176 coord[0] = (vertices[v[j]](0) + vertices[v[(j+1)%3]](0))/2.; 05177 coord[1] = (vertices[v[j]](1) + vertices[v[(j+1)%3]](1))/2.; 05178 Vertex V(coord[0], coord[1]); 05179 vertices.Append(V); 05180 05181 // Put the element that may need refinement (because of this 05182 // bisection) in edge1, or -1 if no more refinement is needed. 05183 if (edge1[bisect[j]] == i) 05184 edge1[bisect[j]] = edge2[bisect[j]]; 05185 05186 middle[bisect[j]] = v_new[j]; 05187 } 05188 else 05189 { 05190 v_new[j] = middle[bisect[j]]; 05191 05192 // This edge will require no more refinement. 05193 edge1[bisect[j]] = -1; 05194 } 05195 05196 // 2. Set the node indeces for the new elements in v1, v2, v3 & v4 so that 05197 // the edges marked for refinement be between the first two nodes. 05198 v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2]; 05199 v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1]; 05200 v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2]; 05201 v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0]; 05202 05203 elements.Append(new Triangle(v1, elements[i]->GetAttribute())); 05204 elements.Append(new Triangle(v2, elements[i]->GetAttribute())); 05205 elements.Append(new Triangle(v3, elements[i]->GetAttribute())); 05206 if (WantTwoLevelState) 05207 { 05208 QuadrisectedElement *aux = new QuadrisectedElement(elements[i]); 05209 aux->FirstChild = new Triangle(v4, elements[i]->GetAttribute()); 05210 aux->Child2 = NumOfElements; 05211 aux->Child3 = NumOfElements+1; 05212 aux->Child4 = NumOfElements+2; 05213 elements[i] = aux; 05214 } 05215 else 05216 { 05217 elements[i]->SetVertices(v4); 05218 } 05219 05220 NumOfElements += 3; 05221 } 05222 else 05223 mfem_error("Uniform refinement for now works only for triangles."); 05224 } 05225 05226 void Mesh::SetState(int s) 05227 { 05228 if (State != Mesh::NORMAL && s == Mesh::NORMAL) 05229 { 05230 // two level state --->> normal state 05231 int i, t; 05232 05233 for (i = 0; i < f_NumOfElements; ) 05234 { 05235 t = elements[i]->GetType(); 05236 if (t == Element::BISECTED || 05237 t == Element::QUADRISECTED || 05238 t == Element::OCTASECTED) 05239 { 05240 RefinedElement *aux = (RefinedElement *) elements[i]; 05241 elements[i] = aux->FirstChild; 05242 FreeElement(aux->CoarseElem); 05243 FreeElement(aux); 05244 } 05245 else 05246 i++; 05247 } 05248 05249 for (i = 0; i < f_NumOfBdrElements; ) 05250 { 05251 t = boundary[i]->GetType(); 05252 if (t == Element::BISECTED || 05253 t == Element::QUADRISECTED || 05254 t == Element::OCTASECTED) 05255 { 05256 RefinedElement *aux = (RefinedElement *) boundary[i]; 05257 boundary[i] = aux->FirstChild; 05258 FreeElement(aux->CoarseElem); 05259 FreeElement(aux); 05260 } 05261 else 05262 i++; 05263 } 05264 05265 if (el_to_edge != NULL) 05266 { 05267 delete c_el_to_edge; 05268 el_to_edge = f_el_to_edge; 05269 if (Dim == 2) 05270 { 05271 if (State == Mesh::TWO_LEVEL_COARSE) 05272 Swap(be_to_edge, fc_be_to_edge); 05273 fc_be_to_edge.DeleteAll(); 05274 } 05275 if (Dim == 3) 05276 { 05277 delete c_bel_to_edge; 05278 bel_to_edge = f_bel_to_edge; 05279 } 05280 } 05281 if (el_to_face != NULL) 05282 { 05283 delete c_el_to_face; 05284 el_to_face = f_el_to_face; 05285 if (State == Mesh::TWO_LEVEL_COARSE) 05286 Swap(faces_info, fc_faces_info); 05287 fc_faces_info.DeleteAll(); 05288 } 05289 05290 NumOfVertices = f_NumOfVertices; 05291 NumOfEdges = f_NumOfEdges; 05292 if (Dim == 3) 05293 NumOfFaces = f_NumOfFaces; 05294 NumOfElements = f_NumOfElements; 05295 NumOfBdrElements = f_NumOfBdrElements; 05296 RefinedElement::State = RefinedElement::FINE; 05297 State = s; 05298 } 05299 else if (State == Mesh::TWO_LEVEL_COARSE && s == Mesh::TWO_LEVEL_FINE) 05300 { 05301 if (el_to_edge != NULL) 05302 { 05303 el_to_edge = f_el_to_edge; 05304 if (Dim == 2) 05305 Swap(be_to_edge, fc_be_to_edge); 05306 if (Dim == 3) 05307 bel_to_edge = f_bel_to_edge; 05308 } 05309 if (el_to_face != NULL) 05310 { 05311 el_to_face = f_el_to_face; 05312 Swap(faces_info, fc_faces_info); 05313 } 05314 NumOfVertices = f_NumOfVertices; 05315 NumOfEdges = f_NumOfEdges; 05316 if (Dim == 3) 05317 NumOfFaces = f_NumOfFaces; 05318 NumOfElements = f_NumOfElements; 05319 NumOfBdrElements = f_NumOfBdrElements; 05320 RefinedElement::State = RefinedElement::FINE; 05321 State = s; 05322 } 05323 else if (State == Mesh::TWO_LEVEL_FINE && s == Mesh::TWO_LEVEL_COARSE) 05324 { 05325 if (el_to_edge != NULL) 05326 { 05327 el_to_edge = c_el_to_edge; 05328 if (Dim == 2) 05329 Swap(be_to_edge, fc_be_to_edge); 05330 if (Dim == 3) 05331 bel_to_edge = c_bel_to_edge; 05332 } 05333 if (el_to_face != NULL) 05334 { 05335 el_to_face = c_el_to_face; 05336 Swap(faces_info, fc_faces_info); 05337 } 05338 NumOfVertices = c_NumOfVertices; 05339 NumOfEdges = c_NumOfEdges; 05340 if (Dim == 3) 05341 NumOfFaces = c_NumOfFaces; 05342 NumOfElements = c_NumOfElements; 05343 NumOfBdrElements = c_NumOfBdrElements; 05344 RefinedElement::State = RefinedElement::COARSE; 05345 State = s; 05346 } 05347 else if (State != s) 05348 mfem_error("Oops! Mesh::SetState"); 05349 } 05350 05351 int Mesh::GetNumFineElems(int i) 05352 { 05353 int t; 05354 05355 if (Dim == 2) 05356 { 05357 t = elements[i]->GetType(); 05358 if (t == Element::QUADRISECTED) 05359 return 4; 05360 else if (t == Element::BISECTED) 05361 { 05362 // assuming that the elements are either BisectedElements or 05363 // regular elements 05364 int n = 1; 05365 BisectedElement *aux = (BisectedElement *) elements[i]; 05366 do 05367 { 05368 n += GetNumFineElems(aux->SecondChild); 05369 if (aux->FirstChild->GetType() != Element::BISECTED) 05370 break; 05371 aux = (BisectedElement *) (aux->FirstChild); 05372 } 05373 while (1); 05374 return n; 05375 } 05376 } 05377 else if (Dim == 3) 05378 { 05379 // assuming that the element is a BisectedElement, 05380 // OctasectedElement (with children that are regular elements) or 05381 // regular element 05382 t = elements[i]->GetType(); 05383 if (t == Element::BISECTED) 05384 { 05385 int n = 1; 05386 BisectedElement *aux = (BisectedElement *) elements[i]; 05387 do 05388 { 05389 n += GetNumFineElems (aux->SecondChild); 05390 if (aux->FirstChild->GetType() != Element::BISECTED) 05391 break; 05392 aux = (BisectedElement *) (aux->FirstChild); 05393 } 05394 while (1); 05395 return n; 05396 } 05397 else if (t == Element::OCTASECTED) 05398 return 8; 05399 return 1; // regular element (i.e. it is not refined) 05400 } 05401 05402 return 1; // the element is not refined 05403 } 05404 05405 int Mesh::GetBisectionHierarchy(Element *E) 05406 { 05407 if (E->GetType() == Element::BISECTED) 05408 { 05409 int L, R, n, s, lb, rb; 05410 05411 L = GetBisectionHierarchy(((BisectedElement *)E)->FirstChild); 05412 n = ((BisectedElement *)E)->SecondChild; 05413 R = GetBisectionHierarchy(elements[n]); 05414 n = 1; s = 1; 05415 lb = rb = 1; 05416 do 05417 { 05418 int nlb, nrb; 05419 nlb = nrb = 0; 05420 while (lb > 0) 05421 { 05422 n |= ((L & 1) << s); 05423 s++; 05424 nlb += (L & 1); 05425 L = (L >> 1); 05426 lb--; 05427 } 05428 while (rb > 0) 05429 { 05430 n |= ((R & 1) << s); 05431 s++; 05432 nrb += (R & 1); 05433 R = (R >> 1); 05434 rb--; 05435 } 05436 lb = 2 * nlb; rb = 2 * nrb; 05437 } 05438 while (lb > 0 || rb > 0); 05439 return n; 05440 } 05441 return 0; 05442 } 05443 05444 int Mesh::GetRefinementType(int i) 05445 { 05446 int t; 05447 05448 if (Dim == 2) 05449 { 05450 t = elements[i]->GetType(); 05451 if (t == Element::QUADRISECTED) 05452 { 05453 t = ((QuadrisectedElement *)elements[i])->CoarseElem->GetType(); 05454 if (t == Element::QUADRILATERAL) 05455 return 1; // refinement type for quadrisected QUADRILATERAL 05456 else 05457 return 2; // refinement type for quadrisected TRIANGLE 05458 } 05459 else if (t == Element::BISECTED) 05460 { 05461 int type; 05462 type = GetBisectionHierarchy(elements[i]); 05463 if (type == 0) 05464 mfem_error("Mesh::GetRefinementType(...)"); 05465 return type+2; 05466 } 05467 } 05468 else if (Dim == 3) 05469 { 05470 int redges[2], type, flag; 05471 Element *E = elements[i]; 05472 Tetrahedron *tet; 05473 05474 t = E->GetType(); 05475 if (t != Element::BISECTED) 05476 { 05477 if (t == Element::OCTASECTED) 05478 return 1; // refinement type for octasected CUBE 05479 else 05480 return 0; 05481 } 05482 // Bisected TETRAHEDRON 05483 tet = (Tetrahedron *) (((BisectedElement *) E)->CoarseElem); 05484 tet->ParseRefinementFlag(redges, type, flag); 05485 if (type == Tetrahedron::TYPE_A && redges[0] == 2) 05486 type = 5; 05487 else if (type == Tetrahedron::TYPE_M && redges[0] == 2) 05488 type = 6; 05489 type++; 05490 type |= ( GetBisectionHierarchy(E) << 3 ); 05491 if (type < 8) type = 0; 05492 05493 return type; 05494 } 05495 05496 return 0; // no refinement 05497 } 05498 05499 int Mesh::GetFineElem(int i, int j) 05500 { 05501 int t; 05502 05503 if (Dim == 2) 05504 { 05505 t = elements[i]->GetType(); 05506 if (t == Element::QUADRISECTED) 05507 { 05508 QuadrisectedElement *aux = (QuadrisectedElement *) elements[i]; 05509 if (aux->CoarseElem->GetType() == Element::QUADRILATERAL) 05510 switch (j) 05511 { 05512 case 0: return i; 05513 case 1: return aux->Child2; 05514 case 2: return aux->Child3; 05515 case 3: return aux->Child4; 05516 default: *((int *)NULL) = -1; // crash it 05517 } 05518 else // quadrisected TRIANGLE 05519 switch (j) 05520 { 05521 case 0: return aux->Child2; 05522 case 1: return aux->Child3; 05523 case 2: return aux->Child4; 05524 case 3: return i; 05525 default: *((int *)NULL) = -1; // crash it 05526 } 05527 } 05528 else if (t == Element::BISECTED) 05529 { 05530 int n = 0; 05531 BisectedElement *aux = (BisectedElement *) elements[i]; 05532 do 05533 { 05534 int k = GetFineElem(aux->SecondChild, j-n); 05535 if (k >= 0) 05536 return k; 05537 n -= k; // (-k) is the number of the leaves in this SecondChild 05538 // n is the number of the leaves in 05539 // the SecondChild-ren so far 05540 if (aux->FirstChild->GetType() != Element::BISECTED) 05541 break; 05542 aux = (BisectedElement *) (aux->FirstChild); 05543 } 05544 while (1); 05545 if (j > n) // i.e. if (j >= n+1) 05546 return -(n+1); 05547 return i; // j == n, i.e. j is the index of the last leaf 05548 } 05549 } 05550 else if (Dim == 3) 05551 { 05552 t = elements[i]->GetType(); 05553 if (t == Element::BISECTED) 05554 { 05555 int n = 0; 05556 BisectedElement *aux = (BisectedElement *) elements[i]; 05557 do 05558 { 05559 int k = GetFineElem(aux->SecondChild, j-n); 05560 if (k >= 0) 05561 return k; 05562 n -= k; // (-k) is the number of the leaves in this SecondChild 05563 // n is the number of the leaves in 05564 // the SecondChild-ren so far 05565 if (aux->FirstChild->GetType() != Element::BISECTED) 05566 break; 05567 aux = (BisectedElement *) (aux->FirstChild); 05568 } 05569 while (1); 05570 if (j > n) // i.e. if (j >= n+1) 05571 return -(n+1); 05572 return i; // j == n, i.e. j is the index of the last leaf 05573 } 05574 else if (t == Element::OCTASECTED) 05575 { 05576 if (j == 0) return i; 05577 return ((OctasectedElement *) elements[i])->Child[j-1]; 05578 } 05579 } 05580 05581 if (j > 0) 05582 return -1; 05583 05584 return i; // no refinement 05585 } 05586 05587 void Mesh::BisectTriTrans(DenseMatrix &pointmat, Triangle *tri, int child) 05588 { 05589 double np[2]; 05590 05591 if (child == 0) // left triangle 05592 { 05593 // Set the new coordinates of the vertices 05594 np[0] = 0.5 * ( pointmat(0,0) + pointmat(0,1) ); 05595 np[1] = 0.5 * ( pointmat(1,0) + pointmat(1,1) ); 05596 pointmat(0,1) = pointmat(0,0); pointmat(1,1) = pointmat(1,0); 05597 pointmat(0,0) = pointmat(0,2); pointmat(1,0) = pointmat(1,2); 05598 pointmat(0,2) = np[0]; pointmat(1,2) = np[1]; 05599 } 05600 else // right triangle 05601 { 05602 // Set the new coordinates of the vertices 05603 np[0] = 0.5 * ( pointmat(0,0) + pointmat(0,1) ); 05604 np[1] = 0.5 * ( pointmat(1,0) + pointmat(1,1) ); 05605 pointmat(0,0) = pointmat(0,1); pointmat(1,0) = pointmat(1,1); 05606 pointmat(0,1) = pointmat(0,2); pointmat(1,1) = pointmat(1,2); 05607 pointmat(0,2) = np[0]; pointmat(1,2) = np[1]; 05608 } 05609 } 05610 05611 void Mesh::BisectTetTrans(DenseMatrix &pointmat, Tetrahedron *tet, int child) 05612 { 05613 int i, j, redges[2], type, flag, ind[4]; 05614 double t[4]; 05615 05616 tet->ParseRefinementFlag(redges, type, flag); 05617 05618 if (child == 0) // left tetrahedron 05619 { 05620 // Set the new coordinates of the vertices 05621 pointmat(0,1) = 0.5 * ( pointmat(0,0) + pointmat(0,1) ); 05622 pointmat(1,1) = 0.5 * ( pointmat(1,0) + pointmat(1,1) ); 05623 pointmat(2,1) = 0.5 * ( pointmat(2,0) + pointmat(2,1) ); 05624 // Permute the vertices according to the type & redges 05625 switch (redges[0]) 05626 { 05627 case 2: ind[0] = 0; ind[1] = 3; ind[2] = 1; ind[3] = 2; break; 05628 case 3: ind[0] = 1; ind[1] = 3; ind[2] = 2; ind[3] = 0; break; 05629 case 5: ind[0] = 2; ind[1] = 3; ind[2] = 0; ind[3] = 1; 05630 } 05631 } 05632 else // right tetrahedron 05633 { 05634 // Set the new coordinates of the vertices 05635 pointmat(0,0) = 0.5 * ( pointmat(0,0) + pointmat(0,1) ); 05636 pointmat(1,0) = 0.5 * ( pointmat(1,0) + pointmat(1,1) ); 05637 pointmat(2,0) = 0.5 * ( pointmat(2,0) + pointmat(2,1) ); 05638 // Permute the vertices according to the type & redges 05639 switch (redges[1]) 05640 { 05641 case 1: ind[0] = 3; ind[1] = 1; ind[2] = 0; ind[3] = 2; break; 05642 case 4: ind[0] = 3; ind[1] = 0; ind[2] = 2; ind[3] = 1; break; 05643 case 5: ind[0] = 3; ind[1] = 2; ind[2] = 1; ind[3] = 0; 05644 } 05645 } 05646 // Do the permutation 05647 for (i = 0; i < 3; i++) 05648 { 05649 for (j = 0; j < 4; j++) 05650 t[j] = pointmat(i,j); 05651 for (j = 0; j < 4; j++) 05652 pointmat(i,ind[j]) = t[j]; 05653 } 05654 } 05655 05656 int Mesh::GetFineElemPath(int i, int j) 05657 { 05658 // if (Dim == 3) 05659 { 05660 if (elements[i]->GetType() == Element::BISECTED) 05661 { 05662 int n = 0, l = 0; 05663 BisectedElement *aux = (BisectedElement *) elements[i]; 05664 do 05665 { 05666 int k = GetFineElemPath(aux->SecondChild, j-n); 05667 if (k >= 0) 05668 return ((k << 1)+1) << l; 05669 n -= k; // (-k) is the number of the leaves in this SecondChild 05670 // n is the number of the leaves in 05671 // the SecondChild-ren so far 05672 l++; 05673 if (aux->FirstChild->GetType() != Element::BISECTED) 05674 break; 05675 aux = (BisectedElement *) (aux->FirstChild); 05676 } 05677 while (1); 05678 if (j > n) // i.e. if (j >= n+1) 05679 return -(n+1); 05680 return 0; // j == n, i.e. j is the index of the last leaf 05681 } 05682 if (j > 0) 05683 return -1; 05684 } 05685 05686 return 0; 05687 } 05688 05689 ElementTransformation * Mesh::GetFineElemTrans(int i, int j) 05690 { 05691 int t; 05692 05693 if (Dim == 2) 05694 { 05695 DenseMatrix &pm = Transformation.GetPointMat(); 05696 Transformation.Attribute = 0; 05697 Transformation.ElementNo = 0; 05698 t = elements[i]->GetType(); 05699 if (t == Element::QUADRISECTED) 05700 { 05701 t = ((QuadrisectedElement *)elements[i])->CoarseElem->GetType(); 05702 if (t == Element::QUADRILATERAL) 05703 { 05704 // quadrisected QUADRILATERAL 05705 Transformation.SetFE(&QuadrilateralFE); 05706 pm.SetSize(2, 4); 05707 switch (j) 05708 { 05709 case 0: 05710 pm(0,0) = 0.0; pm(1,0) = 0.0; // x; y; 05711 pm(0,1) = 0.5; pm(1,1) = 0.0; 05712 pm(0,2) = 0.5; pm(1,2) = 0.5; 05713 pm(0,3) = 0.0; pm(1,3) = 0.5; 05714 break; 05715 case 1: 05716 pm(0,0) = 0.5; pm(1,0) = 0.0; 05717 pm(0,1) = 1.0; pm(1,1) = 0.0; 05718 pm(0,2) = 1.0; pm(1,2) = 0.5; 05719 pm(0,3) = 0.5; pm(1,3) = 0.5; 05720 break; 05721 case 2: 05722 pm(0,0) = 0.5; pm(1,0) = 0.5; 05723 pm(0,1) = 1.0; pm(1,1) = 0.5; 05724 pm(0,2) = 1.0; pm(1,2) = 1.0; 05725 pm(0,3) = 0.5; pm(1,3) = 1.0; 05726 break; 05727 case 3: 05728 pm(0,0) = 0.0; pm(1,0) = 0.5; 05729 pm(0,1) = 0.5; pm(1,1) = 0.5; 05730 pm(0,2) = 0.5; pm(1,2) = 1.0; 05731 pm(0,3) = 0.0; pm(1,3) = 1.0; 05732 break; 05733 default: 05734 mfem_error("Mesh::GetFineElemTrans(...) 1"); 05735 } 05736 } 05737 else 05738 { 05739 // quadrisected TRIANGLE 05740 Transformation.SetFE(&TriangleFE); 05741 pm.SetSize(2, 3); 05742 switch (j) 05743 { 05744 case 0: 05745 pm(0,0) = 0.0; pm(0,1) = 0.5; pm(0,2) = 0.0; // x 05746 pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 0.5; // y 05747 break; 05748 case 1: 05749 pm(0,0) = 0.5; pm(0,1) = 1.0; pm(0,2) = 0.5; 05750 pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 0.5; 05751 break; 05752 case 2: 05753 pm(0,0) = 0.0; pm(0,1) = 0.5; pm(0,2) = 0.0; 05754 pm(1,0) = 0.5; pm(1,1) = 0.5; pm(1,2) = 1.0; 05755 break; 05756 case 3: 05757 pm(0,0) = 0.5; pm(0,1) = 0.0; pm(0,2) = 0.5; 05758 pm(1,0) = 0.5; pm(1,1) = 0.5; pm(1,2) = 0.0; 05759 break; 05760 default: 05761 mfem_error("Mesh::GetFineElemTrans(...) 2"); 05762 } 05763 } 05764 } 05765 else if (t == Element::BISECTED) 05766 { 05767 // bisected TRIANGLE 05768 Transformation.SetFE(&TriangleFE); 05769 pm.SetSize(2, 3); 05770 05771 int path; 05772 Element *E; 05773 05774 // pm is initialzed with the coordinates of the vertices of the 05775 // reference triangle 05776 pm(0,0) = 0.0; pm(0,1) = 1.0; pm(0,2) = 0.0; 05777 pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 1.0; 05778 05779 path = GetFineElemPath(i, j); 05780 05781 E = elements[i]; 05782 while (E->GetType() == Element::BISECTED) 05783 { 05784 BisectedElement *aux = (BisectedElement *) E; 05785 05786 BisectTriTrans(pm, (Triangle *) aux->CoarseElem, path & 1); 05787 E = (path & 1) ? elements[aux->SecondChild] : aux->FirstChild; 05788 path = path >> 1; 05789 } 05790 } 05791 else 05792 { 05793 // identity transformation 05794 Transformation.SetFE(&TriangleFE); 05795 pm.SetSize(2, 3); 05796 pm(0,0) = 0.0; pm(0,1) = 1.0; pm(0,2) = 0.0; 05797 pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 1.0; 05798 } 05799 return &Transformation; 05800 } 05801 else if (Dim == 3) 05802 { 05803 if (elements[i]->GetType() == Element::OCTASECTED) 05804 { 05805 int jj; 05806 double dx, dy, dz; 05807 DenseMatrix &pm = Transformation.GetPointMat(); 05808 Transformation.SetFE(&HexahedronFE); 05809 Transformation.Attribute = 0; 05810 Transformation.ElementNo = 0; 05811 pm.SetSize(3, 8); 05812 if (j < 4) dz = 0.0; 05813 else dz = 0.5; 05814 jj = j % 4; 05815 if (jj < 2) dy = 0.0; 05816 else dy = 0.5; 05817 if (jj == 0 || jj == 3) dx = 0.0; 05818 else dx = 0.5; 05819 pm(0,0) = dx; pm(1,0) = dy; pm(2,0) = dz; 05820 pm(0,1) = 0.5 + dx; pm(1,1) = dy; pm(2,1) = dz; 05821 pm(0,2) = 0.5 + dx; pm(1,2) = 0.5 + dy; pm(2,2) = dz; 05822 pm(0,3) = dx; pm(1,3) = 0.5 + dy; pm(2,3) = dz; 05823 pm(0,4) = dx; pm(1,4) = dy; pm(2,4) = 0.5 + dz; 05824 pm(0,5) = 0.5 + dx; pm(1,5) = dy; pm(2,5) = 0.5 + dz; 05825 pm(0,6) = 0.5 + dx; pm(1,6) = 0.5 + dy; pm(2,6) = 0.5 + dz; 05826 pm(0,7) = dx; pm(1,7) = 0.5 + dy; pm(2,7) = 0.5 + dz; 05827 return &Transformation; 05828 } 05829 int path; 05830 Element *E; 05831 DenseMatrix &pm = Transformation.GetPointMat(); 05832 Transformation.SetFE(&TetrahedronFE); 05833 Transformation.Attribute = 0; 05834 Transformation.ElementNo = 0; 05835 pm.SetSize(3, 4); 05836 05837 // pm is initialzed with the coordinates of the vertices of the 05838 // reference tetrahedron 05839 pm(0,0) = 0.0; pm(0,1) = 1.0; pm(0,2) = 0.0; pm(0,3) = 0.0; 05840 pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 1.0; pm(1,3) = 0.0; 05841 pm(2,0) = 0.0; pm(2,1) = 0.0; pm(2,2) = 0.0; pm(2,3) = 1.0; 05842 05843 path = GetFineElemPath(i, j); 05844 05845 E = elements[i]; 05846 while (E->GetType() == Element::BISECTED) 05847 { 05848 BisectedElement *aux = (BisectedElement *) E; 05849 05850 BisectTetTrans(pm, (Tetrahedron *) aux->CoarseElem, path & 1); 05851 E = (path & 1) ? elements[aux->SecondChild] : aux->FirstChild; 05852 path = path >> 1; 05853 } 05854 } 05855 05856 return &Transformation; // no refinement 05857 } 05858 05859 void Mesh::PrintXG(ostream &out) const 05860 { 05861 int i, j; 05862 Array<int> v; 05863 05864 if (Dim == 2) 05865 { 05866 // Print the type of the mesh. 05867 if (Nodes == NULL) 05868 out << "areamesh2\n\n"; 05869 else 05870 out << "curved_areamesh2\n\n"; 05871 05872 // Print the boundary elements. 05873 out << NumOfBdrElements << '\n'; 05874 for (i = 0; i < NumOfBdrElements; i++) 05875 { 05876 boundary[i]->GetVertices(v); 05877 05878 out << boundary[i]->GetAttribute(); 05879 for (j = 0; j < v.Size(); j++) 05880 out << ' ' << v[j] + 1; 05881 out << '\n'; 05882 } 05883 05884 // Print the elements. 05885 out << NumOfElements << '\n'; 05886 for (i = 0; i < NumOfElements; i++) 05887 { 05888 elements[i]->GetVertices(v); 05889 05890 out << elements[i]->GetAttribute() << ' ' << v.Size(); 05891 for (j = 0; j < v.Size(); j++) 05892 out << ' ' << v[j] + 1; 05893 out << '\n'; 05894 } 05895 05896 if (Nodes == NULL) 05897 { 05898 // Print the vertices. 05899 out << NumOfVertices << '\n'; 05900 for (i = 0; i < NumOfVertices; i++) 05901 { 05902 out << vertices[i](0); 05903 for (j = 1; j < Dim; j++) 05904 out << ' ' << vertices[i](j); 05905 out << '\n'; 05906 } 05907 } 05908 else 05909 { 05910 out << NumOfVertices << '\n'; 05911 Nodes->Save(out); 05912 } 05913 } 05914 else // ===== Dim != 2 ===== 05915 { 05916 if (Nodes) 05917 { 05918 mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D"); 05919 } 05920 05921 if (meshgen == 1) 05922 { 05923 int nv; 05924 const int *ind; 05925 05926 out << "NETGEN_Neutral_Format\n"; 05927 // print the vertices 05928 out << NumOfVertices << '\n'; 05929 for (i = 0; i < NumOfVertices; i++) 05930 { 05931 for (j = 0; j < Dim; j++) 05932 out << ' ' << vertices[i](j); 05933 out << '\n'; 05934 } 05935 05936 // print the elements 05937 out << NumOfElements << '\n'; 05938 for (i = 0; i < NumOfElements; i++) 05939 { 05940 nv = elements[i]->GetNVertices(); 05941 ind = elements[i]->GetVertices(); 05942 out << elements[i]->GetAttribute(); 05943 for (j = 0; j < nv; j++) 05944 out << ' ' << ind[j]+1; 05945 out << '\n'; 05946 } 05947 05948 // print the boundary information. 05949 out << NumOfBdrElements << '\n'; 05950 for (i = 0; i < NumOfBdrElements; i++) 05951 { 05952 nv = boundary[i]->GetNVertices(); 05953 ind = boundary[i]->GetVertices(); 05954 out << boundary[i]->GetAttribute(); 05955 for (j = 0; j < nv; j++) 05956 out << ' ' << ind[j]+1; 05957 out << '\n'; 05958 } 05959 } 05960 else if (meshgen == 2) // TrueGrid 05961 { 05962 int nv; 05963 const int *ind; 05964 05965 out << "TrueGrid\n" 05966 << "1 " << NumOfVertices << " " << NumOfElements 05967 << " 0 0 0 0 0 0 0\n" 05968 << "0 0 0 1 0 0 0 0 0 0 0\n" 05969 << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n" 05970 << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n" 05971 << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"; 05972 05973 for (i = 0; i < NumOfVertices; i++) 05974 out << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1) 05975 << ' ' << vertices[i](2) << " 0.0\n"; 05976 05977 for (i = 0; i < NumOfElements; i++) 05978 { 05979 nv = elements[i]->GetNVertices(); 05980 ind = elements[i]->GetVertices(); 05981 out << i+1 << ' ' << elements[i]->GetAttribute(); 05982 for (j = 0; j < nv; j++) 05983 out << ' ' << ind[j]+1; 05984 out << '\n'; 05985 } 05986 05987 for (i = 0; i < NumOfBdrElements; i++) 05988 { 05989 nv = boundary[i]->GetNVertices(); 05990 ind = boundary[i]->GetVertices(); 05991 out << boundary[i]->GetAttribute(); 05992 for (j = 0; j < nv; j++) 05993 out << ' ' << ind[j]+1; 05994 out << " 1.0 1.0 1.0 1.0\n"; 05995 } 05996 } 05997 } 05998 05999 out << flush; 06000 } 06001 06002 void Mesh::Print(ostream &out) const 06003 { 06004 int i, j; 06005 06006 if (NURBSext) 06007 { 06008 NURBSext->Print(out); 06009 out << '\n'; 06010 Nodes->Save(out); 06011 return; 06012 } 06013 06014 out << "MFEM mesh v1.0\n"; 06015 06016 // optional 06017 out << 06018 "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n" 06019 "# POINT = 0\n" 06020 "# SEGMENT = 1\n" 06021 "# TRIANGLE = 2\n" 06022 "# SQUARE = 3\n" 06023 "# TETRAHEDRON = 4\n" 06024 "# CUBE = 5\n" 06025 "#\n"; 06026 06027 out << "\ndimension\n" << Dim 06028 << "\n\nelements\n" << NumOfElements << '\n'; 06029 for (i = 0; i < NumOfElements; i++) 06030 PrintElement(elements[i], out); 06031 06032 out << "\nboundary\n" << NumOfBdrElements << '\n'; 06033 for (i = 0; i < NumOfBdrElements; i++) 06034 PrintElement(boundary[i], out); 06035 06036 out << "\nvertices\n" << NumOfVertices << '\n'; 06037 if (Nodes == NULL) 06038 { 06039 out << Dim << '\n'; 06040 for (i = 0; i < NumOfVertices; i++) 06041 { 06042 out << vertices[i](0); 06043 for (j = 1; j < Dim; j++) 06044 out << ' ' << vertices[i](j); 06045 out << '\n'; 06046 } 06047 } 06048 else 06049 { 06050 out << "\nnodes\n"; 06051 Nodes->Save(out); 06052 } 06053 } 06054 06055 void Mesh::PrintTopo(ostream &out,const Array<int> &e_to_k) const 06056 { 06057 int i; 06058 Array<int> vert; 06059 06060 out << "MFEM NURBS mesh v1.0\n"; 06061 06062 // optional 06063 out << 06064 "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n" 06065 "# SEGMENT = 1\n" 06066 "# SQUARE = 3\n" 06067 "# CUBE = 5\n" 06068 "#\n"; 06069 06070 out << "\ndimension\n" << Dim 06071 << "\n\nelements\n" << NumOfElements << '\n'; 06072 for (i = 0; i < NumOfElements; i++) 06073 PrintElement(elements[i], out); 06074 06075 out << "\nboundary\n" << NumOfBdrElements << '\n'; 06076 for (i = 0; i < NumOfBdrElements; i++) 06077 PrintElement(boundary[i], out); 06078 06079 out << "\nedges\n" << NumOfEdges << '\n'; 06080 for (i = 0; i < NumOfEdges; i++) 06081 { 06082 edge_vertex->GetRow(i, vert); 06083 int ki = e_to_k[i]; 06084 if (ki < 0) 06085 ki = -1 - ki; 06086 out << ki << ' ' << vert[0] << ' ' << vert[1] << '\n'; 06087 } 06088 out << "\nvertices\n" << NumOfVertices << '\n'; 06089 } 06090 06091 void Mesh::PrintVTK(ostream &out) 06092 { 06093 out << 06094 "# vtk DataFile Version 3.0\n" 06095 "Generated by MFEM\n" 06096 "ASCII\n" 06097 "DATASET UNSTRUCTURED_GRID\n"; 06098 06099 if (Nodes == NULL) 06100 { 06101 out << "POINTS " << NumOfVertices << " double\n"; 06102 for (int i = 0; i < NumOfVertices; i++) 06103 { 06104 out << vertices[i](0); 06105 int j; 06106 for (j = 1; j < Dim; j++) 06107 out << ' ' << vertices[i](j); 06108 for ( ; j < 3; j++) 06109 out << ' ' << 0.0; 06110 out << '\n'; 06111 } 06112 } 06113 else 06114 { 06115 Array<int> vdofs(3); 06116 out << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n"; 06117 for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++) 06118 { 06119 vdofs.SetSize(1); 06120 vdofs[0] = i; 06121 Nodes->FESpace()->DofsToVDofs(vdofs); 06122 out << (*Nodes)(vdofs[0]); 06123 int j; 06124 for (j = 1; j < Dim; j++) 06125 out << ' ' << (*Nodes)(vdofs[j]); 06126 for ( ; j < 3; j++) 06127 out << ' ' << 0.0; 06128 out << '\n'; 06129 } 06130 } 06131 06132 int order = -1; 06133 if (Nodes == NULL) 06134 { 06135 int size = 0; 06136 for (int i = 0; i < NumOfElements; i++) 06137 size += elements[i]->GetNVertices() + 1; 06138 out << "CELLS " << NumOfElements << ' ' << size << '\n'; 06139 for (int i = 0; i < NumOfElements; i++) 06140 { 06141 const int *v = elements[i]->GetVertices(); 06142 const int nv = elements[i]->GetNVertices(); 06143 out << nv; 06144 for (int j = 0; j < nv; j++) 06145 out << ' ' << v[j]; 06146 out << '\n'; 06147 } 06148 order = 1; 06149 } 06150 else 06151 { 06152 Array<int> dofs; 06153 int size = 0; 06154 for (int i = 0; i < NumOfElements; i++) 06155 { 06156 Nodes->FESpace()->GetElementDofs(i, dofs); 06157 size += dofs.Size() + 1; 06158 } 06159 out << "CELLS " << NumOfElements << ' ' << size << '\n'; 06160 const char *fec_name = Nodes->FESpace()->FEColl()->Name(); 06161 if (!strcmp(fec_name, "Linear")) 06162 order = 1; 06163 else if (!strcmp(fec_name, "Quadratic")) 06164 order = 2; 06165 if (order == -1) 06166 { 06167 cerr << "Mesh::PrintVTK : can not save '" 06168 << fec_name << "' elements!" << endl; 06169 mfem_error(); 06170 } 06171 for (int i = 0; i < NumOfElements; i++) 06172 { 06173 Nodes->FESpace()->GetElementDofs(i, dofs); 06174 out << dofs.Size(); 06175 if (order == 1) 06176 { 06177 for (int j = 0; j < dofs.Size(); j++) 06178 out << ' ' << dofs[j]; 06179 } 06180 else if (order == 2) 06181 { 06182 const int *vtk_mfem; 06183 switch (elements[i]->GetGeometryType()) 06184 { 06185 case Geometry::TRIANGLE: 06186 case Geometry::SQUARE: 06187 vtk_mfem = vtk_quadratic_hex; break; // identity map 06188 case Geometry::TETRAHEDRON: 06189 vtk_mfem = vtk_quadratic_tet; break; 06190 case Geometry::CUBE: 06191 vtk_mfem = vtk_quadratic_hex; break; 06192 } 06193 for (int j = 0; j < dofs.Size(); j++) 06194 out << ' ' << dofs[vtk_mfem[j]]; 06195 } 06196 out << '\n'; 06197 } 06198 } 06199 06200 out << "CELL_TYPES " << NumOfElements << '\n'; 06201 for (int i = 0; i < NumOfElements; i++) 06202 { 06203 int vtk_cell_type; 06204 if (order == 1) 06205 { 06206 switch (elements[i]->GetGeometryType()) 06207 { 06208 case Geometry::TRIANGLE: vtk_cell_type = 5; break; 06209 case Geometry::SQUARE: vtk_cell_type = 9; break; 06210 case Geometry::TETRAHEDRON: vtk_cell_type = 10; break; 06211 case Geometry::CUBE: vtk_cell_type = 12; break; 06212 } 06213 } 06214 else if (order == 2) 06215 { 06216 switch (elements[i]->GetGeometryType()) 06217 { 06218 case Geometry::TRIANGLE: vtk_cell_type = 22; break; 06219 case Geometry::SQUARE: vtk_cell_type = 28; break; 06220 case Geometry::TETRAHEDRON: vtk_cell_type = 24; break; 06221 case Geometry::CUBE: vtk_cell_type = 29; break; 06222 } 06223 } 06224 06225 out << vtk_cell_type << '\n'; 06226 } 06227 06228 // write attributes 06229 out << "CELL_DATA " << NumOfElements << '\n' 06230 << "SCALARS material int\n" 06231 << "LOOKUP_TABLE default\n"; 06232 for (int i = 0; i < NumOfElements; i++) 06233 { 06234 out << elements[i]->GetAttribute() << '\n'; 06235 } 06236 } 06237 06238 void Mesh::PrintVTK(ostream &out, int ref, int field_data) 06239 { 06240 int np, nc, size; 06241 RefinedGeometry *RefG; 06242 DenseMatrix pmat; 06243 06244 out << 06245 "# vtk DataFile Version 3.0\n" 06246 "Generated by MFEM\n" 06247 "ASCII\n" 06248 "DATASET UNSTRUCTURED_GRID\n"; 06249 06250 // additional dataset information 06251 if (field_data) 06252 { 06253 out << "FIELD FieldData 1" << endl 06254 << "MaterialIds " << 1 << " " << attributes.Size() << " int" << endl; 06255 for (int i = 0; i < attributes.Size(); i++) 06256 out << attributes[i] << " "; 06257 out << endl; 06258 } 06259 06260 // count the points, cells, size 06261 np = nc = size = 0; 06262 for (int i = 0; i < GetNE(); i++) 06263 { 06264 int geom = GetElementBaseGeometry(i); 06265 int nv = Geometries.GetVertices(geom)->GetNPoints(); 06266 RefG = GlobGeometryRefiner.Refine(geom, ref, 1); 06267 np += RefG->RefPts.GetNPoints(); 06268 nc += RefG->RefGeoms.Size() / nv; 06269 size += (RefG->RefGeoms.Size() / nv) * (nv + 1); 06270 } 06271 out << "POINTS " << np << " double\n"; 06272 // write the points 06273 for (int i = 0; i < GetNE(); i++) 06274 { 06275 RefG = GlobGeometryRefiner.Refine( 06276 GetElementBaseGeometry(i), ref, 1); 06277 06278 GetElementTransformation(i)->Transform(RefG->RefPts, pmat); 06279 06280 for (int j = 0; j < pmat.Width(); j++) 06281 { 06282 out << pmat(0, j) << ' ' << pmat(1, j) << ' '; 06283 if (pmat.Height() == 2) 06284 out << 0.0; 06285 else 06286 out << pmat(2, j); 06287 out << '\n'; 06288 } 06289 } 06290 06291 // write the cells 06292 out << "CELLS " << nc << ' ' << size << '\n'; 06293 np = 0; 06294 for (int i = 0; i < GetNE(); i++) 06295 { 06296 int geom = GetElementBaseGeometry(i); 06297 int nv = Geometries.GetVertices(geom)->GetNPoints(); 06298 RefG = GlobGeometryRefiner.Refine(geom, ref, 1); 06299 Array<int> &RG = RefG->RefGeoms; 06300 06301 for (int j = 0; j < RG.Size(); ) 06302 { 06303 out << nv; 06304 for (int k = 0; k < nv; k++, j++) 06305 out << ' ' << np + RG[j]; 06306 out << '\n'; 06307 } 06308 np += RefG->RefPts.GetNPoints(); 06309 } 06310 out << "CELL_TYPES " << nc << '\n'; 06311 for (int i = 0; i < GetNE(); i++) 06312 { 06313 int geom = GetElementBaseGeometry(i); 06314 int nv = Geometries.GetVertices(geom)->GetNPoints(); 06315 RefG = GlobGeometryRefiner.Refine(geom, ref, 1); 06316 Array<int> &RG = RefG->RefGeoms; 06317 int vtk_cell_type = 5; 06318 06319 switch (geom) 06320 { 06321 case Geometry::TRIANGLE: vtk_cell_type = 5; break; 06322 case Geometry::SQUARE: vtk_cell_type = 9; break; 06323 case Geometry::TETRAHEDRON: vtk_cell_type = 10; break; 06324 case Geometry::CUBE: vtk_cell_type = 12; break; 06325 } 06326 06327 for (int j = 0; j < RG.Size(); j += nv) 06328 { 06329 out << vtk_cell_type << '\n'; 06330 } 06331 } 06332 // write attributes (materials) 06333 out << "CELL_DATA " << nc << '\n' 06334 << "SCALARS material int\n" 06335 << "LOOKUP_TABLE default\n"; 06336 for (int i = 0; i < GetNE(); i++) 06337 { 06338 int geom = GetElementBaseGeometry(i); 06339 int nv = Geometries.GetVertices(geom)->GetNPoints(); 06340 RefG = GlobGeometryRefiner.Refine(geom, ref, 1); 06341 int attr = GetAttribute(i); 06342 for (int j = 0; j < RefG->RefGeoms.Size(); j += nv) 06343 { 06344 out << attr << '\n'; 06345 } 06346 } 06347 06348 Array<int> coloring; 06349 srandom(time(0)); 06350 double a = double(random()) / (double(RAND_MAX) + 1.); 06351 int el0 = (int)floor(a * GetNE()); 06352 GetElementColoring(coloring, el0); 06353 out << "SCALARS element_coloring int\n" 06354 << "LOOKUP_TABLE default\n"; 06355 for (int i = 0; i < GetNE(); i++) 06356 { 06357 int geom = GetElementBaseGeometry(i); 06358 int nv = Geometries.GetVertices(geom)->GetNPoints(); 06359 RefG = GlobGeometryRefiner.Refine(geom, ref, 1); 06360 for (int j = 0; j < RefG->RefGeoms.Size(); j += nv) 06361 { 06362 out << coloring[i] + 1 << '\n'; 06363 } 06364 } 06365 // prepare to write data 06366 out << "POINT_DATA " << np << '\n'; 06367 } 06368 06369 void Mesh::GetElementColoring(Array<int> &colors, int el0) 06370 { 06371 int delete_el_to_el = (el_to_el) ? (0) : (1); 06372 const Table &el_el = ElementToElementTable(); 06373 int num_el = GetNE(), stack_p, stack_top_p, max_num_col; 06374 Array<int> el_stack(num_el); 06375 06376 const int *i_el_el = el_el.GetI(); 06377 const int *j_el_el = el_el.GetJ(); 06378 06379 colors.SetSize(num_el); 06380 colors = -2; 06381 max_num_col = 1; 06382 stack_p = stack_top_p = 0; 06383 for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el) 06384 { 06385 if (colors[el] != -2) 06386 continue; 06387 06388 colors[el] = -1; 06389 el_stack[stack_top_p++] = el; 06390 06391 for ( ; stack_p < stack_top_p; stack_p++) 06392 { 06393 int i = el_stack[stack_p]; 06394 int num_nb = i_el_el[i+1] - i_el_el[i]; 06395 if (max_num_col < num_nb + 1) 06396 max_num_col = num_nb + 1; 06397 for (int j = i_el_el[i]; j < i_el_el[i+1]; j++) 06398 { 06399 int k = j_el_el[j]; 06400 if (colors[k] == -2) 06401 { 06402 colors[k] = -1; 06403 el_stack[stack_top_p++] = k; 06404 } 06405 } 06406 } 06407 } 06408 06409 Array<int> col_marker(max_num_col); 06410 06411 for (stack_p = 0; stack_p < stack_top_p; stack_p++) 06412 { 06413 int i = el_stack[stack_p], col; 06414 col_marker = 0; 06415 for (int j = i_el_el[i]; j < i_el_el[i+1]; j++) 06416 { 06417 col = colors[j_el_el[j]]; 06418 if (col != -1) 06419 col_marker[col] = 1; 06420 } 06421 06422 for (col = 0; col < max_num_col; col++) 06423 if (col_marker[col] == 0) 06424 break; 06425 06426 colors[i] = col; 06427 } 06428 06429 if (delete_el_to_el) 06430 { 06431 delete el_to_el; 06432 el_to_el = NULL; 06433 } 06434 } 06435 06436 void Mesh::PrintWithPartitioning(int *partitioning, ostream &out, 06437 int elem_attr) const 06438 { 06439 if (Dim != 3 && Dim != 2) return; 06440 06441 int i, j, k, l, nv, nbe, *v; 06442 06443 out << "MFEM mesh v1.0\n"; 06444 06445 // optional 06446 out << 06447 "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n" 06448 "# POINT = 0\n" 06449 "# SEGMENT = 1\n" 06450 "# TRIANGLE = 2\n" 06451 "# SQUARE = 3\n" 06452 "# TETRAHEDRON = 4\n" 06453 "# CUBE = 5\n" 06454 "#\n"; 06455 06456 out << "\ndimension\n" << Dim 06457 << "\n\nelements\n" << NumOfElements << '\n'; 06458 for (i = 0; i < NumOfElements; i++) 06459 { 06460 out << int((elem_attr) ? partitioning[i] : elements[i]->GetAttribute()) 06461 << ' ' << elements[i]->GetGeometryType(); 06462 nv = elements[i]->GetNVertices(); 06463 v = elements[i]->GetVertices(); 06464 for (j = 0; j < nv; j++) 06465 out << ' ' << v[j]; 06466 out << '\n'; 06467 } 06468 nbe = 0; 06469 for (i = 0; i < NumOfFaces; i++) 06470 { 06471 if ((l = faces_info[i].Elem2No) >= 0) 06472 { 06473 k = partitioning[faces_info[i].Elem1No]; 06474 l = partitioning[l]; 06475 if (k != l) 06476 nbe += 2; 06477 } 06478 else 06479 nbe++; 06480 } 06481 out << "\nboundary\n" << nbe << '\n'; 06482 for (i = 0; i < NumOfFaces; i++) 06483 { 06484 if ((l = faces_info[i].Elem2No) >= 0) 06485 { 06486 k = partitioning[faces_info[i].Elem1No]; 06487 l = partitioning[l]; 06488 if (k != l) 06489 { 06490 nv = faces[i]->GetNVertices(); 06491 v = faces[i]->GetVertices(); 06492 out << k+1 << ' ' << faces[i]->GetGeometryType(); 06493 for (j = 0; j < nv; j++) 06494 out << ' ' << v[j]; 06495 out << '\n'; 06496 out << l+1 << ' ' << faces[i]->GetGeometryType(); 06497 for (j = nv-1; j >= 0; j--) 06498 out << ' ' << v[j]; 06499 out << '\n'; 06500 } 06501 } 06502 else 06503 { 06504 k = partitioning[faces_info[i].Elem1No]; 06505 nv = faces[i]->GetNVertices(); 06506 v = faces[i]->GetVertices(); 06507 out << k+1 << ' ' << faces[i]->GetGeometryType(); 06508 for (j = 0; j < nv; j++) 06509 out << ' ' << v[j]; 06510 out << '\n'; 06511 } 06512 } 06513 out << "\nvertices\n" << NumOfVertices << '\n'; 06514 if (Nodes == NULL) 06515 { 06516 out << Dim << '\n'; 06517 for (i = 0; i < NumOfVertices; i++) 06518 { 06519 out << vertices[i](0); 06520 for (j = 1; j < Dim; j++) 06521 out << ' ' << vertices[i](j); 06522 out << '\n'; 06523 } 06524 } 06525 else 06526 { 06527 out << "\nnodes\n"; 06528 Nodes->Save(out); 06529 } 06530 } 06531 06532 void Mesh::PrintElementsWithPartitioning(int *partitioning, 06533 ostream &out, 06534 int interior_faces) 06535 { 06536 if (Dim != 3 && Dim != 2) return; 06537 06538 int i, j, k, l, s; 06539 06540 int nv; 06541 const int *ind; 06542 06543 int *vcount = new int[NumOfVertices]; 06544 for (i = 0; i < NumOfVertices; i++) 06545 vcount[i] = 0; 06546 for (i = 0; i < NumOfElements; i++) 06547 { 06548 nv = elements[i]->GetNVertices(); 06549 ind = elements[i]->GetVertices(); 06550 for (j = 0; j < nv; j++) 06551 vcount[ind[j]]++; 06552 } 06553 06554 int *voff = new int[NumOfVertices+1]; 06555 voff[0] = 0; 06556 for (i = 1; i <= NumOfVertices; i++) 06557 voff[i] = vcount[i-1] + voff[i-1]; 06558 06559 int **vown = new int*[NumOfVertices]; 06560 for (i = 0; i < NumOfVertices; i++) 06561 vown[i] = new int[vcount[i]]; 06562 06563 // 2D 06564 if (Dim == 2) 06565 { 06566 int nv, nbe; 06567 int *ind; 06568 06569 Table edge_el; 06570 Transpose(ElementToEdgeTable(), edge_el); 06571 06572 // Fake printing of the elements. 06573 for (i = 0; i < NumOfElements; i++) 06574 { 06575 nv = elements[i]->GetNVertices(); 06576 ind = elements[i]->GetVertices(); 06577 for (j = 0; j < nv; j++) 06578 { 06579 vcount[ind[j]]--; 06580 vown[ind[j]][vcount[ind[j]]] = i; 06581 } 06582 } 06583 06584 for (i = 0; i < NumOfVertices; i++) 06585 vcount[i] = voff[i+1] - voff[i]; 06586 06587 nbe = 0; 06588 for (i = 0; i < edge_el.Size(); i++) 06589 { 06590 const int *el = edge_el.GetRow(i); 06591 if (edge_el.RowSize(i) > 1) 06592 { 06593 k = partitioning[el[0]]; 06594 l = partitioning[el[1]]; 06595 if (interior_faces || k != l) 06596 nbe += 2; 06597 } 06598 else 06599 nbe++; 06600 } 06601 06602 // Print the type of the mesh and the boundary elements. 06603 out << "areamesh2\n\n" << nbe << '\n'; 06604 06605 for (i = 0; i < edge_el.Size(); i++) 06606 { 06607 const int *el = edge_el.GetRow(i); 06608 if (edge_el.RowSize(i) > 1) 06609 { 06610 k = partitioning[el[0]]; 06611 l = partitioning[el[1]]; 06612 if (interior_faces || k != l) 06613 { 06614 Array<int> ev; 06615 GetEdgeVertices(i,ev); 06616 out << k+1; // attribute 06617 for (j = 0; j < 2; j++) 06618 for (s = 0; s < vcount[ev[j]]; s++) 06619 if (vown[ev[j]][s] == el[0]) 06620 out << ' ' << voff[ev[j]]+s+1; 06621 out << '\n'; 06622 out << l+1; // attribute 06623 for (j = 1; j >= 0; j--) 06624 for (s = 0; s < vcount[ev[j]]; s++) 06625 if (vown[ev[j]][s] == el[1]) 06626 out << ' ' << voff[ev[j]]+s+1; 06627 out << '\n'; 06628 } 06629 } 06630 else 06631 { 06632 k = partitioning[el[0]]; 06633 Array<int> ev; 06634 GetEdgeVertices(i,ev); 06635 out << k+1; // attribute 06636 for (j = 0; j < 2; j++) 06637 for (s = 0; s < vcount[ev[j]]; s++) 06638 if (vown[ev[j]][s] == el[0]) 06639 out << ' ' << voff[ev[j]]+s+1; 06640 out << '\n'; 06641 } 06642 } 06643 06644 // Print the elements. 06645 out << NumOfElements << '\n'; 06646 for (i = 0; i < NumOfElements; i++) 06647 { 06648 nv = elements[i]->GetNVertices(); 06649 ind = elements[i]->GetVertices(); 06650 out << partitioning[i]+1 << ' '; // use subdomain number as attribute 06651 out << nv << ' '; 06652 for (j = 0; j < nv; j++) 06653 { 06654 out << ' ' << voff[ind[j]]+vcount[ind[j]]--; 06655 vown[ind[j]][vcount[ind[j]]] = i; 06656 } 06657 out << '\n'; 06658 } 06659 06660 for (i = 0; i < NumOfVertices; i++) 06661 vcount[i] = voff[i+1] - voff[i]; 06662 06663 // Print the vertices. 06664 out << voff[NumOfVertices] << '\n'; 06665 for (i = 0; i < NumOfVertices; i++) 06666 for (k = 0; k < vcount[i]; k++) 06667 { 06668 for (j = 0; j < Dim; j++) 06669 out << vertices[i](j) << ' '; 06670 out << '\n'; 06671 } 06672 out << flush; 06673 return; 06674 } 06675 06676 // Dim is 3 06677 if (meshgen == 1) 06678 { 06679 out << "NETGEN_Neutral_Format\n"; 06680 // print the vertices 06681 out << voff[NumOfVertices] << '\n'; 06682 for (i = 0; i < NumOfVertices; i++) 06683 for (k = 0; k < vcount[i]; k++) 06684 { 06685 for (j = 0; j < Dim; j++) 06686 out << ' ' << vertices[i](j); 06687 out << '\n'; 06688 } 06689 06690 // print the elements 06691 out << NumOfElements << '\n'; 06692 for (i = 0; i < NumOfElements; i++) 06693 { 06694 nv = elements[i]->GetNVertices(); 06695 ind = elements[i]->GetVertices(); 06696 out << partitioning[i]+1; // use subdomain number as attribute 06697 for (j = 0; j < nv; j++) 06698 { 06699 out << ' ' << voff[ind[j]]+vcount[ind[j]]--; 06700 vown[ind[j]][vcount[ind[j]]] = i; 06701 } 06702 out << '\n'; 06703 } 06704 06705 for (i = 0; i < NumOfVertices; i++) 06706 vcount[i] = voff[i+1] - voff[i]; 06707 06708 // print the boundary information. 06709 int k, l, nbe; 06710 nbe = 0; 06711 for (i = 0; i < NumOfFaces; i++) 06712 if ((l = faces_info[i].Elem2No) >= 0) 06713 { 06714 k = partitioning[faces_info[i].Elem1No]; 06715 l = partitioning[l]; 06716 if (interior_faces || k != l) 06717 nbe += 2; 06718 } 06719 else 06720 nbe++; 06721 06722 out << nbe << '\n'; 06723 for (i = 0; i < NumOfFaces; i++) 06724 if ((l = faces_info[i].Elem2No) >= 0) 06725 { 06726 k = partitioning[faces_info[i].Elem1No]; 06727 l = partitioning[l]; 06728 if (interior_faces || k != l) 06729 { 06730 nv = faces[i]->GetNVertices(); 06731 ind = faces[i]->GetVertices(); 06732 out << k+1; // attribute 06733 for (j = 0; j < nv; j++) 06734 for (s = 0; s < vcount[ind[j]]; s++) 06735 if (vown[ind[j]][s] == faces_info[i].Elem1No) 06736 out << ' ' << voff[ind[j]]+s+1; 06737 out << '\n'; 06738 out << l+1; // attribute 06739 for (j = nv-1; j >= 0; j--) 06740 for (s = 0; s < vcount[ind[j]]; s++) 06741 if (vown[ind[j]][s] == faces_info[i].Elem2No) 06742 out << ' ' << voff[ind[j]]+s+1; 06743 out << '\n'; 06744 } 06745 } 06746 else 06747 { 06748 k = partitioning[faces_info[i].Elem1No]; 06749 nv = faces[i]->GetNVertices(); 06750 ind = faces[i]->GetVertices(); 06751 out << k+1; // attribute 06752 for (j = 0; j < nv; j++) 06753 for (s = 0; s < vcount[ind[j]]; s++) 06754 if (vown[ind[j]][s] == faces_info[i].Elem1No) 06755 out << ' ' << voff[ind[j]]+s+1; 06756 out << '\n'; 06757 } 06758 06759 for (i = 0; i < NumOfVertices; i++) 06760 delete [] vown[i]; 06761 } 06762 else if (meshgen == 2) // TrueGrid 06763 { 06764 // count the number of the boundary elements. 06765 int k, l, nbe; 06766 nbe = 0; 06767 for (i = 0; i < NumOfFaces; i++) 06768 if ((l = faces_info[i].Elem2No) >= 0) 06769 { 06770 k = partitioning[faces_info[i].Elem1No]; 06771 l = partitioning[l]; 06772 if (interior_faces || k != l) 06773 nbe += 2; 06774 } 06775 else 06776 nbe++; 06777 06778 06779 out << "TrueGrid\n" 06780 << "1 " << voff[NumOfVertices] << " " << NumOfElements 06781 << " 0 0 0 0 0 0 0\n" 06782 << "0 0 0 1 0 0 0 0 0 0 0\n" 06783 << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n" 06784 << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n" 06785 << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"; 06786 06787 for (i = 0; i < NumOfVertices; i++) 06788 for (k = 0; k < vcount[i]; k++) 06789 out << voff[i]+k << " 0.0 " << vertices[i](0) << ' ' 06790 << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n"; 06791 06792 for (i = 0; i < NumOfElements; i++) 06793 { 06794 nv = elements[i]->GetNVertices(); 06795 ind = elements[i]->GetVertices(); 06796 out << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute 06797 for (j = 0; j < nv; j++) 06798 { 06799 out << ' ' << voff[ind[j]]+vcount[ind[j]]--; 06800 vown[ind[j]][vcount[ind[j]]] = i; 06801 } 06802 out << '\n'; 06803 } 06804 06805 for (i = 0; i < NumOfVertices; i++) 06806 vcount[i] = voff[i+1] - voff[i]; 06807 06808 // boundary elements 06809 for (i = 0; i < NumOfFaces; i++) 06810 if ((l = faces_info[i].Elem2No) >= 0) 06811 { 06812 k = partitioning[faces_info[i].Elem1No]; 06813 l = partitioning[l]; 06814 if (interior_faces || k != l) 06815 { 06816 nv = faces[i]->GetNVertices(); 06817 ind = faces[i]->GetVertices(); 06818 out << k+1; // attribute 06819 for (j = 0; j < nv; j++) 06820 for (s = 0; s < vcount[ind[j]]; s++) 06821 if (vown[ind[j]][s] == faces_info[i].Elem1No) 06822 out << ' ' << voff[ind[j]]+s+1; 06823 out << " 1.0 1.0 1.0 1.0\n"; 06824 out << l+1; // attribute 06825 for (j = nv-1; j >= 0; j--) 06826 for (s = 0; s < vcount[ind[j]]; s++) 06827 if (vown[ind[j]][s] == faces_info[i].Elem2No) 06828 out << ' ' << voff[ind[j]]+s+1; 06829 out << " 1.0 1.0 1.0 1.0\n"; 06830 } 06831 } 06832 else 06833 { 06834 k = partitioning[faces_info[i].Elem1No]; 06835 nv = faces[i]->GetNVertices(); 06836 ind = faces[i]->GetVertices(); 06837 out << k+1; // attribute 06838 for (j = 0; j < nv; j++) 06839 for (s = 0; s < vcount[ind[j]]; s++) 06840 if (vown[ind[j]][s] == faces_info[i].Elem1No) 06841 out << ' ' << voff[ind[j]]+s+1; 06842 out << " 1.0 1.0 1.0 1.0\n"; 06843 } 06844 } 06845 06846 out << flush; 06847 06848 delete [] vcount; 06849 delete [] voff; 06850 delete [] vown; 06851 } 06852 06853 void Mesh::ScaleSubdomains(double sf) 06854 { 06855 int i,j,k; 06856 Array<int> vert; 06857 DenseMatrix pointmat; 06858 int na = attributes.Size(); 06859 double *cg = new double[na*Dim]; 06860 int *nbea = new int[na]; 06861 06862 int *vn = new int[NumOfVertices]; 06863 for (i = 0; i < NumOfVertices; i++) 06864 vn[i] = 0; 06865 for (i = 0; i < na; i++) 06866 { 06867 for (j = 0; j < Dim; j++) 06868 cg[i*Dim+j] = 0.0; 06869 nbea[i] = 0; 06870 } 06871 06872 for (i = 0; i < NumOfElements; i++) 06873 { 06874 GetElementVertices(i, vert); 06875 for (k = 0; k < vert.Size(); k++) 06876 vn[vert[k]] = 1; 06877 } 06878 06879 for (i = 0; i < NumOfElements; i++) 06880 { 06881 int bea = GetAttribute(i)-1; 06882 GetPointMatrix(i, pointmat); 06883 GetElementVertices(i, vert); 06884 06885 for (k = 0; k < vert.Size(); k++) 06886 if (vn[vert[k]] == 1) 06887 { 06888 nbea[bea]++; 06889 for (j = 0; j < Dim; j++) 06890 cg[bea*Dim+j] += pointmat(j,k); 06891 vn[vert[k]] = 2; 06892 } 06893 } 06894 06895 for (i = 0; i < NumOfElements; i++) 06896 { 06897 int bea = GetAttribute(i)-1; 06898 GetElementVertices (i, vert); 06899 06900 for (k = 0; k < vert.Size(); k++) 06901 if (vn[vert[k]]) 06902 { 06903 for (j = 0; j < Dim; j++) 06904 vertices[vert[k]](j) = sf*vertices[vert[k]](j) + 06905 (1-sf)*cg[bea*Dim+j]/nbea[bea]; 06906 vn[vert[k]] = 0; 06907 } 06908 } 06909 06910 delete [] cg; 06911 delete [] nbea; 06912 delete [] vn; 06913 } 06914 06915 void Mesh::ScaleElements(double sf) 06916 { 06917 int i,j,k; 06918 Array<int> vert; 06919 DenseMatrix pointmat; 06920 int na = NumOfElements; 06921 double *cg = new double[na*Dim]; 06922 int *nbea = new int[na]; 06923 06924 int *vn = new int[NumOfVertices]; 06925 for (i = 0; i < NumOfVertices; i++) 06926 vn[i] = 0; 06927 for (i = 0; i < na; i++) 06928 { 06929 for (j = 0; j < Dim; j++) 06930 cg[i*Dim+j] = 0.0; 06931 nbea[i] = 0; 06932 } 06933 06934 for (i = 0; i < NumOfElements; i++) 06935 { 06936 GetElementVertices(i, vert); 06937 for (k = 0; k < vert.Size(); k++) 06938 vn[vert[k]] = 1; 06939 } 06940 06941 for (i = 0; i < NumOfElements; i++) 06942 { 06943 int bea = i; 06944 GetPointMatrix(i, pointmat); 06945 GetElementVertices(i, vert); 06946 06947 for (k = 0; k < vert.Size(); k++) 06948 if (vn[vert[k]] == 1) 06949 { 06950 nbea[bea]++; 06951 for (j = 0; j < Dim; j++) 06952 cg[bea*Dim+j] += pointmat(j,k); 06953 vn[vert[k]] = 2; 06954 } 06955 } 06956 06957 for (i = 0; i < NumOfElements; i++) 06958 { 06959 int bea = i; 06960 GetElementVertices(i, vert); 06961 06962 for (k = 0; k < vert.Size(); k++) 06963 if (vn[vert[k]]) 06964 { 06965 for (j = 0; j < Dim; j++) 06966 vertices[vert[k]](j) = sf*vertices[vert[k]](j) + 06967 (1-sf)*cg[bea*Dim+j]/nbea[bea]; 06968 vn[vert[k]] = 0; 06969 } 06970 } 06971 06972 delete [] cg; 06973 delete [] nbea; 06974 delete [] vn; 06975 } 06976 06977 void Mesh::Transform(void (*f)(const Vector&, Vector&)) 06978 { 06979 if (Nodes == NULL) 06980 { 06981 Vector vold(Dim), vnew(NULL, Dim); 06982 for (int i = 0; i < vertices.Size(); i++) 06983 { 06984 for (int j = 0; j < Dim; j++) 06985 vold(j) = vertices[i](j); 06986 vnew.SetData(vertices[i]()); 06987 (*f)(vold, vnew); 06988 } 06989 } 06990 else 06991 { 06992 GridFunction xnew(Nodes->FESpace()); 06993 VectorFunctionCoefficient f_pert(Dim, f); 06994 xnew.ProjectCoefficient(f_pert); 06995 *Nodes = xnew; 06996 } 06997 } 06998 06999 void Mesh::FreeElement(Element *E) 07000 { 07001 #ifdef MFEM_USE_MEMALLOC 07002 if (E) 07003 switch (E->GetType()) 07004 { 07005 case Element::TETRAHEDRON: TetMemory.Free((Tetrahedron *)E); break; 07006 case Element::BISECTED: BEMemory.Free((BisectedElement *)E); break; 07007 default: delete E; break; 07008 } 07009 #else 07010 delete E; 07011 #endif 07012 } 07013 07014 Mesh::~Mesh() 07015 { 07016 int i; 07017 07018 if (own_nodes) delete Nodes; 07019 07020 delete NURBSext; 07021 07022 for (i = 0; i < NumOfElements; i++) 07023 FreeElement(elements[i]); 07024 07025 for (i = 0; i < NumOfBdrElements; i++) 07026 FreeElement(boundary[i]); 07027 07028 for (i = 0; i < faces.Size(); i++) 07029 FreeElement(faces[i]); 07030 07031 DeleteTables(); 07032 }