MFEM  v3.1
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
mesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
3 // reserved. See file COPYRIGHT for details.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability see http://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the GNU Lesser General Public License (as published by the Free
10 // Software Foundation) version 2.1 dated February 1999.
11 
12 // Implementation of data type mesh
13 
14 #include "mesh_headers.hpp"
15 #include "../fem/fem.hpp"
16 #include "../general/sort_pairs.hpp"
17 
18 #include <iostream>
19 #include <sstream>
20 #include <fstream>
21 #include <limits>
22 #include <cmath>
23 #include <cstring>
24 #include <ctime>
25 
26 #ifdef MFEM_USE_GECKO
27 #include "graph.h"
28 #endif
29 
30 namespace mfem
31 {
32 
33 using namespace std;
34 
36 {
37  int geom = GetElementBaseGeometry(i);
38  ElementTransformation *eltransf = GetElementTransformation(i);
39  eltransf->SetIntPoint(&Geometries.GetCenter(geom));
40  Geometries.JacToPerfJac(geom, eltransf->Jacobian(), J);
41 }
42 
43 double Mesh::GetElementSize(int i, int type)
44 {
45  DenseMatrix J(Dim);
46  GetElementJacobian(i, J);
47  if (type == 0)
48  {
49  return pow(fabs(J.Det()), 1./Dim);
50  }
51  else if (type == 1)
52  {
53  return J.CalcSingularvalue(Dim-1); // h_min
54  }
55  else
56  {
57  return J.CalcSingularvalue(0); // h_max
58  }
59 }
60 
61 double Mesh::GetElementSize(int i, const Vector &dir)
62 {
63  DenseMatrix J(Dim);
64  Vector d_hat(Dim);
65  GetElementJacobian(i, J);
66  J.MultTranspose(dir, d_hat);
67  return sqrt((d_hat * d_hat) / (dir * dir));
68 }
69 
71 {
72  ElementTransformation *et = GetElementTransformation(i);
73  const IntegrationRule &ir = IntRules.Get(GetElementBaseGeometry(i),
74  et->OrderJ());
75  double volume = 0.0;
76  for (int j = 0; j < ir.GetNPoints(); j++)
77  {
78  const IntegrationPoint &ip = ir.IntPoint(j);
79  et->SetIntPoint(&ip);
80  volume += ip.weight * et->Weight();
81  }
82 
83  return volume;
84 }
85 
86 void Mesh::PrintCharacteristics(Vector *Vh, Vector *Vk, std::ostream &out)
87 {
88  int i, dim, sdim;
89  DenseMatrix J;
90  double h_min, h_max, kappa_min, kappa_max, h, kappa;
91 
92  out << "Mesh Characteristics:";
93 
94  dim = Dimension();
95  sdim = SpaceDimension();
96  J.SetSize(sdim, dim);
97 
98  if (Vh) { Vh->SetSize(NumOfElements); }
99  if (Vk) { Vk->SetSize(NumOfElements); }
100 
101  h_min = kappa_min = numeric_limits<double>::infinity();
102  h_max = kappa_max = -h_min;
103  for (i = 0; i < NumOfElements; i++)
104  {
105  GetElementJacobian(i, J);
106  h = pow(fabs(J.Weight()), 1.0/double(dim));
107  kappa = (dim == sdim) ?
108  J.CalcSingularvalue(0) / J.CalcSingularvalue(dim-1) : -1.0;
109  if (Vh) { (*Vh)(i) = h; }
110  if (Vk) { (*Vk)(i) = kappa; }
111 
112  if (h < h_min) { h_min = h; }
113  if (h > h_max) { h_max = h; }
114  if (kappa < kappa_min) { kappa_min = kappa; }
115  if (kappa > kappa_max) { kappa_max = kappa; }
116  }
117 
118  if (dim == 1)
119  {
120  out << '\n'
121  << "Number of vertices : " << GetNV() << '\n'
122  << "Number of elements : " << GetNE() << '\n'
123  << "Number of bdr elem : " << GetNBE() << '\n'
124  << "h_min : " << h_min << '\n'
125  << "h_max : " << h_max << '\n';
126  }
127  else if (dim == 2)
128  {
129  out << '\n'
130  << "Number of vertices : " << GetNV() << '\n'
131  << "Number of edges : " << GetNEdges() << '\n'
132  << "Number of elements : " << GetNE() << '\n'
133  << "Number of bdr elem : " << GetNBE() << '\n'
134  << "Euler Number : " << EulerNumber2D() << '\n'
135  << "h_min : " << h_min << '\n'
136  << "h_max : " << h_max << '\n'
137  << "kappa_min : " << kappa_min << '\n'
138  << "kappa_max : " << kappa_max << '\n';
139  }
140  else
141  {
142  out << '\n'
143  << "Number of vertices : " << GetNV() << '\n'
144  << "Number of edges : " << GetNEdges() << '\n'
145  << "Number of faces : " << GetNFaces() << '\n'
146  << "Number of elements : " << GetNE() << '\n'
147  << "Number of bdr elem : " << GetNBE() << '\n'
148  << "Euler Number : " << EulerNumber() << '\n'
149  << "h_min : " << h_min << '\n'
150  << "h_max : " << h_max << '\n'
151  << "kappa_min : " << kappa_min << '\n'
152  << "kappa_max : " << kappa_max << '\n';
153  }
154  out << '\n' << std::flush;
155 }
156 
158 {
159  switch (ElemType)
160  {
161  case Element::POINT : return &PointFE;
162  case Element::SEGMENT : return &SegmentFE;
163  case Element::TRIANGLE : return &TriangleFE;
165  case Element::TETRAHEDRON : return &TetrahedronFE;
166  case Element::HEXAHEDRON : return &HexahedronFE;
167  }
168  mfem_error("Mesh::GetTransformationFEforElement - unknown ElementType");
169  return &TriangleFE;
170 }
171 
172 
174 {
175  ElTr->Attribute = GetAttribute(i);
176  ElTr->ElementNo = i;
177  if (Nodes == NULL)
178  {
179  GetPointMatrix(i, ElTr->GetPointMat());
180  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
181  }
182  else
183  {
184  DenseMatrix &pm = ElTr->GetPointMat();
185  Array<int> vdofs;
186  Nodes->FESpace()->GetElementVDofs(i, vdofs);
187 
188  int n = vdofs.Size()/spaceDim;
189  pm.SetSize(spaceDim, n);
190  for (int k = 0; k < spaceDim; k++)
191  {
192  for (int j = 0; j < n; j++)
193  {
194  pm(k,j) = (*Nodes)(vdofs[n*k+j]);
195  }
196  }
197  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
198  }
199 }
200 
201 void Mesh::GetElementTransformation(int i, const Vector &nodes,
203 {
204  ElTr->Attribute = GetAttribute(i);
205  ElTr->ElementNo = i;
206  DenseMatrix &pm = ElTr->GetPointMat();
207  if (Nodes == NULL)
208  {
209  int nv = elements[i]->GetNVertices();
210  const int *v = elements[i]->GetVertices();
211  int n = vertices.Size();
212  pm.SetSize(spaceDim, nv);
213  for (int k = 0; k < spaceDim; k++)
214  {
215  for (int j = 0; j < nv; j++)
216  {
217  pm(k, j) = nodes(k*n+v[j]);
218  }
219  }
220  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
221  }
222  else
223  {
224  Array<int> vdofs;
225  Nodes->FESpace()->GetElementVDofs(i, vdofs);
226  int n = vdofs.Size()/spaceDim;
227  pm.SetSize(spaceDim, n);
228  for (int k = 0; k < spaceDim; k++)
229  {
230  for (int j = 0; j < n; j++)
231  {
232  pm(k,j) = nodes(vdofs[n*k+j]);
233  }
234  }
235  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
236  }
237 }
238 
240 {
241  GetElementTransformation(i, &Transformation);
242 
243  return &Transformation;
244 }
245 
247 {
248  GetBdrElementTransformation(i, &FaceTransformation);
249  return &FaceTransformation;
250 }
251 
253 {
254  ElTr->Attribute = GetBdrAttribute(i);
255  ElTr->ElementNo = i; // boundary element number
256  if (Nodes == NULL)
257  {
258  GetBdrPointMatrix(i, ElTr->GetPointMat());
259  ElTr->SetFE(
260  GetTransformationFEforElementType(GetBdrElementType(i)));
261  }
262  else
263  {
264  DenseMatrix &pm = ElTr->GetPointMat();
265  Array<int> vdofs;
266  Nodes->FESpace()->GetBdrElementVDofs(i, vdofs);
267  int n = vdofs.Size()/spaceDim;
268  pm.SetSize(spaceDim, n);
269  for (int k = 0; k < spaceDim; k++)
270  {
271  for (int j = 0; j < n; j++)
272  {
273  pm(k,j) = (*Nodes)(vdofs[n*k+j]);
274  }
275  }
276  ElTr->SetFE(Nodes->FESpace()->GetBE(i));
277  }
278 }
279 
281 {
282  FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute();
283  FTr->ElementNo = FaceNo;
284  DenseMatrix &pm = FTr->GetPointMat();
285  if (Nodes == NULL)
286  {
287  const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
288  const int nv = (Dim == 1) ? 1 : faces[FaceNo]->GetNVertices();
289  pm.SetSize(spaceDim, nv);
290  for (int i = 0; i < spaceDim; i++)
291  {
292  for (int j = 0; j < nv; j++)
293  {
294  pm(i, j) = vertices[v[j]](i);
295  }
296  }
297  FTr->SetFE(GetTransformationFEforElementType(
298  (Dim == 1) ? Element::POINT : faces[FaceNo]->GetType()));
299  }
300  else
301  {
302  const FiniteElement *face_el = Nodes->FESpace()->GetFaceElement(FaceNo);
303  if (face_el)
304  {
305  Array<int> vdofs;
306  Nodes->FESpace()->GetFaceVDofs(FaceNo, vdofs);
307  int n = vdofs.Size()/spaceDim;
308  pm.SetSize(spaceDim, n);
309  for (int i = 0; i < spaceDim; i++)
310  {
311  for (int j = 0; j < n; j++)
312  {
313  pm(i, j) = (*Nodes)(vdofs[n*i+j]);
314  }
315  }
316  FTr->SetFE(face_el);
317  }
318  else
319  {
320  int face_geom =
321  (Dim == 1) ? Geometry::POINT : faces[FaceNo]->GetGeometryType();
322  FaceInfo &face_info = faces_info[FaceNo];
323 
324  face_el = Nodes->FESpace()->GetTraceElement(face_info.Elem1No,
325  (Geometry::Type)face_geom);
326 
327  switch (face_geom)
328  {
329  case Geometry::POINT:
330  GetLocalPtToSegTransformation(FaceElemTr.Loc1.Transf,
331  face_info.Elem1Inf);
332  break;
333  case Geometry::SEGMENT:
334  if (GetElementType(face_info.Elem1No) == Element::TRIANGLE)
335  GetLocalSegToTriTransformation(FaceElemTr.Loc1.Transf,
336  face_info.Elem1Inf);
337  else // assume the element is a quad
338  GetLocalSegToQuadTransformation(FaceElemTr.Loc1.Transf,
339  face_info.Elem1Inf);
340  break;
341  case Geometry::TRIANGLE:
342  // --- assume the face is a triangle -- face of a tetrahedron
343  GetLocalTriToTetTransformation(FaceElemTr.Loc1.Transf,
344  face_info.Elem1Inf);
345  break;
346  case Geometry::SQUARE:
347  // --- assume the face is a quad -- face of a hexahedron
348  GetLocalQuadToHexTransformation(FaceElemTr.Loc1.Transf,
349  face_info.Elem1Inf);
350  break;
351  }
352 
353  IntegrationRule eir(face_el->GetDof());
354  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
355  // 'Transformation' is not used
356  Nodes->GetVectorValues(Transformation, eir, pm);
357 
358  FTr->SetFE(face_el);
359  }
360  }
361 }
362 
364 {
365  GetFaceTransformation(FaceNo, &FaceTransformation);
366  return &FaceTransformation;
367 }
368 
370 {
371  if (Dim == 2)
372  {
373  GetFaceTransformation(EdgeNo, EdTr);
374  return;
375  }
376  if (Dim == 1)
377  {
378  mfem_error("Mesh::GetEdgeTransformation not defined in 1D \n");
379  }
380 
381  EdTr->Attribute = 1;
382  EdTr->ElementNo = EdgeNo;
383  DenseMatrix &pm = EdTr->GetPointMat();
384  if (Nodes == NULL)
385  {
386  Array<int> v;
387  GetEdgeVertices(EdgeNo, v);
388  const int nv = 2;
389  pm.SetSize(spaceDim, nv);
390  for (int i = 0; i < spaceDim; i++)
391  {
392  for (int j = 0; j < nv; j++)
393  {
394  pm(i, j) = vertices[v[j]](i);
395  }
396  }
397  EdTr->SetFE(GetTransformationFEforElementType(Element::SEGMENT));
398 
399  }
400  else
401  {
402  Array<int> vdofs;
403  Nodes->FESpace()->GetEdgeVDofs(EdgeNo, vdofs);
404  int n = vdofs.Size()/spaceDim;
405  pm.SetSize(spaceDim, n);
406  for (int i = 0; i < spaceDim; i++)
407  {
408  for (int j = 0; j < n; j++)
409  {
410  pm(i, j) = (*Nodes)(vdofs[n*i+j]);
411  }
412  }
413  EdTr->SetFE(GetTransformationFEforElementType(Element::SEGMENT));
414  }
415 }
416 
418 {
419  GetEdgeTransformation(EdgeNo, &EdgeTransformation);
420  return &EdgeTransformation;
421 }
422 
423 
425  IsoparametricTransformation &Transf, int i)
426 {
427  const IntegrationRule *SegVert;
428  DenseMatrix &locpm = Transf.GetPointMat();
429 
430  Transf.SetFE(&PointFE);
432  locpm.SetSize(1, 1);
433  locpm(0, 0) = SegVert->IntPoint(i/64).x;
434  // (i/64) is the local face no. in the segment
435  // (i%64) is the orientation of the point (not used)
436 }
437 
439  IsoparametricTransformation &Transf, int i)
440 {
441  // tri_faces is the same as Triangle::edges
442  static const int tri_faces[3][2] = {{0, 1}, {1, 2}, {2, 0}};
443  static const int seg_inv_orient[2][2] = {{0, 1}, {1, 0}};
444  int j;
445  const int *tv, *so;
446  const IntegrationRule *TriVert;
447  DenseMatrix &locpm = Transf.GetPointMat();
448 
449  Transf.SetFE(&SegmentFE);
450  tv = tri_faces[i/64]; // (i/64) is the local face no. in the triangle
451  so = seg_inv_orient[i%64]; // (i%64) is the orientation of the segment
453  locpm.SetSize(2, 2);
454  for (j = 0; j < 2; j++)
455  {
456  locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x;
457  locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y;
458  }
459 }
460 
462  IsoparametricTransformation &Transf, int i)
463 {
464  // quad_faces is the same as Quadrilateral::edges
465  static const int quad_faces[4][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 0}};
466  static const int seg_inv_orient[2][2] = {{0, 1}, {1, 0}};
467  int j;
468  const int *qv, *so;
469  const IntegrationRule *QuadVert;
470  DenseMatrix &locpm = Transf.GetPointMat();
471 
472  Transf.SetFE(&SegmentFE);
473  qv = quad_faces[i/64]; // (i/64) is the local face no. in the quad
474  so = seg_inv_orient[i%64]; // (i%64) is the orientation of the segment
476  locpm.SetSize(2, 2);
477  for (j = 0; j < 2; j++)
478  {
479  locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x;
480  locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y;
481  }
482 }
483 
484 const int Mesh::tet_faces[4][3] =
485 {
486  {1, 2, 3}, {0, 3, 2},
487  {0, 1, 3}, {0, 2, 1}
488 };
489 
490 // same as Hexahedron::faces
491 const int Mesh::hex_faces[6][4] =
492 {
493  {3, 2, 1, 0}, {0, 1, 5, 4},
494  {1, 2, 6, 5}, {2, 3, 7, 6},
495  {3, 0, 4, 7}, {4, 5, 6, 7}
496 };
497 
498 const int Mesh::tri_orientations[6][3] =
499 {
500  {0, 1, 2}, {1, 0, 2},
501  {2, 0, 1}, {2, 1, 0},
502  {1, 2, 0}, {0, 2, 1}
503 };
504 
505 const int Mesh::quad_orientations[8][4] =
506 {
507  {0, 1, 2, 3}, {0, 3, 2, 1},
508  {1, 2, 3, 0}, {1, 0, 3, 2},
509  {2, 3, 0, 1}, {2, 1, 0, 3},
510  {3, 0, 1, 2}, {3, 2, 1, 0}
511 };
512 
514  IsoparametricTransformation &Transf, int i)
515 {
516  DenseMatrix &locpm = Transf.GetPointMat();
517 
518  Transf.SetFE(&TriangleFE);
519  // (i/64) is the local face no. in the tet
520  const int *tv = tet_faces[i/64];
521  // (i%64) is the orientation of the tetrahedron face
522  // w.r.t. the face element
523  const int *to = tri_orientations[i%64];
524  const IntegrationRule *TetVert =
526  locpm.SetSize(3, 3);
527  for (int j = 0; j < 3; j++)
528  {
529  const IntegrationPoint &vert = TetVert->IntPoint(tv[to[j]]);
530  locpm(0, j) = vert.x;
531  locpm(1, j) = vert.y;
532  locpm(2, j) = vert.z;
533  }
534 }
535 
537  IsoparametricTransformation &Transf, int i)
538 {
539  DenseMatrix &locpm = Transf.GetPointMat();
540 
541  Transf.SetFE(&QuadrilateralFE);
542  // (i/64) is the local face no. in the hex
543  const int *hv = hex_faces[i/64];
544  // (i%64) is the orientation of the quad
545  const int *qo = quad_orientations[i%64];
547  locpm.SetSize(3, 4);
548  for (int j = 0; j < 4; j++)
549  {
550  const IntegrationPoint &vert = HexVert->IntPoint(hv[qo[j]]);
551  locpm(0, j) = vert.x;
552  locpm(1, j) = vert.y;
553  locpm(2, j) = vert.z;
554  }
555 }
556 
558  int mask)
559 {
560  FaceInfo &face_info = faces_info[FaceNo];
561 
562  FaceElemTr.Elem1 = NULL;
563  FaceElemTr.Elem2 = NULL;
564 
565  // setup the transformation for the first element
566  FaceElemTr.Elem1No = face_info.Elem1No;
567  if (mask & 1)
568  {
569  GetElementTransformation(FaceElemTr.Elem1No, &Transformation);
570  FaceElemTr.Elem1 = &Transformation;
571  }
572 
573  // setup the transformation for the second element
574  // return NULL in the Elem2 field if there's no second element, i.e.
575  // the face is on the "boundary"
576  FaceElemTr.Elem2No = face_info.Elem2No;
577  if ((mask & 2) && FaceElemTr.Elem2No >= 0)
578  {
579 #ifdef MFEM_DEBUG
580  if (NURBSext && (mask & 1)) { MFEM_ABORT("NURBS mesh not supported!"); }
581 #endif
582  GetElementTransformation(FaceElemTr.Elem2No, &Transformation2);
583  FaceElemTr.Elem2 = &Transformation2;
584  }
585 
586  FaceElemTr.FaceGeom = (Dim == 1) ? Geometry::POINT
587  : faces[FaceNo]->GetGeometryType();
588 
589  // setup the face transformation
590  FaceElemTr.Face = (mask & 16) ? GetFaceTransformation(FaceNo) : NULL;
591 
592  // setup Loc1 & Loc2
593  int face_type = (Dim == 1) ? Element::POINT : faces[FaceNo]->GetType();
594  switch (face_type)
595  {
596  case Element::POINT:
597  if (mask & 4)
598  {
599  GetLocalPtToSegTransformation(FaceElemTr.Loc1.Transf,
600  face_info.Elem1Inf);
601  }
602  if (FaceElemTr.Elem2No >= 0 && (mask & 8))
603  {
604  GetLocalPtToSegTransformation(FaceElemTr.Loc2.Transf,
605  face_info.Elem2Inf);
606  }
607  break;
608 
609  case Element::SEGMENT:
610  if (mask & 4)
611  {
612  if (GetElementType(face_info.Elem1No) == Element::TRIANGLE)
613  {
614  GetLocalSegToTriTransformation(FaceElemTr.Loc1.Transf,
615  face_info.Elem1Inf);
616  }
617  else // assume the element is a quad
618  {
619  GetLocalSegToQuadTransformation(FaceElemTr.Loc1.Transf,
620  face_info.Elem1Inf);
621  }
622  }
623 
624  if (FaceElemTr.Elem2No >= 0 && (mask & 8))
625  {
626  if (GetElementType(face_info.Elem2No) == Element::TRIANGLE)
627  {
628  GetLocalSegToTriTransformation(FaceElemTr.Loc2.Transf,
629  face_info.Elem2Inf);
630  }
631  else // assume the element is a quad
632  {
633  GetLocalSegToQuadTransformation(FaceElemTr.Loc2.Transf,
634  face_info.Elem2Inf);
635  }
636  if (IsSlaveFace(face_info))
637  {
638  ApplySlaveTransformation(FaceElemTr.Loc2.Transf, face_info);
639  const int *fv = faces[FaceNo]->GetVertices();
640  if (fv[0] > fv[1])
641  {
642  DenseMatrix &pm = FaceElemTr.Loc2.Transf.GetPointMat();
643  mfem::Swap<double>(pm(0,0), pm(0,1));
644  mfem::Swap<double>(pm(1,0), pm(1,1));
645  }
646  }
647  }
648  break;
649 
650  case Element::TRIANGLE:
651  // --------- assumes the face is a triangle -- face of a tetrahedron
652  if (mask & 4)
653  {
654  GetLocalTriToTetTransformation(FaceElemTr.Loc1.Transf,
655  face_info.Elem1Inf);
656  }
657  if (FaceElemTr.Elem2No >= 0 && (mask & 8))
658  {
659  GetLocalTriToTetTransformation(FaceElemTr.Loc2.Transf,
660  face_info.Elem2Inf);
661  if (IsSlaveFace(face_info))
662  {
663  ApplySlaveTransformation(FaceElemTr.Loc2.Transf, face_info);
664  }
665  }
666  break;
667 
669  // --------- assumes the face is a quad -- face of a hexahedron
670  if (mask & 4)
671  {
672  GetLocalQuadToHexTransformation(FaceElemTr.Loc1.Transf,
673  face_info.Elem1Inf);
674  }
675  if (FaceElemTr.Elem2No >= 0 && (mask & 8))
676  {
677  GetLocalQuadToHexTransformation(FaceElemTr.Loc2.Transf,
678  face_info.Elem2Inf);
679  if (IsSlaveFace(face_info))
680  {
681  ApplySlaveTransformation(FaceElemTr.Loc2.Transf, face_info);
682  }
683  }
684  break;
685  }
686 
687  return &FaceElemTr;
688 }
689 
691 {
692  return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
693 }
694 
696  const FaceInfo &fi)
697 {
698 #ifdef MFEM_THREAD_SAFE
699  DenseMatrix composition;
700 #else
701  static DenseMatrix composition;
702 #endif
703  MFEM_ASSERT(fi.NCFace >= 0, "");
704  transf.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
705  transf.GetPointMat() = composition;
706 }
707 
709 {
711  int fn;
712  if (Dim == 3)
713  {
714  fn = be_to_face[BdrElemNo];
715  }
716  else if (Dim == 2)
717  {
718  fn = be_to_edge[BdrElemNo];
719  }
720  else
721  {
722  fn = boundary[BdrElemNo]->GetVertices()[0];
723  }
724  // Check if the face is interior, shared, or non-conforming.
725  if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
726  {
727  return NULL;
728  }
729  tr = GetFaceElementTransformations(fn);
730  tr->Face->Attribute = boundary[BdrElemNo]->GetAttribute();
731  return tr;
732 }
733 
734 void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2)
735 {
736  *Elem1 = faces_info[Face].Elem1No;
737  *Elem2 = faces_info[Face].Elem2No;
738 }
739 
740 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2)
741 {
742  *Inf1 = faces_info[Face].Elem1Inf;
743  *Inf2 = faces_info[Face].Elem2Inf;
744 }
745 
747 {
748  NumOfVertices = NumOfElements = NumOfBdrElements = NumOfEdges = -1;
749  WantTwoLevelState = 0;
750  State = Mesh::NORMAL;
751  Nodes = NULL;
752  own_nodes = 1;
753  NURBSext = NULL;
754  ncmesh = NULL;
755  nc_coarse_level = NULL;
756 }
757 
759 {
760  el_to_edge =
761  el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
762 }
763 
765 {
766  delete el_to_edge;
767  delete el_to_face;
768  delete el_to_el;
769 
770  if (Dim == 3)
771  {
772  delete bel_to_edge;
773  }
774 
775  delete face_edge;
776  delete edge_vertex;
777 
778  InitTables();
779 
780  delete nc_coarse_level;
781  nc_coarse_level = NULL;
782 }
783 
785 {
786  delete el_to_el;
787  delete face_edge;
788  delete edge_vertex;
789 
790  el_to_el = face_edge = edge_vertex = NULL;
791 
792  delete nc_coarse_level;
793  nc_coarse_level = NULL;
794 }
795 
797 {
798  Array<int> attribs;
799 
800  attribs.SetSize(GetNBE());
801  for (int i = 0; i < attribs.Size(); i++)
802  {
803  attribs[i] = GetBdrAttribute(i);
804  }
805  attribs.Sort();
806  attribs.Unique();
807  attribs.Copy(bdr_attributes);
808  if (bdr_attributes.Size() > 0 && bdr_attributes[0] <= 0)
809  {
810  MFEM_WARNING("Non-positive attributes on the boundary!");
811  }
812 
813  attribs.SetSize(GetNE());
814  for (int i = 0; i < attribs.Size(); i++)
815  {
816  attribs[i] = GetAttribute(i);
817  }
818  attribs.Sort();
819  attribs.Unique();
820  attribs.Copy(attributes);
821  if (attributes.Size() > 0 && attributes[0] <= 0)
822  {
823  MFEM_WARNING("Non-positive attributes in the domain!");
824  }
825 }
826 
827 void Mesh::InitMesh(int _Dim, int _spaceDim, int NVert, int NElem, int NBdrElem)
828 {
829  Dim = _Dim;
830  spaceDim = _spaceDim;
831 
832  Init();
833  InitTables();
834 
835  NumOfVertices = 0;
836  vertices.SetSize(NVert); // just allocate space for vertices
837 
838  NumOfElements = 0;
839  elements.SetSize(NElem); // just allocate space for Element *
840 
841  NumOfBdrElements = 0;
842  boundary.SetSize(NBdrElem); // just allocate space for Element *
843 }
844 
845 void Mesh::AddVertex(const double *x)
846 {
847  double *y = vertices[NumOfVertices]();
848 
849  for (int i = 0; i < spaceDim; i++)
850  {
851  y[i] = x[i];
852  }
853  NumOfVertices++;
854 }
855 
856 void Mesh::AddTri(const int *vi, int attr)
857 {
858  elements[NumOfElements++] = new Triangle(vi, attr);
859 }
860 
861 void Mesh::AddTriangle(const int *vi, int attr)
862 {
863  elements[NumOfElements++] = new Triangle(vi, attr);
864 }
865 
866 void Mesh::AddQuad(const int *vi, int attr)
867 {
868  elements[NumOfElements++] = new Quadrilateral(vi, attr);
869 }
870 
871 void Mesh::AddTet(const int *vi, int attr)
872 {
873 #ifdef MFEM_USE_MEMALLOC
874  Tetrahedron *tet;
875  tet = TetMemory.Alloc();
876  tet->SetVertices(vi);
877  tet->SetAttribute(attr);
878  elements[NumOfElements++] = tet;
879 #else
880  elements[NumOfElements++] = new Tetrahedron(vi, attr);
881 #endif
882 }
883 
884 void Mesh::AddHex(const int *vi, int attr)
885 {
886  elements[NumOfElements++] = new Hexahedron(vi, attr);
887 }
888 
889 void Mesh::AddHexAsTets(const int *vi, int attr)
890 {
891  static const int hex_to_tet[6][4] =
892  {
893  { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
894  { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
895  };
896  int ti[4];
897 
898  for (int i = 0; i < 6; i++)
899  {
900  for (int j = 0; j < 4; j++)
901  {
902  ti[j] = vi[hex_to_tet[i][j]];
903  }
904  AddTet(ti, attr);
905  }
906 }
907 
908 void Mesh::AddBdrSegment(const int *vi, int attr)
909 {
910  boundary[NumOfBdrElements++] = new Segment(vi, attr);
911 }
912 
913 void Mesh::AddBdrTriangle(const int *vi, int attr)
914 {
915  boundary[NumOfBdrElements++] = new Triangle(vi, attr);
916 }
917 
918 void Mesh::AddBdrQuad(const int *vi, int attr)
919 {
920  boundary[NumOfBdrElements++] = new Quadrilateral(vi, attr);
921 }
922 
923 void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
924 {
925  static const int quad_to_tri[2][3] = { { 0, 1, 2 }, { 0, 2, 3 } };
926  int ti[3];
927 
928  for (int i = 0; i < 2; i++)
929  {
930  for (int j = 0; j < 3; j++)
931  {
932  ti[j] = vi[quad_to_tri[i][j]];
933  }
934  AddBdrTriangle(ti, attr);
935  }
936 }
937 
939 {
940  int i, j;
941  Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
942 
943  // GenerateFaces();
944 
945  for (i = 0; i < boundary.Size(); i++)
946  {
947  FreeElement(boundary[i]);
948  }
949 
950  if (Dim == 3)
951  {
952  delete bel_to_edge;
953  bel_to_edge = NULL;
954  }
955 
956  // count the 'NumOfBdrElements'
957  NumOfBdrElements = 0;
958  for (i = 0; i < faces_info.Size(); i++)
959  {
960  if (faces_info[i].Elem2No < 0) { NumOfBdrElements++; }
961  }
962 
963  boundary.SetSize(NumOfBdrElements);
964  be2face.SetSize(NumOfBdrElements);
965  for (j = i = 0; i < faces_info.Size(); i++)
966  {
967  if (faces_info[i].Elem2No < 0)
968  {
969  boundary[j] = faces[i]->Duplicate(this);
970  be2face[j++] = i;
971  }
972  }
973  // In 3D, 'bel_to_edge' is destroyed but it's not updated.
974 }
975 
976 typedef struct
977 {
978  int edge;
979  double length;
980 }
981 edge_length;
982 
983 // Used by qsort to sort edges in increasing (according their length) order.
984 static int edge_compare(const void *ii, const void *jj)
985 {
986  edge_length *i = (edge_length *)ii, *j = (edge_length *)jj;
987  if (i->length > j->length) { return (1); }
988  if (i->length < j->length) { return (-1); }
989  return (0);
990 }
991 
992 void Mesh::FinalizeTriMesh(int generate_edges, int refine, bool fix_orientation)
993 {
994  CheckElementOrientation(fix_orientation);
995 
996  if (refine)
997  {
998  MarkTriMeshForRefinement();
999  }
1000 
1001  if (generate_edges)
1002  {
1003  el_to_edge = new Table;
1004  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1005  GenerateFaces();
1006  CheckBdrElementOrientation();
1007  }
1008  else
1009  {
1010  NumOfEdges = 0;
1011  }
1012 
1013  NumOfFaces = 0;
1014 
1015  SetAttributes();
1016 
1017  meshgen = 1;
1018 }
1019 
1020 void Mesh::FinalizeQuadMesh(int generate_edges, int refine,
1021  bool fix_orientation)
1022 {
1023  if (fix_orientation)
1024  {
1025  CheckElementOrientation(fix_orientation);
1026  }
1027 
1028  if (generate_edges)
1029  {
1030  el_to_edge = new Table;
1031  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1032  GenerateFaces();
1033  CheckBdrElementOrientation();
1034  }
1035  else
1036  {
1037  NumOfEdges = 0;
1038  }
1039 
1040  NumOfFaces = 0;
1041 
1042  SetAttributes();
1043 
1044  meshgen = 2;
1045 }
1046 
1047 
1048 #ifdef MFEM_USE_GECKO
1050 {
1051  Gecko::Graph graph;
1052 
1053  //We will put some accesors in for these later
1054  Gecko::Functional *functional =
1055  new Gecko::FunctionalGeometric(); // ordering functional
1056  unsigned int iterations = 1; // number of V cycles
1057  unsigned int window = 2; // initial window size
1058  unsigned int period = 1; // iterations between window increment
1059  unsigned int seed = 0; // random number seed
1060 
1061  //Run through all the elements and insert the nodes in the graph for them
1062  for (int elemid = 0; elemid < GetNE(); ++elemid)
1063  {
1064  graph.insert();
1065  }
1066 
1067  //Run through all the elems and insert arcs to the graph for each element face
1068  //Indices in Gecko are 1 based hence the +1 on the insertion
1069  const Table &my_el_to_el = ElementToElementTable();
1070  for (int elemid = 0; elemid < GetNE(); ++elemid)
1071  {
1072  const int *neighid = my_el_to_el.GetRow(elemid);
1073  for (int i = 0; i < my_el_to_el.RowSize(elemid); ++i)
1074  {
1075  graph.insert(elemid + 1, neighid[i] + 1);
1076  }
1077  }
1078 
1079  //Get the reordering from Gecko and copy it into the ordering Array<int>
1080  graph.order(functional, iterations, window, period, seed);
1081  ordering.DeleteAll();
1082  ordering.SetSize(GetNE());
1083  Gecko::Node::Index NE = GetNE();
1084  for (Gecko::Node::Index gnodeid = 1; gnodeid <= NE; ++gnodeid)
1085  {
1086  ordering[gnodeid - 1] = graph.rank(gnodeid);
1087  }
1088 
1089  delete functional;
1090 }
1091 #endif
1092 
1093 
1094 void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
1095 {
1096  if (NURBSext)
1097  {
1098  MFEM_WARNING("element reordering of NURBS meshes is not supported.");
1099  return;
1100  }
1101  if (ncmesh)
1102  {
1103  MFEM_WARNING("element reordering of non-conforming meshes is not"
1104  " supported.");
1105  return;
1106  }
1107  MFEM_VERIFY(ordering.Size() == GetNE(), "invalid reordering array.")
1108  SetState(Mesh::NORMAL);
1109 
1110  // Data members that need to be updated:
1111 
1112  // - elements - reorder of the pointers and the vertex ids if reordering
1113  // the vertices
1114  // - vertices - if reordering the vertices
1115  // - boundary - update the vertex ids, if reordering the vertices
1116  // - faces - regenerate
1117  // - faces_info - regenerate
1118 
1119  // Deleted by DeleteTables():
1120  // - el_to_edge - rebuild in 2D and 3D only
1121  // - el_to_face - rebuild in 3D only
1122  // - bel_to_edge - rebuild in 3D only
1123  // - el_to_el - no need to rebuild
1124  // - face_edge - no need to rebuild
1125  // - edge_vertex - no need to rebuild
1126 
1127  // - be_to_edge - 2D only
1128  // - be_to_face - 3D only
1129 
1130  // - Nodes
1131 
1132  //Save the locations of the Nodes so we can rebuild them later
1133  Array<Vector*> old_elem_node_vals;
1134  FiniteElementSpace *nodes_fes = NULL;
1135  if (Nodes)
1136  {
1137  old_elem_node_vals.SetSize(GetNE());
1138  nodes_fes = Nodes->FESpace();
1139  Array<int> old_dofs;
1140  Vector vals;
1141  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
1142  {
1143  nodes_fes->GetElementVDofs(old_elid, old_dofs);
1144  Nodes->GetSubVector(old_dofs, vals);
1145  old_elem_node_vals[old_elid] = new Vector(vals);
1146  }
1147  }
1148 
1149  //Get the newly ordered elements
1150  Array<Element *> new_elements(GetNE());
1151  for (int old_elid = 0; old_elid < ordering.Size(); ++old_elid)
1152  {
1153  int new_elid = ordering[old_elid];
1154  new_elements[new_elid] = elements[old_elid];
1155  }
1156  mfem::Swap(elements, new_elements);
1157  new_elements.DeleteAll();
1158 
1159  if (reorder_vertices)
1160  {
1161  //Get the new vertex ordering permutation vectors and fill the new vertices
1162  Array<int> vertex_ordering(GetNV());
1163  vertex_ordering = -1;
1164  Array<Vertex> new_vertices(GetNV());
1165  int new_vertex_ind = 0;
1166  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
1167  {
1168  int *elem_vert = elements[new_elid]->GetVertices();
1169  int nv = elements[new_elid]->GetNVertices();
1170  for (int vi = 0; vi < nv; ++vi)
1171  {
1172  int old_vertex_ind = elem_vert[vi];
1173  if (vertex_ordering[old_vertex_ind] == -1)
1174  {
1175  vertex_ordering[old_vertex_ind] = new_vertex_ind;
1176  new_vertices[new_vertex_ind] = vertices[old_vertex_ind];
1177  new_vertex_ind++;
1178  }
1179  }
1180  }
1181  mfem::Swap(vertices, new_vertices);
1182  new_vertices.DeleteAll();
1183 
1184  //Replace the vertex ids in the elements with the reordered vertex numbers
1185  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
1186  {
1187  int *elem_vert = elements[new_elid]->GetVertices();
1188  int nv = elements[new_elid]->GetNVertices();
1189  for (int vi = 0; vi < nv; ++vi)
1190  {
1191  elem_vert[vi] = vertex_ordering[elem_vert[vi]];
1192  }
1193  }
1194 
1195  //Replace the vertex ids in the boundary with reordered vertex numbers
1196  for (int belid = 0; belid < GetNBE(); ++belid)
1197  {
1198  int *be_vert = boundary[belid]->GetVertices();
1199  int nv = boundary[belid]->GetNVertices();
1200  for (int vi = 0; vi < nv; ++vi)
1201  {
1202  be_vert[vi] = vertex_ordering[be_vert[vi]];
1203  }
1204  }
1205  }
1206 
1207  // Destroy tables that need to be rebuild
1208  DeleteTables();
1209 
1210  if (Dim > 1)
1211  {
1212  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
1213  el_to_edge = new Table;
1214  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1215  }
1216  if (Dim > 2)
1217  {
1218  // generate el_to_face, be_to_face
1219  GetElementToFaceTable();
1220  }
1221  // Update faces and faces_info
1222  GenerateFaces();
1223 
1224  //Build the nodes from the saved locations if they were around before
1225  if (Nodes)
1226  {
1227  nodes_fes->Update();
1228  Array<int> new_dofs;
1229  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
1230  {
1231  int new_elid = ordering[old_elid];
1232  nodes_fes->GetElementVDofs(new_elid, new_dofs);
1233  Nodes->SetSubVector(new_dofs, *(old_elem_node_vals[old_elid]));
1234  delete old_elem_node_vals[old_elid];
1235  }
1236  }
1237 }
1238 
1239 
1241 {
1242  if (meshgen & 1)
1243  {
1244  if (Dim == 2)
1245  {
1246  MarkTriMeshForRefinement();
1247  }
1248  else if (Dim == 3)
1249  {
1250  MarkTetMeshForRefinement();
1251  }
1252  }
1253 }
1254 
1256 {
1257  // Mark the longest triangle edge by rotating the indeces so that
1258  // vertex 0 - vertex 1 to be the longest element's edge.
1259  DenseMatrix pmat;
1260  for (int i = 0; i < NumOfElements; i++)
1261  {
1262  if (elements[i]->GetType() == Element::TRIANGLE)
1263  {
1264  GetPointMatrix(i, pmat);
1265  elements[i]->MarkEdge(pmat);
1266  }
1267  }
1268 }
1269 
1271 {
1272  NumOfEdges = v_to_v.NumberOfEntries();
1273  edge_length *length = new edge_length[NumOfEdges];
1274  for (int i = 0; i < NumOfVertices; i++)
1275  {
1276  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
1277  {
1278  int j = it.Index();
1279  length[j].length = GetLength(i, it.Column());
1280  length[j].edge = j;
1281  }
1282  }
1283 
1284  // sort in increasing order
1285  qsort(length, NumOfEdges, sizeof(edge_length), edge_compare);
1286 
1287  order.SetSize(NumOfEdges);
1288  for (int i = 0; i < NumOfEdges; i++)
1289  {
1290  order[length[i].edge] = i;
1291  }
1292 
1293  delete [] length;
1294 }
1295 
1297 {
1298  // Mark the longest tetrahedral edge by rotating the indices so that
1299  // vertex 0 - vertex 1 is the longest edge in the element.
1300  DSTable v_to_v(NumOfVertices);
1301  GetVertexToVertexTable(v_to_v);
1302  Array<int> order;
1303 
1304  GetEdgeOrdering(v_to_v, order);
1305 
1306  for (int i = 0; i < NumOfElements; i++)
1307  {
1308  if (elements[i]->GetType() == Element::TETRAHEDRON)
1309  {
1310  elements[i]->MarkEdge(v_to_v, order);
1311  }
1312  }
1313  for (int i = 0; i < NumOfBdrElements; i++)
1314  {
1315  if (boundary[i]->GetType() == Element::TRIANGLE)
1316  {
1317  boundary[i]->MarkEdge(v_to_v, order);
1318  }
1319  }
1320 }
1321 
1322 void Mesh::PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
1323 {
1324  if (*old_v_to_v && *old_elem_vert)
1325  {
1326  return;
1327  }
1328 
1329  FiniteElementSpace *fes = Nodes->FESpace();
1330  const FiniteElementCollection *fec = fes->FEColl();
1331 
1332  if (*old_v_to_v == NULL)
1333  {
1334  int num_edge_dofs = fec->DofForGeometry(Geometry::SEGMENT);
1335  if (num_edge_dofs > 0)
1336  {
1337  *old_v_to_v = new DSTable(NumOfVertices);
1338  GetVertexToVertexTable(*(*old_v_to_v));
1339  }
1340  }
1341  if (*old_elem_vert == NULL)
1342  {
1343  // assuming all elements have the same geometry
1344  int num_elem_dofs = fec->DofForGeometry(GetElementBaseGeometry(0));
1345  if (num_elem_dofs > 1)
1346  {
1347  *old_elem_vert = new Table;
1348  (*old_elem_vert)->MakeI(GetNE());
1349  for (int i = 0; i < GetNE(); i++)
1350  {
1351  (*old_elem_vert)->AddColumnsInRow(i, elements[i]->GetNVertices());
1352  }
1353  (*old_elem_vert)->MakeJ();
1354  for (int i = 0; i < GetNE(); i++)
1355  {
1356  (*old_elem_vert)->AddConnections(i, elements[i]->GetVertices(),
1357  elements[i]->GetNVertices());
1358  }
1359  (*old_elem_vert)->ShiftUpI();
1360  }
1361  }
1362 }
1363 
1364 void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
1365 {
1366  FiniteElementSpace *fes = Nodes->FESpace();
1367  const FiniteElementCollection *fec = fes->FEColl();
1368  int num_edge_dofs = fec->DofForGeometry(Geometry::SEGMENT);
1369  // assuming all faces have the same geometry
1370  int num_face_dofs =
1371  (Dim < 3) ? 0 : fec->DofForGeometry(GetFaceBaseGeometry(0));
1372  // assuming all elements have the same geometry
1373  int num_elem_dofs = fec->DofForGeometry(GetElementBaseGeometry(0));
1374 
1375  // reorder the Nodes
1376  Vector onodes = *Nodes;
1377 
1378  Array<int> old_dofs, new_dofs;
1379  int offset;
1380 #ifdef MFEM_DEBUG
1381  int redges = 0;
1382 #endif
1383 
1384  // vertex dofs do not need to be moved
1385  offset = NumOfVertices * fec->DofForGeometry(Geometry::POINT);
1386 
1387  // edge dofs:
1388  // edge enumeration may be different but edge orientation is the same
1389  if (num_edge_dofs > 0)
1390  {
1391  DSTable new_v_to_v(NumOfVertices);
1392  GetVertexToVertexTable(new_v_to_v);
1393 
1394  for (int i = 0; i < NumOfVertices; i++)
1395  {
1396  for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it)
1397  {
1398  int old_i = (*old_v_to_v)(i, it.Column());
1399  int new_i = it.Index();
1400 #ifdef MFEM_DEBUG
1401  if (old_i != new_i)
1402  {
1403  redges++;
1404  }
1405 #endif
1406  old_dofs.SetSize(num_edge_dofs);
1407  new_dofs.SetSize(num_edge_dofs);
1408  for (int j = 0; j < num_edge_dofs; j++)
1409  {
1410  old_dofs[j] = offset + old_i * num_edge_dofs + j;
1411  new_dofs[j] = offset + new_i * num_edge_dofs + j;
1412  }
1413  fes->DofsToVDofs(old_dofs);
1414  fes->DofsToVDofs(new_dofs);
1415  for (int j = 0; j < old_dofs.Size(); j++)
1416  {
1417  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
1418  }
1419  }
1420  }
1421  offset += NumOfEdges * num_edge_dofs;
1422  }
1423 #ifdef MFEM_DEBUG
1424  cout << "Mesh::DoNodeReorder : redges = " << redges << endl;
1425 #endif
1426 
1427  // face dofs:
1428  // both enumeration and orientation of the faces may be different
1429  if (num_face_dofs > 0)
1430  {
1431  // generate the old face-vertex table using the unmodified 'faces'
1432  Table old_face_vertex;
1433  old_face_vertex.MakeI(NumOfFaces);
1434  for (int i = 0; i < NumOfFaces; i++)
1435  {
1436  old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices());
1437  }
1438  old_face_vertex.MakeJ();
1439  for (int i = 0; i < NumOfFaces; i++)
1440  old_face_vertex.AddConnections(i, faces[i]->GetVertices(),
1441  faces[i]->GetNVertices());
1442  old_face_vertex.ShiftUpI();
1443 
1444  // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info'
1445  STable3D *faces_tbl = GetElementToFaceTable(1);
1446  GenerateFaces();
1447 
1448  // loop over the old face numbers
1449  for (int i = 0; i < NumOfFaces; i++)
1450  {
1451  int *old_v = old_face_vertex.GetRow(i), *new_v;
1452  int new_i, new_or, *dof_ord;
1453  switch (old_face_vertex.RowSize(i))
1454  {
1455  case 3:
1456  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
1457  new_v = faces[new_i]->GetVertices();
1458  new_or = GetTriOrientation(old_v, new_v);
1459  dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, new_or);
1460  break;
1461  case 4:
1462  default:
1463  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
1464  new_v = faces[new_i]->GetVertices();
1465  new_or = GetQuadOrientation(old_v, new_v);
1466  dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, new_or);
1467  break;
1468  }
1469 
1470  old_dofs.SetSize(num_face_dofs);
1471  new_dofs.SetSize(num_face_dofs);
1472  for (int j = 0; j < num_face_dofs; j++)
1473  {
1474  old_dofs[j] = offset + i * num_face_dofs + j;
1475  new_dofs[j] = offset + new_i * num_face_dofs + dof_ord[j];
1476  // we assumed the dofs are non-directional
1477  // i.e. dof_ord[j] is >= 0
1478  }
1479  fes->DofsToVDofs(old_dofs);
1480  fes->DofsToVDofs(new_dofs);
1481  for (int j = 0; j < old_dofs.Size(); j++)
1482  {
1483  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
1484  }
1485  }
1486 
1487  offset += NumOfFaces * num_face_dofs;
1488  delete faces_tbl;
1489  }
1490 
1491  // element dofs:
1492  // element orientation may be different
1493  if (num_elem_dofs > 1)
1494  {
1495  // matters when the 'fec' is
1496  // (this code is executed only for triangles/tets)
1497  // - Pk on triangles, k >= 4
1498  // - Qk on quads, k >= 3
1499  // - Pk on tets, k >= 5
1500  // - Qk on hexes, k >= 3
1501  // - DG spaces
1502  // - ...
1503 
1504  // loop over all elements
1505  for (int i = 0; i < GetNE(); i++)
1506  {
1507  int *old_v = old_elem_vert->GetRow(i);
1508  int *new_v = elements[i]->GetVertices();
1509  int new_or, *dof_ord;
1510  int geom = elements[i]->GetGeometryType();
1511  switch (geom)
1512  {
1513  case Geometry::SEGMENT:
1514  new_or = (old_v[0] == new_v[0]) ? +1 : -1;
1515  break;
1516  case Geometry::TRIANGLE:
1517  new_or = GetTriOrientation(old_v, new_v);
1518  break;
1519  case Geometry::SQUARE:
1520  new_or = GetQuadOrientation(old_v, new_v);
1521  break;
1522  default:
1523  new_or = 0;
1524  cerr << "Mesh::DoNodeReorder : " << Geometry::Name[geom]
1525  << " elements (" << fec->Name()
1526  << " FE collection) are not supported yet!" << endl;
1527  mfem_error();
1528  break;
1529  }
1530  dof_ord = fec->DofOrderForOrientation(geom, new_or);
1531  if (dof_ord == NULL)
1532  {
1533  cerr << "Mesh::DoNodeReorder : FE collection '" << fec->Name()
1534  << "' does not define reordering for " << Geometry::Name[geom]
1535  << " elements!" << endl;
1536  mfem_error();
1537  }
1538  old_dofs.SetSize(num_elem_dofs);
1539  new_dofs.SetSize(num_elem_dofs);
1540  for (int j = 0; j < num_elem_dofs; j++)
1541  {
1542  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
1543  old_dofs[j] = offset + dof_ord[j];
1544  new_dofs[j] = offset + j;
1545  }
1546  fes->DofsToVDofs(old_dofs);
1547  fes->DofsToVDofs(new_dofs);
1548  for (int j = 0; j < old_dofs.Size(); j++)
1549  {
1550  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
1551  }
1552 
1553  offset += num_elem_dofs;
1554  }
1555  }
1556 
1557  // Update Tables, faces, etc
1558  if (Dim > 2)
1559  {
1560  if (num_face_dofs == 0)
1561  {
1562  // needed for FE spaces that have face dofs, even if
1563  // the 'Nodes' do not have face dofs.
1564  GetElementToFaceTable();
1565  GenerateFaces();
1566  }
1567  CheckBdrElementOrientation();
1568  }
1569  if (el_to_edge)
1570  {
1571  // update 'el_to_edge', 'be_to_edge' (2D), 'bel_to_edge' (3D)
1572  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1573  if (Dim == 2)
1574  {
1575  // update 'faces' and 'faces_info'
1576  GenerateFaces();
1577  CheckBdrElementOrientation();
1578  }
1579  }
1580 }
1581 
1582 void Mesh::FinalizeTetMesh(int generate_edges, int refine, bool fix_orientation)
1583 {
1584  CheckElementOrientation(fix_orientation);
1585 
1586  if (NumOfBdrElements == 0)
1587  {
1588  GetElementToFaceTable();
1589  GenerateFaces();
1590  GenerateBoundaryElements();
1591  }
1592 
1593  if (refine)
1594  {
1595  MarkTetMeshForRefinement();
1596  }
1597 
1598  GetElementToFaceTable();
1599  GenerateFaces();
1600 
1601  CheckBdrElementOrientation();
1602 
1603  if (generate_edges == 1)
1604  {
1605  el_to_edge = new Table;
1606  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1607  }
1608  else
1609  {
1610  el_to_edge = NULL; // Not really necessary -- InitTables was called
1611  bel_to_edge = NULL;
1612  NumOfEdges = 0;
1613  }
1614 
1615  SetAttributes();
1616 
1617  meshgen = 1;
1618 }
1619 
1620 void Mesh::FinalizeHexMesh(int generate_edges, int refine, bool fix_orientation)
1621 {
1622  CheckElementOrientation(fix_orientation);
1623 
1624  GetElementToFaceTable();
1625  GenerateFaces();
1626 
1627  if (NumOfBdrElements == 0)
1628  {
1629  GenerateBoundaryElements();
1630  }
1631 
1632  CheckBdrElementOrientation();
1633 
1634  if (generate_edges)
1635  {
1636  el_to_edge = new Table;
1637  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1638  }
1639  else
1640  {
1641  NumOfEdges = 0;
1642  }
1643 
1644  SetAttributes();
1645 
1646  meshgen = 2;
1647 }
1648 
1649 void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
1650  int generate_edges, double sx, double sy, double sz)
1651 {
1652  int x, y, z;
1653 
1654  int NVert, NElem, NBdrElem;
1655 
1656  NVert = (nx+1) * (ny+1) * (nz+1);
1657  NElem = nx * ny * nz;
1658  NBdrElem = 2*(nx*ny+nx*nz+ny*nz);
1659  if (type == Element::TETRAHEDRON)
1660  {
1661  NElem *= 6;
1662  NBdrElem *= 2;
1663  }
1664 
1665  InitMesh(3, 3, NVert, NElem, NBdrElem);
1666 
1667  double coord[3];
1668  int ind[8];
1669 
1670  // Sets vertices and the corresponding coordinates
1671  for (z = 0; z <= nz; z++)
1672  {
1673  coord[2] = ((double) z / nz) * sz;
1674  for (y = 0; y <= ny; y++)
1675  {
1676  coord[1] = ((double) y / ny) * sy;
1677  for (x = 0; x <= nx; x++)
1678  {
1679  coord[0] = ((double) x / nx) * sx;
1680  AddVertex(coord);
1681  }
1682  }
1683  }
1684 
1685 #define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
1686 
1687  // Sets elements and the corresponding indices of vertices
1688  for (z = 0; z < nz; z++)
1689  {
1690  for (y = 0; y < ny; y++)
1691  {
1692  for (x = 0; x < nx; x++)
1693  {
1694  ind[0] = VTX(x , y , z );
1695  ind[1] = VTX(x+1, y , z );
1696  ind[2] = VTX(x+1, y+1, z );
1697  ind[3] = VTX(x , y+1, z );
1698  ind[4] = VTX(x , y , z+1);
1699  ind[5] = VTX(x+1, y , z+1);
1700  ind[6] = VTX(x+1, y+1, z+1);
1701  ind[7] = VTX(x , y+1, z+1);
1702  if (type == Element::TETRAHEDRON)
1703  {
1704  AddHexAsTets(ind, 1);
1705  }
1706  else
1707  {
1708  AddHex(ind, 1);
1709  }
1710  }
1711  }
1712  }
1713 
1714  // Sets boundary elements and the corresponding indices of vertices
1715  // bottom, bdr. attribute 1
1716  for (y = 0; y < ny; y++)
1717  for (x = 0; x < nx; x++)
1718  {
1719  ind[0] = VTX(x , y , 0);
1720  ind[1] = VTX(x , y+1, 0);
1721  ind[2] = VTX(x+1, y+1, 0);
1722  ind[3] = VTX(x+1, y , 0);
1723  if (type == Element::TETRAHEDRON)
1724  {
1725  AddBdrQuadAsTriangles(ind, 1);
1726  }
1727  else
1728  {
1729  AddBdrQuad(ind, 1);
1730  }
1731  }
1732  // top, bdr. attribute 6
1733  for (y = 0; y < ny; y++)
1734  for (x = 0; x < nx; x++)
1735  {
1736  ind[0] = VTX(x , y , nz);
1737  ind[1] = VTX(x+1, y , nz);
1738  ind[2] = VTX(x+1, y+1, nz);
1739  ind[3] = VTX(x , y+1, nz);
1740  if (type == Element::TETRAHEDRON)
1741  {
1742  AddBdrQuadAsTriangles(ind, 6);
1743  }
1744  else
1745  {
1746  AddBdrQuad(ind, 6);
1747  }
1748  }
1749  // left, bdr. attribute 5
1750  for (z = 0; z < nz; z++)
1751  for (y = 0; y < ny; y++)
1752  {
1753  ind[0] = VTX(0 , y , z );
1754  ind[1] = VTX(0 , y , z+1);
1755  ind[2] = VTX(0 , y+1, z+1);
1756  ind[3] = VTX(0 , y+1, z );
1757  if (type == Element::TETRAHEDRON)
1758  {
1759  AddBdrQuadAsTriangles(ind, 5);
1760  }
1761  else
1762  {
1763  AddBdrQuad(ind, 5);
1764  }
1765  }
1766  // right, bdr. attribute 3
1767  for (z = 0; z < nz; z++)
1768  for (y = 0; y < ny; y++)
1769  {
1770  ind[0] = VTX(nx, y , z );
1771  ind[1] = VTX(nx, y+1, z );
1772  ind[2] = VTX(nx, y+1, z+1);
1773  ind[3] = VTX(nx, y , z+1);
1774  if (type == Element::TETRAHEDRON)
1775  {
1776  AddBdrQuadAsTriangles(ind, 3);
1777  }
1778  else
1779  {
1780  AddBdrQuad(ind, 3);
1781  }
1782  }
1783  // front, bdr. attribute 2
1784  for (x = 0; x < nx; x++)
1785  for (z = 0; z < nz; z++)
1786  {
1787  ind[0] = VTX(x , 0, z );
1788  ind[1] = VTX(x+1, 0, z );
1789  ind[2] = VTX(x+1, 0, z+1);
1790  ind[3] = VTX(x , 0, z+1);
1791  if (type == Element::TETRAHEDRON)
1792  {
1793  AddBdrQuadAsTriangles(ind, 2);
1794  }
1795  else
1796  {
1797  AddBdrQuad(ind, 2);
1798  }
1799  }
1800  // back, bdr. attribute 4
1801  for (x = 0; x < nx; x++)
1802  for (z = 0; z < nz; z++)
1803  {
1804  ind[0] = VTX(x , ny, z );
1805  ind[1] = VTX(x , ny, z+1);
1806  ind[2] = VTX(x+1, ny, z+1);
1807  ind[3] = VTX(x+1, ny, z );
1808  if (type == Element::TETRAHEDRON)
1809  {
1810  AddBdrQuadAsTriangles(ind, 4);
1811  }
1812  else
1813  {
1814  AddBdrQuad(ind, 4);
1815  }
1816  }
1817 
1818 #if 0
1819  ofstream test_stream("debug.mesh");
1820  Print(test_stream);
1821  test_stream.close();
1822 #endif
1823 
1824  int refine = 1;
1825  bool fix_orientation = true;
1826 
1827  if (type == Element::TETRAHEDRON)
1828  {
1829  FinalizeTetMesh(generate_edges, refine, fix_orientation);
1830  }
1831  else
1832  {
1833  FinalizeHexMesh(generate_edges, refine, fix_orientation);
1834  }
1835 }
1836 
1837 void Mesh::Make2D(int nx, int ny, Element::Type type, int generate_edges,
1838  double sx, double sy)
1839 {
1840  int i, j, k;
1841 
1842  Dim = spaceDim = 2;
1843 
1844  Init();
1845  InitTables();
1846 
1847  // Creates quadrilateral mesh
1848  if (type == Element::QUADRILATERAL)
1849  {
1850  meshgen = 2;
1851  NumOfVertices = (nx+1) * (ny+1);
1852  NumOfElements = nx * ny;
1853  NumOfBdrElements = 2 * nx + 2 * ny;
1854  vertices.SetSize(NumOfVertices);
1855  elements.SetSize(NumOfElements);
1856  boundary.SetSize(NumOfBdrElements);
1857  double cx, cy;
1858  int ind[4];
1859 
1860  // Sets vertices and the corresponding coordinates
1861  k = 0;
1862  for (j = 0; j < ny+1; j++)
1863  {
1864  cy = ((double) j / ny) * sy;
1865  for (i = 0; i < nx+1; i++)
1866  {
1867  cx = ((double) i / nx) * sx;
1868  vertices[k](0) = cx;
1869  vertices[k](1) = cy;
1870  k++;
1871  }
1872  }
1873 
1874  // Sets elements and the corresponding indices of vertices
1875  k = 0;
1876  for (j = 0; j < ny; j++)
1877  {
1878  for (i = 0; i < nx; i++)
1879  {
1880  ind[0] = i + j*(nx+1);
1881  ind[1] = i + 1 +j*(nx+1);
1882  ind[2] = i + 1 + (j+1)*(nx+1);
1883  ind[3] = i + (j+1)*(nx+1);
1884  elements[k] = new Quadrilateral(ind);
1885  k++;
1886  }
1887  }
1888 
1889  // Sets boundary elements and the corresponding indices of vertices
1890  int m = (nx+1)*ny;
1891  for (i = 0; i < nx; i++)
1892  {
1893  boundary[i] = new Segment(i, i+1, 1);
1894  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
1895  }
1896  m = nx+1;
1897  for (j = 0; j < ny; j++)
1898  {
1899  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
1900  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
1901  }
1902  }
1903 
1904  // Creates triangular mesh
1905  if (type == Element::TRIANGLE)
1906  {
1907  meshgen = 1;
1908  NumOfVertices = (nx+1) * (ny+1);
1909  NumOfElements = 2 * nx * ny;
1910  NumOfBdrElements = 2 * nx + 2 * ny;
1911  vertices.SetSize(NumOfVertices);
1912  elements.SetSize(NumOfElements);
1913  boundary.SetSize(NumOfBdrElements);
1914  double cx, cy;
1915  int ind[3];
1916 
1917  // Sets vertices and the corresponding coordinates
1918  k = 0;
1919  for (j = 0; j < ny+1; j++)
1920  {
1921  cy = ((double) j / ny) * sy;
1922  for (i = 0; i < nx+1; i++)
1923  {
1924  cx = ((double) i / nx) * sx;
1925  vertices[k](0) = cx;
1926  vertices[k](1) = cy;
1927  k++;
1928  }
1929  }
1930 
1931  // Sets the elements and the corresponding indices of vertices
1932  k = 0;
1933  for (j = 0; j < ny; j++)
1934  {
1935  for (i = 0; i < nx; i++)
1936  {
1937  ind[0] = i + j*(nx+1);
1938  ind[1] = i + 1 + (j+1)*(nx+1);
1939  ind[2] = i + (j+1)*(nx+1);
1940  elements[k] = new Triangle(ind);
1941  k++;
1942  ind[1] = i + 1 + j*(nx+1);
1943  ind[2] = i + 1 + (j+1)*(nx+1);
1944  elements[k] = new Triangle(ind);
1945  k++;
1946  }
1947  }
1948 
1949  // Sets boundary elements and the corresponding indices of vertices
1950  int m = (nx+1)*ny;
1951  for (i = 0; i < nx; i++)
1952  {
1953  boundary[i] = new Segment(i, i+1, 1);
1954  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
1955  }
1956  m = nx+1;
1957  for (j = 0; j < ny; j++)
1958  {
1959  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
1960  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
1961  }
1962 
1963  MarkTriMeshForRefinement();
1964  }
1965 
1966  CheckElementOrientation();
1967 
1968  if (generate_edges == 1)
1969  {
1970  el_to_edge = new Table;
1971  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1972  GenerateFaces();
1973  CheckBdrElementOrientation();
1974  }
1975  else
1976  {
1977  NumOfEdges = 0;
1978  }
1979 
1980  NumOfFaces = 0;
1981 
1982  attributes.Append(1);
1983  bdr_attributes.Append(1); bdr_attributes.Append(2);
1984  bdr_attributes.Append(3); bdr_attributes.Append(4);
1985 }
1986 
1987 void Mesh::Make1D(int n, double sx)
1988 {
1989  int j, ind[1];
1990 
1991  Dim = 1;
1992  spaceDim = 1;
1993 
1994  Init();
1995  InitTables();
1996 
1997  meshgen = 1;
1998 
1999  NumOfVertices = n + 1;
2000  NumOfElements = n;
2001  NumOfBdrElements = 2;
2002  vertices.SetSize(NumOfVertices);
2003  elements.SetSize(NumOfElements);
2004  boundary.SetSize(NumOfBdrElements);
2005 
2006  // Sets vertices and the corresponding coordinates
2007  for (j = 0; j < n+1; j++)
2008  {
2009  vertices[j](0) = ((double) j / n) * sx;
2010  }
2011 
2012  // Sets elements and the corresponding indices of vertices
2013  for (j = 0; j < n; j++)
2014  {
2015  elements[j] = new Segment(j, j+1, 1);
2016  }
2017 
2018  // Sets the boundary elements
2019  ind[0] = 0;
2020  boundary[0] = new Point(ind, 1);
2021  ind[0] = n;
2022  boundary[1] = new Point(ind, 2);
2023 
2024  NumOfEdges = 0;
2025  NumOfFaces = 0;
2026 
2027  GenerateFaces();
2028 
2029  attributes.Append(1);
2030  bdr_attributes.Append(1); bdr_attributes.Append(2);
2031 }
2032 
2033 Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
2034 {
2035  Dim = mesh.Dim;
2036  spaceDim = mesh.spaceDim;
2037  NumOfVertices = mesh.NumOfVertices;
2038  NumOfElements = mesh.NumOfElements;
2039  NumOfBdrElements = mesh.NumOfBdrElements;
2040  NumOfEdges = mesh.NumOfEdges;
2041  NumOfFaces = mesh.NumOfFaces;
2042 
2043  meshgen = mesh.meshgen;
2044 
2045  // Only allow copy of meshes in NORMAL (not TWO_LEVEL_*) state.
2046  MFEM_VERIFY(mesh.State == NORMAL, "source mesh is not in a NORMAL state");
2047  State = NORMAL;
2048  WantTwoLevelState = mesh.WantTwoLevelState;
2049 
2050  // Duplicate the elements
2051  elements.SetSize(NumOfElements);
2052  for (int i = 0; i < NumOfElements; i++)
2053  {
2054  elements[i] = mesh.elements[i]->Duplicate(this);
2055  }
2056 
2057  // Copy the vertices
2058  MFEM_ASSERT(mesh.vertices.Size() == NumOfVertices, "internal MFEM error!");
2059  mesh.vertices.Copy(vertices);
2060 
2061  // Duplicate the boundary
2062  boundary.SetSize(NumOfBdrElements);
2063  for (int i = 0; i < NumOfBdrElements; i++)
2064  {
2065  boundary[i] = mesh.boundary[i]->Duplicate(this);
2066  }
2067 
2068  // Copy the element-to-face Table, el_to_face
2069  el_to_face = (mesh.el_to_face) ? new Table(*mesh.el_to_face) : NULL;
2070 
2071  // Copy the boundary-to-face Array, be_to_face.
2072  mesh.be_to_face.Copy(be_to_face);
2073 
2074  // Copy the element-to-edge Table, el_to_edge
2075  el_to_edge = (mesh.el_to_edge) ? new Table(*mesh.el_to_edge) : NULL;
2076 
2077  // Copy the boudary-to-edge Table, bel_to_edge (3D)
2078  bel_to_edge = (mesh.bel_to_edge) ? new Table(*mesh.bel_to_edge) : NULL;
2079 
2080  // Copy the boudary-to-edge Array, be_to_edge (2D)
2081  mesh.be_to_edge.Copy(be_to_edge);
2082 
2083  // Duplicate the faces and faces_info.
2084  faces.SetSize(mesh.faces.Size());
2085  for (int i = 0; i < faces.Size(); i++)
2086  {
2087  Element *face = mesh.faces[i]; // in 1D the faces are NULL
2088  faces[i] = (face) ? face->Duplicate(this) : NULL;
2089  }
2090  mesh.faces_info.Copy(faces_info);
2091 
2092  // Do NOT copy the element-to-element Table, el_to_el
2093  el_to_el = NULL;
2094 
2095  // Do NOT copy the face-to-edge Table, face_edge
2096  face_edge = NULL;
2097 
2098  // Copy the edge-to-vertex Table, edge_vertex
2099  edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
2100 
2101  // Do not copy any of the coarse (c_*), fine (f_*) or fine/coarse (fc_*)
2102  // data members.
2103 
2104  // Do NOT copy the coarse non-conforming Mesh, 'nc_coarse_level'
2105  nc_coarse_level = NULL;
2106 
2107  // Copy the attributes and bdr_attributes
2108  mesh.attributes.Copy(attributes);
2109  mesh.bdr_attributes.Copy(bdr_attributes);
2110 
2111  // No support for NURBS meshes, yet. Need deep copy for NURBSExtension.
2112  MFEM_VERIFY(mesh.NURBSext == NULL,
2113  "copying NURBS meshes is not implemented");
2114  NURBSext = NULL;
2115 
2116  // No support for non-conforming meshes, yet. Need deep copy for NCMesh.
2117  MFEM_VERIFY(mesh.ncmesh == NULL,
2118  "copying non-conforming meshes is not implemented");
2119  ncmesh = NULL;
2120 
2121  // Duplicate the Nodes, including the FiniteElementCollection and the
2122  // FiniteElementSpace
2123  if (mesh.Nodes && copy_nodes)
2124  {
2125  FiniteElementSpace *fes = mesh.Nodes->FESpace();
2126  const FiniteElementCollection *fec = fes->FEColl();
2127  FiniteElementCollection *fec_copy =
2129  FiniteElementSpace *fes_copy =
2130  new FiniteElementSpace(this, fec_copy, fes->GetVDim(),
2131  fes->GetOrdering());
2132  Nodes = new GridFunction(fes_copy);
2133  Nodes->MakeOwner(fec_copy);
2134  *Nodes = *mesh.Nodes;
2135  own_nodes = 1;
2136  }
2137  else
2138  {
2139  Nodes = mesh.Nodes;
2140  own_nodes = 0;
2141  }
2142 }
2143 
2144 Mesh::Mesh(std::istream &input, int generate_edges, int refine,
2145  bool fix_orientation)
2146 {
2147  Init();
2148  InitTables();
2149  Load(input, generate_edges, refine, fix_orientation);
2150 }
2151 
2153 {
2154  switch (geom)
2155  {
2156  case Geometry::POINT: return (new Point);
2157  case Geometry::SEGMENT: return (new Segment);
2158  case Geometry::TRIANGLE: return (new Triangle);
2159  case Geometry::SQUARE: return (new Quadrilateral);
2160  case Geometry::CUBE: return (new Hexahedron);
2161  case Geometry::TETRAHEDRON:
2162 #ifdef MFEM_USE_MEMALLOC
2163  return TetMemory.Alloc();
2164 #else
2165  return (new Tetrahedron);
2166 #endif
2167  }
2168 
2169  return NULL;
2170 }
2171 
2173 {
2174  int geom, nv, *v;
2175  Element *el;
2176 
2177  input >> geom;
2178  el = NewElement(geom);
2179  nv = el->GetNVertices();
2180  v = el->GetVertices();
2181  for (int i = 0; i < nv; i++)
2182  {
2183  input >> v[i];
2184  }
2185 
2186  return el;
2187 }
2188 
2189 void Mesh::PrintElementWithoutAttr(const Element *el, std::ostream &out)
2190 {
2191  out << el->GetGeometryType();
2192  const int nv = el->GetNVertices();
2193  const int *v = el->GetVertices();
2194  for (int j = 0; j < nv; j++)
2195  {
2196  out << ' ' << v[j];
2197  }
2198  out << '\n';
2199 }
2200 
2201 Element *Mesh::ReadElement(std::istream &input)
2202 {
2203  int attr;
2204  Element *el;
2205 
2206  input >> attr;
2207  el = ReadElementWithoutAttr(input);
2208  el->SetAttribute(attr);
2209 
2210  return el;
2211 }
2212 
2213 void Mesh::PrintElement(const Element *el, std::ostream &out)
2214 {
2215  out << el->GetAttribute() << ' ';
2216  PrintElementWithoutAttr(el, out);
2217 }
2218 
2220 {
2221  meshgen = 0;
2222  for (int i = 0; i < NumOfElements; i++)
2223  {
2224  switch (elements[i]->GetType())
2225  {
2226  case Element::SEGMENT:
2227  case Element::TRIANGLE:
2228  case Element::TETRAHEDRON:
2229  meshgen |= 1; break;
2230 
2232  case Element::HEXAHEDRON:
2233  meshgen |= 2;
2234  }
2235  }
2236 }
2237 
2238 // see Tetrahedron::edges
2239 static const int vtk_quadratic_tet[10] =
2240 { 0, 1, 2, 3, 4, 7, 5, 6, 8, 9 };
2241 
2242 // see Hexahedron::edges & Mesh::GenerateFaces
2243 static const int vtk_quadratic_hex[27] =
2244 {
2245  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
2246  24, 22, 21, 23, 20, 25, 26
2247 };
2248 
2249 void skip_comment_lines(std::istream &is, const char comment_char)
2250 {
2251  while (1)
2252  {
2253  is >> ws;
2254  if (is.peek() != comment_char)
2255  {
2256  break;
2257  }
2258  is.ignore(numeric_limits<streamsize>::max(), '\n');
2259  }
2260 }
2261 
2262 void Mesh::Load(std::istream &input, int generate_edges, int refine,
2263  bool fix_orientation)
2264 {
2265  int i, j, ints[32], n, attr, curved = 0, read_gf = 1;
2266  const int buflen = 1024;
2267  char buf[buflen];
2268 
2269  if (!input)
2270  {
2271  MFEM_ABORT("Input stream is not open");
2272  }
2273 
2274  if (NumOfVertices != -1)
2275  {
2276  // Delete the elements.
2277  for (i = 0; i < NumOfElements; i++)
2278  {
2279  FreeElement(elements[i]);
2280  }
2281  elements.DeleteAll();
2282  NumOfElements = 0;
2283 
2284  // Delete the vertices.
2285  vertices.DeleteAll();
2286  NumOfVertices = 0;
2287 
2288  // Delete the boundary elements.
2289  for (i = 0; i < NumOfBdrElements; i++)
2290  {
2291  FreeElement(boundary[i]);
2292  }
2293  boundary.DeleteAll();
2294  NumOfBdrElements = 0;
2295 
2296  // Delete interior faces (if generated)
2297  for (i = 0; i < faces.Size(); i++)
2298  {
2299  FreeElement(faces[i]);
2300  }
2301  faces.DeleteAll();
2302  NumOfFaces = 0;
2303 
2304  faces_info.DeleteAll();
2305 
2306  // Delete the edges (if generated).
2307  DeleteTables();
2308  be_to_edge.DeleteAll();
2309  be_to_face.DeleteAll();
2310  NumOfEdges = 0;
2311 
2312  // TODO: make this a Destroy function
2313  }
2314 
2315  delete ncmesh;
2316  ncmesh = NULL;
2317 
2318  if (own_nodes) { delete Nodes; }
2319  Nodes = NULL;
2320 
2321  InitTables();
2322  spaceDim = 0;
2323 
2324  string mesh_type;
2325  input >> ws;
2326  getline(input, mesh_type);
2327 
2328  bool mfem_v10 = (mesh_type == "MFEM mesh v1.0");
2329  bool mfem_v11 = (mesh_type == "MFEM mesh v1.1");
2330 
2331  if (mfem_v10 || mfem_v11)
2332  {
2333  // Read MFEM mesh v1.0 format
2334  string ident;
2335 
2336  // read lines beginning with '#' (comments)
2337  skip_comment_lines(input, '#');
2338  input >> ident; // 'dimension'
2339 
2340  MFEM_VERIFY(ident == "dimension", "invalid mesh file");
2341  input >> Dim;
2342 
2343  skip_comment_lines(input, '#');
2344  input >> ident; // 'elements'
2345 
2346  MFEM_VERIFY(ident == "elements", "invalid mesh file");
2347  input >> NumOfElements;
2348  elements.SetSize(NumOfElements);
2349  for (j = 0; j < NumOfElements; j++)
2350  {
2351  elements[j] = ReadElement(input);
2352  }
2353 
2354  skip_comment_lines(input, '#');
2355  input >> ident; // 'boundary'
2356 
2357  MFEM_VERIFY(ident == "boundary", "invalid mesh file");
2358  input >> NumOfBdrElements;
2359  boundary.SetSize(NumOfBdrElements);
2360  for (j = 0; j < NumOfBdrElements; j++)
2361  {
2362  boundary[j] = ReadElement(input);
2363  }
2364 
2365  skip_comment_lines(input, '#');
2366  input >> ident;
2367 
2368  if (ident == "vertex_parents" && mfem_v11)
2369  {
2370  ncmesh = new NCMesh(this, &input);
2371  // NOTE: the constructor above will call LoadVertexParents
2372 
2373  skip_comment_lines(input, '#');
2374  input >> ident;
2375 
2376  if (ident == "coarse_elements")
2377  {
2378  ncmesh->LoadCoarseElements(input);
2379 
2380  skip_comment_lines(input, '#');
2381  input >> ident;
2382  }
2383  }
2384 
2385  MFEM_VERIFY(ident == "vertices", "invalid mesh file");
2386  input >> NumOfVertices;
2387  vertices.SetSize(NumOfVertices);
2388 
2389  input >> ws >> ident;
2390  if (ident != "nodes")
2391  {
2392  // read the vertices
2393  spaceDim = atoi(ident.c_str());
2394  for (j = 0; j < NumOfVertices; j++)
2395  {
2396  for (i = 0; i < spaceDim; i++)
2397  {
2398  input >> vertices[j](i);
2399  }
2400  }
2401 
2402  // initialize vertex positions in NCMesh
2403  if (ncmesh) { ncmesh->SetVertexPositions(vertices); }
2404  }
2405  else
2406  {
2407  // prepare to read the nodes
2408  input >> ws;
2409  curved = 1;
2410  }
2411  }
2412  else if (mesh_type == "linemesh")
2413  {
2414  int j,p1,p2,a;
2415 
2416  Dim = 1;
2417 
2418  input >> NumOfVertices;
2419  vertices.SetSize(NumOfVertices);
2420  // Sets vertices and the corresponding coordinates
2421  for (j = 0; j < NumOfVertices; j++)
2422  {
2423  input >> vertices[j](0);
2424  }
2425 
2426  input >> NumOfElements;
2427  elements.SetSize(NumOfElements);
2428  // Sets elements and the corresponding indices of vertices
2429  for (j = 0; j < NumOfElements; j++)
2430  {
2431  input >> a >> p1 >> p2;
2432  elements[j] = new Segment(p1-1, p2-1, a);
2433  }
2434 
2435  int ind[1];
2436  input >> NumOfBdrElements;
2437  boundary.SetSize(NumOfBdrElements);
2438  for (j = 0; j < NumOfBdrElements; j++)
2439  {
2440  input >> a >> ind[0];
2441  ind[0]--;
2442  boundary[j] = new Point(ind,a);
2443  }
2444  }
2445  else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2")
2446  {
2447  // Read planar mesh in Netgen format.
2448  Dim = 2;
2449 
2450  if (mesh_type == "curved_areamesh2")
2451  {
2452  curved = 1;
2453  }
2454 
2455  // Read the boundary elements.
2456  input >> NumOfBdrElements;
2457  boundary.SetSize(NumOfBdrElements);
2458  for (i = 0; i < NumOfBdrElements; i++)
2459  {
2460  input >> attr
2461  >> ints[0] >> ints[1];
2462  ints[0]--; ints[1]--;
2463  boundary[i] = new Segment(ints, attr);
2464  }
2465 
2466  // Read the elements.
2467  input >> NumOfElements;
2468  elements.SetSize(NumOfElements);
2469  for (i = 0; i < NumOfElements; i++)
2470  {
2471  input >> attr >> n;
2472  for (j = 0; j < n; j++)
2473  {
2474  input >> ints[j];
2475  ints[j]--;
2476  }
2477  switch (n)
2478  {
2479  case 2:
2480  elements[i] = new Segment(ints, attr);
2481  break;
2482  case 3:
2483  elements[i] = new Triangle(ints, attr);
2484  break;
2485  case 4:
2486  elements[i] = new Quadrilateral(ints, attr);
2487  break;
2488  }
2489  }
2490 
2491  if (!curved)
2492  {
2493  // Read the vertices.
2494  input >> NumOfVertices;
2495  vertices.SetSize(NumOfVertices);
2496  for (i = 0; i < NumOfVertices; i++)
2497  for (j = 0; j < Dim; j++)
2498  {
2499  input >> vertices[i](j);
2500  }
2501  }
2502  else
2503  {
2504  input >> NumOfVertices;
2505  vertices.SetSize(NumOfVertices);
2506  input >> ws;
2507  }
2508  }
2509  else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format")
2510  {
2511  // Read a Netgen format mesh of tetrahedra.
2512  Dim = 3;
2513 
2514  // Read the vertices
2515  input >> NumOfVertices;
2516 
2517  vertices.SetSize(NumOfVertices);
2518  for (i = 0; i < NumOfVertices; i++)
2519  for (j = 0; j < Dim; j++)
2520  {
2521  input >> vertices[i](j);
2522  }
2523 
2524  // Read the elements
2525  input >> NumOfElements;
2526  elements.SetSize(NumOfElements);
2527  for (i = 0; i < NumOfElements; i++)
2528  {
2529  input >> attr;
2530  for (j = 0; j < 4; j++)
2531  {
2532  input >> ints[j];
2533  ints[j]--;
2534  }
2535 #ifdef MFEM_USE_MEMALLOC
2536  Tetrahedron *tet;
2537  tet = TetMemory.Alloc();
2538  tet->SetVertices(ints);
2539  tet->SetAttribute(attr);
2540  elements[i] = tet;
2541 #else
2542  elements[i] = new Tetrahedron(ints, attr);
2543 #endif
2544  }
2545 
2546  // Read the boundary information.
2547  input >> NumOfBdrElements;
2548  boundary.SetSize(NumOfBdrElements);
2549  for (i = 0; i < NumOfBdrElements; i++)
2550  {
2551  input >> attr;
2552  for (j = 0; j < 3; j++)
2553  {
2554  input >> ints[j];
2555  ints[j]--;
2556  }
2557  boundary[i] = new Triangle(ints, attr);
2558  }
2559  }
2560  else if (mesh_type == "TrueGrid")
2561  {
2562  // Reading TrueGrid mesh.
2563 
2564  // TODO: find the actual dimension
2565  Dim = 3;
2566 
2567  if (Dim == 2)
2568  {
2569  int vari;
2570  double varf;
2571 
2572  input >> vari >> NumOfVertices >> vari >> vari >> NumOfElements;
2573  input.getline(buf, buflen);
2574  input.getline(buf, buflen);
2575  input >> vari;
2576  input.getline(buf, buflen);
2577  input.getline(buf, buflen);
2578  input.getline(buf, buflen);
2579 
2580  // Read the vertices.
2581  vertices.SetSize(NumOfVertices);
2582  for (i = 0; i < NumOfVertices; i++)
2583  {
2584  input >> vari >> varf >> vertices[i](0) >> vertices[i](1);
2585  input.getline(buf, buflen);
2586  }
2587 
2588  // Read the elements.
2589  elements.SetSize(NumOfElements);
2590  for (i = 0; i < NumOfElements; i++)
2591  {
2592  input >> vari >> attr;
2593  for (j = 0; j < 4; j++)
2594  {
2595  input >> ints[j];
2596  ints[j]--;
2597  }
2598  input.getline(buf, buflen);
2599  input.getline(buf, buflen);
2600  elements[i] = new Quadrilateral(ints, attr);
2601  }
2602  }
2603  else if (Dim == 3)
2604  {
2605  int vari;
2606  double varf;
2607  input >> vari >> NumOfVertices >> NumOfElements;
2608  input.getline(buf, buflen);
2609  input.getline(buf, buflen);
2610  input >> vari >> vari >> NumOfBdrElements;
2611  input.getline(buf, buflen);
2612  input.getline(buf, buflen);
2613  input.getline(buf, buflen);
2614  // Read the vertices.
2615  vertices.SetSize(NumOfVertices);
2616  for (i = 0; i < NumOfVertices; i++)
2617  {
2618  input >> vari >> varf >> vertices[i](0) >> vertices[i](1)
2619  >> vertices[i](2);
2620  input.getline(buf, buflen);
2621  }
2622  // Read the elements.
2623  elements.SetSize(NumOfElements);
2624  for (i = 0; i < NumOfElements; i++)
2625  {
2626  input >> vari >> attr;
2627  for (j = 0; j < 8; j++)
2628  {
2629  input >> ints[j];
2630  ints[j]--;
2631  }
2632  input.getline(buf, buflen);
2633  elements[i] = new Hexahedron(ints, attr);
2634  }
2635  // Read the boundary elements.
2636  boundary.SetSize(NumOfBdrElements);
2637  for (i = 0; i < NumOfBdrElements; i++)
2638  {
2639  input >> attr;
2640  for (j = 0; j < 4; j++)
2641  {
2642  input >> ints[j];
2643  ints[j]--;
2644  }
2645  input.getline(buf, buflen);
2646  boundary[i] = new Quadrilateral(ints, attr);
2647  }
2648  }
2649  }
2650  else if (mesh_type == "# vtk DataFile Version 3.0" ||
2651  mesh_type == "# vtk DataFile Version 2.0")
2652  {
2653  // Reading VTK mesh
2654 
2655  string buff;
2656  getline(input, buff); // comment line
2657  getline(input, buff);
2658  if (buff != "ASCII")
2659  {
2660  mfem_error("Mesh::Load : VTK mesh is not in ASCII format!");
2661  return;
2662  }
2663  getline(input, buff);
2664  if (buff != "DATASET UNSTRUCTURED_GRID")
2665  {
2666  mfem_error("Mesh::Load : VTK mesh is not UNSTRUCTURED_GRID!");
2667  return;
2668  }
2669 
2670  // Read the points, skipping optional sections such as the FIELD data from
2671  // VisIt's VTK export (or from Mesh::PrintVTK with field_data==1).
2672  do
2673  {
2674  input >> buff;
2675  if (!input.good())
2676  {
2677  mfem_error("Mesh::Load : VTK mesh does not have POINTS data!");
2678  }
2679  }
2680  while (buff != "POINTS");
2681  int np = 0;
2682  Vector points;
2683  {
2684  input >> np >> ws;
2685  points.SetSize(3*np);
2686  getline(input, buff); // "double"
2687  for (i = 0; i < points.Size(); i++)
2688  {
2689  input >> points(i);
2690  }
2691  }
2692 
2693  // Read the cells
2694  NumOfElements = n = 0;
2695  Array<int> cells_data;
2696  input >> ws >> buff;
2697  if (buff == "CELLS")
2698  {
2699  input >> NumOfElements >> n >> ws;
2700  cells_data.SetSize(n);
2701  for (i = 0; i < n; i++)
2702  {
2703  input >> cells_data[i];
2704  }
2705  }
2706 
2707  // Read the cell types
2708  Dim = 0;
2709  int order = 1;
2710  input >> ws >> buff;
2711  if (buff == "CELL_TYPES")
2712  {
2713  input >> NumOfElements;
2714  elements.SetSize(NumOfElements);
2715  for (j = i = 0; i < NumOfElements; i++)
2716  {
2717  int ct;
2718  input >> ct;
2719  switch (ct)
2720  {
2721  case 5: // triangle
2722  Dim = 2;
2723  elements[i] = new Triangle(&cells_data[j+1]);
2724  break;
2725  case 9: // quadrilateral
2726  Dim = 2;
2727  elements[i] = new Quadrilateral(&cells_data[j+1]);
2728  break;
2729  case 10: // tetrahedron
2730  Dim = 3;
2731 #ifdef MFEM_USE_MEMALLOC
2732  elements[i] = TetMemory.Alloc();
2733  elements[i]->SetVertices(&cells_data[j+1]);
2734 #else
2735  elements[i] = new Tetrahedron(&cells_data[j+1]);
2736 #endif
2737  break;
2738  case 12: // hexahedron
2739  Dim = 3;
2740  elements[i] = new Hexahedron(&cells_data[j+1]);
2741  break;
2742 
2743  case 22: // quadratic triangle
2744  Dim = 2;
2745  order = 2;
2746  elements[i] = new Triangle(&cells_data[j+1]);
2747  break;
2748  case 28: // biquadratic quadrilateral
2749  Dim = 2;
2750  order = 2;
2751  elements[i] = new Quadrilateral(&cells_data[j+1]);
2752  break;
2753  case 24: // quadratic tetrahedron
2754  Dim = 3;
2755  order = 2;
2756 #ifdef MFEM_USE_MEMALLOC
2757  elements[i] = TetMemory.Alloc();
2758  elements[i]->SetVertices(&cells_data[j+1]);
2759 #else
2760  elements[i] = new Tetrahedron(&cells_data[j+1]);
2761 #endif
2762  break;
2763  case 29: // triquadratic hexahedron
2764  Dim = 3;
2765  order = 2;
2766  elements[i] = new Hexahedron(&cells_data[j+1]);
2767  break;
2768  default:
2769  cerr << "Mesh::Load : VTK mesh : cell type " << ct
2770  << " is not supported!" << endl;
2771  mfem_error();
2772  return;
2773  }
2774  j += cells_data[j] + 1;
2775  }
2776  }
2777 
2778  // Read attributes
2779  streampos sp = input.tellg();
2780  input >> ws >> buff;
2781  if (buff == "CELL_DATA")
2782  {
2783  input >> n >> ws;
2784  getline(input, buff);
2785  // "SCALARS material dataType numComp"
2786  if (!strncmp(buff.c_str(), "SCALARS material", 16))
2787  {
2788  getline(input, buff); // "LOOKUP_TABLE default"
2789  for (i = 0; i < NumOfElements; i++)
2790  {
2791  input >> attr;
2792  elements[i]->SetAttribute(attr);
2793  }
2794  }
2795  else
2796  {
2797  input.seekg(sp);
2798  }
2799  }
2800  else
2801  {
2802  input.seekg(sp);
2803  }
2804 
2805  if (order == 1)
2806  {
2807  cells_data.DeleteAll();
2808  NumOfVertices = np;
2809  vertices.SetSize(np);
2810  for (i = 0; i < np; i++)
2811  {
2812  vertices[i](0) = points(3*i+0);
2813  vertices[i](1) = points(3*i+1);
2814  vertices[i](2) = points(3*i+2);
2815  }
2816  points.Destroy();
2817 
2818  // No boundary is defined in a VTK mesh
2819  NumOfBdrElements = 0;
2820  }
2821  else if (order == 2)
2822  {
2823  curved = 1;
2824 
2825  // generate new enumeration for the vertices
2826  Array<int> pts_dof(np);
2827  pts_dof = -1;
2828  for (n = i = 0; i < NumOfElements; i++)
2829  {
2830  int *v = elements[i]->GetVertices();
2831  int nv = elements[i]->GetNVertices();
2832  for (j = 0; j < nv; j++)
2833  if (pts_dof[v[j]] == -1)
2834  {
2835  pts_dof[v[j]] = n++;
2836  }
2837  }
2838  // keep the original ordering of the vertices
2839  for (n = i = 0; i < np; i++)
2840  if (pts_dof[i] != -1)
2841  {
2842  pts_dof[i] = n++;
2843  }
2844  // update the element vertices
2845  for (i = 0; i < NumOfElements; i++)
2846  {
2847  int *v = elements[i]->GetVertices();
2848  int nv = elements[i]->GetNVertices();
2849  for (j = 0; j < nv; j++)
2850  {
2851  v[j] = pts_dof[v[j]];
2852  }
2853  }
2854  // Define the 'vertices' from the 'points' through the 'pts_dof' map
2855  NumOfVertices = n;
2856  vertices.SetSize(n);
2857  for (i = 0; i < np; i++)
2858  {
2859  if ((j = pts_dof[i]) != -1)
2860  {
2861  vertices[j](0) = points(3*i+0);
2862  vertices[j](1) = points(3*i+1);
2863  vertices[j](2) = points(3*i+2);
2864  }
2865  }
2866 
2867  // No boundary is defined in a VTK mesh
2868  NumOfBdrElements = 0;
2869 
2870  // Generate faces and edges so that we can define quadratic
2871  // FE space on the mesh
2872 
2873  // Generate faces
2874  if (Dim > 2)
2875  {
2876  GetElementToFaceTable();
2877  GenerateFaces();
2878  }
2879  else
2880  {
2881  NumOfFaces = 0;
2882  }
2883 
2884  // Generate edges
2885  el_to_edge = new Table;
2886  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2887  if (Dim == 2)
2888  {
2889  GenerateFaces(); // 'Faces' in 2D refers to the edges
2890  }
2891 
2892  // Define quadratic FE space
2894  FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim);
2895  Nodes = new GridFunction(fes);
2896  Nodes->MakeOwner(fec); // Nodes will destroy 'fec' and 'fes'
2897  own_nodes = 1;
2898 
2899  // Map vtk points to edge/face/element dofs
2900  Array<int> dofs;
2901  for (n = i = 0; i < NumOfElements; i++)
2902  {
2903  fes->GetElementDofs(i, dofs);
2904  const int *vtk_mfem;
2905  switch (elements[i]->GetGeometryType())
2906  {
2907  case Geometry::TRIANGLE:
2908  case Geometry::SQUARE:
2909  vtk_mfem = vtk_quadratic_hex; break; // identity map
2910  case Geometry::TETRAHEDRON:
2911  vtk_mfem = vtk_quadratic_tet; break;
2912  case Geometry::CUBE:
2913  default:
2914  vtk_mfem = vtk_quadratic_hex; break;
2915  }
2916 
2917  for (n++, j = 0; j < dofs.Size(); j++, n++)
2918  {
2919  if (pts_dof[cells_data[n]] == -1)
2920  {
2921  pts_dof[cells_data[n]] = dofs[vtk_mfem[j]];
2922  }
2923  else
2924  {
2925  if (pts_dof[cells_data[n]] != dofs[vtk_mfem[j]])
2926  mfem_error("Mesh::Load : VTK mesh : "
2927  "inconsistent quadratic mesh!");
2928  }
2929  }
2930  }
2931 
2932  // Define the 'Nodes' from the 'points' through the 'pts_dof' map
2933  for (i = 0; i < np; i++)
2934  {
2935  dofs.SetSize(1);
2936  if ((dofs[0] = pts_dof[i]) != -1)
2937  {
2938  fes->DofsToVDofs(dofs);
2939  for (j = 0; j < dofs.Size(); j++)
2940  {
2941  (*Nodes)(dofs[j]) = points(3*i+j);
2942  }
2943  }
2944  }
2945 
2946  read_gf = 0;
2947  }
2948  }
2949  else if (mesh_type == "MFEM NURBS mesh v1.0")
2950  {
2951  NURBSext = new NURBSExtension(input);
2952 
2953  Dim = NURBSext->Dimension();
2954  NumOfVertices = NURBSext->GetNV();
2955  NumOfElements = NURBSext->GetNE();
2956  NumOfBdrElements = NURBSext->GetNBE();
2957 
2958  NURBSext->GetElementTopo(elements);
2959  NURBSext->GetBdrElementTopo(boundary);
2960 
2961  vertices.SetSize(NumOfVertices);
2962  curved = 1;
2963  if (NURBSext->HavePatches())
2964  {
2965  NURBSFECollection *fec = new NURBSFECollection(NURBSext->GetOrder());
2966  FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
2968  Nodes = new GridFunction(fes);
2969  Nodes->MakeOwner(fec);
2970  NURBSext->SetCoordsFromPatches(*Nodes);
2971  own_nodes = 1;
2972  read_gf = 0;
2973  int vd = Nodes->VectorDim();
2974  for (i = 0; i < vd; i++)
2975  {
2976  Vector vert_val;
2977  Nodes->GetNodalValues(vert_val, i+1);
2978  for (j = 0; j < NumOfVertices; j++)
2979  {
2980  vertices[j](i) = vert_val(j);
2981  }
2982  }
2983  }
2984  else
2985  {
2986  read_gf = 1;
2987  }
2988  }
2989  else if (mesh_type == "MFEM INLINE mesh v1.0")
2990  {
2991  // Initialize to negative numbers so that we know if they've
2992  // been set. We're using Element::POINT as our flag, since
2993  // we're not going to make a 0D mesh, ever.
2994  int nx = -1;
2995  int ny = -1;
2996  int nz = -1;
2997  double sx = -1.0;
2998  double sy = -1.0;
2999  double sz = -1.0;
3001 
3002  while (true)
3003  {
3004  skip_comment_lines(input, '#');
3005  // Break out if we reached the end of the file after
3006  // gobbling up the whitespace and comments after the last keyword.
3007  if (!input.good())
3008  {
3009  break;
3010  }
3011 
3012  // Read the next keyword
3013  std::string name;
3014  input >> name;
3015  input >> std::ws;
3016  // Make sure there's an equal sign
3017  MFEM_VERIFY(input.get() == '=',
3018  "Inline mesh expected '=' after keyword " << name);
3019  input >> std::ws;
3020 
3021  if (name == "nx")
3022  {
3023  input >> nx;
3024  }
3025  else if (name == "ny")
3026  {
3027  input >> ny;
3028  }
3029  else if (name == "nz")
3030  {
3031  input >> nz;
3032  }
3033  else if (name == "sx")
3034  {
3035  input >> sx;
3036  }
3037  else if (name == "sy")
3038  {
3039  input >> sy;
3040  }
3041  else if (name == "sz")
3042  {
3043  input >> sz;
3044  }
3045  else if (name == "type")
3046  {
3047  std::string eltype;
3048  input >> eltype;
3049  if (eltype == "segment")
3050  {
3051  type = Element::SEGMENT;
3052  }
3053  else if (eltype == "quad")
3054  {
3055  type = Element::QUADRILATERAL;
3056  }
3057  else if (eltype == "tri")
3058  {
3059  type = Element::TRIANGLE;
3060  }
3061  else if (eltype == "hex")
3062  {
3063  type = Element::HEXAHEDRON;
3064  }
3065  else if (eltype == "tet")
3066  {
3067  type = Element::TETRAHEDRON;
3068  }
3069  else
3070  {
3071  MFEM_ABORT("unrecognized element type (read '" << eltype
3072  << "') in inline mesh format. "
3073  "Allowed: segment, tri, tet, quad, hex");
3074  }
3075  }
3076  else
3077  {
3078  MFEM_ABORT("unrecognized keyword (" << name
3079  << ") in inline mesh format. "
3080  "Allowed: nx, ny, nz, type, sx, sy, sz");
3081  }
3082 
3083  input >> std::ws;
3084  // Allow an optional semi-colon at the end of each line.
3085  if (input.peek() == ';')
3086  {
3087  input.get();
3088  }
3089 
3090  // Done reading file
3091  if (!input)
3092  {
3093  break;
3094  }
3095  }
3096 
3097  // Now make the mesh.
3098  if (type == Element::SEGMENT)
3099  {
3100  MFEM_VERIFY(nx > 0 && sx > 0.0,
3101  "invalid 1D inline mesh format, all values must be "
3102  "positive\n"
3103  << " nx = " << nx << "\n"
3104  << " sx = " << sx << "\n");
3105  Make1D(nx, sx);
3106  }
3107  else if (type == Element::TRIANGLE || type == Element::QUADRILATERAL)
3108  {
3109  MFEM_VERIFY(nx > 0 && ny > 0 && sx > 0.0 && sy > 0.0,
3110  "invalid 2D inline mesh format, all values must be "
3111  "positive\n"
3112  << " nx = " << nx << "\n"
3113  << " ny = " << ny << "\n"
3114  << " sx = " << sx << "\n"
3115  << " sy = " << sy << "\n");
3116  Make2D(nx, ny, type, generate_edges, sx, sy);
3117  }
3118  else if (type == Element::TETRAHEDRON || type == Element::HEXAHEDRON)
3119  {
3120  MFEM_VERIFY(nx > 0 && ny > 0 && nz > 0 &&
3121  sx > 0.0 && sy > 0.0 && sz > 0.0,
3122  "invalid 3D inline mesh format, all values must be "
3123  "positive\n"
3124  << " nx = " << nx << "\n"
3125  << " ny = " << ny << "\n"
3126  << " nz = " << nz << "\n"
3127  << " sx = " << sx << "\n"
3128  << " sy = " << sy << "\n"
3129  << " sz = " << sz << "\n");
3130  Make3D(nx, ny, nz, type, generate_edges, sx, sy, sz);
3131  }
3132  else
3133  {
3134  mfem_error("Mesh::Load : For inline mesh, must specify an "
3135  "element type = [segment, tri, quad, tet, hex]");
3136  }
3137  return; // done with inline mesh construction
3138  }
3139  else
3140  {
3141  MFEM_ABORT("Unknown input mesh format");
3142  return;
3143  }
3144 
3145  // at this point the following should be defined:
3146  // 1) Dim
3147  // 2) NumOfElements, elements
3148  // 3) NumOfBdrElements, boundary
3149  // 4) NumOfVertices, with allocated space in vertices
3150  // 5) curved
3151  // 5a) if curved == 0, vertices must be defined
3152  // 5b) if curved != 0 and read_gf != 0,
3153  // 'input' must point to a GridFunction
3154  // 5c) if curved != 0 and read_gf == 0,
3155  // vertices and Nodes must be defined
3156 
3157  if (spaceDim == 0)
3158  {
3159  spaceDim = Dim;
3160  }
3161 
3162  // set the mesh type ('meshgen')
3163  SetMeshGen();
3164 
3165  if (NumOfBdrElements == 0 && Dim > 2)
3166  {
3167  // in 3D, generate boundary elements before we 'MarkForRefinement'
3168  GetElementToFaceTable();
3169  GenerateFaces();
3170  GenerateBoundaryElements();
3171  }
3172 
3173  if (!curved)
3174  {
3175  // check and fix element orientation
3176  CheckElementOrientation(fix_orientation);
3177 
3178  if (refine)
3179  {
3180  MarkForRefinement();
3181  }
3182  }
3183 
3184  if (Dim == 1)
3185  {
3186  GenerateFaces();
3187  }
3188 
3189  // generate the faces
3190  if (Dim > 2)
3191  {
3192  GetElementToFaceTable();
3193  GenerateFaces();
3194  // check and fix boundary element orientation
3195  if ( !(curved && (meshgen & 1)) )
3196  {
3197  CheckBdrElementOrientation();
3198  }
3199  }
3200  else
3201  {
3202  NumOfFaces = 0;
3203  }
3204 
3205  // generate edges if requested
3206  if (Dim > 1 && generate_edges == 1)
3207  {
3208  // el_to_edge may already be allocated (P2 VTK meshes)
3209  if (!el_to_edge) { el_to_edge = new Table; }
3210  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3211  if (Dim == 2)
3212  {
3213  GenerateFaces(); // 'Faces' in 2D refers to the edges
3214  if (NumOfBdrElements == 0)
3215  {
3216  GenerateBoundaryElements();
3217  }
3218  // check and fix boundary element orientation
3219  if ( !(curved && (meshgen & 1)) )
3220  {
3221  CheckBdrElementOrientation();
3222  }
3223  }
3224  c_el_to_edge = NULL;
3225  }
3226  else
3227  {
3228  NumOfEdges = 0;
3229  }
3230 
3231  if (ncmesh)
3232  {
3233  // tell NCMesh the numbering of edges/faces
3234  ncmesh->OnMeshUpdated(this);
3235 
3236  // update faces_info with NC relations
3237  GenerateNCFaceInfo();
3238  }
3239 
3240  // generate the arrays 'attributes' and ' bdr_attributes'
3241  SetAttributes();
3242 
3243  if (curved)
3244  {
3245  if (read_gf)
3246  {
3247  Nodes = new GridFunction(this, input);
3248  own_nodes = 1;
3249  spaceDim = Nodes->VectorDim();
3250  // Set the 'vertices' from the 'Nodes'
3251  for (i = 0; i < spaceDim; i++)
3252  {
3253  Vector vert_val;
3254  Nodes->GetNodalValues(vert_val, i+1);
3255  for (j = 0; j < NumOfVertices; j++)
3256  {
3257  vertices[j](i) = vert_val(j);
3258  }
3259  }
3260  }
3261 
3262  // Check orientation and mark edges; only for triangles / tets
3263  if (meshgen & 1)
3264  {
3265  DSTable *old_v_to_v = NULL;
3266  Table *old_elem_vert = NULL;
3267  if (fix_orientation || refine)
3268  {
3269  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
3270  }
3271 
3272  // check orientation and mark for refinement using just vertices
3273  // (i.e. higher order curvature is not used)
3274  CheckElementOrientation(fix_orientation);
3275  if (refine)
3276  {
3277  MarkForRefinement(); // changes topology!
3278  }
3279 
3280  if (fix_orientation || refine)
3281  {
3282  DoNodeReorder(old_v_to_v, old_elem_vert);
3283  delete old_elem_vert;
3284  delete old_v_to_v;
3285  }
3286  }
3287  }
3288 
3289  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
3290 }
3291 
3292 Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
3293 {
3294  int i, j, ie, ib, iv, *v, nv;
3295  Element *el;
3296  Mesh *m;
3297 
3298  Init();
3299  InitTables();
3300 
3301  Dim = mesh_array[0]->Dimension();
3302  spaceDim = mesh_array[0]->SpaceDimension();
3303 
3304  if (mesh_array[0]->NURBSext)
3305  {
3306  // assuming the pieces form a partition of a NURBS mesh
3307  NURBSext = new NURBSExtension(mesh_array, num_pieces);
3308 
3309  NumOfVertices = NURBSext->GetNV();
3310  NumOfElements = NURBSext->GetNE();
3311 
3312  NURBSext->GetElementTopo(elements);
3313 
3314  // NumOfBdrElements = NURBSext->GetNBE();
3315  // NURBSext->GetBdrElementTopo(boundary);
3316 
3317  Array<int> lvert_vert, lelem_elem;
3318 
3319  // Here, for visualization purposes, we copy the boundary elements from
3320  // the individual pieces which include the interior boundaries.
3321  // This creates 'boundary' array that is different from the one generated
3322  // by the NURBSExtension which, in particular, makes the boundary-dof
3323  // table invalid. This, in turn, causes GetBdrElementTransformation to
3324  // not function properly.
3325  NumOfBdrElements = 0;
3326  for (i = 0; i < num_pieces; i++)
3327  {
3328  NumOfBdrElements += mesh_array[i]->GetNBE();
3329  }
3330  boundary.SetSize(NumOfBdrElements);
3331  vertices.SetSize(NumOfVertices);
3332  ib = 0;
3333  for (i = 0; i < num_pieces; i++)
3334  {
3335  m = mesh_array[i];
3336  m->NURBSext->GetVertexLocalToGlobal(lvert_vert);
3337  m->NURBSext->GetElementLocalToGlobal(lelem_elem);
3338  // copy the element attributes
3339  for (j = 0; j < m->GetNE(); j++)
3340  {
3341  elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j));
3342  }
3343  // copy the boundary
3344  for (j = 0; j < m->GetNBE(); j++)
3345  {
3346  el = m->GetBdrElement(j)->Duplicate(this);
3347  v = el->GetVertices();
3348  nv = el->GetNVertices();
3349  for (int k = 0; k < nv; k++)
3350  {
3351  v[k] = lvert_vert[v[k]];
3352  }
3353  boundary[ib++] = el;
3354  }
3355  // copy the vertices
3356  for (j = 0; j < m->GetNV(); j++)
3357  {
3358  vertices[lvert_vert[j]].SetCoords(m->GetVertex(j));
3359  }
3360  }
3361  }
3362  else // not a NURBS mesh
3363  {
3364  NumOfElements = 0;
3365  NumOfBdrElements = 0;
3366  NumOfVertices = 0;
3367  for (i = 0; i < num_pieces; i++)
3368  {
3369  m = mesh_array[i];
3370  NumOfElements += m->GetNE();
3371  NumOfBdrElements += m->GetNBE();
3372  NumOfVertices += m->GetNV();
3373  }
3374  elements.SetSize(NumOfElements);
3375  boundary.SetSize(NumOfBdrElements);
3376  vertices.SetSize(NumOfVertices);
3377  ie = ib = iv = 0;
3378  for (i = 0; i < num_pieces; i++)
3379  {
3380  m = mesh_array[i];
3381  // copy the elements
3382  for (j = 0; j < m->GetNE(); j++)
3383  {
3384  el = m->GetElement(j)->Duplicate(this);
3385  v = el->GetVertices();
3386  nv = el->GetNVertices();
3387  for (int k = 0; k < nv; k++)
3388  {
3389  v[k] += iv;
3390  }
3391  elements[ie++] = el;
3392  }
3393  // copy the boundary elements
3394  for (j = 0; j < m->GetNBE(); j++)
3395  {
3396  el = m->GetBdrElement(j)->Duplicate(this);
3397  v = el->GetVertices();
3398  nv = el->GetNVertices();
3399  for (int k = 0; k < nv; k++)
3400  {
3401  v[k] += iv;
3402  }
3403  boundary[ib++] = el;
3404  }
3405  // copy the vertices
3406  for (j = 0; j < m->GetNV(); j++)
3407  {
3408  vertices[iv++].SetCoords(m->GetVertex(j));
3409  }
3410  }
3411  }
3412 
3413  // set the mesh type ('meshgen')
3414  meshgen = 0;
3415  for (i = 0; i < num_pieces; i++)
3416  {
3417  meshgen |= mesh_array[i]->MeshGenerator();
3418  }
3419 
3420  // generate faces
3421  if (Dim > 2)
3422  {
3423  GetElementToFaceTable();
3424  GenerateFaces();
3425  }
3426  else
3427  {
3428  NumOfFaces = 0;
3429  }
3430 
3431  // generate edges
3432  if (Dim > 1)
3433  {
3434  el_to_edge = new Table;
3435  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3436  if (Dim == 2)
3437  {
3438  GenerateFaces(); // 'Faces' in 2D refers to the edges
3439  }
3440  }
3441  else
3442  {
3443  NumOfEdges = 0;
3444  }
3445 
3446  // generate the arrays 'attributes' and ' bdr_attributes'
3447  SetAttributes();
3448 
3449  // copy the nodes (curvilinear meshes)
3450  GridFunction *g = mesh_array[0]->GetNodes();
3451  if (g)
3452  {
3453  Array<GridFunction *> gf_array(num_pieces);
3454  for (i = 0; i < num_pieces; i++)
3455  {
3456  gf_array[i] = mesh_array[i]->GetNodes();
3457  }
3458  Nodes = new GridFunction(this, gf_array, num_pieces);
3459  own_nodes = 1;
3460  }
3461 
3462 #ifdef MFEM_DEBUG
3463  CheckElementOrientation(false);
3464  CheckBdrElementOrientation(false);
3465 #endif
3466 }
3467 
3469 {
3470  if (NURBSext == NULL)
3471  {
3472  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
3473  }
3474 
3475  if (kv.Size() != NURBSext->GetNKV())
3476  {
3477  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
3478  }
3479 
3480  NURBSext->ConvertToPatches(*Nodes);
3481 
3482  NURBSext->KnotInsert(kv);
3483 
3484  UpdateNURBS();
3485 }
3486 
3488 {
3489  // do not check for NURBSext since this method is protected
3490  NURBSext->ConvertToPatches(*Nodes);
3491 
3492  NURBSext->UniformRefinement();
3493 
3494  UpdateNURBS();
3495 }
3496 
3498 {
3499  if (NURBSext == NULL)
3500  {
3501  mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!");
3502  }
3503 
3504  NURBSext->ConvertToPatches(*Nodes);
3505 
3506  NURBSext->DegreeElevate(t);
3507 
3508  NURBSFECollection *nurbs_fec =
3509  dynamic_cast<NURBSFECollection *>(Nodes->OwnFEC());
3510  if (!nurbs_fec)
3511  {
3512  mfem_error("Mesh::DegreeElevate");
3513  }
3514  nurbs_fec->UpdateOrder(nurbs_fec->GetOrder() + t);
3515 
3516  UpdateNURBS();
3517 }
3518 
3520 {
3521  NURBSext->SetKnotsFromPatches();
3522 
3523  Dim = NURBSext->Dimension();
3524  spaceDim = Dim;
3525 
3526  if (NumOfElements != NURBSext->GetNE())
3527  {
3528  for (int i = 0; i < elements.Size(); i++)
3529  {
3530  FreeElement(elements[i]);
3531  }
3532  NumOfElements = NURBSext->GetNE();
3533  NURBSext->GetElementTopo(elements);
3534  }
3535 
3536  if (NumOfBdrElements != NURBSext->GetNBE())
3537  {
3538  for (int i = 0; i < boundary.Size(); i++)
3539  {
3540  FreeElement(boundary[i]);
3541  }
3542  NumOfBdrElements = NURBSext->GetNBE();
3543  NURBSext->GetBdrElementTopo(boundary);
3544  }
3545 
3546  Nodes->FESpace()->Update();
3547  Nodes->Update();
3548  NURBSext->SetCoordsFromPatches(*Nodes);
3549 
3550  if (NumOfVertices != NURBSext->GetNV())
3551  {
3552  NumOfVertices = NURBSext->GetNV();
3553  vertices.SetSize(NumOfVertices);
3554  int vd = Nodes->VectorDim();
3555  for (int i = 0; i < vd; i++)
3556  {
3557  Vector vert_val;
3558  Nodes->GetNodalValues(vert_val, i+1);
3559  for (int j = 0; j < NumOfVertices; j++)
3560  {
3561  vertices[j](i) = vert_val(j);
3562  }
3563  }
3564  }
3565 
3566  if (el_to_edge)
3567  {
3568  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3569  if (Dim == 2)
3570  {
3571  GenerateFaces();
3572  }
3573  }
3574 
3575  if (el_to_face)
3576  {
3577  GetElementToFaceTable();
3578  GenerateFaces();
3579  }
3580 }
3581 
3582 void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot)
3583 {
3584  Init();
3585  InitTables();
3586 
3587  int j;
3588 
3589  // Read MFEM NURBS mesh v1.0 format
3590  string ident;
3591 
3592  skip_comment_lines(input, '#');
3593 
3594  input >> ident; // 'dimension'
3595  input >> Dim;
3596  spaceDim = Dim;
3597 
3598  skip_comment_lines(input, '#');
3599 
3600  input >> ident; // 'elements'
3601  input >> NumOfElements;
3602  elements.SetSize(NumOfElements);
3603  for (j = 0; j < NumOfElements; j++)
3604  {
3605  elements[j] = ReadElement(input);
3606  }
3607 
3608  skip_comment_lines(input, '#');
3609 
3610  input >> ident; // 'boundary'
3611  input >> NumOfBdrElements;
3612  boundary.SetSize(NumOfBdrElements);
3613  for (j = 0; j < NumOfBdrElements; j++)
3614  {
3615  boundary[j] = ReadElement(input);
3616  }
3617 
3618  skip_comment_lines(input, '#');
3619 
3620  input >> ident; // 'edges'
3621  input >> NumOfEdges;
3622  edge_vertex = new Table(NumOfEdges, 2);
3623  edge_to_knot.SetSize(NumOfEdges);
3624  for (j = 0; j < NumOfEdges; j++)
3625  {
3626  int *v = edge_vertex->GetRow(j);
3627  input >> edge_to_knot[j] >> v[0] >> v[1];
3628  if (v[0] > v[1])
3629  {
3630  edge_to_knot[j] = -1 - edge_to_knot[j];
3631  }
3632  }
3633 
3634  skip_comment_lines(input, '#');
3635 
3636  input >> ident; // 'vertices'
3637  input >> NumOfVertices;
3638  vertices.SetSize(0);
3639 
3640  meshgen = 2;
3641 
3642  // generate the faces
3643  if (Dim > 2)
3644  {
3645  GetElementToFaceTable();
3646  GenerateFaces();
3647  if (NumOfBdrElements == 0)
3648  {
3649  GenerateBoundaryElements();
3650  }
3651  CheckBdrElementOrientation();
3652  }
3653  else
3654  {
3655  NumOfFaces = 0;
3656  }
3657 
3658  // generate edges
3659  if (Dim > 1)
3660  {
3661  el_to_edge = new Table;
3662  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3663  if (Dim < 3)
3664  {
3665  GenerateFaces();
3666  if (NumOfBdrElements == 0)
3667  {
3668  GenerateBoundaryElements();
3669  }
3670  CheckBdrElementOrientation();
3671  }
3672  }
3673  else
3674  {
3675  NumOfEdges = 0;
3676  }
3677 
3678  // generate the arrays 'attributes' and ' bdr_attributes'
3679  SetAttributes();
3680 }
3681 
3683 {
3684  if (p.Size() >= v.Size())
3685  {
3686  for (int d = 0; d < v.Size(); d++)
3687  {
3688  v(d) = p(d);
3689  }
3690  }
3691  else
3692  {
3693  int d;
3694  for (d = 0; d < p.Size(); d++)
3695  {
3696  v(d) = p(d);
3697  }
3698  for ( ; d < v.Size(); d++)
3699  {
3700  v(d) = 0.0;
3701  }
3702  }
3703 }
3704 
3705 void Mesh::GetNodes(GridFunction &nodes) const
3706 {
3707  if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
3708  {
3709  const int newSpaceDim = nodes.FESpace()->GetVDim();
3711  nodes.ProjectCoefficient(xyz);
3712  }
3713  else
3714  {
3715  nodes = *Nodes;
3716  }
3717 }
3718 
3720 {
3721  GridFunction *nodes = new GridFunction(nfes);
3722  SetNodalGridFunction(nodes, true);
3723 }
3724 
3725 void Mesh::SetNodalGridFunction(GridFunction *nodes, bool make_owner)
3726 {
3727  GetNodes(*nodes);
3728  NewNodes(*nodes, make_owner);
3729 }
3730 
3732 {
3733  return ((Nodes) ? Nodes->FESpace() : NULL);
3734 }
3735 
3736 void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
3737 {
3738  space_dim = (space_dim == -1) ? spaceDim : space_dim;
3740  if (discont)
3741  {
3742  const int type = 1; // Gauss-Lobatto points
3743  nfec = new L2_FECollection(order, Dim, type);
3744  }
3745  else
3746  {
3747  nfec = new H1_FECollection(order, Dim);
3748  }
3749  FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
3750  ordering);
3751  SetNodalFESpace(nfes);
3752  Nodes->MakeOwner(nfec);
3753 }
3754 
3756 {
3757  switch (Dim)
3758  {
3759  case 1: return GetNV();
3760  case 2: return GetNEdges();
3761  case 3: return GetNFaces();
3762  }
3763  return 0;
3764 }
3765 
3766 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
3767 static const char *fixed_or_not[] = { "fixed", "NOT FIXED" };
3768 #endif
3769 
3771 {
3772  int i, j, k, wo = 0, fo = 0, *vi = 0;
3773  double *v[4];
3774 
3775  if (Dim == 2 && spaceDim == 2)
3776  {
3777  DenseMatrix J(2, 2);
3778 
3779  for (i = 0; i < NumOfElements; i++)
3780  {
3781  if (Nodes == NULL)
3782  {
3783  vi = elements[i]->GetVertices();
3784  for (j = 0; j < 3; j++)
3785  {
3786  v[j] = vertices[vi[j]]();
3787  }
3788  for (j = 0; j < 2; j++)
3789  for (k = 0; k < 2; k++)
3790  {
3791  J(j, k) = v[j+1][k] - v[0][k];
3792  }
3793  }
3794  else
3795  {
3796  // only check the Jacobian at the center of the element
3797  GetElementJacobian(i, J);
3798  }
3799  if (J.Det() < 0.0)
3800  {
3801  if (fix_it)
3802  {
3803  switch (GetElementType(i))
3804  {
3805  case Element::TRIANGLE:
3806  mfem::Swap(vi[0], vi[1]);
3807  break;
3809  mfem::Swap(vi[1], vi[3]);
3810  break;
3811  }
3812  fo++;
3813  }
3814  wo++;
3815  }
3816  }
3817  }
3818 
3819  if (Dim == 3)
3820  {
3821  DenseMatrix J(3, 3);
3822 
3823  for (i = 0; i < NumOfElements; i++)
3824  {
3825  vi = elements[i]->GetVertices();
3826  switch (GetElementType(i))
3827  {
3828  case Element::TETRAHEDRON:
3829  if (Nodes == NULL)
3830  {
3831  for (j = 0; j < 4; j++)
3832  {
3833  v[j] = vertices[vi[j]]();
3834  }
3835  for (j = 0; j < 3; j++)
3836  for (k = 0; k < 3; k++)
3837  {
3838  J(j, k) = v[j+1][k] - v[0][k];
3839  }
3840  }
3841  else
3842  {
3843  // only check the Jacobian at the center of the element
3844  GetElementJacobian(i, J);
3845  }
3846  if (J.Det() < 0.0)
3847  {
3848  wo++;
3849  if (fix_it)
3850  {
3851  mfem::Swap(vi[0], vi[1]);
3852  fo++;
3853  }
3854  }
3855  break;
3856 
3857  case Element::HEXAHEDRON:
3858  // only check the Jacobian at the center of the element
3859  GetElementJacobian(i, J);
3860  if (J.Det() < 0.0)
3861  {
3862  wo++;
3863  if (fix_it)
3864  {
3865  // how?
3866  }
3867  }
3868  break;
3869  }
3870  }
3871  }
3872 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
3873  if (wo > 0)
3874  cout << "Elements with wrong orientation: " << wo << " / "
3875  << NumOfElements << " (" << fixed_or_not[(wo == fo) ? 0 : 1]
3876  << ")" << endl;
3877 #endif
3878 }
3879 
3880 int Mesh::GetTriOrientation(const int *base, const int *test)
3881 {
3882  int orient;
3883 
3884  if (test[0] == base[0])
3885  if (test[1] == base[1])
3886  {
3887  orient = 0; // (0, 1, 2)
3888  }
3889  else
3890  {
3891  orient = 5; // (0, 2, 1)
3892  }
3893  else if (test[0] == base[1])
3894  if (test[1] == base[0])
3895  {
3896  orient = 1; // (1, 0, 2)
3897  }
3898  else
3899  {
3900  orient = 2; // (1, 2, 0)
3901  }
3902  else // test[0] == base[2]
3903  if (test[1] == base[0])
3904  {
3905  orient = 4; // (2, 0, 1)
3906  }
3907  else
3908  {
3909  orient = 3; // (2, 1, 0)
3910  }
3911 
3912 #ifdef MFEM_DEBUG
3913  const int *aor = tri_orientations[orient];
3914  for (int j = 0; j < 3; j++)
3915  if (test[aor[j]] != base[j])
3916  {
3917  mfem_error("Mesh::GetTriOrientation(...)");
3918  }
3919 #endif
3920 
3921  return orient;
3922 }
3923 
3924 int Mesh::GetQuadOrientation(const int *base, const int *test)
3925 {
3926  int i;
3927 
3928  for (i = 0; i < 4; i++)
3929  if (test[i] == base[0])
3930  {
3931  break;
3932  }
3933 
3934 #ifdef MFEM_DEBUG
3935  int orient;
3936  if (test[(i+1)%4] == base[1])
3937  {
3938  orient = 2*i;
3939  }
3940  else
3941  {
3942  orient = 2*i+1;
3943  }
3944  const int *aor = quad_orientations[orient];
3945  for (int j = 0; j < 4; j++)
3946  if (test[aor[j]] != base[j])
3947  {
3948  cerr << "Mesh::GetQuadOrientation(...)" << endl;
3949  cerr << " base = [";
3950  for (int k = 0; k < 4; k++)
3951  {
3952  cerr << " " << base[k];
3953  }
3954  cerr << " ]\n test = [";
3955  for (int k = 0; k < 4; k++)
3956  {
3957  cerr << " " << test[k];
3958  }
3959  cerr << " ]" << endl;
3960  mfem_error();
3961  }
3962 #endif
3963 
3964  if (test[(i+1)%4] == base[1])
3965  {
3966  return 2*i;
3967  }
3968 
3969  return 2*i+1;
3970 }
3971 
3973 {
3974  int i, wo = 0;
3975 
3976  if (Dim == 2)
3977  {
3978  for (i = 0; i < NumOfBdrElements; i++)
3979  {
3980  if (faces_info[be_to_edge[i]].Elem2No < 0) // boundary face
3981  {
3982  int *bv = boundary[i]->GetVertices();
3983  int *fv = faces[be_to_edge[i]]->GetVertices();
3984  if (bv[0] != fv[0])
3985  {
3986  if (fix_it)
3987  {
3988  mfem::Swap<int>(bv[0], bv[1]);
3989  }
3990  wo++;
3991  }
3992  }
3993  }
3994  }
3995 
3996  if (Dim == 3)
3997  {
3998  int el, *bv, *ev;
3999  int v[4];
4000 
4001  for (i = 0; i < NumOfBdrElements; i++)
4002  {
4003  if (faces_info[be_to_face[i]].Elem2No < 0)
4004  {
4005  // boundary face
4006  bv = boundary[i]->GetVertices();
4007  el = faces_info[be_to_face[i]].Elem1No;
4008  ev = elements[el]->GetVertices();
4009  switch (GetElementType(el))
4010  {
4011  case Element::TETRAHEDRON:
4012  {
4013  int *fv = faces[be_to_face[i]]->GetVertices();
4014  int orientation; // orientation of the bdr. elem. w.r.t. the
4015  // corresponding face element (that's the base)
4016  orientation = GetTriOrientation(fv, bv);
4017  if (orientation % 2)
4018  {
4019  // wrong orientation -- swap vertices 0 and 1 so that
4020  // we don't change the marked edge: (0,1,2) -> (1,0,2)
4021  if (fix_it)
4022  {
4023  mfem::Swap<int>(bv[0], bv[1]);
4024  }
4025  wo++;
4026  }
4027  }
4028  break;
4029 
4030  case Element::HEXAHEDRON:
4031  {
4032  int lf = faces_info[be_to_face[i]].Elem1Inf/64;
4033  for (int j = 0; j < 4; j++)
4034  {
4035  v[j] = ev[hex_faces[lf][j]];
4036  }
4037  if (GetQuadOrientation(v, bv) % 2)
4038  {
4039  if (fix_it)
4040  {
4041  mfem::Swap<int>(bv[0], bv[2]);
4042  }
4043  wo++;
4044  }
4045  break;
4046  }
4047  }
4048  }
4049  }
4050  }
4051  // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
4052 #ifdef MFEM_DEBUG
4053  if (wo > 0)
4054  {
4055  cout << "Boundary elements with wrong orientation: " << wo << " / "
4056  << NumOfBdrElements << " (" << fixed_or_not[fix_it ? 0 : 1]
4057  << ")" << endl;
4058  }
4059 #endif
4060 }
4061 
4062 void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const
4063 {
4064  if (el_to_edge)
4065  {
4066  el_to_edge->GetRow(i, edges);
4067  }
4068  else
4069  {
4070  mfem_error("Mesh::GetElementEdges(...) element to edge table "
4071  "is not generated.");
4072  }
4073 
4074  const int *v = elements[i]->GetVertices();
4075  const int ne = elements[i]->GetNEdges();
4076  cor.SetSize(ne);
4077  for (int j = 0; j < ne; j++)
4078  {
4079  const int *e = elements[i]->GetEdgeVertices(j);
4080  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
4081  }
4082 }
4083 
4084 void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const
4085 {
4086  if (Dim == 2)
4087  {
4088  edges.SetSize(1);
4089  cor.SetSize(1);
4090  edges[0] = be_to_edge[i];
4091  const int *v = boundary[i]->GetVertices();
4092  cor[0] = (v[0] < v[1]) ? (1) : (-1);
4093  }
4094  else if (Dim == 3)
4095  {
4096  if (bel_to_edge)
4097  {
4098  bel_to_edge->GetRow(i, edges);
4099  }
4100  else
4101  {
4102  mfem_error("Mesh::GetBdrElementEdges(...)");
4103  }
4104 
4105  const int *v = boundary[i]->GetVertices();
4106  const int ne = boundary[i]->GetNEdges();
4107  cor.SetSize(ne);
4108  for (int j = 0; j < ne; j++)
4109  {
4110  const int *e = boundary[i]->GetEdgeVertices(j);
4111  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
4112  }
4113  }
4114 }
4115 
4116 void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const
4117 {
4118  if (Dim == 2)
4119  {
4120  edges.SetSize(1);
4121  edges[0] = i;
4122  o.SetSize(1);
4123  const int *v = faces[i]->GetVertices();
4124  o[0] = (v[0] < v[1]) ? (1) : (-1);
4125  }
4126 
4127  if (Dim != 3)
4128  {
4129  return;
4130  }
4131 
4132  MFEM_ASSERT(State != TWO_LEVEL_COARSE, "internal MFEM error!");
4133 
4134  GetFaceEdgeTable(); // generate face_edge Table (if not generated)
4135 
4136  face_edge->GetRow(i, edges);
4137 
4138  const int *v = faces[i]->GetVertices();
4139  const int ne = faces[i]->GetNEdges();
4140  o.SetSize(ne);
4141  for (int j = 0; j < ne; j++)
4142  {
4143  const int *e = faces[i]->GetEdgeVertices(j);
4144  o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
4145  }
4146 }
4147 
4148 void Mesh::GetEdgeVertices(int i, Array<int> &vert) const
4149 {
4150  MFEM_ASSERT(State != TWO_LEVEL_COARSE, "internal MFEM error!");
4151 
4152  // the two vertices are sorted: vert[0] < vert[1]
4153  // this is consistent with the global edge orientation
4154  GetEdgeVertexTable(); // generate edge_vertex Table (if not generated)
4155  edge_vertex->GetRow(i, vert);
4156 }
4157 
4159 {
4160  if (face_edge)
4161  {
4162  return face_edge;
4163  }
4164 
4165  if (Dim != 3)
4166  {
4167  return NULL;
4168  }
4169 
4170 #ifdef MFEM_DEBUG
4171  if (faces.Size() != NumOfFaces)
4172  {
4173  mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!");
4174  }
4175 #endif
4176 
4177  DSTable v_to_v(NumOfVertices);
4178  GetVertexToVertexTable(v_to_v);
4179 
4180  face_edge = new Table;
4181  GetElementArrayEdgeTable(faces, v_to_v, *face_edge);
4182 
4183  return (face_edge);
4184 }
4185 
4187 {
4188  if (edge_vertex)
4189  {
4190  return edge_vertex;
4191  }
4192 
4193  DSTable v_to_v(NumOfVertices);
4194  GetVertexToVertexTable(v_to_v);
4195 
4196  int nedges = v_to_v.NumberOfEntries();
4197  edge_vertex = new Table(nedges, 2);
4198  for (int i = 0; i < NumOfVertices; i++)
4199  {
4200  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
4201  {
4202  int j = it.Index();
4203  edge_vertex->Push(j, i);
4204  edge_vertex->Push(j, it.Column());
4205  }
4206  }
4207  edge_vertex->Finalize();
4208 
4209  return edge_vertex;
4210 }
4211 
4213 {
4214  int i, j, nv, *v;
4215 
4216  Table *vert_elem = new Table;
4217 
4218  vert_elem->MakeI(NumOfVertices);
4219 
4220  for (i = 0; i < NumOfElements; i++)
4221  {
4222  nv = elements[i]->GetNVertices();
4223  v = elements[i]->GetVertices();
4224  for (j = 0; j < nv; j++)
4225  {
4226  vert_elem->AddAColumnInRow(v[j]);
4227  }
4228  }
4229 
4230  vert_elem->MakeJ();
4231 
4232  for (i = 0; i < NumOfElements; i++)
4233  {
4234  nv = elements[i]->GetNVertices();
4235  v = elements[i]->GetVertices();
4236  for (j = 0; j < nv; j++)
4237  {
4238  vert_elem->AddConnection(v[j], i);
4239  }
4240  }
4241 
4242  vert_elem->ShiftUpI();
4243 
4244  return vert_elem;
4245 }
4246 
4248 {
4249  Table *face_elem = new Table;
4250 
4251  face_elem->MakeI(faces_info.Size());
4252 
4253  for (int i = 0; i < faces_info.Size(); i++)
4254  {
4255  if (faces_info[i].Elem2No >= 0)
4256  {
4257  face_elem->AddColumnsInRow(i, 2);
4258  }
4259  else
4260  {
4261  face_elem->AddAColumnInRow(i);
4262  }
4263  }
4264 
4265  face_elem->MakeJ();
4266 
4267  for (int i = 0; i < faces_info.Size(); i++)
4268  {
4269  face_elem->AddConnection(i, faces_info[i].Elem1No);
4270  if (faces_info[i].Elem2No >= 0)
4271  {
4272  face_elem->AddConnection(i, faces_info[i].Elem2No);
4273  }
4274  }
4275 
4276  face_elem->ShiftUpI();
4277 
4278  return face_elem;
4279 }
4280 
4282 const
4283 {
4284  int n, j;
4285 
4286  if (el_to_face)
4287  {
4288  el_to_face->GetRow(i, fcs);
4289  }
4290  else
4291  {
4292  mfem_error("Mesh::GetElementFaces(...) : el_to_face not generated.");
4293  }
4294 
4295  n = fcs.Size();
4296  cor.SetSize(n);
4297  for (j = 0; j < n; j++)
4298  if (faces_info[fcs[j]].Elem1No == i)
4299  {
4300  cor[j] = faces_info[fcs[j]].Elem1Inf % 64;
4301  }
4302 #ifdef MFEM_DEBUG
4303  else if (faces_info[fcs[j]].Elem2No == i)
4304  {
4305  cor[j] = faces_info[fcs[j]].Elem2Inf % 64;
4306  }
4307  else
4308  {
4309  mfem_error("Mesh::GetElementFaces(...) : 2");
4310  }
4311 #else
4312  else
4313  {
4314  cor[j] = faces_info[fcs[j]].Elem2Inf % 64;
4315  }
4316 #endif
4317 }
4318 
4319 void Mesh::GetBdrElementFace(int i, int *f, int *o) const
4320 {
4321  const int *bv, *fv;
4322 
4323  if (State == Mesh::TWO_LEVEL_COARSE)
4324  {
4325  // the coarse level 'be_to_face' and 'faces' are destroyed
4326  mfem_error("Mesh::GetBdrElementFace (...)");
4327  }
4328 
4329  *f = be_to_face[i];
4330  bv = boundary[i]->GetVertices();
4331  fv = faces[be_to_face[i]]->GetVertices();
4332 
4333  // find the orientation of the bdr. elem. w.r.t.
4334  // the corresponding face element (that's the base)
4335  switch (GetBdrElementType(i))
4336  {
4337  case Element::TRIANGLE:
4338  *o = GetTriOrientation(fv, bv);
4339  break;
4341  *o = GetQuadOrientation(fv, bv);
4342  break;
4343  default:
4344  mfem_error("Mesh::GetBdrElementFace(...) 2");
4345  }
4346 }
4347 
4349 {
4350  // Here, we assume all faces are of the same type
4351  switch (GetElementType(0))
4352  {
4353  case Element::SEGMENT:
4354  return Geometry::POINT;
4355 
4356  case Element::TRIANGLE:
4358  return Geometry::SEGMENT; // in 2D 'face' is an edge
4359 
4360  case Element::TETRAHEDRON:
4361  return Geometry::TRIANGLE;
4362  case Element::HEXAHEDRON:
4363  return Geometry::SQUARE;
4364  default:
4365  mfem_error("Mesh::GetFaceBaseGeometry(...) #1");
4366  }
4367  return (-1);
4368 }
4369 
4371 {
4372  switch (Dim)
4373  {
4374  case 1: return boundary[i]->GetVertices()[0];
4375  case 2: return be_to_edge[i];
4376  case 3: return be_to_face[i];
4377  default: mfem_error("Mesh::GetBdrElementEdgeIndex: invalid dimension!");
4378  }
4379  return -1;
4380 }
4381 
4382 int Mesh::GetElementType(int i) const
4383 {
4384  Element *El = elements[i];
4385  int t = El->GetType();
4386 
4387  while (1)
4388  if (t == Element::BISECTED ||
4389  t == Element::QUADRISECTED ||
4390  t == Element::OCTASECTED)
4391  {
4392  t = (El = ((RefinedElement *) El)->IAm())->GetType();
4393  }
4394  else
4395  {
4396  break;
4397  }
4398  return t;
4399 }
4400 
4401 int Mesh::GetBdrElementType(int i) const
4402 {
4403  Element *El = boundary[i];
4404  int t = El->GetType();
4405 
4406  while (1)
4407  if (t == Element::BISECTED || t == Element::QUADRISECTED)
4408  {
4409  t = (El = ((RefinedElement *) El)->IAm())->GetType();
4410  }
4411  else
4412  {
4413  break;
4414  }
4415  return t;
4416 }
4417 
4418 void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const
4419 {
4420  int k, j, nv;
4421  const int *v;
4422 
4423  v = elements[i]->GetVertices();
4424  nv = elements[i]->GetNVertices();
4425 
4426  pointmat.SetSize(spaceDim, nv);
4427  for (k = 0; k < spaceDim; k++)
4428  for (j = 0; j < nv; j++)
4429  {
4430  pointmat(k, j) = vertices[v[j]](k);
4431  }
4432 }
4433 
4434 void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const
4435 {
4436  int k, j, nv;
4437  const int *v;
4438 
4439  v = boundary[i]->GetVertices();
4440  nv = boundary[i]->GetNVertices();
4441 
4442  pointmat.SetSize(spaceDim, nv);
4443  for (k = 0; k < spaceDim; k++)
4444  for (j = 0; j < nv; j++)
4445  {
4446  pointmat(k, j) = vertices[v[j]](k);
4447  }
4448 }
4449 
4450 double Mesh::GetLength(int i, int j) const
4451 {
4452  const double *vi = vertices[i]();
4453  const double *vj = vertices[j]();
4454  double length = 0.;
4455 
4456  for (int k = 0; k < spaceDim; k++)
4457  {
4458  length += (vi[k]-vj[k])*(vi[k]-vj[k]);
4459  }
4460 
4461  return sqrt(length);
4462 }
4463 
4464 // static method
4466  const DSTable &v_to_v, Table &el_to_edge)
4467 {
4468  el_to_edge.MakeI(elem_array.Size());
4469  for (int i = 0; i < elem_array.Size(); i++)
4470  {
4471  el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges());
4472  }
4473  el_to_edge.MakeJ();
4474  for (int i = 0; i < elem_array.Size(); i++)
4475  {
4476  const int *v = elem_array[i]->GetVertices();
4477  const int ne = elem_array[i]->GetNEdges();
4478  for (int j = 0; j < ne; j++)
4479  {
4480  const int *e = elem_array[i]->GetEdgeVertices(j);
4481  el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]]));
4482  }
4483  }
4484  el_to_edge.ShiftUpI();
4485 }
4486 
4488 {
4489  if (edge_vertex)
4490  {
4491  for (int i = 0; i < edge_vertex->Size(); i++)
4492  {
4493  const int *v = edge_vertex->GetRow(i);
4494  v_to_v.Push(v[0], v[1]);
4495  }
4496  }
4497  else
4498  {
4499  for (int i = 0; i < NumOfElements; i++)
4500  {
4501  const int *v = elements[i]->GetVertices();
4502  const int ne = elements[i]->GetNEdges();
4503  for (int j = 0; j < ne; j++)
4504  {
4505  const int *e = elements[i]->GetEdgeVertices(j);
4506  v_to_v.Push(v[e[0]], v[e[1]]);
4507  }
4508  }
4509  }
4510 }
4511 
4513 {
4514  int i, NumberOfEdges;
4515 
4516  DSTable v_to_v(NumOfVertices);
4517  GetVertexToVertexTable(v_to_v);
4518 
4519  NumberOfEdges = v_to_v.NumberOfEntries();
4520 
4521  // Fill the element to edge table
4522  GetElementArrayEdgeTable(elements, v_to_v, e_to_f);
4523 
4524  if (Dim == 2)
4525  {
4526  // Initialize the indices for the boundary elements.
4527  be_to_f.SetSize(NumOfBdrElements);
4528  for (i = 0; i < NumOfBdrElements; i++)
4529  {
4530  const int *v = boundary[i]->GetVertices();
4531  be_to_f[i] = v_to_v(v[0], v[1]);
4532  }
4533  }
4534  else if (Dim == 3)
4535  {
4536  if (bel_to_edge == NULL)
4537  {
4538  bel_to_edge = new Table;
4539  }
4540  GetElementArrayEdgeTable(boundary, v_to_v, *bel_to_edge);
4541  }
4542  else
4543  {
4544  mfem_error("1D GetElementToEdgeTable is not yet implemented.");
4545  }
4546 
4547  // Return the number of edges
4548  return NumberOfEdges;
4549 }
4550 
4552 {
4553  if (el_to_el)
4554  {
4555  return *el_to_el;
4556  }
4557 
4558  int num_faces = GetNumFaces();
4559  MFEM_ASSERT(faces_info.Size() == num_faces, "faces were not generated!");
4560 
4561  Array<Connection> conn;
4562  conn.Reserve(2*num_faces);
4563 
4564  for (int i = 0; i < faces_info.Size(); i++)
4565  {
4566  const FaceInfo &fi = faces_info[i];
4567  if (fi.Elem2No >= 0)
4568  {
4569  conn.Append(Connection(fi.Elem1No, fi.Elem2No));
4570  conn.Append(Connection(fi.Elem2No, fi.Elem1No));
4571  }
4572  }
4573 
4574  conn.Sort();
4575  conn.Unique();
4576  el_to_el = new Table(NumOfElements, conn);
4577 
4578  return *el_to_el;
4579 }
4580 
4582 {
4583  if (el_to_face == NULL)
4584  {
4585  mfem_error("Mesh::ElementToFaceTable()");
4586  }
4587  return *el_to_face;
4588 }
4589 
4591 {
4592  if (el_to_edge == NULL)
4593  {
4594  mfem_error("Mesh::ElementToEdgeTable()");
4595  }
4596  return *el_to_edge;
4597 }
4598 
4599 void Mesh::AddPointFaceElement(int lf, int gf, int el)
4600 {
4601  if (faces_info[gf].Elem1No == -1) // this will be elem1
4602  {
4603  // faces[gf] = new Point(&gf);
4604  faces_info[gf].Elem1No = el;
4605  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
4606  faces_info[gf].Elem2No = -1; // in case there's no other side
4607  faces_info[gf].Elem2Inf = -1; // face is not shared
4608  }
4609  else // this will be elem2
4610  {
4611  faces_info[gf].Elem2No = el;
4612  faces_info[gf].Elem2Inf = 64 * lf + 1;
4613  }
4614 }
4615 
4616 void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
4617 {
4618  if (faces[gf] == NULL) // this will be elem1
4619  {
4620  faces[gf] = new Segment(v0, v1);
4621  faces_info[gf].Elem1No = el;
4622  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
4623  faces_info[gf].Elem2No = -1; // in case there's no other side
4624  faces_info[gf].Elem2Inf = -1; // face is not shared
4625  }
4626  else // this will be elem2
4627  {
4628  int *v = faces[gf]->GetVertices();
4629  faces_info[gf].Elem2No = el;
4630  if ( v[1] == v0 && v[0] == v1 )
4631  {
4632  faces_info[gf].Elem2Inf = 64 * lf + 1;
4633  }
4634  else if ( v[0] == v0 && v[1] == v1 )
4635  {
4636  faces_info[gf].Elem2Inf = 64 * lf;
4637  }
4638  else
4639  {
4640  MFEM_ASSERT((v[1] == v0 && v[0] == v1)||
4641  (v[0] == v0 && v[1] == v1), "");
4642  }
4643  }
4644 }
4645 
4646 void Mesh::AddTriangleFaceElement(int lf, int gf, int el,
4647  int v0, int v1, int v2)
4648 {
4649  if (faces[gf] == NULL) // this will be elem1
4650  {
4651  faces[gf] = new Triangle(v0, v1, v2);
4652  faces_info[gf].Elem1No = el;
4653  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
4654  faces_info[gf].Elem2No = -1; // in case there's no other side
4655  faces_info[gf].Elem2Inf = -1; // face is not shared
4656  }
4657  else // this will be elem2
4658  {
4659  int orientation, vv[3] = { v0, v1, v2 };
4660  orientation = GetTriOrientation(faces[gf]->GetVertices(), vv);
4661  MFEM_ASSERT(orientation % 2 != 0, "");
4662  faces_info[gf].Elem2No = el;
4663  faces_info[gf].Elem2Inf = 64 * lf + orientation;
4664  }
4665 }
4666 
4667 void Mesh::AddQuadFaceElement(int lf, int gf, int el,
4668  int v0, int v1, int v2, int v3)
4669 {
4670  if (faces_info[gf].Elem1No < 0) // this will be elem1
4671  {
4672  faces[gf] = new Quadrilateral(v0, v1, v2, v3);
4673  faces_info[gf].Elem1No = el;
4674  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
4675  faces_info[gf].Elem2No = -1; // in case there's no other side
4676  faces_info[gf].Elem2Inf = -1; // face is not shared
4677  }
4678  else // this will be elem2
4679  {
4680  int vv[4] = { v0, v1, v2, v3 };
4681  int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv);
4682  MFEM_ASSERT(oo % 2 != 0, "");
4683  faces_info[gf].Elem2No = el;
4684  faces_info[gf].Elem2Inf = 64 * lf + oo;
4685  }
4686 }
4687 
4689 {
4690  int i, nfaces = GetNumFaces();
4691 
4692  for (i = 0; i < faces.Size(); i++)
4693  {
4694  FreeElement(faces[i]);
4695  }
4696 
4697  // (re)generate the interior faces and the info for them
4698  faces.SetSize(nfaces);
4699  faces_info.SetSize(nfaces);
4700  for (i = 0; i < nfaces; i++)
4701  {
4702  faces[i] = NULL;
4703  faces_info[i].Elem1No = -1;
4704  faces_info[i].NCFace = -1;
4705  }
4706  for (i = 0; i < NumOfElements; i++)
4707  {
4708  const int *v = elements[i]->GetVertices();
4709  const int *ef;
4710  if (Dim == 1)
4711  {
4712  AddPointFaceElement(0, v[0], i);
4713  AddPointFaceElement(1, v[1], i);
4714  }
4715  else if (Dim == 2)
4716  {
4717  ef = el_to_edge->GetRow(i);
4718  const int ne = elements[i]->GetNEdges();
4719  for (int j = 0; j < ne; j++)
4720  {
4721  const int *e = elements[i]->GetEdgeVertices(j);
4722  AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]);
4723  }
4724  }
4725  else
4726  {
4727  ef = el_to_face->GetRow(i);
4728  switch (GetElementType(i))
4729  {
4730  case Element::TETRAHEDRON:
4731  {
4732  for (int j = 0; j < 4; j++)
4733  {
4734  const int *fv = tet_faces[j];
4735  AddTriangleFaceElement(j, ef[j], i,
4736  v[fv[0]], v[fv[1]], v[fv[2]]);
4737  }
4738  break;
4739  }
4740  case Element::HEXAHEDRON:
4741  {
4742  for (int j = 0; j < 6; j++)
4743  {
4744  const int *fv = hex_faces[j];
4745  AddQuadFaceElement(j, ef[j], i,
4746  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
4747  }
4748  break;
4749  }
4750  default:
4751  MFEM_ABORT("Unexpected type of Element.");
4752  }
4753  }
4754  }
4755 }
4756 
4758 {
4759  MFEM_VERIFY(ncmesh, "missing NCMesh.");
4760 
4761  for (int i = 0; i < faces_info.Size(); i++)
4762  {
4763  faces_info[i].NCFace = -1;
4764  }
4765 
4766  const NCMesh::NCList &list =
4767  (Dim == 2) ? ncmesh->GetEdgeList() : ncmesh->GetFaceList();
4768 
4769  nc_faces_info.SetSize(0);
4770  nc_faces_info.Reserve(list.masters.size() + list.slaves.size());
4771 
4772  // add records for master faces
4773  for (unsigned i = 0; i < list.masters.size(); i++)
4774  {
4775  const NCMesh::Master &master = list.masters[i];
4776  faces_info[master.index].NCFace = nc_faces_info.Size();
4777  nc_faces_info.Append(NCFaceInfo(false, master.local, NULL));
4778  // NOTE: one of the unused members stores local face no. to be used below
4779  }
4780 
4781  // add records for slave faces
4782  for (unsigned i = 0; i < list.slaves.size(); i++)
4783  {
4784  const NCMesh::Slave &slave = list.slaves[i];
4785  FaceInfo &slave_fi = faces_info[slave.index];
4786  FaceInfo &master_fi = faces_info[slave.master];
4787  NCFaceInfo &master_nc = nc_faces_info[master_fi.NCFace];
4788 
4789  slave_fi.NCFace = nc_faces_info.Size();
4790  nc_faces_info.Append(NCFaceInfo(true, slave.master, &slave.point_matrix));
4791 
4792  slave_fi.Elem2No = master_fi.Elem1No;
4793  slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
4794  // NOTE: orientation part of Elem2Inf is encoded in the point matrix
4795  if (Dim == 2)
4796  {
4797  const int *fv = faces[slave.master]->GetVertices();
4798  if (fv[0] > fv[1])
4799  {
4800  slave_fi.Elem2Inf++;
4801  }
4802  }
4803  }
4804 }
4805 
4807 {
4808  STable3D *faces_tbl = new STable3D(NumOfVertices);
4809  for (int i = 0; i < NumOfElements; i++)
4810  {
4811  const int *v = elements[i]->GetVertices();
4812  switch (GetElementType(i))
4813  {
4814  case Element::TETRAHEDRON:
4815  {
4816  for (int j = 0; j < 4; j++)
4817  {
4818  const int *fv = tet_faces[j];
4819  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
4820  }
4821  break;
4822  }
4823  case Element::HEXAHEDRON:
4824  {
4825  // find the face by the vertices with the smallest 3 numbers
4826  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
4827  for (int j = 0; j < 6; j++)
4828  {
4829  const int *fv = hex_faces[j];
4830  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
4831  }
4832  break;
4833  }
4834  default:
4835  MFEM_ABORT("Unexpected type of Element.");
4836  }
4837  }
4838  return faces_tbl;
4839 }
4840 
4842 {
4843  int i, *v;
4844  STable3D *faces_tbl;
4845 
4846  if (el_to_face != NULL)
4847  {
4848  delete el_to_face;
4849  }
4850  el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra
4851  faces_tbl = new STable3D(NumOfVertices);
4852  for (i = 0; i < NumOfElements; i++)
4853  {
4854  v = elements[i]->GetVertices();
4855  switch (GetElementType(i))
4856  {
4857  case Element::TETRAHEDRON:
4858  {
4859  for (int j = 0; j < 4; j++)
4860  {
4861  const int *fv = tet_faces[j];
4862  el_to_face->Push(
4863  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
4864  }
4865  break;
4866  }
4867  case Element::HEXAHEDRON:
4868  {
4869  // find the face by the vertices with the smallest 3 numbers
4870  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
4871  for (int j = 0; j < 6; j++)
4872  {
4873  const int *fv = hex_faces[j];
4874  el_to_face->Push(
4875  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
4876  }
4877  break;
4878  }
4879  default:
4880  MFEM_ABORT("Unexpected type of Element.");
4881  }
4882  }
4883  el_to_face->Finalize();
4884  NumOfFaces = faces_tbl->NumberOfElements();
4885  be_to_face.SetSize(NumOfBdrElements);
4886  for (i = 0; i < NumOfBdrElements; i++)
4887  {
4888  v = boundary[i]->GetVertices();
4889  switch (GetBdrElementType(i))
4890  {
4891  case Element::TRIANGLE:
4892  {
4893  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]);
4894  break;
4895  }
4897  {
4898  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
4899  break;
4900  }
4901  default:
4902  MFEM_ABORT("Unexpected type of boundary Element.");
4903  }
4904  }
4905 
4906  if (ret_ftbl)
4907  {
4908  return faces_tbl;
4909  }
4910  delete faces_tbl;
4911  return NULL;
4912 }
4913 
4915 {
4916  int *v;
4917 
4918  if (Dim != 3 || !(meshgen & 1))
4919  {
4920  return;
4921  }
4922 
4923  DSTable *old_v_to_v = NULL;
4924  Table *old_elem_vert = NULL;
4925 
4926  if (Nodes)
4927  {
4928  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
4929  }
4930 
4931  DeleteCoarseTables();
4932 
4933  for (int i = 0; i < NumOfElements; i++)
4934  {
4935  if (GetElementType(i) == Element::TETRAHEDRON)
4936  {
4937  v = elements[i]->GetVertices();
4938 
4939  Rotate3(v[0], v[1], v[2]);
4940  if (v[0] < v[3])
4941  {
4942  Rotate3(v[1], v[2], v[3]);
4943  }
4944  else
4945  {
4946  ShiftL2R(v[0], v[1], v[3]);
4947  }
4948  }
4949  }
4950 
4951  for (int i = 0; i < NumOfBdrElements; i++)
4952  {
4953  if (GetBdrElementType(i) == Element::TRIANGLE)
4954  {
4955  v = boundary[i]->GetVertices();
4956 
4957  Rotate3(v[0], v[1], v[2]);
4958  }
4959  }
4960 
4961  if (!Nodes)
4962  {
4963  GetElementToFaceTable();
4964  GenerateFaces();
4965  if (el_to_edge)
4966  {
4967  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
4968  }
4969  }
4970  else
4971  {
4972  DoNodeReorder(old_v_to_v, old_elem_vert);
4973  delete old_elem_vert;
4974  delete old_v_to_v;
4975  }
4976 }
4977 
4978 #ifdef MFEM_USE_MPI
4979 // auxiliary function for qsort
4980 static int mfem_less(const void *x, const void *y)
4981 {
4982  if (*(int*)x < *(int*)y)
4983  {
4984  return 1;
4985  }
4986  if (*(int*)x > *(int*)y)
4987  {
4988  return -1;
4989  }
4990  return 0;
4991 }
4992 #ifndef MFEM_USE_METIS_5
4993 // METIS 4 prototypes
4994 typedef int idxtype;
4995 extern "C" {
4997  int*, int*, int*, int*, int*, idxtype*);
4999  int*, int*, int*, int*, int*, idxtype*);
5001  int*, int*, int*, int*, int*, idxtype*);
5002 }
5003 #else
5004 // METIS 5 prototypes
5005 typedef int idx_t;
5006 typedef float real_t;
5007 extern "C" {
5009  idx_t *nvtxs, idx_t *ncon, idx_t *xadj,
5010  idx_t *adjncy, idx_t *vwgt, idx_t *vsize, idx_t *adjwgt,
5011  idx_t *nparts, real_t *tpwgts, real_t *ubvec, idx_t *options,
5012  idx_t *edgecut, idx_t *part);
5013  int METIS_PartGraphKway(
5014  idx_t *nvtxs, idx_t *ncon, idx_t *xadj,
5015  idx_t *adjncy, idx_t *vwgt, idx_t *vsize, idx_t *adjwgt,
5016  idx_t *nparts, real_t *tpwgts, real_t *ubvec, idx_t *options,
5017  idx_t *edgecut, idx_t *part);
5018  int METIS_SetDefaultOptions(idx_t *options);
5019 }
5020 #endif
5021 #endif
5022 
5024 {
5025  int *partitioning;
5026  double pmin[3] = { numeric_limits<double>::infinity(),
5027  numeric_limits<double>::infinity(),
5028  numeric_limits<double>::infinity()
5029  };
5030  double pmax[3] = { -numeric_limits<double>::infinity(),
5031  -numeric_limits<double>::infinity(),
5032  -numeric_limits<double>::infinity()
5033  };
5034  // find a bounding box using the vertices
5035  for (int vi = 0; vi < NumOfVertices; vi++)
5036  {
5037  const double *p = vertices[vi]();
5038  for (int i = 0; i < spaceDim; i++)
5039  {
5040  if (p[i] < pmin[i]) { pmin[i] = p[i]; }
5041  if (p[i] > pmax[i]) { pmax[i] = p[i]; }
5042  }
5043  }
5044 
5045  partitioning = new int[NumOfElements];
5046 
5047  // determine the partitioning using the centers of the elements
5048  double ppt[3];
5049  Vector pt(ppt, spaceDim);
5050  for (int el = 0; el < NumOfElements; el++)
5051  {
5052  GetElementTransformation(el)->Transform(
5053  Geometries.GetCenter(GetElementBaseGeometry(el)), pt);
5054  int part = 0;
5055  for (int i = spaceDim-1; i >= 0; i--)
5056  {
5057  int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i])));
5058  if (idx < 0) { idx = 0; }
5059  if (idx >= nxyz[i]) { idx = nxyz[i]-1; }
5060  part = part * nxyz[i] + idx;
5061  }
5062  partitioning[el] = part;
5063  }
5064 
5065  return partitioning;
5066 }
5067 
5068 int *Mesh::GeneratePartitioning(int nparts, int part_method)
5069 {
5070 #ifdef MFEM_USE_MPI
5071  int i, *partitioning;
5072 
5073  ElementToElementTable();
5074 
5075  partitioning = new int[NumOfElements];
5076 
5077  if (nparts == 1)
5078  {
5079  for (i = 0; i < NumOfElements; i++)
5080  {
5081  partitioning[i] = 0;
5082  }
5083  }
5084  else
5085  {
5086  int *I, *J, n;
5087 #ifndef MFEM_USE_METIS_5
5088  int wgtflag = 0;
5089  int numflag = 0;
5090  int options[5];
5091 #else
5092  int ncon = 1;
5093  int err;
5094  int options[40];
5095 #endif
5096  int edgecut;
5097 
5098  n = NumOfElements;
5099  I = el_to_el->GetI();
5100  J = el_to_el->GetJ();
5101 #ifndef MFEM_USE_METIS_5
5102  options[0] = 0;
5103 #else
5104  METIS_SetDefaultOptions(options);
5105  options[10] = 1; // set METIS_OPTION_CONTIG
5106 #endif
5107 
5108  // Sort the neighbor lists
5109  if (part_method >= 0 && part_method <= 2)
5110  for (i = 0; i < n; i++)
5111  {
5112  qsort(&J[I[i]], I[i+1]-I[i], sizeof(int), &mfem_less);
5113  }
5114 
5115  // This function should be used to partition a graph into a small
5116  // number of partitions (less than 8).
5117  if (part_method == 0 || part_method == 3)
5118  {
5119 #ifndef MFEM_USE_METIS_5
5121  (idxtype *) I,
5122  (idxtype *) J,
5123  (idxtype *) NULL,
5124  (idxtype *) NULL,
5125  &wgtflag,
5126  &numflag,
5127  &nparts,
5128  options,
5129  &edgecut,
5130  (idxtype *) partitioning);
5131 #else
5132  err = METIS_PartGraphRecursive(&n,
5133  &ncon,
5134  I,
5135  J,
5136  (idx_t *) NULL,
5137  (idx_t *) NULL,
5138  (idx_t *) NULL,
5139  &nparts,
5140  (real_t *) NULL,
5141  (real_t *) NULL,
5142  options,
5143  &edgecut,
5144  partitioning);
5145  if (err != 1)
5146  mfem_error("Mesh::GeneratePartitioning: "
5147  " error in METIS_PartGraphRecursive!");
5148 #endif
5149  }
5150 
5151  // This function should be used to partition a graph into a large
5152  // number of partitions (greater than 8).
5153  if (part_method == 1 || part_method == 4)
5154  {
5155 #ifndef MFEM_USE_METIS_5
5157  (idxtype *) I,
5158  (idxtype *) J,
5159  (idxtype *) NULL,
5160  (idxtype *) NULL,
5161  &wgtflag,
5162  &numflag,
5163  &nparts,
5164  options,
5165  &edgecut,
5166  (idxtype *) partitioning);
5167 #else
5168  err = METIS_PartGraphKway(&n,
5169  &ncon,
5170  I,
5171  J,
5172  (idx_t *) NULL,
5173  (idx_t *) NULL,
5174  (idx_t *) NULL,
5175  &nparts,
5176  (real_t *) NULL,
5177  (real_t *) NULL,
5178  options,
5179  &edgecut,
5180  partitioning);
5181  if (err != 1)
5182  mfem_error("Mesh::GeneratePartitioning: "
5183  " error in METIS_PartGraphKway!");
5184 #endif
5185  }
5186 
5187  // The objective of this partitioning is to minimize the total
5188  // communication volume
5189  if (part_method == 2 || part_method == 5)
5190  {
5191 #ifndef MFEM_USE_METIS_5
5193  (idxtype *) I,
5194  (idxtype *) J,
5195  (idxtype *) NULL,
5196  (idxtype *) NULL,
5197  &wgtflag,
5198  &numflag,
5199  &nparts,
5200  options,
5201  &edgecut,
5202  (idxtype *) partitioning);
5203 #else
5204  options[1] = 1; // set METIS_OPTION_OBJTYPE to METIS_OBJTYPE_VOL
5205  err = METIS_PartGraphKway(&n,
5206  &ncon,
5207  I,
5208  J,
5209  (idx_t *) NULL,
5210  (idx_t *) NULL,
5211  (idx_t *) NULL,
5212  &nparts,
5213  (real_t *) NULL,
5214  (real_t *) NULL,
5215  options,
5216  &edgecut,
5217  partitioning);
5218  if (err != 1)
5219  mfem_error("Mesh::GeneratePartitioning: "
5220  " error in METIS_PartGraphKway!");
5221 #endif
5222  }
5223 
5224 #ifdef MFEM_DEBUG
5225  cout << "Mesh::GeneratePartitioning(...): edgecut = "
5226  << edgecut << endl;
5227 #endif
5228  }
5229 
5230  if (el_to_el)
5231  {
5232  delete el_to_el;
5233  }
5234  el_to_el = NULL;
5235 
5236  // Check for empty partitionings (a "feature" in METIS)
5237  {
5238  Array< Pair<int,int> > psize(nparts);
5239  for (i = 0; i < nparts; i++)
5240  {
5241  psize[i].one = 0;
5242  psize[i].two = i;
5243  }
5244 
5245  for (i = 0; i < NumOfElements; i++)
5246  {
5247  psize[partitioning[i]].one++;
5248  }
5249 
5250  int empty_parts = 0;
5251  for (i = 0; i < nparts; i++)
5252  if (psize[i].one == 0)
5253  {
5254  empty_parts++;
5255  }
5256 
5257  // This code just split the largest partitionings in two.
5258  // Do we need to replace it with something better?
5259  if (empty_parts)
5260  {
5261  cerr << "Mesh::GeneratePartitioning returned " << empty_parts
5262  << " empty parts!" << endl;
5263 
5264  SortPairs<int,int>(psize, nparts);
5265 
5266  for (i = nparts-1; i > nparts-1-empty_parts; i--)
5267  {
5268  psize[i].one /= 2;
5269  }
5270 
5271  for (int j = 0; j < NumOfElements; j++)
5272  for (i = nparts-1; i > nparts-1-empty_parts; i--)
5273  if (psize[i].one == 0 || partitioning[j] != psize[i].two)
5274  {
5275  continue;
5276  }
5277  else
5278  {
5279  partitioning[j] = psize[nparts-1-i].two;
5280  psize[i].one--;
5281  }
5282  }
5283  }
5284 
5285  return partitioning;
5286 
5287 #else
5288 
5289  mfem_error("Mesh::GeneratePartitioning(...): "
5290  "MFEM was compiled without Metis.");
5291 
5292  return NULL;
5293 
5294 #endif
5295 }
5296 
5297 /* required: 0 <= partitioning[i] < num_part */
5299  const Array<int> &partitioning,
5300  Array<int> &component,
5301  Array<int> &num_comp)
5302 {
5303  int i, j, k;
5304  int num_elem, *i_elem_elem, *j_elem_elem;
5305 
5306  num_elem = elem_elem.Size();
5307  i_elem_elem = elem_elem.GetI();
5308  j_elem_elem = elem_elem.GetJ();
5309 
5310  component.SetSize(num_elem);
5311 
5312  Array<int> elem_stack(num_elem);
5313  int stack_p, stack_top_p, elem;
5314  int num_part;
5315 
5316  num_part = -1;
5317  for (i = 0; i < num_elem; i++)
5318  {
5319  if (partitioning[i] > num_part)
5320  {
5321  num_part = partitioning[i];
5322  }
5323  component[i] = -1;
5324  }
5325  num_part++;
5326 
5327  num_comp.SetSize(num_part);
5328  for (i = 0; i < num_part; i++)
5329  {
5330  num_comp[i] = 0;
5331  }
5332 
5333  stack_p = 0;
5334  stack_top_p = 0; // points to the first unused element in the stack
5335  for (elem = 0; elem < num_elem; elem++)
5336  {
5337  if (component[elem] >= 0)
5338  {
5339  continue;
5340  }
5341 
5342  component[elem] = num_comp[partitioning[elem]]++;
5343 
5344  elem_stack[stack_top_p++] = elem;
5345 
5346  for ( ; stack_p < stack_top_p; stack_p++)
5347  {
5348  i = elem_stack[stack_p];
5349  for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++)
5350  {
5351  k = j_elem_elem[j];
5352  if (partitioning[k] == partitioning[i])
5353  {
5354  if (component[k] < 0)
5355  {
5356  component[k] = component[i];
5357  elem_stack[stack_top_p++] = k;
5358  }
5359  else if (component[k] != component[i])
5360  {
5361  mfem_error("FindPartitioningComponents");
5362  }
5363  }
5364  }
5365  }
5366  }
5367 }
5368 
5369 void Mesh::CheckPartitioning(int *partitioning)
5370 {
5371  int i, n_empty, n_mcomp;
5372  Array<int> component, num_comp;
5373  const Array<int> _partitioning(partitioning, GetNE());
5374 
5375  ElementToElementTable();
5376 
5377  FindPartitioningComponents(*el_to_el, _partitioning, component, num_comp);
5378 
5379  n_empty = n_mcomp = 0;
5380  for (i = 0; i < num_comp.Size(); i++)
5381  if (num_comp[i] == 0)
5382  {
5383  n_empty++;
5384  }
5385  else if (num_comp[i] > 1)
5386  {
5387  n_mcomp++;
5388  }
5389 
5390  if (n_empty > 0)
5391  {
5392  cout << "Mesh::CheckPartitioning(...) :\n"
5393  << "The following subdomains are empty :\n";
5394  for (i = 0; i < num_comp.Size(); i++)
5395  if (num_comp[i] == 0)
5396  {
5397  cout << ' ' << i;
5398  }
5399  cout << endl;
5400  }
5401  if (n_mcomp > 0)
5402  {
5403  cout << "Mesh::CheckPartitioning(...) :\n"
5404  << "The following subdomains are NOT connected :\n";
5405  for (i = 0; i < num_comp.Size(); i++)
5406  if (num_comp[i] > 1)
5407  {
5408  cout << ' ' << i;
5409  }
5410  cout << endl;
5411  }
5412  if (n_empty == 0 && n_mcomp == 0)
5413  cout << "Mesh::CheckPartitioning(...) : "
5414  "All subdomains are connected." << endl;
5415 
5416  if (el_to_el)
5417  {
5418  delete el_to_el;
5419  }
5420  el_to_el = NULL;
5421 }
5422 
5423 // compute the coefficients of the polynomial in t:
5424 // c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B)
5425 // where A, B are (d x d), d=2,3
5426 void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
5427 {
5428  const double *a = A.Data();
5429  const double *b = B.Data();
5430 
5431  c.SetSize(A.Width()+1);
5432  switch (A.Width())
5433  {
5434  case 2:
5435  {
5436  // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ |b0 b2|
5437  // |a1 a3| + \ |a1 b3| |b1 a3| / * t + |b1 b3| * t^2
5438  c(0) = a[0]*a[3]-a[1]*a[2];
5439  c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2];
5440  c(2) = b[0]*b[3]-b[1]*b[2];
5441  }
5442  break;
5443 
5444  case 3:
5445  {
5446  /* |a0 a3 a6|
5447  * det(A+t*B) = |a1 a4 a7| +
5448  * |a2 a5 a8|
5449 
5450  * / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \
5451  * + | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t +
5452  * \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| /
5453 
5454  * / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \
5455  * + | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 +
5456  * \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| /
5457 
5458  * |b0 b3 b6|
5459  * + |b1 b4 b7| * t^3
5460  * |b2 b5 b8| */
5461  c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) +
5462  a[1] * (a[5] * a[6] - a[3] * a[8]) +
5463  a[2] * (a[3] * a[7] - a[4] * a[6]));
5464 
5465  c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) +
5466  b[1] * (a[5] * a[6] - a[3] * a[8]) +
5467  b[2] * (a[3] * a[7] - a[4] * a[6]) +
5468 
5469  a[0] * (b[4] * a[8] - b[5] * a[7]) +
5470  a[1] * (b[5] * a[6] - b[3] * a[8]) +
5471  a[2] * (b[3] * a[7] - b[4] * a[6]) +
5472 
5473  a[0] * (a[4] * b[8] - a[5] * b[7]) +
5474  a[1] * (a[5] * b[6] - a[3] * b[8]) +
5475  a[2] * (a[3] * b[7] - a[4] * b[6]));
5476 
5477  c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) +
5478  a[1] * (b[5] * b[6] - b[3] * b[8]) +
5479  a[2] * (b[3] * b[7] - b[4] * b[6]) +
5480 
5481  b[0] * (a[4] * b[8] - a[5] * b[7]) +
5482  b[1] * (a[5] * b[6] - a[3] * b[8]) +
5483  b[2] * (a[3] * b[7] - a[4] * b[6]) +
5484 
5485  b[0] * (b[4] * a[8] - b[5] * a[7]) +
5486  b[1] * (b[5] * a[6] - b[3] * a[8]) +
5487  b[2] * (b[3] * a[7] - b[4] * a[6]));
5488 
5489  c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) +
5490  b[1] * (b[5] * b[6] - b[3] * b[8]) +
5491  b[2] * (b[3] * b[7] - b[4] * b[6]));
5492  }
5493  break;
5494 
5495  default:
5496  mfem_error("DetOfLinComb(...)");
5497  }
5498 }
5499 
5500 // compute the real roots of
5501 // z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3;
5502 // the roots are returned in x, sorted in increasing order;
5503 // it is assumed that x is at least of size d;
5504 // return the number of roots counting multiplicity;
5505 // return -1 if all z(i) are 0.
5506 int FindRoots(const Vector &z, Vector &x)
5507 {
5508  int d = z.Size()-1;
5509  if (d > 3 || d < 0)
5510  {
5511  mfem_error("FindRoots(...)");
5512  }
5513 
5514  while (z(d) == 0.0)
5515  {
5516  if (d == 0)
5517  {
5518  return (-1);
5519  }
5520  d--;
5521  }
5522  switch (d)
5523  {
5524  case 0:
5525  {
5526  return 0;
5527  }
5528 
5529  case 1:
5530  {
5531  x(0) = -z(0)/z(1);
5532  return 1;
5533  }
5534 
5535  case 2:
5536  {
5537  double a = z(2), b = z(1), c = z(0);
5538  double D = b*b-4*a*c;
5539  if (D < 0.0)
5540  {
5541  return 0;
5542  }
5543  if (D == 0.0)
5544  {
5545  x(0) = x(1) = -0.5 * b / a;
5546  return 2; // root with multiplicity 2
5547  }
5548  if (b == 0.0)
5549  {
5550  x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a));
5551  return 2;
5552  }
5553  else
5554  {
5555  double t;
5556  if (b > 0.0)
5557  {
5558  t = -0.5 * (b + sqrt(D));
5559  }
5560  else
5561  {
5562  t = -0.5 * (b - sqrt(D));
5563  }
5564  x(0) = t / a;
5565  x(1) = c / t;
5566  if (x(0) > x(1))
5567  {
5568  Swap<double>(x(0), x(1));
5569  }
5570  return 2;
5571  }
5572  }
5573 
5574  case 3:
5575  {
5576  double a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3);
5577 
5578  // find the real roots of x^3 + a x^2 + b x + c = 0
5579  double Q = (a * a - 3 * b) / 9;
5580  double R = (2 * a * a * a - 9 * a * b + 27 * c) / 54;
5581  double Q3 = Q * Q * Q;
5582  double R2 = R * R;
5583 
5584  if (R2 == Q3)
5585  {
5586  if (Q == 0)
5587  {
5588  x(0) = x(1) = x(2) = - a / 3;
5589  }
5590  else
5591  {
5592  double sqrtQ = sqrt(Q);
5593 
5594  if (R > 0)
5595  {
5596  x(0) = -2 * sqrtQ - a / 3;
5597  x(1) = x(2) = sqrtQ - a / 3;
5598  }
5599  else
5600  {
5601  x(0) = x(1) = - sqrtQ - a / 3;
5602  x(2) = 2 * sqrtQ - a / 3;
5603  }
5604  }
5605  return 3;
5606  }
5607  else if (R2 < Q3)
5608  {
5609  double theta = acos(R / sqrt(Q3));
5610  double A = -2 * sqrt(Q);
5611  double x0, x1, x2;
5612  x0 = A * cos(theta / 3) - a / 3;
5613  x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3;
5614  x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3;
5615 
5616  /* Sort x0, x1, x2 */
5617  if (x0 > x1)
5618  {
5619  Swap<double>(x0, x1);
5620  }
5621  if (x1 > x2)
5622  {
5623  Swap<double>(x1, x2);
5624  if (x0 > x1)
5625  {
5626  Swap<double>(x0, x1);
5627  }
5628  }
5629  x(0) = x0;
5630  x(1) = x1;
5631  x(2) = x2;
5632  return 3;
5633  }
5634  else
5635  {
5636  double A;
5637  if (R >= 0.0)
5638  {
5639  A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0);
5640  }
5641  else
5642  {
5643  A = pow(sqrt(R2 - Q3) - R, 1.0/3.0);
5644  }
5645  x(0) = A + Q / A - a / 3;
5646  return 1;
5647  }
5648  }
5649  }
5650  return 0;
5651 }
5652 
5653 void FindTMax(Vector &c, Vector &x, double &tmax,
5654  const double factor, const int Dim)
5655 {
5656  const double c0 = c(0);
5657  c(0) = c0 * (1.0 - pow(factor, -Dim));
5658  int nr = FindRoots(c, x);
5659  for (int j = 0; j < nr; j++)
5660  {
5661  if (x(j) > tmax)
5662  {
5663  break;
5664  }
5665  if (x(j) >= 0.0)
5666  {
5667  tmax = x(j);
5668  break;
5669  }
5670  }
5671  c(0) = c0 * (1.0 - pow(factor, Dim));
5672  nr = FindRoots(c, x);
5673  for (int j = 0; j < nr; j++)
5674  {
5675  if (x(j) > tmax)
5676  {
5677  break;
5678  }
5679  if (x(j) >= 0.0)
5680  {
5681  tmax = x(j);
5682  break;
5683  }
5684  }
5685 }
5686 
5687 void Mesh::CheckDisplacements(const Vector &displacements, double &tmax)
5688 {
5689  int nvs = vertices.Size();
5690  DenseMatrix P, V, DS, PDS(spaceDim), VDS(spaceDim);
5691  Vector c(spaceDim+1), x(spaceDim);
5692  const double factor = 2.0;
5693 
5694  // check for tangling assuming constant speed
5695  if (tmax < 1.0)
5696  {
5697  tmax = 1.0;
5698  }
5699  for (int i = 0; i < NumOfElements; i++)
5700  {
5701  Element *el = elements[i];
5702  int nv = el->GetNVertices();
5703  int *v = el->GetVertices();
5704  P.SetSize(spaceDim, nv);
5705  V.SetSize(spaceDim, nv);
5706  for (int j = 0; j < spaceDim; j++)
5707  for (int k = 0; k < nv; k++)
5708  {
5709  P(j, k) = vertices[v[k]](j);
5710  V(j, k) = displacements(v[k]+j*nvs);
5711  }
5712  DS.SetSize(nv, spaceDim);
5713  const FiniteElement *fe =
5714  GetTransformationFEforElementType(el->GetType());
5715  // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1
5716  switch (el->GetType())
5717  {
5718  case Element::TRIANGLE:
5719  case Element::TETRAHEDRON:
5720  {
5721  // DS is constant
5722  fe->CalcDShape(Geometries.GetCenter(fe->GetGeomType()), DS);
5723  Mult(P, DS, PDS);
5724  Mult(V, DS, VDS);
5725  DetOfLinComb(PDS, VDS, c);
5726  if (c(0) <= 0.0)
5727  {
5728  tmax = 0.0;
5729  }
5730  else
5731  {
5732  FindTMax(c, x, tmax, factor, Dim);
5733  }
5734  }
5735  break;
5736 
5738  {
5739  const IntegrationRule &ir = fe->GetNodes();
5740  for (int j = 0; j < nv; j++)
5741  {
5742  fe->CalcDShape(ir.IntPoint(j), DS);
5743  Mult(P, DS, PDS);
5744  Mult(V, DS, VDS);
5745  DetOfLinComb(PDS, VDS, c);
5746  if (c(0) <= 0.0)
5747  {
5748  tmax = 0.0;
5749  }
5750  else
5751  {
5752  FindTMax(c, x, tmax, factor, Dim);
5753  }
5754  }
5755  }
5756  break;
5757 
5758  default:
5759  mfem_error("Mesh::CheckDisplacements(...)");
5760  }
5761  }
5762 }
5763 
5764 void Mesh::MoveVertices(const Vector &displacements)
5765 {
5766  for (int i = 0, nv = vertices.Size(); i < nv; i++)
5767  for (int j = 0; j < spaceDim; j++)
5768  {
5769  vertices[i](j) += displacements(j*nv+i);
5770  }
5771 }
5772 
5773 void Mesh::GetVertices(Vector &vert_coord) const
5774 {
5775  int nv = vertices.Size();
5776  vert_coord.SetSize(nv*spaceDim);
5777  for (int i = 0; i < nv; i++)
5778  for (int j = 0; j < spaceDim; j++)
5779  {
5780  vert_coord(j*nv+i) = vertices[i](j);
5781  }
5782 }
5783 
5784 void Mesh::SetVertices(const Vector &vert_coord)
5785 {
5786  for (int i = 0, nv = vertices.Size(); i < nv; i++)
5787  for (int j = 0; j < spaceDim; j++)
5788  {
5789  vertices[i](j) = vert_coord(j*nv+i);
5790  }
5791 }
5792 
5793 void Mesh::GetNode(int i, double *coord)
5794 {
5795  if (Nodes)
5796  {
5797  FiniteElementSpace *fes = Nodes->FESpace();
5798  for (int j = 0; j < spaceDim; j++)
5799  {
5800  coord[j] = (*Nodes)(fes->DofToVDof(i, j));
5801  }
5802  }
5803  else
5804  {
5805  for (int j = 0; j < spaceDim; j++)
5806  {
5807  coord[j] = vertices[i](j);
5808  }
5809  }
5810 }
5811 
5812 void Mesh::SetNode(int i, const double *coord)
5813 {
5814  if (Nodes)
5815  {
5816  FiniteElementSpace *fes = Nodes->FESpace();
5817  for (int j = 0; j < spaceDim; j++)
5818  {
5819  (*Nodes)(fes->DofToVDof(i, j)) = coord[j];
5820  }
5821  }
5822  else
5823  {
5824  for (int j = 0; j < spaceDim; j++)
5825  {
5826  vertices[i](j) = coord[j];
5827  }
5828 
5829  }
5830 }
5831 
5832 void Mesh::MoveNodes(const Vector &displacements)
5833 {
5834  if (Nodes)
5835  {
5836  (*Nodes) += displacements;
5837  }
5838  else
5839  {
5840  MoveVertices(displacements);
5841  }
5842 }
5843 
5844 void Mesh::GetNodes(Vector &node_coord) const
5845 {
5846  if (Nodes)
5847  {
5848  node_coord = (*Nodes);
5849  }
5850  else
5851  {
5852  GetVertices(node_coord);
5853  }
5854 }
5855 
5856 void Mesh::SetNodes(const Vector &node_coord)
5857 {
5858  if (Nodes)
5859  {
5860  (*Nodes) = node_coord;
5861  }
5862  else
5863  {
5864  SetVertices(node_coord);
5865  }
5866 }
5867 
5868 void Mesh::NewNodes(GridFunction &nodes, bool make_owner)
5869 {
5870  if (own_nodes) { delete Nodes; }
5871  Nodes = &nodes;
5872  spaceDim = Nodes->FESpace()->GetVDim();
5873  own_nodes = (int)make_owner;
5874 
5875  if (NURBSext != nodes.FESpace()->GetNURBSext())
5876  {
5877  delete NURBSext;
5878  NURBSext = nodes.FESpace()->StealNURBSext();
5879  }
5880 }
5881 
5882 void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_)
5883 {
5884  mfem::Swap<GridFunction*>(Nodes, nodes);
5885  mfem::Swap<int>(own_nodes, own_nodes_);
5886  // TODO:
5887  // if (nodes)
5888  // nodes->FESpace()->MakeNURBSextOwner();
5889  // NURBSext = (Nodes) ? Nodes->FESpace()->StealNURBSext() : NULL;
5890 }
5891 
5892 void Mesh::AverageVertices(int * indexes, int n, int result)
5893 {
5894  int j, k;
5895 
5896  for (k = 0; k < spaceDim; k++)
5897  {
5898  vertices[result](k) = vertices[indexes[0]](k);
5899  }
5900 
5901  for (j = 1; j < n; j++)
5902  for (k = 0; k < spaceDim; k++)
5903  {
5904  vertices[result](k) += vertices[indexes[j]](k);
5905  }
5906 
5907  for (k = 0; k < spaceDim; k++)
5908  {
5909  vertices[result](k) *= (1.0 / n);
5910  }
5911 }
5912 
5914 {
5915  Nodes->FESpace()->UpdateAndInterpolate(Nodes);
5916  // update the vertices?
5917 }
5918 
5920 {
5921  int i, j, *v, vv[2], attr, wtls = WantTwoLevelState;
5922  const int *e;
5923 
5924  if (Nodes) // curved mesh
5925  {
5926  UseTwoLevelState(1);
5927  }
5928 
5929  SetState(Mesh::NORMAL);
5930 
5931  if (el_to_edge == NULL)
5932  {
5933  el_to_edge = new Table;
5934  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
5935  }
5936 
5937  int oedge = NumOfVertices;
5938  int oelem = oedge + NumOfEdges;
5939 
5940  DeleteCoarseTables();
5941 
5942  vertices.SetSize(oelem + NumOfElements);
5943 
5944  for (i = 0; i < NumOfElements; i++)
5945  {
5946  v = elements[i]->GetVertices();
5947 
5948  AverageVertices(v, 4, oelem+i);
5949 
5950  e = el_to_edge->GetRow(i);
5951 
5952  vv[0] = v[0], vv[1] = v[1]; AverageVertices(vv, 2, oedge+e[0]);
5953  vv[0] = v[1], vv[1] = v[2]; AverageVertices(vv, 2, oedge+e[1]);
5954  vv[0] = v[2], vv[1] = v[3]; AverageVertices(vv, 2, oedge+e[2]);
5955  vv[0] = v[3], vv[1] = v[0]; AverageVertices(vv, 2, oedge+e[3]);
5956  }
5957 
5958  elements.SetSize(4 * NumOfElements);
5959  for (i = 0; i < NumOfElements; i++)
5960  {
5961  attr = elements[i]->GetAttribute();
5962  v = elements[i]->GetVertices();
5963  e = el_to_edge->GetRow(i);
5964  j = NumOfElements + 3 * i;
5965 
5966  elements[j+0] = new Quadrilateral(oedge+e[0], v[1], oedge+e[1],
5967  oelem+i, attr);
5968  elements[j+1] = new Quadrilateral(oelem+i, oedge+e[1], v[2],
5969  oedge+e[2], attr);
5970  elements[j+2] = new Quadrilateral(oedge+e[3], oelem+i, oedge+e[2],
5971  v[3], attr);
5972 
5973  if (WantTwoLevelState)
5974  {
5975  QuadrisectedElement *qe;
5976 
5977  qe = new QuadrisectedElement(elements[i]->Duplicate(this));
5978  qe->FirstChild = elements[i];
5979  qe->Child2 = j;
5980  qe->Child3 = j+1;
5981  qe->Child4 = j+2;
5982  elements[i] = qe;
5983  }
5984 
5985  v[1] = oedge+e[0];
5986  v[2] = oelem+i;
5987  v[3] = oedge+e[3];
5988  }
5989 
5990  boundary.SetSize(2 * NumOfBdrElements);
5991  for (i = 0; i < NumOfBdrElements; i++)
5992  {
5993  attr = boundary[i]->GetAttribute();
5994  v = boundary[i]->GetVertices();
5995  j = NumOfBdrElements + i;
5996 
5997  boundary[j] = new Segment(oedge+be_to_edge[i], v[1], attr);
5998 
5999  if (WantTwoLevelState)
6000  {
6001 #ifdef MFEM_USE_MEMALLOC
6002  BisectedElement *be = BEMemory.Alloc();
6003 #else
6004  BisectedElement *be = new BisectedElement;
6005 #endif
6006  be->SetCoarseElem(boundary[i]->Duplicate(this));
6007  be->FirstChild = boundary[i];
6008  be->SecondChild = j;
6009  boundary[i] = be;
6010  }
6011 
6012  v[1] = oedge+be_to_edge[i];
6013  }
6014 
6015  if (WantTwoLevelState)
6016  {
6017  c_NumOfVertices = NumOfVertices;
6018  c_NumOfEdges = NumOfEdges;
6019  c_NumOfElements = NumOfElements;
6020  c_NumOfBdrElements = NumOfBdrElements;
6021 
6023  State = Mesh::TWO_LEVEL_FINE;
6024  }
6025 
6026  NumOfVertices = oelem + NumOfElements;
6027  NumOfElements = 4 * NumOfElements;
6028  NumOfBdrElements = 2 * NumOfBdrElements;
6029  NumOfFaces = 0;
6030 
6031  if (WantTwoLevelState)
6032  {
6033  f_NumOfVertices = NumOfVertices;
6034  f_NumOfElements = NumOfElements;
6035  f_NumOfBdrElements = NumOfBdrElements;
6036  }
6037 
6038  if (el_to_edge != NULL)
6039  {
6040  if (WantTwoLevelState)
6041  {
6042  c_el_to_edge = el_to_edge;
6043  mfem::Swap(be_to_edge, fc_be_to_edge); // save coarse be_to_edge
6044  f_el_to_edge = new Table;
6045  NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge);
6046  el_to_edge = f_el_to_edge;
6047  f_NumOfEdges = NumOfEdges;
6048  }
6049  else
6050  {
6051  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
6052  }
6053  GenerateFaces();
6054  }
6055 
6056  if (Nodes) // curved mesh
6057  {
6058  UpdateNodes();
6059  UseTwoLevelState(wtls);
6060  }
6061 
6062 #ifdef MFEM_DEBUG
6063  CheckElementOrientation(false);
6064  CheckBdrElementOrientation(false);
6065 #endif
6066 }
6067 
6069 {
6070  int i, wtls = WantTwoLevelState;
6071  int * v;
6072  const int *e, *f;
6073  int vv[4];
6074 
6075  if (Nodes) // curved mesh
6076  {
6077  UseTwoLevelState(1);
6078  }
6079 
6080  SetState(Mesh::NORMAL);
6081 
6082  if (el_to_edge == NULL)
6083  {
6084  el_to_edge = new Table;
6085  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
6086  }
6087  if (el_to_face == NULL)
6088  {
6089  GetElementToFaceTable();
6090  }
6091 
6092  int oedge = NumOfVertices;
6093  int oface = oedge + NumOfEdges;
6094  int oelem = oface + NumOfFaces;
6095 
6096  DeleteCoarseTables();
6097 
6098  vertices.SetSize(oelem + NumOfElements);
6099  for (i = 0; i < NumOfElements; i++)
6100  {
6101  MFEM_ASSERT(elements[i]->GetType() == Element::HEXAHEDRON,
6102  "Element is not a hex!");
6103  v = elements[i]->GetVertices();
6104 
6105  AverageVertices(v, 8, oelem+i);
6106 
6107  f = el_to_face->GetRow(i);
6108 
6109  for (int j = 0; j < 6; j++)
6110  {
6111  for (int k = 0; k < 4; k++)
6112  {
6113  vv[k] = v[hex_faces[j][k]];
6114  }
6115  AverageVertices(vv, 4, oface+f[j]);
6116  }
6117 
6118  e = el_to_edge->GetRow(i);
6119 
6120  for (int j = 0; j < 12; j++)
6121  {
6122  for (int k = 0; k < 2; k++)
6123  {
6124  vv[k] = v[Hexahedron::edges[j][k]];
6125  }
6126  AverageVertices(vv, 2, oedge+e[j]);
6127  }
6128  }
6129 
6130  int attr, j, k;
6131  elements.SetSize(8 * NumOfElements);
6132  for (i = 0; i < NumOfElements; i++)
6133  {
6134  attr = elements[i]->GetAttribute();
6135  v = elements[i]->GetVertices();
6136  e = el_to_edge->GetRow(i);
6137  f = el_to_face->GetRow(i);
6138  j = NumOfElements + 7 * i;
6139 
6140  elements[j+0] = new Hexahedron(oedge+e[0], v[1], oedge+e[1], oface+f[0],
6141  oface+f[1], oedge+e[9], oface+f[2],
6142  oelem+i, attr);
6143  elements[j+1] = new Hexahedron(oface+f[0], oedge+e[1], v[2], oedge+e[2],
6144  oelem+i, oface+f[2], oedge+e[10],
6145  oface+f[3], attr);
6146  elements[j+2] = new Hexahedron(oedge+e[3], oface+f[0], oedge+e[2], v[3],
6147  oface+f[4], oelem+i, oface+f[3],
6148  oedge+e[11], attr);
6149  elements[j+3] = new Hexahedron(oedge+e[8], oface+f[1], oelem+i,
6150  oface+f[4], v[4], oedge+e[4], oface+f[5],
6151  oedge+e[7], attr);
6152  elements[j+4] = new Hexahedron(oface+f[1], oedge+e[9], oface+f[2],
6153  oelem+i, oedge+e[4], v[5], oedge+e[5],
6154  oface+f[5], attr);
6155  elements[j+5] = new Hexahedron(oelem+i, oface+f[2], oedge+e[10],
6156  oface+f[3], oface+f[5], oedge+e[5], v[6],
6157  oedge+e[6], attr);
6158  elements[j+6] = new Hexahedron(oface+f[4], oelem+i, oface+f[3],
6159  oedge+e[11], oedge+e[7], oface+f[5],
6160  oedge+e[6], v[7], attr);
6161 
6162  if (WantTwoLevelState)
6163  {
6164  OctasectedElement *oe;
6165 
6166  oe = new OctasectedElement(elements[i]->Duplicate(this));
6167  oe->FirstChild = elements[i];
6168  for (k = 0; k < 7; k++)
6169  {
6170  oe->Child[k] = j + k;
6171  }
6172  elements[i] = oe;
6173  }
6174 
6175  v[1] = oedge+e[0];
6176  v[2] = oface+f[0];
6177  v[3] = oedge+e[3];
6178  v[4] = oedge+e[8];
6179  v[5] = oface+f[1];
6180  v[6] = oelem+i;
6181  v[7] = oface+f[4];
6182  }
6183 
6184  boundary.SetSize(4 * NumOfBdrElements);
6185  for (i = 0; i < NumOfBdrElements; i++)
6186  {
6187  MFEM_ASSERT(boundary[i]->GetType() == Element::QUADRILATERAL,
6188  "boundary Element is not a quad!");
6189  attr = boundary[i]->GetAttribute();
6190  v = boundary[i]->GetVertices();
6191  e = bel_to_edge->GetRow(i);
6192  f = & be_to_face[i];
6193  j = NumOfBdrElements + 3 * i;
6194 
6195  boundary[j+0] = new Quadrilateral(oedge+e[0], v[1], oedge+e[1],
6196  oface+f[0], attr);
6197  boundary[j+1] = new Quadrilateral(oface+f[0], oedge+e[1], v[2],
6198  oedge+e[2], attr);
6199  boundary[j+2] = new Quadrilateral(oedge+e[3], oface+f[0], oedge+e[2],
6200  v[3], attr);
6201 
6202  if (WantTwoLevelState)
6203  {
6204  QuadrisectedElement *qe;
6205 
6206  qe = new QuadrisectedElement(boundary[i]->Duplicate(this));
6207  qe->FirstChild = boundary[i];
6208  qe->Child2 = j;
6209  qe->Child3 = j+1;
6210  qe->Child4 = j+2;
6211  boundary[i] = qe;
6212  }
6213 
6214  v[1] = oedge+e[0];
6215  v[2] = oface+f[0];
6216  v[3] = oedge+e[3];
6217  }
6218 
6219  if (WantTwoLevelState)
6220  {
6221  c_NumOfVertices = NumOfVertices;
6222  c_NumOfEdges = NumOfEdges;
6223  c_NumOfFaces = NumOfFaces;
6224  c_NumOfElements = NumOfElements;
6225  c_NumOfBdrElements = NumOfBdrElements;
6226 
6228  State = Mesh::TWO_LEVEL_FINE;
6229  }
6230 
6231  NumOfVertices = oelem + NumOfElements;
6232  NumOfElements = 8 * NumOfElements;
6233  NumOfBdrElements = 4 * NumOfBdrElements;
6234 
6235  if (WantTwoLevelState)
6236  {
6237  f_NumOfVertices = NumOfVertices;
6238  f_NumOfElements = NumOfElements;
6239  f_NumOfBdrElements = NumOfBdrElements;
6240  }
6241 
6242  if (el_to_face != NULL)
6243  {
6244  if (WantTwoLevelState)
6245  {
6246  c_el_to_face = el_to_face;
6247  el_to_face = NULL;
6248  mfem::Swap(faces_info, fc_faces_info);
6249  }
6250  GetElementToFaceTable();
6251  GenerateFaces();
6252  if (WantTwoLevelState)
6253  {
6254  f_el_to_face = el_to_face;
6255  f_NumOfFaces = NumOfFaces;
6256  }
6257  }
6258 
6259 #ifdef MFEM_DEBUG
6260  CheckBdrElementOrientation(false);
6261 #endif
6262 
6263  if (el_to_edge != NULL)
6264  {
6265  if (WantTwoLevelState)
6266  {
6267  c_el_to_edge = el_to_edge;
6268  f_el_to_edge = new Table;
6269  c_bel_to_edge = bel_to_edge;
6270  bel_to_edge = NULL;
6271  NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge);
6272  el_to_edge = f_el_to_edge;
6273  f_bel_to_edge = bel_to_edge;
6274  f_NumOfEdges = NumOfEdges;
6275  }
6276  else
6277  {
6278  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
6279  }
6280  }
6281 
6282  if (Nodes) // curved mesh
6283  {
6284  UpdateNodes();
6285  UseTwoLevelState(wtls);
6286  }
6287 
6288  // When 'WantTwoLevelState' is true the coarse level
6289  // 'be_to_face' and 'faces'
6290  // are destroyed !!!
6291 }
6292 
6293 void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
6294 {
6295  int i, j, ind, nedges, wtls = WantTwoLevelState;
6296  Array<int> v;
6297 
6298  if (ncmesh)
6299  {
6300  mfem_error("Local and nonconforming refinements cannot be mixed.");
6301  }
6302 
6303  if (Nodes) // curved mesh
6304  {
6305  UseTwoLevelState(1);
6306  }
6307 
6308  SetState(Mesh::NORMAL);
6309  DeleteCoarseTables();
6310 
6311  if (Dim == 1) // --------------------------------------------------------
6312  {
6313  if (WantTwoLevelState)
6314  {
6315  c_NumOfVertices = NumOfVertices;
6316  c_NumOfElements = NumOfElements;
6317  c_NumOfBdrElements = NumOfBdrElements;
6318  c_NumOfEdges = 0;
6319  }
6320  int cne = NumOfElements, cnv = NumOfVertices;
6321  NumOfVertices += marked_el.Size();
6322  NumOfElements += marked_el.Size();
6323  vertices.SetSize(NumOfVertices);
6324  elements.SetSize(NumOfElements);
6325  for (j = 0; j < marked_el.Size(); j++)
6326  {
6327  i = marked_el[j];
6328  Segment *c_seg = (Segment *)elements[i];
6329  int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
6330  int new_v = cnv + j, new_e = cne + j;
6331  AverageVertices(vert, 2, new_v);
6332  elements[new_e] = new Segment(new_v, vert[1], attr);
6333  if (WantTwoLevelState)
6334  {
6335 #ifdef MFEM_USE_MEMALLOC
6336  BisectedElement *aux = BEMemory.Alloc();
6337  aux->SetCoarseElem(c_seg);
6338 #else
6339  BisectedElement *aux = new BisectedElement(c_seg);
6340 #endif
6341  aux->FirstChild = new Segment(vert[0], new_v, attr);
6342  aux->SecondChild = new_e;
6343  elements[i] = aux;
6344  }
6345  else
6346  {
6347  vert[1] = new_v;
6348  }
6349  }
6350  if (WantTwoLevelState)
6351  {
6352  f_NumOfVertices = NumOfVertices;
6353  f_NumOfElements = NumOfElements;
6354  f_NumOfBdrElements = NumOfBdrElements;
6355  f_NumOfEdges = 0;
6356 
6358  State = Mesh::TWO_LEVEL_FINE;
6359  }
6360  GenerateFaces();
6361  } // end of 'if (Dim == 1)'
6362  else if (Dim == 2) // ---------------------------------------------------
6363  {
6364  if (WantTwoLevelState)
6365  {
6366  c_NumOfVertices = NumOfVertices;
6367  c_NumOfEdges = NumOfEdges;
6368  c_NumOfElements = NumOfElements;
6369  c_NumOfBdrElements = NumOfBdrElements;
6370  }
6371 
6372  // 1. Get table of vertex to vertex connections.
6373  DSTable v_to_v(NumOfVertices);
6374  GetVertexToVertexTable(v_to_v);
6375 
6376  // 2. Get edge to element connections in arrays edge1 and edge2
6377  nedges = v_to_v.NumberOfEntries();
6378  int *edge1 = new int[nedges];
6379  int *edge2 = new int[nedges];
6380  int *middle = new int[nedges];
6381 
6382  for (i = 0; i < nedges; i++)
6383  {
6384  edge1[i] = edge2[i] = middle[i] = -1;
6385  }
6386 
6387  for (i = 0; i < NumOfElements; i++)
6388  {
6389  elements[i]->GetVertices(v);
6390  for (j = 1; j < v.Size(); j++)
6391  {
6392  ind = v_to_v(v[j-1], v[j]);
6393  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
6394  }
6395  ind = v_to_v(v[0], v[v.Size()-1]);
6396  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
6397  }
6398 
6399  // 3. Do the red refinement.
6400  for (i = 0; i < marked_el.Size(); i++)
6401  {
6402  RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
6403  }
6404 
6405  // 4. Do the green refinement (to get conforming mesh).
6406  int need_refinement;
6407  do
6408  {
6409  need_refinement = 0;
6410  for (i = 0; i < nedges; i++)
6411  if (middle[i] != -1 && edge1[i] != -1)
6412  {
6413  need_refinement = 1;
6414  GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
6415  }
6416  }
6417  while (need_refinement == 1);
6418 
6419  // 5. Update the boundary elements.
6420  int v1[2], v2[2], bisect, temp;
6421  temp = NumOfBdrElements;
6422  for (i = 0; i < temp; i++)
6423  {
6424  boundary[i]->GetVertices(v);
6425  bisect = v_to_v(v[0], v[1]);
6426  if (middle[bisect] != -1) // the element was refined (needs updating)
6427  {
6428  if (boundary[i]->GetType() == Element::SEGMENT)
6429  {
6430  v1[0] = v[0]; v1[1] = middle[bisect];
6431  v2[0] = middle[bisect]; v2[1] = v[1];
6432 
6433  if (WantTwoLevelState)
6434  {
6435  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
6436 #ifdef MFEM_USE_MEMALLOC
6437  BisectedElement *aux = BEMemory.Alloc();
6438  aux->SetCoarseElem(boundary[i]);
6439 #else
6440  BisectedElement *aux = new BisectedElement(boundary[i]);
6441 #endif
6442  aux->FirstChild =
6443  new Segment(v1, boundary[i]->GetAttribute());
6444  aux->SecondChild = NumOfBdrElements;
6445  boundary[i] = aux;
6446  NumOfBdrElements++;
6447  }
6448  else
6449  {
6450  boundary[i]->SetVertices(v1);
6451  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
6452  }
6453  }
6454  else
6455  mfem_error("Only bisection of segment is implemented"
6456  " for bdr elem.");
6457  }
6458  }
6459  NumOfBdrElements = boundary.Size();
6460 
6461  // 6. Free the allocated memory.
6462  delete [] edge1;
6463  delete [] edge2;
6464  delete [] middle;
6465 
6466  if (WantTwoLevelState)
6467  {
6468  f_NumOfVertices = NumOfVertices;
6469  f_NumOfElements = NumOfElements;
6470  f_NumOfBdrElements = NumOfBdrElements;
6472  State = Mesh::TWO_LEVEL_FINE;
6473  }
6474 
6475  if (el_to_edge != NULL)
6476  {
6477  if (WantTwoLevelState)
6478  {
6479  c_el_to_edge = el_to_edge;
6480  mfem::Swap(be_to_edge, fc_be_to_edge); // save coarse be_to_edge
6481  f_el_to_edge = new Table;
6482  NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge);
6483  el_to_edge = f_el_to_edge;
6484  f_NumOfEdges = NumOfEdges;
6485  }
6486  else
6487  {
6488  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
6489  }
6490  GenerateFaces();
6491  }
6492 
6493  }
6494  else if (Dim == 3) // ---------------------------------------------------
6495  {
6496  if (WantTwoLevelState)
6497  {
6498  c_NumOfVertices = NumOfVertices;
6499  c_NumOfEdges = NumOfEdges;
6500  c_NumOfFaces = NumOfFaces;
6501  c_NumOfElements = NumOfElements;
6502  c_NumOfBdrElements = NumOfBdrElements;
6503  }
6504 
6505  // 1. Get table of vertex to vertex connections.
6506  DSTable v_to_v(NumOfVertices);
6507  GetVertexToVertexTable(v_to_v);
6508 
6509  // 2. Get edge to element connections in arrays edge1 and edge2
6510  nedges = v_to_v.NumberOfEntries();
6511  int *middle = new int[nedges];
6512 
6513  for (i = 0; i < nedges; i++)
6514  {
6515  middle[i] = -1;
6516  }
6517 
6518  // 3. Do the red refinement.
6519  int ii;
6520  switch (type)
6521  {
6522  case 1:
6523  for (i = 0; i < marked_el.Size(); i++)
6524  {
6525  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
6526  }
6527  break;
6528  case 2:
6529  for (i = 0; i < marked_el.Size(); i++)
6530  {
6531  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
6532 
6533  Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle);
6534  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
6535  }
6536  break;
6537  case 3:
6538  for (i = 0; i < marked_el.Size(); i++)
6539  {
6540  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
6541 
6542  ii = NumOfElements - 1;
6543  Bisection(ii, v_to_v, NULL, NULL, middle);
6544  Bisection(NumOfElements - 1, v_to_v, NULL, NULL, middle);
6545  Bisection(ii, v_to_v, NULL, NULL, middle);
6546 
6547  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
6548  Bisection(NumOfElements-1, v_to_v, NULL, NULL, middle);
6549  Bisection(marked_el[i], v_to_v, NULL, NULL, middle);
6550  }
6551  break;
6552  }
6553 
6554  if (WantTwoLevelState)
6555  {
6557  State = Mesh::TWO_LEVEL_FINE;
6558  }
6559 
6560  // 4. Do the green refinement (to get conforming mesh).
6561  int need_refinement;
6562  // int need_refinement, onoe, max_gen = 0;
6563  do
6564  {
6565  // int redges[2], type, flag;
6566  need_refinement = 0;
6567  // onoe = NumOfElements;
6568  // for (i = 0; i < onoe; i++)
6569  for (i = 0; i < NumOfElements; i++)
6570  {
6571  // ((Tetrahedron *)elements[i])->ParseRefinementFlag(redges, type, flag);
6572  // if (flag > max_gen) max_gen = flag;
6573  if (elements[i]->NeedRefinement(v_to_v, middle))
6574  {
6575  need_refinement = 1;
6576  Bisection(i, v_to_v, NULL, NULL, middle);
6577  }
6578  }
6579  }
6580  while (need_refinement == 1);
6581 
6582  // cout << "Maximum generation: " << max_gen << endl;
6583 
6584  // 5. Update the boundary elements.
6585  do
6586  {
6587  need_refinement = 0;
6588  for (i = 0; i < NumOfBdrElements; i++)
6589  if (boundary[i]->NeedRefinement(v_to_v, middle))
6590  {
6591  need_refinement = 1;
6592  Bisection(i, v_to_v, middle);
6593  }
6594  }
6595  while (need_refinement == 1);
6596 
6597  // 6. Un-mark the Pf elements.
6598  int refinement_edges[2], type, flag;
6599  for (i = 0; i < NumOfElements; i++)
6600  {
6601  Element *El = elements[i];
6602  while (El->GetType() == Element::BISECTED)
6603  {
6604  El = ((BisectedElement *) El)->FirstChild;
6605  }
6606  ((Tetrahedron *)El)->ParseRefinementFlag(refinement_edges, type,
6607  flag);
6608  if (type == Tetrahedron::TYPE_PF)
6609  ((Tetrahedron *)El)->CreateRefinementFlag(refinement_edges,
6611  flag);
6612  }
6613 
6614  NumOfBdrElements = boundary.Size();
6615 
6616  // 7. Free the allocated memory.
6617  delete [] middle;
6618 
6619  if (el_to_edge != NULL)
6620  {
6621  if (WantTwoLevelState)
6622  {
6623  c_el_to_edge = el_to_edge;
6624  f_el_to_edge = new Table;
6625  c_bel_to_edge = bel_to_edge;
6626  bel_to_edge = NULL;
6627  NumOfEdges = GetElementToEdgeTable(*f_el_to_edge, be_to_edge);
6628  el_to_edge = f_el_to_edge;
6629  f_bel_to_edge = bel_to_edge;
6630  }
6631  else
6632  {
6633  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
6634  }
6635  }
6636  if (el_to_face != NULL)
6637  {
6638  if (WantTwoLevelState)
6639  {
6640  c_el_to_face = el_to_face;
6641  el_to_face = NULL;
6642  mfem::Swap(faces_info, fc_faces_info);
6643  }
6644  GetElementToFaceTable();
6645  GenerateFaces();
6646  if (WantTwoLevelState)
6647  {
6648  f_el_to_face = el_to_face;
6649  }
6650  }
6651 
6652  if (WantTwoLevelState)
6653  {
6654  f_NumOfVertices = NumOfVertices;
6655  f_NumOfEdges = NumOfEdges;
6656  f_NumOfFaces = NumOfFaces;
6657  f_NumOfElements = NumOfElements;
6658  f_NumOfBdrElements = NumOfBdrElements;
6659  }
6660 
6661  } // end 'if (Dim == 3)'
6662 
6663  if (Nodes) // curved mesh
6664  {
6665  UpdateNodes();
6666  UseTwoLevelState(wtls);
6667  }
6668 
6669 #ifdef MFEM_DEBUG
6670  CheckElementOrientation(false);
6671 #endif
6672 }
6673 
6675  int nc_limit)
6676 {
6677  if (NURBSext)
6678  {
6679  MFEM_ABORT("Mesh::NonconformingRefinement: NURBS meshes are not supported."
6680  " Project the NURBS to Nodes first.");
6681  }
6682 
6683  int wtls = WantTwoLevelState;
6684 
6685  if (Nodes) // curved mesh
6686  {
6687  UseTwoLevelState(1);
6688  }
6689 
6690  SetState(Mesh::NORMAL);
6691  DeleteCoarseTables();
6692 
6693  if (!ncmesh)
6694  {
6695  // start tracking refinement hierarchy
6696  ncmesh = new NCMesh(this);
6697  }
6698 
6699  if (WantTwoLevelState)
6700  {
6701  ncmesh->MarkCoarseLevel();
6702  }
6703 
6704  // do the refinements
6705  ncmesh->Refine(refinements);
6706 
6707  if (nc_limit > 0)
6708  {
6709  ncmesh->LimitNCLevel(nc_limit);
6710  }
6711 
6712  // create a second mesh containing the finest elements from 'ncmesh'
6713  Mesh* mesh2 = new Mesh(*ncmesh);
6714 
6715  ncmesh->OnMeshUpdated(mesh2);
6716 
6717  // now swap the meshes, the second mesh will become the old coarse mesh
6718  // and this mesh will be the new fine mesh
6719  Swap(*mesh2, false);
6720 
6721  // retain the coarse mesh if two-level state was requested, delete otherwise
6722  if (WantTwoLevelState)
6723  {
6724  nc_coarse_level = mesh2;
6725  State = TWO_LEVEL_FINE;
6726  }
6727  else
6728  {
6729  delete mesh2;
6730  }
6731 
6732  GenerateNCFaceInfo();
6733 
6734  if (Nodes) // curved mesh
6735  {
6736  UpdateNodes();
6737  UseTwoLevelState(wtls);
6738  }
6739 }
6740 
6741 void Mesh::InitFromNCMesh(const NCMesh &ncmesh)
6742 {
6743  Dim = ncmesh.Dimension();
6744  spaceDim = ncmesh.SpaceDimension();
6745 
6746  DeleteTables();
6747 
6748  ncmesh.GetMeshComponents(vertices, elements, boundary);
6749 
6750  NumOfVertices = vertices.Size();
6751  NumOfElements = elements.Size();
6752  NumOfBdrElements = boundary.Size();
6753 
6754  SetMeshGen(); // set the mesh type ('meshgen')
6755 
6756  NumOfEdges = NumOfFaces = 0;
6757  if (Dim > 1)
6758  {
6759  el_to_edge = new Table;
6760  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
6761  c_el_to_edge = NULL;
6762  }
6763  if (Dim > 2)
6764  {
6765  GetElementToFaceTable();
6766  }
6767  GenerateFaces();
6768 #ifdef MFEM_DEBUG
6769  CheckBdrElementOrientation(false);
6770 #endif
6771  // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
6772  // outside after this method.
6773 }
6774 
6775 Mesh::Mesh(const NCMesh &ncmesh)
6776 {
6777  Init();
6778  InitTables();
6779  InitFromNCMesh(ncmesh);
6780  SetAttributes();
6781 }
6782 
6783 void Mesh::Swap(Mesh& other, bool non_geometry)
6784 {
6785  mfem::Swap(Dim, other.Dim);
6786  mfem::Swap(spaceDim, other.spaceDim);
6787 
6788  mfem::Swap(NumOfVertices, other.NumOfVertices);
6789  mfem::Swap(NumOfElements, other.NumOfElements);
6790  mfem::Swap(NumOfBdrElements, other.NumOfBdrElements);
6791  mfem::Swap(NumOfEdges, other.NumOfEdges);
6792  mfem::Swap(NumOfFaces, other.NumOfFaces);
6793 
6794  mfem::Swap(meshgen, other.meshgen);
6795 
6796  mfem::Swap(elements, other.elements);
6797  mfem::Swap(vertices, other.vertices);
6798  mfem::Swap(boundary, other.boundary);
6799  mfem::Swap(faces, other.faces);
6800  mfem::Swap(faces_info, other.faces_info);
6801  mfem::Swap(nc_faces_info, other.nc_faces_info);
6802 
6803  mfem::Swap(el_to_edge, other.el_to_edge);
6804  mfem::Swap(el_to_face, other.el_to_face);
6805  mfem::Swap(el_to_el, other.el_to_el);
6806  mfem::Swap(be_to_edge, other.be_to_edge);
6807  mfem::Swap(bel_to_edge, other.bel_to_edge);
6808  mfem::Swap(be_to_face, other.be_to_face);
6809  mfem::Swap(face_edge, other.face_edge);
6810  mfem::Swap(edge_vertex, other.edge_vertex);
6811 
6812  mfem::Swap(attributes, other.attributes);
6813  mfem::Swap(bdr_attributes, other.bdr_attributes);
6814 
6815  if (non_geometry)
6816  {
6817  mfem::Swap(NURBSext, other.NURBSext);
6818  mfem::Swap(ncmesh, other.ncmesh);
6819 
6820  mfem::Swap(Nodes, other.Nodes);
6821  mfem::Swap(own_nodes, other.own_nodes);
6822  }
6823 
6824  // NOTE: two-level-state related members are ignored here
6825 }
6826 
6828 {
6829  if (NURBSext)
6830  {
6831  NURBSUniformRefinement();
6832  }
6833  else if (meshgen == 1 || ncmesh)
6834  {
6835  Array<int> elem_to_refine(GetNE());
6836  for (int i = 0; i < elem_to_refine.Size(); i++)
6837  {
6838  elem_to_refine[i] = i;
6839  }
6840 
6841  if (!ncmesh)
6842  {
6843  LocalRefinement(elem_to_refine);
6844  }
6845  else
6846  {
6847  GeneralRefinement(elem_to_refine, 1);
6848  }
6849  }
6850  else if (Dim == 2)
6851  {
6852  QuadUniformRefinement();
6853  }
6854  else if (Dim == 3)
6855  {
6856  HexUniformRefinement();
6857  }
6858  else
6859  {
6860  mfem_error("Mesh::UniformRefinement()");
6861  }
6862 }
6863 
6865  int nonconforming, int nc_limit)
6866 {
6867  if (Dim == 1)
6868  {
6869  nonconforming = 0;
6870  }
6871  else if (nonconforming < 0)
6872  {
6873  // determine if nonconforming refinement is suitable
6874  int type = elements[0]->GetType();
6875  if (type == Element::HEXAHEDRON || type == Element::QUADRILATERAL)
6876  {
6877  nonconforming = 1;
6878  }
6879  else
6880  {
6881  nonconforming = 0;
6882  }
6883  }
6884 
6885  if (nonconforming || ncmesh != NULL)
6886  {
6887  // non-conforming refinement (hanging nodes)
6888  NonconformingRefinement(refinements, nc_limit);
6889  }
6890  else
6891  {
6892  Array<int> el_to_refine;
6893  for (int i = 0; i < refinements.Size(); i++)
6894  {
6895  el_to_refine.Append(refinements[i].index);
6896  }
6897 
6898  // infer 'type' of local refinement from first element's 'ref_type'
6899  int type, rt = (refinements.Size() ? refinements[0].ref_type : 7);
6900  if (rt == 1 || rt == 2 || rt == 4)
6901  {
6902  type = 1;
6903  }
6904  else if (rt == 3 || rt == 5 || rt == 6)
6905  {
6906  type = 2;
6907  }
6908  else
6909  {
6910  type = 3;
6911  }
6912 
6913  // red-green refinement, no hanging nodes
6914  LocalRefinement(el_to_refine, type);
6915  }
6916 }
6917 
6918 void Mesh::GeneralRefinement(const Array<int> &el_to_refine, int nonconforming,
6919  int nc_limit)
6920 {
6921  Array<Refinement> refinements;
6922  for (int i = 0; i < el_to_refine.Size(); i++)
6923  {
6924  refinements.Append(Refinement(el_to_refine[i], 7));
6925  }
6926  GeneralRefinement(refinements, nonconforming, nc_limit);
6927 }
6928 
6930 {
6931  if (meshgen & 2)
6932  {
6933  Array<int> empty;
6934  GeneralRefinement(empty, 1);
6935  }
6936 }
6937 
6938 void Mesh::RandomRefinement(int levels, int frac, bool aniso,
6939  int nonconforming, int nc_limit, int seed)
6940 {
6941  srand(seed);
6942  for (int i = 0; i < levels; i++)
6943  {
6944  Array<Refinement> refs;
6945  for (int j = 0; j < GetNE(); j++)
6946  {
6947  if (!(rand() % frac))
6948  {
6949  int type = 7;
6950  if (aniso)
6951  {
6952  type = (Dim == 3) ? (rand() % 7 + 1) : (rand() % 3 + 1);
6953  }
6954  refs.Append(Refinement(j, type));
6955  }
6956  }
6957  GeneralRefinement(refs, nonconforming, nc_limit);
6958  }
6959 }
6960 
6961 void Mesh::RefineAtVertex(const Vertex& vert, int levels, double eps,
6962  int nonconforming)
6963 {
6964  Array<int> v;
6965  for (int k = 0; k < levels; k++)
6966  {
6967  Array<Refinement> refs;
6968  for (int i = 0; i < GetNE(); i++)
6969  {
6970  GetElementVertices(i, v);
6971  bool refine = false;
6972  for (int j = 0; j < v.Size(); j++)
6973  {
6974  double dist = 0.0;
6975  for (int l = 0; l < spaceDim; l++)
6976  {
6977  double d = vert(l) - vertices[v[j]](l);
6978  dist += d*d;
6979  }
6980  if (dist <= eps*eps) { refine = true; break; }
6981  }
6982  if (refine)
6983  {
6984  refs.Append(Refinement(i));
6985  }
6986  }
6987  GeneralRefinement(refs, nonconforming);
6988  }
6989 }
6990 
6991 void Mesh::Bisection(int i, const DSTable &v_to_v,
6992  int *edge1, int *edge2, int *middle)
6993 {
6994  int *vert;
6995  int v[2][4], v_new, bisect, t;
6996  Element **pce = &elements[i];
6997  Vertex V;
6998 
6999  t = pce[0]->GetType();
7000  if (WantTwoLevelState)
7001  {
7002  while (1)
7003  {
7004  if (t == Element::BISECTED)
7005  {
7006  pce = & ( ((BisectedElement *) pce[0])->FirstChild );
7007  }
7008  else if (t == Element::QUADRISECTED)
7009  {
7010  pce = & ( ((QuadrisectedElement *) pce[0])->FirstChild );
7011  }
7012  else
7013  {
7014  break;
7015  }
7016  t = pce[0]->GetType();
7017  }
7018  }
7019 
7020  if (t == Element::TRIANGLE)
7021  {
7022  Triangle *tri = (Triangle *) pce[0];
7023 
7024  vert = tri->GetVertices();
7025 
7026  // 1. Get the index for the new vertex in v_new.
7027  bisect = v_to_v(vert[0], vert[1]);
7028 #ifdef MFEM_DEBUG
7029  if (bisect < 0)
7030  {
7031  mfem_error("Mesh::Bisection(...) of triangle! #1");
7032  }
7033 #endif
7034  if (middle[bisect] == -1)
7035  {
7036  v_new = NumOfVertices++;
7037  for (int d = 0; d < spaceDim; d++)
7038  {
7039  V(d) = 0.5 * (vertices[vert[0]](d) + vertices[vert[1]](d));
7040  }
7041  vertices.Append(V);
7042 
7043  // Put the element that may need refinement (because of this
7044  // bisection) in edge1, or -1 if no more refinement is needed.
7045  if (edge1[bisect] == i)
7046  {
7047  edge1[bisect] = edge2[bisect];
7048  }
7049 
7050  middle[bisect] = v_new;
7051  }
7052  else
7053  {
7054  v_new = middle[bisect];
7055 
7056  // This edge will require no more refinement.
7057  edge1[bisect] = -1;
7058  }
7059 
7060  // 2. Set the node indices for the new elements in v[0] and v[1] so that
7061  // the edge marked for refinement is between the first two nodes.
7062  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
7063  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
7064 
7065  if (WantTwoLevelState)
7066  {
7067 #ifdef MFEM_USE_MEMALLOC
7068  BisectedElement *aux = BEMemory.Alloc();
7069  aux->SetCoarseElem(tri);
7070 #else
7071  BisectedElement *aux = new BisectedElement(tri);
7072 #endif
7073  aux->FirstChild = tri = new Triangle(v[0], tri->GetAttribute());
7074  aux->SecondChild = NumOfElements;
7075  pce[0] = aux;
7076  }
7077  else
7078  {
7079  tri->SetVertices(v[0]); // changes vert[0..2] !!!
7080  }
7081  elements.Append(new Triangle(v[1], tri->GetAttribute()));
7082 
7083  // 3. edge1 and edge2 may have to be changed for the second triangle.
7084  if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
7085  {
7086  bisect = v_to_v(v[1][0], v[1][1]);
7087 #ifdef MFEM_DEBUG
7088  if (bisect < 0)
7089  {
7090  mfem_error("Mesh::Bisection(...) of triangle! #2");
7091  }
7092 #endif
7093  if (edge1[bisect] == i)
7094  {
7095  edge1[bisect] = NumOfElements;
7096  }
7097  else if (edge2[bisect] == i)
7098  {
7099  edge2[bisect] = NumOfElements;
7100  }
7101  }
7102  NumOfElements++;
7103  }
7104  else if (t == Element::TETRAHEDRON)
7105  {
7106  int j, type, new_type, old_redges[2], new_redges[2][2], flag;
7107  Tetrahedron *tet = (Tetrahedron *) pce[0];
7108 
7109  if (tet->GetRefinementFlag() == 0)
7110  mfem_error("Mesh::Bisection : TETRAHEDRON element is not marked for "
7111  "refinement.");
7112 
7113  vert = tet->GetVertices();
7114 
7115  // 1. Get the index for the new vertex in v_new.
7116  bisect = v_to_v(vert[0], vert[1]);
7117  if (bisect == -1)
7118  {
7119  tet->ParseRefinementFlag(old_redges, type, flag);
7120  cerr << "Error in Bisection(...) of tetrahedron!" << endl
7121  << " redge[0] = " << old_redges[0]
7122  << " redge[1] = " << old_redges[1]
7123  << " type = " << type
7124  << " flag = " << flag << endl;
7125  mfem_error();
7126  }
7127 
7128  if (middle[bisect] == -1)
7129  {
7130  v_new = NumOfVertices++;
7131  for (j = 0; j < 3; j++)
7132  {
7133  V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j));
7134  }
7135  vertices.Append(V);
7136 
7137  middle[bisect] = v_new;
7138  }
7139  else
7140  {
7141  v_new = middle[bisect];
7142  }
7143 
7144  // 2. Set the node indices for the new elements in v[2][4] so that
7145  // the edge marked for refinement is between the first two nodes.
7146  tet->ParseRefinementFlag(old_redges, type, flag);
7147 
7148  v[0][3] = v_new;
7149  v[1][3] = v_new;
7150  new_redges[0][0] = 2;
7151  new_redges[0][1] = 1;
7152  new_redges[1][0] = 2;
7153  new_redges[1][1] = 1;
7154  switch (old_redges[0])
7155  {
7156  case 2:
7157  v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3];
7158  if (type == Tetrahedron::TYPE_PF) { new_redges[0][1] = 4; }
7159  break;
7160  case 3:
7161  v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2];
7162  break;
7163  case 5:
7164  v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0];
7165  }
7166  switch (old_redges[1])
7167  {
7168  case 1:
7169  v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3];
7170  if (type == Tetrahedron::TYPE_PF) { new_redges[1][0] = 3; }
7171  break;
7172  case 4:
7173  v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2];
7174  break;
7175  case 5:
7176  v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1];
7177  }
7178 
7179  int attr = tet->GetAttribute();
7180  if (WantTwoLevelState)
7181  {
7182 #ifdef MFEM_USE_MEMALLOC
7183  BisectedElement *aux = BEMemory.Alloc();
7184  aux->SetCoarseElem(tet);
7185  tet = TetMemory.Alloc();
7186  tet->SetVertices(v[0]);
7187  tet->SetAttribute(attr);
7188 #else