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
7189  BisectedElement *aux = new BisectedElement(tet);
7190  tet = new Tetrahedron(v[0], attr);
7191 #endif
7192  aux->FirstChild = tet;
7193  aux->SecondChild = NumOfElements;
7194  pce[0] = aux;
7195  // 'tet' now points to the first child
7196  }
7197  else
7198  {
7199  tet->SetVertices(v[0]);
7200  }
7201 
7202  {
7203 #ifdef MFEM_USE_MEMALLOC
7204  Tetrahedron *tet2 = TetMemory.Alloc();
7205  tet2->SetVertices(v[1]);
7206  tet2->SetAttribute(attr);
7207  elements.Append(tet2);
7208 #else
7209  elements.Append(new Tetrahedron(v[1], attr));
7210 #endif
7211  }
7212 
7213  // 3. Set the bisection flag
7214  switch (type)
7215  {
7216  case Tetrahedron::TYPE_PU:
7217  new_type = Tetrahedron::TYPE_PF; break;
7218  case Tetrahedron::TYPE_PF:
7219  new_type = Tetrahedron::TYPE_A; break;
7220  default:
7221  new_type = Tetrahedron::TYPE_PU;
7222  }
7223 
7224  tet->CreateRefinementFlag(new_redges[0], new_type, flag+1);
7225  ((Tetrahedron *)elements[NumOfElements])->
7226  CreateRefinementFlag(new_redges[1], new_type, flag+1);
7227 
7228  NumOfElements++;
7229  }
7230  else
7231  {
7232  mfem_error("Bisection for now works only for triangles & tetrahedra.");
7233  }
7234 }
7235 
7236 void Mesh::Bisection(int i, const DSTable &v_to_v, int *middle)
7237 {
7238  int *vert;
7239  int v[2][3], v_new, bisect, t;
7240  Element **pce = &boundary[i];
7241 
7242  t = pce[0]->GetType();
7243  if (WantTwoLevelState)
7244  {
7245  while (1)
7246  {
7247  if (t == Element::BISECTED)
7248  {
7249  pce = & ( ((BisectedElement *) pce[0])->FirstChild );
7250  }
7251  else if (t == Element::QUADRISECTED)
7252  {
7253  pce = & ( ((QuadrisectedElement *) pce[0])->FirstChild );
7254  }
7255  else
7256  {
7257  break;
7258  }
7259  t = pce[0]->GetType();
7260  }
7261  }
7262 
7263  if (t == Element::TRIANGLE)
7264  {
7265  Triangle *tri = (Triangle *) pce[0];
7266 
7267  vert = tri->GetVertices();
7268 
7269  // 1. Get the index for the new vertex in v_new.
7270  bisect = v_to_v(vert[0], vert[1]);
7271 #ifdef MFEM_DEBUG
7272  if (bisect < 0)
7273  {
7274  mfem_error("Mesh::Bisection(...) of boundary triangle! #1");
7275  }
7276 #endif
7277  v_new = middle[bisect];
7278 #ifdef MFEM_DEBUG
7279  if (v_new == -1)
7280  {
7281  mfem_error("Mesh::Bisection(...) of boundary triangle! #2");
7282  }
7283 #endif
7284 
7285  // 2. Set the node indices for the new elements in v[0] and v[1] so that
7286  // the edge marked for refinement is between the first two nodes.
7287  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
7288  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
7289  if (WantTwoLevelState)
7290  {
7291 #ifdef MFEM_USE_MEMALLOC
7292  BisectedElement *aux = BEMemory.Alloc();
7293  aux->SetCoarseElem(tri);
7294 #else
7295  BisectedElement *aux = new BisectedElement(tri);
7296 #endif
7297  aux->FirstChild = tri = new Triangle(v[0], tri->GetAttribute());
7298  aux->SecondChild = NumOfBdrElements;
7299  pce[0] = aux;
7300  // 'tri' now points to the first child
7301  }
7302  else
7303  {
7304  tri->SetVertices(v[0]);
7305  }
7306  boundary.Append(new Triangle(v[1], tri->GetAttribute()));
7307 
7308  NumOfBdrElements++;
7309  }
7310  else
7311  {
7312  mfem_error("Bisection of boundary elements works only for triangles!");
7313  }
7314 }
7315 
7316 void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
7317  int *edge1, int *edge2, int *middle)
7318 {
7319  Array<int> v;
7320  int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3];
7321  Vertex V;
7322 
7323  if (elements[i]->GetType() == Element::TRIANGLE)
7324  {
7325  elements[i]->GetVertices(v);
7326 
7327  // 1. Get the indeces for the new vertices in array v_new
7328  bisect[0] = v_to_v(v[0],v[1]);
7329  bisect[1] = v_to_v(v[1],v[2]);
7330  bisect[2] = v_to_v(v[0],v[2]);
7331 #ifdef MFEM_DEBUG
7332  if (bisect[0] < 0 || bisect[1] < 0 || bisect[2] < 0)
7333  {
7334  mfem_error("Mesh::UniformRefinement(...): ERROR");
7335  }
7336 #endif
7337 
7338  for (j = 0; j < 3; j++) // for the 3 edges fix v_new
7339  if (middle[bisect[j]] == -1)
7340  {
7341  v_new[j] = NumOfVertices++;
7342  for (int d = 0; d < spaceDim; d++)
7343  {
7344  V(d) = (vertices[v[j]](d) + vertices[v[(j+1)%3]](d))/2.;
7345  }
7346  vertices.Append(V);
7347 
7348  // Put the element that may need refinement (because of this
7349  // bisection) in edge1, or -1 if no more refinement is needed.
7350  if (edge1[bisect[j]] == i)
7351  {
7352  edge1[bisect[j]] = edge2[bisect[j]];
7353  }
7354 
7355  middle[bisect[j]] = v_new[j];
7356  }
7357  else
7358  {
7359  v_new[j] = middle[bisect[j]];
7360 
7361  // This edge will require no more refinement.
7362  edge1[bisect[j]] = -1;
7363  }
7364 
7365  // 2. Set the node indeces for the new elements in v1, v2, v3 & v4 so that
7366  // the edges marked for refinement be between the first two nodes.
7367  v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2];
7368  v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1];
7369  v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2];
7370  v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0];
7371 
7372  elements.Append(new Triangle(v1, elements[i]->GetAttribute()));
7373  elements.Append(new Triangle(v2, elements[i]->GetAttribute()));
7374  elements.Append(new Triangle(v3, elements[i]->GetAttribute()));
7375  if (WantTwoLevelState)
7376  {
7377  QuadrisectedElement *aux = new QuadrisectedElement(elements[i]);
7378  aux->FirstChild = new Triangle(v4, elements[i]->GetAttribute());
7379  aux->Child2 = NumOfElements;
7380  aux->Child3 = NumOfElements+1;
7381  aux->Child4 = NumOfElements+2;
7382  elements[i] = aux;
7383  }
7384  else
7385  {
7386  elements[i]->SetVertices(v4);
7387  }
7388 
7389  NumOfElements += 3;
7390  }
7391  else
7392  {
7393  mfem_error("Uniform refinement for now works only for triangles.");
7394  }
7395 }
7396 
7397 void Mesh::SetState(int s)
7398 {
7399  if (ncmesh)
7400  {
7401  if (State != Mesh::NORMAL && s == Mesh::NORMAL)
7402  {
7403  delete nc_coarse_level;
7404  nc_coarse_level = NULL;
7405  ncmesh->ClearCoarseLevel();
7406  State = s;
7407  }
7408  else if ((State == Mesh::TWO_LEVEL_COARSE && s == Mesh::TWO_LEVEL_FINE) ||
7409  (State == Mesh::TWO_LEVEL_FINE && s == Mesh::TWO_LEVEL_COARSE))
7410  {
7411  this->Swap(*nc_coarse_level, false);
7412  State = s;
7413  }
7414  else if (State != s)
7415  {
7416  mfem_error("Oops! Mesh::SetState");
7417  }
7418  }
7419  else
7420  {
7421  if (State != Mesh::NORMAL && s == Mesh::NORMAL)
7422  {
7423  // two level state --->> normal state
7424  int i, t;
7425 
7426  for (i = 0; i < f_NumOfElements; )
7427  {
7428  t = elements[i]->GetType();
7429  if (t == Element::BISECTED ||
7430  t == Element::QUADRISECTED ||
7431  t == Element::OCTASECTED)
7432  {
7433  RefinedElement *aux = (RefinedElement *) elements[i];
7434  elements[i] = aux->FirstChild;
7435  FreeElement(aux->CoarseElem);
7436  FreeElement(aux);
7437  }
7438  else
7439  {
7440  i++;
7441  }
7442  }
7443 
7444  for (i = 0; i < f_NumOfBdrElements; )
7445  {
7446  t = boundary[i]->GetType();
7447  if (t == Element::BISECTED ||
7448  t == Element::QUADRISECTED ||
7449  t == Element::OCTASECTED)
7450  {
7451  RefinedElement *aux = (RefinedElement *) boundary[i];
7452  boundary[i] = aux->FirstChild;
7453  FreeElement(aux->CoarseElem);
7454  FreeElement(aux);
7455  }
7456  else
7457  {
7458  i++;
7459  }
7460  }
7461 
7462  if (el_to_edge != NULL)
7463  {
7464  delete c_el_to_edge;
7465  el_to_edge = f_el_to_edge;
7466  if (Dim == 2)
7467  {
7468  if (State == Mesh::TWO_LEVEL_COARSE)
7469  {
7470  mfem::Swap(be_to_edge, fc_be_to_edge);
7471  }
7472  fc_be_to_edge.DeleteAll();
7473  }
7474  if (Dim == 3)
7475  {
7476  delete c_bel_to_edge;
7477  bel_to_edge = f_bel_to_edge;
7478  }
7479  }
7480  if (el_to_face != NULL)
7481  {
7482  delete c_el_to_face;
7483  el_to_face = f_el_to_face;
7484  if (State == Mesh::TWO_LEVEL_COARSE)
7485  {
7486  mfem::Swap(faces_info, fc_faces_info);
7487  }
7488  fc_faces_info.DeleteAll();
7489  }
7490 
7491  NumOfVertices = f_NumOfVertices;
7492  NumOfEdges = f_NumOfEdges;
7493  if (Dim == 3)
7494  {
7495  NumOfFaces = f_NumOfFaces;
7496  }
7497  NumOfElements = f_NumOfElements;
7498  NumOfBdrElements = f_NumOfBdrElements;
7500  State = s;
7501  }
7502  else if (State == Mesh::TWO_LEVEL_COARSE && s == Mesh::TWO_LEVEL_FINE)
7503  {
7504  if (el_to_edge != NULL)
7505  {
7506  el_to_edge = f_el_to_edge;
7507  if (Dim == 2)
7508  {
7509  mfem::Swap(be_to_edge, fc_be_to_edge);
7510  }
7511  if (Dim == 3)
7512  {
7513  bel_to_edge = f_bel_to_edge;
7514  }
7515  }
7516  if (el_to_face != NULL)
7517  {
7518  el_to_face = f_el_to_face;
7519  mfem::Swap(faces_info, fc_faces_info);
7520  }
7521  NumOfVertices = f_NumOfVertices;
7522  NumOfEdges = f_NumOfEdges;
7523  if (Dim == 3)
7524  {
7525  NumOfFaces = f_NumOfFaces;
7526  }
7527  NumOfElements = f_NumOfElements;
7528  NumOfBdrElements = f_NumOfBdrElements;
7530  State = s;
7531  }
7532  else if (State == Mesh::TWO_LEVEL_FINE && s == Mesh::TWO_LEVEL_COARSE)
7533  {
7534  if (el_to_edge != NULL)
7535  {
7536  el_to_edge = c_el_to_edge;
7537  if (Dim == 2)
7538  {
7539  mfem::Swap(be_to_edge, fc_be_to_edge);
7540  }
7541  if (Dim == 3)
7542  {
7543  bel_to_edge = c_bel_to_edge;
7544  }
7545  }
7546  if (el_to_face != NULL)
7547  {
7548  el_to_face = c_el_to_face;
7549  mfem::Swap(faces_info, fc_faces_info);
7550  }
7551  NumOfVertices = c_NumOfVertices;
7552  NumOfEdges = c_NumOfEdges;
7553  if (Dim == 3)
7554  {
7555  NumOfFaces = c_NumOfFaces;
7556  }
7557  NumOfElements = c_NumOfElements;
7558  NumOfBdrElements = c_NumOfBdrElements;
7560  State = s;
7561  }
7562  else if (State != s)
7563  {
7564  mfem_error("Oops! Mesh::SetState");
7565  }
7566  }
7567 }
7568 
7570 {
7571  int t = elements[i]->GetType();
7572 
7573  if (Dim == 1)
7574  {
7575  if (t == Element::BISECTED)
7576  {
7577  return 2;
7578  }
7579  }
7580  else if (Dim == 2)
7581  {
7582  if (t == Element::QUADRISECTED)
7583  {
7584  return 4;
7585  }
7586  else if (t == Element::BISECTED)
7587  {
7588  // assuming that the elements are either BisectedElements or
7589  // regular elements
7590  int n = 1;
7591  BisectedElement *aux = (BisectedElement *) elements[i];
7592  do
7593  {
7594  n += GetNumFineElems(aux->SecondChild);
7595  if (aux->FirstChild->GetType() != Element::BISECTED)
7596  {
7597  break;
7598  }
7599  aux = (BisectedElement *) (aux->FirstChild);
7600  }
7601  while (1);
7602  return n;
7603  }
7604  }
7605  else if (Dim == 3)
7606  {
7607  // assuming that the element is a BisectedElement,
7608  // OctasectedElement (with children that are regular elements) or
7609  // regular element
7610  if (t == Element::BISECTED)
7611  {
7612  int n = 1;
7613  BisectedElement *aux = (BisectedElement *) elements[i];
7614  do
7615  {
7616  n += GetNumFineElems (aux->SecondChild);
7617  if (aux->FirstChild->GetType() != Element::BISECTED)
7618  {
7619  break;
7620  }
7621  aux = (BisectedElement *) (aux->FirstChild);
7622  }
7623  while (1);
7624  return n;
7625  }
7626  else if (t == Element::OCTASECTED)
7627  {
7628  return 8;
7629  }
7630  return 1; // regular element (i.e. it is not refined)
7631  }
7632 
7633  return 1; // the element is not refined
7634 }
7635 
7637 {
7638  if (E->GetType() == Element::BISECTED)
7639  {
7640  int L, R, n, s, lb, rb;
7641 
7642  L = GetBisectionHierarchy(((BisectedElement *)E)->FirstChild);
7643  n = ((BisectedElement *)E)->SecondChild;
7644  R = GetBisectionHierarchy(elements[n]);
7645  n = 1; s = 1;
7646  lb = rb = 1;
7647  do
7648  {
7649  int nlb, nrb;
7650  nlb = nrb = 0;
7651  while (lb > 0)
7652  {
7653  n |= ((L & 1) << s);
7654  s++;
7655  nlb += (L & 1);
7656  L = (L >> 1);
7657  lb--;
7658  }
7659  while (rb > 0)
7660  {
7661  n |= ((R & 1) << s);
7662  s++;
7663  nrb += (R & 1);
7664  R = (R >> 1);
7665  rb--;
7666  }
7667  lb = 2 * nlb; rb = 2 * nrb;
7668  }
7669  while (lb > 0 || rb > 0);
7670  return n;
7671  }
7672  return 0;
7673 }
7674 
7676 {
7677  int t;
7678 
7679  if (Dim == 1)
7680  {
7681  if (elements[i]->GetType() == Element::BISECTED)
7682  {
7683  return 1; // refinement type for bisected SEGMENT
7684  }
7685  }
7686  else if (Dim == 2)
7687  {
7688  t = elements[i]->GetType();
7689  if (t == Element::QUADRISECTED)
7690  {
7691  t = ((QuadrisectedElement *)elements[i])->CoarseElem->GetType();
7692  if (t == Element::QUADRILATERAL)
7693  {
7694  return 1; // refinement type for quadrisected QUADRILATERAL
7695  }
7696  else
7697  {
7698  return 2; // refinement type for quadrisected TRIANGLE
7699  }
7700  }
7701  else if (t == Element::BISECTED)
7702  {
7703  int type;
7704  type = GetBisectionHierarchy(elements[i]);
7705  if (type == 0)
7706  {
7707  mfem_error("Mesh::GetRefinementType(...)");
7708  }
7709  return type+2;
7710  }
7711  }
7712  else if (Dim == 3)
7713  {
7714  int redges[2], type, flag;
7715  Element *E = elements[i];
7716  Tetrahedron *tet;
7717 
7718  t = E->GetType();
7719  if (t != Element::BISECTED)
7720  {
7721  if (t == Element::OCTASECTED)
7722  {
7723  return 1; // refinement type for octasected CUBE
7724  }
7725  else
7726  {
7727  return 0;
7728  }
7729  }
7730  // Bisected TETRAHEDRON
7731  tet = (Tetrahedron *) (((BisectedElement *) E)->CoarseElem);
7732  tet->ParseRefinementFlag(redges, type, flag);
7733  if (type == Tetrahedron::TYPE_A && redges[0] == 2)
7734  {
7735  type = 5;
7736  }
7737  else if (type == Tetrahedron::TYPE_M && redges[0] == 2)
7738  {
7739  type = 6;
7740  }
7741  type++;
7742  type |= ( GetBisectionHierarchy(E) << 3 );
7743  if (type < 8) { type = 0; }
7744 
7745  return type;
7746  }
7747 
7748  return 0; // no refinement
7749 }
7750 
7751 int Mesh::GetFineElem(int i, int j)
7752 {
7753  int t = elements[i]->GetType();
7754 
7755  if (Dim == 1)
7756  {
7757  if (t == Element::BISECTED)
7758  {
7759  switch (j)
7760  {
7761  case 0: return i;
7762  default: return ((BisectedElement *)elements[i])->SecondChild;
7763  }
7764  }
7765  }
7766  else if (Dim == 2)
7767  {
7768  if (t == Element::QUADRISECTED)
7769  {
7770  QuadrisectedElement *aux = (QuadrisectedElement *) elements[i];
7771  if (aux->CoarseElem->GetType() == Element::QUADRILATERAL)
7772  switch (j)
7773  {
7774  case 0: return i;
7775  case 1: return aux->Child2;
7776  case 2: return aux->Child3;
7777  case 3: return aux->Child4;
7778  default: mfem_error("Mesh::GetFineElem #1");
7779  }
7780  else // quadrisected TRIANGLE
7781  switch (j)
7782  {
7783  case 0: return aux->Child2;
7784  case 1: return aux->Child3;
7785  case 2: return aux->Child4;
7786  case 3: return i;
7787  default: mfem_error("Mesh::GetFineElem #2");
7788  }
7789  }
7790  else if (t == Element::BISECTED)
7791  {
7792  int n = 0;
7793  BisectedElement *aux = (BisectedElement *) elements[i];
7794  do
7795  {
7796  int k = GetFineElem(aux->SecondChild, j-n);
7797  if (k >= 0)
7798  {
7799  return k;
7800  }
7801  n -= k; // (-k) is the number of the leaves in this SecondChild
7802  // n is the number of the leaves in
7803  // the SecondChild-ren so far
7804  if (aux->FirstChild->GetType() != Element::BISECTED)
7805  {
7806  break;
7807  }
7808  aux = (BisectedElement *) (aux->FirstChild);
7809  }
7810  while (1);
7811  if (j > n) // i.e. if (j >= n+1)
7812  {
7813  return -(n+1);
7814  }
7815  return i; // j == n, i.e. j is the index of the last leaf
7816  }
7817  }
7818  else if (Dim == 3)
7819  {
7820  if (t == Element::BISECTED)
7821  {
7822  int n = 0;
7823  BisectedElement *aux = (BisectedElement *) elements[i];
7824  do
7825  {
7826  int k = GetFineElem(aux->SecondChild, j-n);
7827  if (k >= 0)
7828  {
7829  return k;
7830  }
7831  n -= k; // (-k) is the number of the leaves in this SecondChild
7832  // n is the number of the leaves in
7833  // the SecondChild-ren so far
7834  if (aux->FirstChild->GetType() != Element::BISECTED)
7835  {
7836  break;
7837  }
7838  aux = (BisectedElement *) (aux->FirstChild);
7839  }
7840  while (1);
7841  if (j > n) // i.e. if (j >= n+1)
7842  {
7843  return -(n+1);
7844  }
7845  return i; // j == n, i.e. j is the index of the last leaf
7846  }
7847  else if (t == Element::OCTASECTED)
7848  {
7849  if (j == 0) { return i; }
7850  return ((OctasectedElement *) elements[i])->Child[j-1];
7851  }
7852  }
7853 
7854  if (j > 0)
7855  {
7856  return -1;
7857  }
7858 
7859  return i; // no refinement
7860 }
7861 
7862 void Mesh::BisectTriTrans(DenseMatrix &pointmat, Triangle *tri, int child)
7863 {
7864  double np[2];
7865 
7866  if (child == 0) // left triangle
7867  {
7868  // Set the new coordinates of the vertices
7869  np[0] = 0.5 * ( pointmat(0,0) + pointmat(0,1) );
7870  np[1] = 0.5 * ( pointmat(1,0) + pointmat(1,1) );
7871  pointmat(0,1) = pointmat(0,0); pointmat(1,1) = pointmat(1,0);
7872  pointmat(0,0) = pointmat(0,2); pointmat(1,0) = pointmat(1,2);
7873  pointmat(0,2) = np[0]; pointmat(1,2) = np[1];
7874  }
7875  else // right triangle
7876  {
7877  // Set the new coordinates of the vertices
7878  np[0] = 0.5 * ( pointmat(0,0) + pointmat(0,1) );
7879  np[1] = 0.5 * ( pointmat(1,0) + pointmat(1,1) );
7880  pointmat(0,0) = pointmat(0,1); pointmat(1,0) = pointmat(1,1);
7881  pointmat(0,1) = pointmat(0,2); pointmat(1,1) = pointmat(1,2);
7882  pointmat(0,2) = np[0]; pointmat(1,2) = np[1];
7883  }
7884 }
7885 
7886 void Mesh::BisectTetTrans(DenseMatrix &pointmat, Tetrahedron *tet, int child)
7887 {
7888  int i, j, redges[2], type, flag, ind[4];
7889  double t[4];
7890 
7891  tet->ParseRefinementFlag(redges, type, flag);
7892 
7893  if (child == 0) // left tetrahedron
7894  {
7895  // Set the new coordinates of the vertices
7896  pointmat(0,1) = 0.5 * ( pointmat(0,0) + pointmat(0,1) );
7897  pointmat(1,1) = 0.5 * ( pointmat(1,0) + pointmat(1,1) );
7898  pointmat(2,1) = 0.5 * ( pointmat(2,0) + pointmat(2,1) );
7899  // Permute the vertices according to the type & redges
7900  switch (redges[0])
7901  {
7902  case 2: ind[0] = 0; ind[1] = 3; ind[2] = 1; ind[3] = 2; break;
7903  case 3: ind[0] = 1; ind[1] = 3; ind[2] = 2; ind[3] = 0; break;
7904  case 5:
7905  default: ind[0] = 2; ind[1] = 3; ind[2] = 0; ind[3] = 1;
7906  }
7907  }
7908  else // right tetrahedron
7909  {
7910  // Set the new coordinates of the vertices
7911  pointmat(0,0) = 0.5 * ( pointmat(0,0) + pointmat(0,1) );
7912  pointmat(1,0) = 0.5 * ( pointmat(1,0) + pointmat(1,1) );
7913  pointmat(2,0) = 0.5 * ( pointmat(2,0) + pointmat(2,1) );
7914  // Permute the vertices according to the type & redges
7915  switch (redges[1])
7916  {
7917  case 1: ind[0] = 3; ind[1] = 1; ind[2] = 0; ind[3] = 2; break;
7918  case 4: ind[0] = 3; ind[1] = 0; ind[2] = 2; ind[3] = 1; break;
7919  case 5:
7920  default: ind[0] = 3; ind[1] = 2; ind[2] = 1; ind[3] = 0;
7921  }
7922  }
7923  // Do the permutation
7924  for (i = 0; i < 3; i++)
7925  {
7926  for (j = 0; j < 4; j++)
7927  {
7928  t[j] = pointmat(i,j);
7929  }
7930  for (j = 0; j < 4; j++)
7931  {
7932  pointmat(i,ind[j]) = t[j];
7933  }
7934  }
7935 }
7936 
7937 int Mesh::GetFineElemPath(int i, int j)
7938 {
7939  // if (Dim == 3)
7940  {
7941  if (elements[i]->GetType() == Element::BISECTED)
7942  {
7943  int n = 0, l = 0;
7944  BisectedElement *aux = (BisectedElement *) elements[i];
7945  do
7946  {
7947  int k = GetFineElemPath(aux->SecondChild, j-n);
7948  if (k >= 0)
7949  {
7950  return ((k << 1)+1) << l;
7951  }
7952  n -= k; // (-k) is the number of the leaves in this SecondChild
7953  // n is the number of the leaves in
7954  // the SecondChild-ren so far
7955  l++;
7956  if (aux->FirstChild->GetType() != Element::BISECTED)
7957  {
7958  break;
7959  }
7960  aux = (BisectedElement *) (aux->FirstChild);
7961  }
7962  while (1);
7963  if (j > n) // i.e. if (j >= n+1)
7964  {
7965  return -(n+1);
7966  }
7967  return 0; // j == n, i.e. j is the index of the last leaf
7968  }
7969  if (j > 0)
7970  {
7971  return -1;
7972  }
7973  }
7974 
7975  return 0;
7976 }
7977 
7979 {
7980  int t;
7981 
7982  if (Dim == 1)
7983  {
7984  DenseMatrix &pm = Transformation.GetPointMat();
7985  Transformation.SetFE(&SegmentFE);
7986  Transformation.Attribute = 0;
7987  Transformation.ElementNo = 0;
7988  pm.SetSize(1, 2);
7989  if (elements[i]->GetType() == Element::BISECTED)
7990  {
7991  switch (j)
7992  {
7993  case 0: pm(0,0) = 0.0; pm(0,1) = 0.5; break;
7994  default: pm(0,0) = 0.5; pm(0,1) = 1.0; break;
7995  }
7996  }
7997  else
7998  {
7999  pm(0,0) = 0.0; pm(0,1) = 1.0;
8000  }
8001  }
8002  else if (Dim == 2)
8003  {
8004  DenseMatrix &pm = Transformation.GetPointMat();
8005  Transformation.Attribute = 0;
8006  Transformation.ElementNo = 0;
8007  t = elements[i]->GetType();
8008  if (t == Element::QUADRISECTED)
8009  {
8010  t = ((QuadrisectedElement *)elements[i])->CoarseElem->GetType();
8011  if (t == Element::QUADRILATERAL)
8012  {
8013  // quadrisected QUADRILATERAL
8014  Transformation.SetFE(&QuadrilateralFE);
8015  pm.SetSize(2, 4);
8016  switch (j)
8017  {
8018  case 0:
8019  pm(0,0) = 0.0; pm(1,0) = 0.0; // x; y;
8020  pm(0,1) = 0.5; pm(1,1) = 0.0;
8021  pm(0,2) = 0.5; pm(1,2) = 0.5;
8022  pm(0,3) = 0.0; pm(1,3) = 0.5;
8023  break;
8024  case 1:
8025  pm(0,0) = 0.5; pm(1,0) = 0.0;
8026  pm(0,1) = 1.0; pm(1,1) = 0.0;
8027  pm(0,2) = 1.0; pm(1,2) = 0.5;
8028  pm(0,3) = 0.5; pm(1,3) = 0.5;
8029  break;
8030  case 2:
8031  pm(0,0) = 0.5; pm(1,0) = 0.5;
8032  pm(0,1) = 1.0; pm(1,1) = 0.5;
8033  pm(0,2) = 1.0; pm(1,2) = 1.0;
8034  pm(0,3) = 0.5; pm(1,3) = 1.0;
8035  break;
8036  case 3:
8037  pm(0,0) = 0.0; pm(1,0) = 0.5;
8038  pm(0,1) = 0.5; pm(1,1) = 0.5;
8039  pm(0,2) = 0.5; pm(1,2) = 1.0;
8040  pm(0,3) = 0.0; pm(1,3) = 1.0;
8041  break;
8042  default:
8043  mfem_error("Mesh::GetFineElemTrans(...) 1");
8044  }
8045  }
8046  else
8047  {
8048  // quadrisected TRIANGLE
8049  Transformation.SetFE(&TriangleFE);
8050  pm.SetSize(2, 3);
8051  switch (j)
8052  {
8053  case 0:
8054  pm(0,0) = 0.0; pm(0,1) = 0.5; pm(0,2) = 0.0; // x
8055  pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 0.5; // y
8056  break;
8057  case 1:
8058  pm(0,0) = 0.5; pm(0,1) = 1.0; pm(0,2) = 0.5;
8059  pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 0.5;
8060  break;
8061  case 2:
8062  pm(0,0) = 0.0; pm(0,1) = 0.5; pm(0,2) = 0.0;
8063  pm(1,0) = 0.5; pm(1,1) = 0.5; pm(1,2) = 1.0;
8064  break;
8065  case 3:
8066  pm(0,0) = 0.5; pm(0,1) = 0.0; pm(0,2) = 0.5;
8067  pm(1,0) = 0.5; pm(1,1) = 0.5; pm(1,2) = 0.0;
8068  break;
8069  default:
8070  mfem_error("Mesh::GetFineElemTrans(...) 2");
8071  }
8072  }
8073  }
8074  else if (t == Element::BISECTED)
8075  {
8076  // bisected TRIANGLE
8077  Transformation.SetFE(&TriangleFE);
8078  pm.SetSize(2, 3);
8079 
8080  int path;
8081  Element *E;
8082 
8083  // pm is initialzed with the coordinates of the vertices of the
8084  // reference triangle
8085  pm(0,0) = 0.0; pm(0,1) = 1.0; pm(0,2) = 0.0;
8086  pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 1.0;
8087 
8088  path = GetFineElemPath(i, j);
8089 
8090  E = elements[i];
8091  while (E->GetType() == Element::BISECTED)
8092  {
8093  BisectedElement *aux = (BisectedElement *) E;
8094 
8095  BisectTriTrans(pm, (Triangle *) aux->CoarseElem, path & 1);
8096  E = (path & 1) ? elements[aux->SecondChild] : aux->FirstChild;
8097  path = path >> 1;
8098  }
8099  }
8100  else
8101  {
8102  // identity transformation
8103  Transformation.SetFE(&TriangleFE);
8104  pm.SetSize(2, 3);
8105  pm(0,0) = 0.0; pm(0,1) = 1.0; pm(0,2) = 0.0;
8106  pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 1.0;
8107  }
8108  return &Transformation;
8109  }
8110  else if (Dim == 3)
8111  {
8112  if (elements[i]->GetType() == Element::OCTASECTED)
8113  {
8114  int jj;
8115  double dx, dy, dz;
8116  DenseMatrix &pm = Transformation.GetPointMat();
8117  Transformation.SetFE(&HexahedronFE);
8118  Transformation.Attribute = 0;
8119  Transformation.ElementNo = 0;
8120  pm.SetSize(3, 8);
8121  if (j < 4) { dz = 0.0; }
8122  else { dz = 0.5; }
8123  jj = j % 4;
8124  if (jj < 2) { dy = 0.0; }
8125  else { dy = 0.5; }
8126  if (jj == 0 || jj == 3) { dx = 0.0; }
8127  else { dx = 0.5; }
8128  pm(0,0) = dx; pm(1,0) = dy; pm(2,0) = dz;
8129  pm(0,1) = 0.5 + dx; pm(1,1) = dy; pm(2,1) = dz;
8130  pm(0,2) = 0.5 + dx; pm(1,2) = 0.5 + dy; pm(2,2) = dz;
8131  pm(0,3) = dx; pm(1,3) = 0.5 + dy; pm(2,3) = dz;
8132  pm(0,4) = dx; pm(1,4) = dy; pm(2,4) = 0.5 + dz;
8133  pm(0,5) = 0.5 + dx; pm(1,5) = dy; pm(2,5) = 0.5 + dz;
8134  pm(0,6) = 0.5 + dx; pm(1,6) = 0.5 + dy; pm(2,6) = 0.5 + dz;
8135  pm(0,7) = dx; pm(1,7) = 0.5 + dy; pm(2,7) = 0.5 + dz;
8136  return &Transformation;
8137  }
8138  int path;
8139  Element *E;
8140  DenseMatrix &pm = Transformation.GetPointMat();
8141  Transformation.SetFE(&TetrahedronFE);
8142  Transformation.Attribute = 0;
8143  Transformation.ElementNo = 0;
8144  pm.SetSize(3, 4);
8145 
8146  // pm is initialzed with the coordinates of the vertices of the
8147  // reference tetrahedron
8148  pm(0,0) = 0.0; pm(0,1) = 1.0; pm(0,2) = 0.0; pm(0,3) = 0.0;
8149  pm(1,0) = 0.0; pm(1,1) = 0.0; pm(1,2) = 1.0; pm(1,3) = 0.0;
8150  pm(2,0) = 0.0; pm(2,1) = 0.0; pm(2,2) = 0.0; pm(2,3) = 1.0;
8151 
8152  path = GetFineElemPath(i, j);
8153 
8154  E = elements[i];
8155  while (E->GetType() == Element::BISECTED)
8156  {
8157  BisectedElement *aux = (BisectedElement *) E;
8158 
8159  BisectTetTrans(pm, (Tetrahedron *) aux->CoarseElem, path & 1);
8160  E = (path & 1) ? elements[aux->SecondChild] : aux->FirstChild;
8161  path = path >> 1;
8162  }
8163  }
8164 
8165  return &Transformation; // no refinement
8166 }
8167 
8168 void Mesh::PrintXG(std::ostream &out) const
8169 {
8170  MFEM_ASSERT(Dim==spaceDim, "2D Manifold meshes not supported");
8171  int i, j;
8172  Array<int> v;
8173 
8174  if (Dim == 2)
8175  {
8176  // Print the type of the mesh.
8177  if (Nodes == NULL)
8178  {
8179  out << "areamesh2\n\n";
8180  }
8181  else
8182  {
8183  out << "curved_areamesh2\n\n";
8184  }
8185 
8186  // Print the boundary elements.
8187  out << NumOfBdrElements << '\n';
8188  for (i = 0; i < NumOfBdrElements; i++)
8189  {
8190  boundary[i]->GetVertices(v);
8191 
8192  out << boundary[i]->GetAttribute();
8193  for (j = 0; j < v.Size(); j++)
8194  {
8195  out << ' ' << v[j] + 1;
8196  }
8197  out << '\n';
8198  }
8199 
8200  // Print the elements.
8201  out << NumOfElements << '\n';
8202  for (i = 0; i < NumOfElements; i++)
8203  {
8204  elements[i]->GetVertices(v);
8205 
8206  out << elements[i]->GetAttribute() << ' ' << v.Size();
8207  for (j = 0; j < v.Size(); j++)
8208  {
8209  out << ' ' << v[j] + 1;
8210  }
8211  out << '\n';
8212  }
8213 
8214  if (Nodes == NULL)
8215  {
8216  // Print the vertices.
8217  out << NumOfVertices << '\n';
8218  for (i = 0; i < NumOfVertices; i++)
8219  {
8220  out << vertices[i](0);
8221  for (j = 1; j < Dim; j++)
8222  {
8223  out << ' ' << vertices[i](j);
8224  }
8225  out << '\n';
8226  }
8227  }
8228  else
8229  {
8230  out << NumOfVertices << '\n';
8231  Nodes->Save(out);
8232  }
8233  }
8234  else // ===== Dim != 2 =====
8235  {
8236  if (Nodes)
8237  {
8238  mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D");
8239  }
8240 
8241  if (meshgen == 1)
8242  {
8243  int nv;
8244  const int *ind;
8245 
8246  out << "NETGEN_Neutral_Format\n";
8247  // print the vertices
8248  out << NumOfVertices << '\n';
8249  for (i = 0; i < NumOfVertices; i++)
8250  {
8251  for (j = 0; j < Dim; j++)
8252  {
8253  out << ' ' << vertices[i](j);
8254  }
8255  out << '\n';
8256  }
8257 
8258  // print the elements
8259  out << NumOfElements << '\n';
8260  for (i = 0; i < NumOfElements; i++)
8261  {
8262  nv = elements[i]->GetNVertices();
8263  ind = elements[i]->GetVertices();
8264  out << elements[i]->GetAttribute();
8265  for (j = 0; j < nv; j++)
8266  {
8267  out << ' ' << ind[j]+1;
8268  }
8269  out << '\n';
8270  }
8271 
8272  // print the boundary information.
8273  out << NumOfBdrElements << '\n';
8274  for (i = 0; i < NumOfBdrElements; i++)
8275  {
8276  nv = boundary[i]->GetNVertices();
8277  ind = boundary[i]->GetVertices();
8278  out << boundary[i]->GetAttribute();
8279  for (j = 0; j < nv; j++)
8280  {
8281  out << ' ' << ind[j]+1;
8282  }
8283  out << '\n';
8284  }
8285  }
8286  else if (meshgen == 2) // TrueGrid
8287  {
8288  int nv;
8289  const int *ind;
8290 
8291  out << "TrueGrid\n"
8292  << "1 " << NumOfVertices << " " << NumOfElements
8293  << " 0 0 0 0 0 0 0\n"
8294  << "0 0 0 1 0 0 0 0 0 0 0\n"
8295  << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
8296  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
8297  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
8298 
8299  for (i = 0; i < NumOfVertices; i++)
8300  out << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1)
8301  << ' ' << vertices[i](2) << " 0.0\n";
8302 
8303  for (i = 0; i < NumOfElements; i++)
8304  {
8305  nv = elements[i]->GetNVertices();
8306  ind = elements[i]->GetVertices();
8307  out << i+1 << ' ' << elements[i]->GetAttribute();
8308  for (j = 0; j < nv; j++)
8309  {
8310  out << ' ' << ind[j]+1;
8311  }
8312  out << '\n';
8313  }
8314 
8315  for (i = 0; i < NumOfBdrElements; i++)
8316  {
8317  nv = boundary[i]->GetNVertices();
8318  ind = boundary[i]->GetVertices();
8319  out << boundary[i]->GetAttribute();
8320  for (j = 0; j < nv; j++)
8321  {
8322  out << ' ' << ind[j]+1;
8323  }
8324  out << " 1.0 1.0 1.0 1.0\n";
8325  }
8326  }
8327  }
8328 
8329  out << flush;
8330 }
8331 
8332 void Mesh::Print(std::ostream &out) const
8333 {
8334  int i, j;
8335 
8336  if (NURBSext)
8337  {
8338  // general format
8339  NURBSext->Print(out);
8340  out << '\n';
8341  Nodes->Save(out);
8342 
8343  // patch-wise format
8344  // NURBSext->ConvertToPatches(*Nodes);
8345  // NURBSext->Print(out);
8346 
8347  return;
8348  }
8349 
8350  out << (ncmesh ? "MFEM mesh v1.1\n" : "MFEM mesh v1.0\n");
8351 
8352  // optional
8353  out <<
8354  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
8355  "# POINT = 0\n"
8356  "# SEGMENT = 1\n"
8357  "# TRIANGLE = 2\n"
8358  "# SQUARE = 3\n"
8359  "# TETRAHEDRON = 4\n"
8360  "# CUBE = 5\n"
8361  "#\n";
8362 
8363  out << "\ndimension\n" << Dim
8364  << "\n\nelements\n" << NumOfElements << '\n';
8365  for (i = 0; i < NumOfElements; i++)
8366  {
8367  PrintElement(elements[i], out);
8368  }
8369 
8370  out << "\nboundary\n" << NumOfBdrElements << '\n';
8371  for (i = 0; i < NumOfBdrElements; i++)
8372  {
8373  PrintElement(boundary[i], out);
8374  }
8375 
8376  if (ncmesh)
8377  {
8378  out << "\nvertex_parents\n";
8379  ncmesh->PrintVertexParents(out);
8380 
8381  out << "\ncoarse_elements\n";
8382  ncmesh->PrintCoarseElements(out);
8383  }
8384 
8385  out << "\nvertices\n" << NumOfVertices << '\n';
8386  if (Nodes == NULL)
8387  {
8388  out << spaceDim << '\n';
8389  for (i = 0; i < NumOfVertices; i++)
8390  {
8391  out << vertices[i](0);
8392  for (j = 1; j < spaceDim; j++)
8393  {
8394  out << ' ' << vertices[i](j);
8395  }
8396  out << '\n';
8397  }
8398  }
8399  else
8400  {
8401  out << "\nnodes\n";
8402  Nodes->Save(out);
8403  }
8404 }
8405 
8406 void Mesh::PrintTopo(std::ostream &out,const Array<int> &e_to_k) const
8407 {
8408  int i;
8409  Array<int> vert;
8410 
8411  out << "MFEM NURBS mesh v1.0\n";
8412 
8413  // optional
8414  out <<
8415  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
8416  "# SEGMENT = 1\n"
8417  "# SQUARE = 3\n"
8418  "# CUBE = 5\n"
8419  "#\n";
8420 
8421  out << "\ndimension\n" << Dim
8422  << "\n\nelements\n" << NumOfElements << '\n';
8423  for (i = 0; i < NumOfElements; i++)
8424  {
8425  PrintElement(elements[i], out);
8426  }
8427 
8428  out << "\nboundary\n" << NumOfBdrElements << '\n';
8429  for (i = 0; i < NumOfBdrElements; i++)
8430  {
8431  PrintElement(boundary[i], out);
8432  }
8433 
8434  out << "\nedges\n" << NumOfEdges << '\n';
8435  for (i = 0; i < NumOfEdges; i++)
8436  {
8437  edge_vertex->GetRow(i, vert);
8438  int ki = e_to_k[i];
8439  if (ki < 0)
8440  {
8441  ki = -1 - ki;
8442  }
8443  out << ki << ' ' << vert[0] << ' ' << vert[1] << '\n';
8444  }
8445  out << "\nvertices\n" << NumOfVertices << '\n';
8446 }
8447 
8448 void Mesh::PrintVTK(std::ostream &out)
8449 {
8450  out <<
8451  "# vtk DataFile Version 3.0\n"
8452  "Generated by MFEM\n"
8453  "ASCII\n"
8454  "DATASET UNSTRUCTURED_GRID\n";
8455 
8456  if (Nodes == NULL)
8457  {
8458  out << "POINTS " << NumOfVertices << " double\n";
8459  for (int i = 0; i < NumOfVertices; i++)
8460  {
8461  out << vertices[i](0);
8462  int j;
8463  for (j = 1; j < spaceDim; j++)
8464  {
8465  out << ' ' << vertices[i](j);
8466  }
8467  for ( ; j < 3; j++)
8468  {
8469  out << ' ' << 0.0;
8470  }
8471  out << '\n';
8472  }
8473  }
8474  else
8475  {
8476  Array<int> vdofs(3);
8477  out << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n";
8478  for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++)
8479  {
8480  vdofs.SetSize(1);
8481  vdofs[0] = i;
8482  Nodes->FESpace()->DofsToVDofs(vdofs);
8483  out << (*Nodes)(vdofs[0]);
8484  int j;
8485  for (j = 1; j < spaceDim; j++)
8486  {
8487  out << ' ' << (*Nodes)(vdofs[j]);
8488  }
8489  for ( ; j < 3; j++)
8490  {
8491  out << ' ' << 0.0;
8492  }
8493  out << '\n';
8494  }
8495  }
8496 
8497  int order = -1;
8498  if (Nodes == NULL)
8499  {
8500  int size = 0;
8501  for (int i = 0; i < NumOfElements; i++)
8502  {
8503  size += elements[i]->GetNVertices() + 1;
8504  }
8505  out << "CELLS " << NumOfElements << ' ' << size << '\n';
8506  for (int i = 0; i < NumOfElements; i++)
8507  {
8508  const int *v = elements[i]->GetVertices();
8509  const int nv = elements[i]->GetNVertices();
8510  out << nv;
8511  for (int j = 0; j < nv; j++)
8512  {
8513  out << ' ' << v[j];
8514  }
8515  out << '\n';
8516  }
8517  order = 1;
8518  }
8519  else
8520  {
8521  Array<int> dofs;
8522  int size = 0;
8523  for (int i = 0; i < NumOfElements; i++)
8524  {
8525  Nodes->FESpace()->GetElementDofs(i, dofs);
8526  size += dofs.Size() + 1;
8527  }
8528  out << "CELLS " << NumOfElements << ' ' << size << '\n';
8529  const char *fec_name = Nodes->FESpace()->FEColl()->Name();
8530  if (!strcmp(fec_name, "Linear") ||
8531  !strcmp(fec_name, "H1_2D_P1") ||
8532  !strcmp(fec_name, "H1_3D_P1"))
8533  {
8534  order = 1;
8535  }
8536  else if (!strcmp(fec_name, "Quadratic") ||
8537  !strcmp(fec_name, "H1_2D_P2") ||
8538  !strcmp(fec_name, "H1_3D_P2"))
8539  {
8540  order = 2;
8541  }
8542  if (order == -1)
8543  {
8544  cerr << "Mesh::PrintVTK : can not save '"
8545  << fec_name << "' elements!" << endl;
8546  mfem_error();
8547  }
8548  for (int i = 0; i < NumOfElements; i++)
8549  {
8550  Nodes->FESpace()->GetElementDofs(i, dofs);
8551  out << dofs.Size();
8552  if (order == 1)
8553  {
8554  for (int j = 0; j < dofs.Size(); j++)
8555  {
8556  out << ' ' << dofs[j];
8557  }
8558  }
8559  else if (order == 2)
8560  {
8561  const int *vtk_mfem;
8562  switch (elements[i]->GetGeometryType())
8563  {
8564  case Geometry::TRIANGLE:
8565  case Geometry::SQUARE:
8566  vtk_mfem = vtk_quadratic_hex; break; // identity map
8567  case Geometry::TETRAHEDRON:
8568  vtk_mfem = vtk_quadratic_tet; break;
8569  case Geometry::CUBE:
8570  default:
8571  vtk_mfem = vtk_quadratic_hex; break;
8572  }
8573  for (int j = 0; j < dofs.Size(); j++)
8574  {
8575  out << ' ' << dofs[vtk_mfem[j]];
8576  }
8577  }
8578  out << '\n';
8579  }
8580  }
8581 
8582  out << "CELL_TYPES " << NumOfElements << '\n';
8583  for (int i = 0; i < NumOfElements; i++)
8584  {
8585  int vtk_cell_type = 5;
8586  if (order == 1)
8587  {
8588  switch (elements[i]->GetGeometryType())
8589  {
8590  case Geometry::TRIANGLE: vtk_cell_type = 5; break;
8591  case Geometry::SQUARE: vtk_cell_type = 9; break;
8592  case Geometry::TETRAHEDRON: vtk_cell_type = 10; break;
8593  case Geometry::CUBE: vtk_cell_type = 12; break;
8594  }
8595  }
8596  else if (order == 2)
8597  {
8598  switch (elements[i]->GetGeometryType())
8599  {
8600  case Geometry::TRIANGLE: vtk_cell_type = 22; break;
8601  case Geometry::SQUARE: vtk_cell_type = 28; break;
8602  case Geometry::TETRAHEDRON: vtk_cell_type = 24; break;
8603  case Geometry::CUBE: vtk_cell_type = 29; break;
8604  }
8605  }
8606 
8607  out << vtk_cell_type << '\n';
8608  }
8609 
8610  // write attributes
8611  out << "CELL_DATA " << NumOfElements << '\n'
8612  << "SCALARS material int\n"
8613  << "LOOKUP_TABLE default\n";
8614  for (int i = 0; i < NumOfElements; i++)
8615  {
8616  out << elements[i]->GetAttribute() << '\n';
8617  }
8618 }
8619 
8620 void Mesh::PrintVTK(std::ostream &out, int ref, int field_data)
8621 {
8622  int np, nc, size;
8623  RefinedGeometry *RefG;
8624  DenseMatrix pmat;
8625 
8626  out <<
8627  "# vtk DataFile Version 3.0\n"
8628  "Generated by MFEM\n"
8629  "ASCII\n"
8630  "DATASET UNSTRUCTURED_GRID\n";
8631 
8632  // additional dataset information
8633  if (field_data)
8634  {
8635  out << "FIELD FieldData 1" << endl
8636  << "MaterialIds " << 1 << " " << attributes.Size() << " int" << endl;
8637  for (int i = 0; i < attributes.Size(); i++)
8638  {
8639  out << attributes[i] << " ";
8640  }
8641  out << endl;
8642  }
8643 
8644  // count the points, cells, size
8645  np = nc = size = 0;
8646  for (int i = 0; i < GetNE(); i++)
8647  {
8648  int geom = GetElementBaseGeometry(i);
8649  int nv = Geometries.GetVertices(geom)->GetNPoints();
8650  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
8651  np += RefG->RefPts.GetNPoints();
8652  nc += RefG->RefGeoms.Size() / nv;
8653  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
8654  }
8655  out << "POINTS " << np << " double\n";
8656  // write the points
8657  for (int i = 0; i < GetNE(); i++)
8658  {
8659  RefG = GlobGeometryRefiner.Refine(
8660  GetElementBaseGeometry(i), ref, 1);
8661 
8662  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
8663 
8664  for (int j = 0; j < pmat.Width(); j++)
8665  {
8666  out << pmat(0, j) << ' ';
8667  if (pmat.Height() > 1)
8668  {
8669  out << pmat(1, j) << ' ';
8670  if (pmat.Height() > 2)
8671  {
8672  out << pmat(2, j);
8673  }
8674  else
8675  {
8676  out << 0.0;
8677  }
8678  }
8679  else
8680  {
8681  out << 0.0 << ' ' << 0.0;
8682  }
8683  out << '\n';
8684  }
8685  }
8686 
8687  // write the cells
8688  out << "CELLS " << nc << ' ' << size << '\n';
8689  np = 0;
8690  for (int i = 0; i < GetNE(); i++)
8691  {
8692  int geom = GetElementBaseGeometry(i);
8693  int nv = Geometries.GetVertices(geom)->GetNPoints();
8694  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
8695  Array<int> &RG = RefG->RefGeoms;
8696 
8697  for (int j = 0; j < RG.Size(); )
8698  {
8699  out << nv;
8700  for (int k = 0; k < nv; k++, j++)
8701  {
8702  out << ' ' << np + RG[j];
8703  }
8704  out << '\n';
8705  }
8706  np += RefG->RefPts.GetNPoints();
8707  }
8708  out << "CELL_TYPES " << nc << '\n';
8709  for (int i = 0; i < GetNE(); i++)
8710  {
8711  int geom = GetElementBaseGeometry(i);
8712  int nv = Geometries.GetVertices(geom)->GetNPoints();
8713  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
8714  Array<int> &RG = RefG->RefGeoms;
8715  int vtk_cell_type = 5;
8716 
8717  switch (geom)
8718  {
8719  case Geometry::SEGMENT: vtk_cell_type = 3; break;
8720  case Geometry::TRIANGLE: vtk_cell_type = 5; break;
8721  case Geometry::SQUARE: vtk_cell_type = 9; break;
8722  case Geometry::TETRAHEDRON: vtk_cell_type = 10; break;
8723  case Geometry::CUBE: vtk_cell_type = 12; break;
8724  }
8725 
8726  for (int j = 0; j < RG.Size(); j += nv)
8727  {
8728  out << vtk_cell_type << '\n';
8729  }
8730  }
8731  // write attributes (materials)
8732  out << "CELL_DATA " << nc << '\n'
8733  << "SCALARS material int\n"
8734  << "LOOKUP_TABLE default\n";
8735  for (int i = 0; i < GetNE(); i++)
8736  {
8737  int geom = GetElementBaseGeometry(i);
8738  int nv = Geometries.GetVertices(geom)->GetNPoints();
8739  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
8740  int attr = GetAttribute(i);
8741  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
8742  {
8743  out << attr << '\n';
8744  }
8745  }
8746 
8747  Array<int> coloring;
8748  srand((unsigned)time(0));
8749  double a = double(rand()) / (double(RAND_MAX) + 1.);
8750  int el0 = (int)floor(a * GetNE());
8751  GetElementColoring(coloring, el0);
8752  out << "SCALARS element_coloring int\n"
8753  << "LOOKUP_TABLE default\n";
8754  for (int i = 0; i < GetNE(); i++)
8755  {
8756  int geom = GetElementBaseGeometry(i);
8757  int nv = Geometries.GetVertices(geom)->GetNPoints();
8758  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
8759  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
8760  {
8761  out << coloring[i] + 1 << '\n';
8762  }
8763  }
8764  // prepare to write data
8765  out << "POINT_DATA " << np << '\n';
8766 }
8767 
8768 void Mesh::GetElementColoring(Array<int> &colors, int el0)
8769 {
8770  int delete_el_to_el = (el_to_el) ? (0) : (1);
8771  const Table &el_el = ElementToElementTable();
8772  int num_el = GetNE(), stack_p, stack_top_p, max_num_col;
8773  Array<int> el_stack(num_el);
8774 
8775  const int *i_el_el = el_el.GetI();
8776  const int *j_el_el = el_el.GetJ();
8777 
8778  colors.SetSize(num_el);
8779  colors = -2;
8780  max_num_col = 1;
8781  stack_p = stack_top_p = 0;
8782  for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el)
8783  {
8784  if (colors[el] != -2)
8785  {
8786  continue;
8787  }
8788 
8789  colors[el] = -1;
8790  el_stack[stack_top_p++] = el;
8791 
8792  for ( ; stack_p < stack_top_p; stack_p++)
8793  {
8794  int i = el_stack[stack_p];
8795  int num_nb = i_el_el[i+1] - i_el_el[i];
8796  if (max_num_col < num_nb + 1)
8797  {
8798  max_num_col = num_nb + 1;
8799  }
8800  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
8801  {
8802  int k = j_el_el[j];
8803  if (colors[k] == -2)
8804  {
8805  colors[k] = -1;
8806  el_stack[stack_top_p++] = k;
8807  }
8808  }
8809  }
8810  }
8811 
8812  Array<int> col_marker(max_num_col);
8813 
8814  for (stack_p = 0; stack_p < stack_top_p; stack_p++)
8815  {
8816  int i = el_stack[stack_p], col;
8817  col_marker = 0;
8818  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
8819  {
8820  col = colors[j_el_el[j]];
8821  if (col != -1)
8822  {
8823  col_marker[col] = 1;
8824  }
8825  }
8826 
8827  for (col = 0; col < max_num_col; col++)
8828  if (col_marker[col] == 0)
8829  {
8830  break;
8831  }
8832 
8833  colors[i] = col;
8834  }
8835 
8836  if (delete_el_to_el)
8837  {
8838  delete el_to_el;
8839  el_to_el = NULL;
8840  }
8841 }
8842 
8843 void Mesh::PrintWithPartitioning(int *partitioning, std::ostream &out,
8844  int elem_attr) const
8845 {
8846  if (Dim != 3 && Dim != 2) { return; }
8847 
8848  int i, j, k, l, nv, nbe, *v;
8849 
8850  out << "MFEM mesh v1.0\n";
8851 
8852  // optional
8853  out <<
8854  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
8855  "# POINT = 0\n"
8856  "# SEGMENT = 1\n"
8857  "# TRIANGLE = 2\n"
8858  "# SQUARE = 3\n"
8859  "# TETRAHEDRON = 4\n"
8860  "# CUBE = 5\n"
8861  "#\n";
8862 
8863  out << "\ndimension\n" << Dim
8864  << "\n\nelements\n" << NumOfElements << '\n';
8865  for (i = 0; i < NumOfElements; i++)
8866  {
8867  out << int((elem_attr) ? partitioning[i]+1 : elements[i]->GetAttribute())
8868  << ' ' << elements[i]->GetGeometryType();
8869  nv = elements[i]->GetNVertices();
8870  v = elements[i]->GetVertices();
8871  for (j = 0; j < nv; j++)
8872  {
8873  out << ' ' << v[j];
8874  }
8875  out << '\n';
8876  }
8877  nbe = 0;
8878  for (i = 0; i < faces_info.Size(); i++)
8879  {
8880  if ((l = faces_info[i].Elem2No) >= 0)
8881  {
8882  k = partitioning[faces_info[i].Elem1No];
8883  l = partitioning[l];
8884  if (k != l)
8885  {
8886  nbe += 2;
8887  }
8888  }
8889  else
8890  {
8891  nbe++;
8892  }
8893  }
8894  out << "\nboundary\n" << nbe << '\n';
8895  for (i = 0; i < faces_info.Size(); i++)
8896  {
8897  if ((l = faces_info[i].Elem2No) >= 0)
8898  {
8899  k = partitioning[faces_info[i].Elem1No];
8900  l = partitioning[l];
8901  if (k != l)
8902  {
8903  nv = faces[i]->GetNVertices();
8904  v = faces[i]->GetVertices();
8905  out << k+1 << ' ' << faces[i]->GetGeometryType();
8906  for (j = 0; j < nv; j++)
8907  {
8908  out << ' ' << v[j];
8909  }
8910  out << '\n';
8911  out << l+1 << ' ' << faces[i]->GetGeometryType();
8912  for (j = nv-1; j >= 0; j--)
8913  {
8914  out << ' ' << v[j];
8915  }
8916  out << '\n';
8917  }
8918  }
8919  else
8920  {
8921  k = partitioning[faces_info[i].Elem1No];
8922  nv = faces[i]->GetNVertices();
8923  v = faces[i]->GetVertices();
8924  out << k+1 << ' ' << faces[i]->GetGeometryType();
8925  for (j = 0; j < nv; j++)
8926  {
8927  out << ' ' << v[j];
8928  }
8929  out << '\n';
8930  }
8931  }
8932  out << "\nvertices\n" << NumOfVertices << '\n';
8933  if (Nodes == NULL)
8934  {
8935  out << spaceDim << '\n';
8936  for (i = 0; i < NumOfVertices; i++)
8937  {
8938  out << vertices[i](0);
8939  for (j = 1; j < spaceDim; j++)
8940  {
8941  out << ' ' << vertices[i](j);
8942  }
8943  out << '\n';
8944  }
8945  }
8946  else
8947  {
8948  out << "\nnodes\n";
8949  Nodes->Save(out);
8950  }
8951 }
8952 
8954  std::ostream &out,
8955  int interior_faces)
8956 {
8957  MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported\n");
8958  if (Dim != 3 && Dim != 2) { return; }
8959 
8960  int i, j, k, l, s;
8961 
8962  int nv;
8963  const int *ind;
8964 
8965  int *vcount = new int[NumOfVertices];
8966  for (i = 0; i < NumOfVertices; i++)
8967  {
8968  vcount[i] = 0;
8969  }
8970  for (i = 0; i < NumOfElements; i++)
8971  {
8972  nv = elements[i]->GetNVertices();
8973  ind = elements[i]->GetVertices();
8974  for (j = 0; j < nv; j++)
8975  {
8976  vcount[ind[j]]++;
8977  }
8978  }
8979 
8980  int *voff = new int[NumOfVertices+1];
8981  voff[0] = 0;
8982  for (i = 1; i <= NumOfVertices; i++)
8983  {
8984  voff[i] = vcount[i-1] + voff[i-1];
8985  }
8986 
8987  int **vown = new int*[NumOfVertices];
8988  for (i = 0; i < NumOfVertices; i++)
8989  {
8990  vown[i] = new int[vcount[i]];
8991  }
8992 
8993  // 2D
8994  if (Dim == 2)
8995  {
8996  int nv, nbe;
8997  int *ind;
8998 
8999  Table edge_el;
9000  Transpose(ElementToEdgeTable(), edge_el);
9001 
9002  // Fake printing of the elements.
9003  for (i = 0; i < NumOfElements; i++)
9004  {
9005  nv = elements[i]->GetNVertices();
9006  ind = elements[i]->GetVertices();
9007  for (j = 0; j < nv; j++)
9008  {
9009  vcount[ind[j]]--;
9010  vown[ind[j]][vcount[ind[j]]] = i;
9011  }
9012  }
9013 
9014  for (i = 0; i < NumOfVertices; i++)
9015  {
9016  vcount[i] = voff[i+1] - voff[i];
9017  }
9018 
9019  nbe = 0;
9020  for (i = 0; i < edge_el.Size(); i++)
9021  {
9022  const int *el = edge_el.GetRow(i);
9023  if (edge_el.RowSize(i) > 1)
9024  {
9025  k = partitioning[el[0]];
9026  l = partitioning[el[1]];
9027  if (interior_faces || k != l)
9028  {
9029  nbe += 2;
9030  }
9031  }
9032  else
9033  {
9034  nbe++;
9035  }
9036  }
9037 
9038  // Print the type of the mesh and the boundary elements.
9039  out << "areamesh2\n\n" << nbe << '\n';
9040 
9041  for (i = 0; i < edge_el.Size(); i++)
9042  {
9043  const int *el = edge_el.GetRow(i);
9044  if (edge_el.RowSize(i) > 1)
9045  {
9046  k = partitioning[el[0]];
9047  l = partitioning[el[1]];
9048  if (interior_faces || k != l)
9049  {
9050  Array<int> ev;
9051  GetEdgeVertices(i,ev);
9052  out << k+1; // attribute
9053  for (j = 0; j < 2; j++)
9054  for (s = 0; s < vcount[ev[j]]; s++)
9055  if (vown[ev[j]][s] == el[0])
9056  {
9057  out << ' ' << voff[ev[j]]+s+1;
9058  }
9059  out << '\n';
9060  out << l+1; // attribute
9061  for (j = 1; j >= 0; j--)
9062  for (s = 0; s < vcount[ev[j]]; s++)
9063  if (vown[ev[j]][s] == el[1])
9064  {
9065  out << ' ' << voff[ev[j]]+s+1;
9066  }
9067  out << '\n';
9068  }
9069  }
9070  else
9071  {
9072  k = partitioning[el[0]];
9073  Array<int> ev;
9074  GetEdgeVertices(i,ev);
9075  out << k+1; // attribute
9076  for (j = 0; j < 2; j++)
9077  for (s = 0; s < vcount[ev[j]]; s++)
9078  if (vown[ev[j]][s] == el[0])
9079  {
9080  out << ' ' << voff[ev[j]]+s+1;
9081  }
9082  out << '\n';
9083  }
9084  }
9085 
9086  // Print the elements.
9087  out << NumOfElements << '\n';
9088  for (i = 0; i < NumOfElements; i++)
9089  {
9090  nv = elements[i]->GetNVertices();
9091  ind = elements[i]->GetVertices();
9092  out << partitioning[i]+1 << ' '; // use subdomain number as attribute
9093  out << nv << ' ';
9094  for (j = 0; j < nv; j++)
9095  {
9096  out << ' ' << voff[ind[j]]+vcount[ind[j]]--;
9097  vown[ind[j]][vcount[ind[j]]] = i;
9098  }
9099  out << '\n';
9100  }
9101 
9102  for (i = 0; i < NumOfVertices; i++)
9103  {
9104  vcount[i] = voff[i+1] - voff[i];
9105  }
9106 
9107  // Print the vertices.
9108  out << voff[NumOfVertices] << '\n';
9109  for (i = 0; i < NumOfVertices; i++)
9110  for (k = 0; k < vcount[i]; k++)
9111  {
9112  for (j = 0; j < Dim; j++)
9113  {
9114  out << vertices[i](j) << ' ';
9115  }
9116  out << '\n';
9117  }
9118  out << flush;
9119  return;
9120  }
9121 
9122  // Dim is 3
9123  if (meshgen == 1)
9124  {
9125  out << "NETGEN_Neutral_Format\n";
9126  // print the vertices
9127  out << voff[NumOfVertices] << '\n';
9128  for (i = 0; i < NumOfVertices; i++)
9129  for (k = 0; k < vcount[i]; k++)
9130  {
9131  for (j = 0; j < Dim; j++)
9132  {
9133  out << ' ' << vertices[i](j);
9134  }
9135  out << '\n';
9136  }
9137 
9138  // print the elements
9139  out << NumOfElements << '\n';
9140  for (i = 0; i < NumOfElements; i++)
9141  {
9142  nv = elements[i]->GetNVertices();
9143  ind = elements[i]->GetVertices();
9144  out << partitioning[i]+1; // use subdomain number as attribute
9145  for (j = 0; j < nv; j++)
9146  {
9147  out << ' ' << voff[ind[j]]+vcount[ind[j]]--;
9148  vown[ind[j]][vcount[ind[j]]] = i;
9149  }
9150  out << '\n';
9151  }
9152 
9153  for (i = 0; i < NumOfVertices; i++)
9154  {
9155  vcount[i] = voff[i+1] - voff[i];
9156  }
9157 
9158  // print the boundary information.
9159  int k, l, nbe;
9160  nbe = 0;
9161  for (i = 0; i < NumOfFaces; i++)
9162  if ((l = faces_info[i].Elem2No) >= 0)
9163  {
9164  k = partitioning[faces_info[i].Elem1No];
9165  l = partitioning[l];
9166  if (interior_faces || k != l)
9167  {
9168  nbe += 2;
9169  }
9170  }
9171  else
9172  {
9173  nbe++;
9174  }
9175 
9176  out << nbe << '\n';
9177  for (i = 0; i < NumOfFaces; i++)
9178  if ((l = faces_info[i].Elem2No) >= 0)
9179  {
9180  k = partitioning[faces_info[i].Elem1No];
9181  l = partitioning[l];
9182  if (interior_faces || k != l)
9183  {
9184  nv = faces[i]->GetNVertices();
9185  ind = faces[i]->GetVertices();
9186  out << k+1; // attribute
9187  for (j = 0; j < nv; j++)
9188  for (s = 0; s < vcount[ind[j]]; s++)
9189  if (vown[ind[j]][s] == faces_info[i].Elem1No)
9190  {
9191  out << ' ' << voff[ind[j]]+s+1;
9192  }
9193  out << '\n';
9194  out << l+1; // attribute
9195  for (j = nv-1; j >= 0; j--)
9196  for (s = 0; s < vcount[ind[j]]; s++)
9197  if (vown[ind[j]][s] == faces_info[i].Elem2No)
9198  {
9199  out << ' ' << voff[ind[j]]+s+1;
9200  }
9201  out << '\n';
9202  }
9203  }
9204  else
9205  {
9206  k = partitioning[faces_info[i].Elem1No];
9207  nv = faces[i]->GetNVertices();
9208  ind = faces[i]->GetVertices();
9209  out << k+1; // attribute
9210  for (j = 0; j < nv; j++)
9211  for (s = 0; s < vcount[ind[j]]; s++)
9212  if (vown[ind[j]][s] == faces_info[i].Elem1No)
9213  {
9214  out << ' ' << voff[ind[j]]+s+1;
9215  }
9216  out << '\n';
9217  }
9218 
9219  for (i = 0; i < NumOfVertices; i++)
9220  {
9221  delete [] vown[i];
9222  }
9223  }
9224  else if (meshgen == 2) // TrueGrid
9225  {
9226  // count the number of the boundary elements.
9227  int k, l, nbe;
9228  nbe = 0;
9229  for (i = 0; i < NumOfFaces; i++)
9230  if ((l = faces_info[i].Elem2No) >= 0)
9231  {
9232  k = partitioning[faces_info[i].Elem1No];
9233  l = partitioning[l];
9234  if (interior_faces || k != l)
9235  {
9236  nbe += 2;
9237  }
9238  }
9239  else
9240  {
9241  nbe++;
9242  }
9243 
9244 
9245  out << "TrueGrid\n"
9246  << "1 " << voff[NumOfVertices] << " " << NumOfElements
9247  << " 0 0 0 0 0 0 0\n"
9248  << "0 0 0 1 0 0 0 0 0 0 0\n"
9249  << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
9250  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
9251  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
9252 
9253  for (i = 0; i < NumOfVertices; i++)
9254  for (k = 0; k < vcount[i]; k++)
9255  out << voff[i]+k << " 0.0 " << vertices[i](0) << ' '
9256  << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n";
9257 
9258  for (i = 0; i < NumOfElements; i++)
9259  {
9260  nv = elements[i]->GetNVertices();
9261  ind = elements[i]->GetVertices();
9262  out << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute
9263  for (j = 0; j < nv; j++)
9264  {
9265  out << ' ' << voff[ind[j]]+vcount[ind[j]]--;
9266  vown[ind[j]][vcount[ind[j]]] = i;
9267  }
9268  out << '\n';
9269  }
9270 
9271  for (i = 0; i < NumOfVertices; i++)
9272  {
9273  vcount[i] = voff[i+1] - voff[i];
9274  }
9275 
9276  // boundary elements
9277  for (i = 0; i < NumOfFaces; i++)
9278  if ((l = faces_info[i].Elem2No) >= 0)
9279  {
9280  k = partitioning[faces_info[i].Elem1No];
9281  l = partitioning[l];
9282  if (interior_faces || k != l)
9283  {
9284  nv = faces[i]->GetNVertices();
9285  ind = faces[i]->GetVertices();
9286  out << k+1; // attribute
9287  for (j = 0; j < nv; j++)
9288  for (s = 0; s < vcount[ind[j]]; s++)
9289  if (vown[ind[j]][s] == faces_info[i].Elem1No)
9290  {
9291  out << ' ' << voff[ind[j]]+s+1;
9292  }
9293  out << " 1.0 1.0 1.0 1.0\n";
9294  out << l+1; // attribute
9295  for (j = nv-1; j >= 0; j--)
9296  for (s = 0; s < vcount[ind[j]]; s++)
9297  if (vown[ind[j]][s] == faces_info[i].Elem2No)
9298  {
9299  out << ' ' << voff[ind[j]]+s+1;
9300  }
9301  out << " 1.0 1.0 1.0 1.0\n";
9302  }
9303  }
9304  else
9305  {
9306  k = partitioning[faces_info[i].Elem1No];
9307  nv = faces[i]->GetNVertices();
9308  ind = faces[i]->GetVertices();
9309  out << k+1; // attribute
9310  for (j = 0; j < nv; j++)
9311  for (s = 0; s < vcount[ind[j]]; s++)
9312  if (vown[ind[j]][s] == faces_info[i].Elem1No)
9313  {
9314  out << ' ' << voff[ind[j]]+s+1;
9315  }
9316  out << " 1.0 1.0 1.0 1.0\n";
9317  }
9318  }
9319 
9320  out << flush;
9321 
9322  delete [] vcount;
9323  delete [] voff;
9324  delete [] vown;
9325 }
9326 
9327 void Mesh::PrintSurfaces(const Table & Aface_face, std::ostream &out) const
9328 {
9329  int i, j;
9330 
9331  if (NURBSext)
9332  {
9333  mfem_error("Mesh::PrintSurfaces"
9334  " NURBS mesh is not supported!");
9335  return;
9336  }
9337 
9338  out << "MFEM mesh v1.0\n";
9339 
9340  // optional
9341  out <<
9342  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
9343  "# POINT = 0\n"
9344  "# SEGMENT = 1\n"
9345  "# TRIANGLE = 2\n"
9346  "# SQUARE = 3\n"
9347  "# TETRAHEDRON = 4\n"
9348  "# CUBE = 5\n"
9349  "#\n";
9350 
9351  out << "\ndimension\n" << Dim
9352  << "\n\nelements\n" << NumOfElements << '\n';
9353  for (i = 0; i < NumOfElements; i++)
9354  {
9355  PrintElement(elements[i], out);
9356  }
9357 
9358  out << "\nboundary\n" << Aface_face.Size_of_connections() << '\n';
9359  const int * const i_AF_f = Aface_face.GetI();
9360  const int * const j_AF_f = Aface_face.GetJ();
9361 
9362  for (int iAF=0; iAF < Aface_face.Size(); ++iAF)
9363  for (const int * iface = j_AF_f + i_AF_f[iAF]; iface < j_AF_f + i_AF_f[iAF+1];
9364  ++iface)
9365  {
9366  out << iAF+1 << ' ';
9367  PrintElementWithoutAttr(faces[*iface],out);
9368  }
9369 
9370  out << "\nvertices\n" << NumOfVertices << '\n';
9371  if (Nodes == NULL)
9372  {
9373  out << spaceDim << '\n';
9374  for (i = 0; i < NumOfVertices; i++)
9375  {
9376  out << vertices[i](0);
9377  for (j = 1; j < spaceDim; j++)
9378  {
9379  out << ' ' << vertices[i](j);
9380  }
9381  out << '\n';
9382  }
9383  }
9384  else
9385  {
9386  out << "\nnodes\n";
9387  Nodes->Save(out);
9388  }
9389 }
9390 
9391 void Mesh::ScaleSubdomains(double sf)
9392 {
9393  int i,j,k;
9394  Array<int> vert;
9395  DenseMatrix pointmat;
9396  int na = attributes.Size();
9397  double *cg = new double[na*spaceDim];
9398  int *nbea = new int[na];
9399 
9400  int *vn = new int[NumOfVertices];
9401  for (i = 0; i < NumOfVertices; i++)
9402  {
9403  vn[i] = 0;
9404  }
9405  for (i = 0; i < na; i++)
9406  {
9407  for (j = 0; j < spaceDim; j++)
9408  {
9409  cg[i*spaceDim+j] = 0.0;
9410  }
9411  nbea[i] = 0;
9412  }
9413 
9414  for (i = 0; i < NumOfElements; i++)
9415  {
9416  GetElementVertices(i, vert);
9417  for (k = 0; k < vert.Size(); k++)
9418  {
9419  vn[vert[k]] = 1;
9420  }
9421  }
9422 
9423  for (i = 0; i < NumOfElements; i++)
9424  {
9425  int bea = GetAttribute(i)-1;
9426  GetPointMatrix(i, pointmat);
9427  GetElementVertices(i, vert);
9428 
9429  for (k = 0; k < vert.Size(); k++)
9430  if (vn[vert[k]] == 1)
9431  {
9432  nbea[bea]++;
9433  for (j = 0; j < spaceDim; j++)
9434  {
9435  cg[bea*spaceDim+j] += pointmat(j,k);
9436  }
9437  vn[vert[k]] = 2;
9438  }
9439  }
9440 
9441  for (i = 0; i < NumOfElements; i++)
9442  {
9443  int bea = GetAttribute(i)-1;
9444  GetElementVertices (i, vert);
9445 
9446  for (k = 0; k < vert.Size(); k++)
9447  if (vn[vert[k]])
9448  {
9449  for (j = 0; j < spaceDim; j++)
9450  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
9451  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
9452  vn[vert[k]] = 0;
9453  }
9454  }
9455 
9456  delete [] cg;
9457  delete [] nbea;
9458  delete [] vn;
9459 }
9460 
9461 void Mesh::ScaleElements(double sf)
9462 {
9463  int i,j,k;
9464  Array<int> vert;
9465  DenseMatrix pointmat;
9466  int na = NumOfElements;
9467  double *cg = new double[na*spaceDim];
9468  int *nbea = new int[na];
9469 
9470  int *vn = new int[NumOfVertices];
9471  for (i = 0; i < NumOfVertices; i++)
9472  {
9473  vn[i] = 0;
9474  }
9475  for (i = 0; i < na; i++)
9476  {
9477  for (j = 0; j < spaceDim; j++)
9478  {
9479  cg[i*spaceDim+j] = 0.0;
9480  }
9481  nbea[i] = 0;
9482  }
9483 
9484  for (i = 0; i < NumOfElements; i++)
9485  {
9486  GetElementVertices(i, vert);
9487  for (k = 0; k < vert.Size(); k++)
9488  {
9489  vn[vert[k]] = 1;
9490  }
9491  }
9492 
9493  for (i = 0; i < NumOfElements; i++)
9494  {
9495  int bea = i;
9496  GetPointMatrix(i, pointmat);
9497  GetElementVertices(i, vert);
9498 
9499  for (k = 0; k < vert.Size(); k++)
9500  if (vn[vert[k]] == 1)
9501  {
9502  nbea[bea]++;
9503  for (j = 0; j < spaceDim; j++)
9504  {
9505  cg[bea*spaceDim+j] += pointmat(j,k);
9506  }
9507  vn[vert[k]] = 2;
9508  }
9509  }
9510 
9511  for (i = 0; i < NumOfElements; i++)
9512  {
9513  int bea = i;
9514  GetElementVertices(i, vert);
9515 
9516  for (k = 0; k < vert.Size(); k++)
9517  if (vn[vert[k]])
9518  {
9519  for (j = 0; j < spaceDim; j++)
9520  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
9521  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
9522  vn[vert[k]] = 0;
9523  }
9524  }
9525 
9526  delete [] cg;
9527  delete [] nbea;
9528  delete [] vn;
9529 }
9530 
9531 void Mesh::Transform(void (*f)(const Vector&, Vector&))
9532 {
9533  // TODO: support for different new spaceDim.
9534  if (Nodes == NULL)
9535  {
9536  Vector vold(spaceDim), vnew(NULL, spaceDim);
9537  for (int i = 0; i < vertices.Size(); i++)
9538  {
9539  for (int j = 0; j < spaceDim; j++)
9540  {
9541  vold(j) = vertices[i](j);
9542  }
9543  vnew.SetData(vertices[i]());
9544  (*f)(vold, vnew);
9545  }
9546  }
9547  else
9548  {
9549  GridFunction xnew(Nodes->FESpace());
9550  VectorFunctionCoefficient f_pert(spaceDim, f);
9551  xnew.ProjectCoefficient(f_pert);
9552  *Nodes = xnew;
9553  }
9554 }
9555 
9557 {
9558  MFEM_VERIFY(spaceDim == deformation.GetVDim(),
9559  "incompatible vector dimensions");
9560  if (Nodes == NULL)
9561  {
9562  LinearFECollection fec;
9563  FiniteElementSpace fes(this, &fec, spaceDim, Ordering::byVDIM);
9564  GridFunction xnew(&fes);
9565  xnew.ProjectCoefficient(deformation);
9566  for (int i = 0; i < NumOfVertices; i++)
9567  for (int d = 0; d < spaceDim; d++)
9568  {
9569  vertices[i](d) = xnew(d + spaceDim*i);
9570  }
9571  }
9572  else
9573  {
9574  GridFunction xnew(Nodes->FESpace());
9575  xnew.ProjectCoefficient(deformation);
9576  *Nodes = xnew;
9577  }
9578 }
9579 
9581 {
9582  if (NURBSext || ncmesh) { return; }
9583 
9584  SetState(Mesh::NORMAL);
9585 
9586  Array<int> v2v(GetNV());
9587  v2v = -1;
9588  for (int i = 0; i < GetNE(); i++)
9589  {
9590  Element *el = GetElement(i);
9591  int nv = el->GetNVertices();
9592  int *v = el->GetVertices();
9593  for (int j = 0; j < nv; j++)
9594  {
9595  v2v[v[j]] = 0;
9596  }
9597  }
9598  for (int i = 0; i < GetNBE(); i++)
9599  {
9600  Element *el = GetBdrElement(i);
9601  int *v = el->GetVertices();
9602  int nv = el->GetNVertices();
9603  for (int j = 0; j < nv; j++)
9604  {
9605  v2v[v[j]] = 0;
9606  }
9607  }
9608  int num_vert = 0;
9609  for (int i = 0; i < v2v.Size(); i++)
9610  {
9611  if (v2v[i] == 0)
9612  {
9613  vertices[num_vert] = vertices[i];
9614  v2v[i] = num_vert++;
9615  }
9616  }
9617 
9618  if (num_vert == v2v.Size()) { return; }
9619 
9620  Vector nodes_by_element;
9621  Array<int> vdofs;
9622  if (Nodes)
9623  {
9624  int s = 0;
9625  for (int i = 0; i < GetNE(); i++)
9626  {
9627  Nodes->FESpace()->GetElementVDofs(i, vdofs);
9628  s += vdofs.Size();
9629  }
9630  nodes_by_element.SetSize(s);
9631  s = 0;
9632  for (int i = 0; i < GetNE(); i++)
9633  {
9634  Nodes->FESpace()->GetElementVDofs(i, vdofs);
9635  Nodes->GetSubVector(vdofs, &nodes_by_element(s));
9636  s += vdofs.Size();
9637  }
9638  }
9639  vertices.SetSize(num_vert);
9640  NumOfVertices = num_vert;
9641  for (int i = 0; i < GetNE(); i++)
9642  {
9643  Element *el = GetElement(i);
9644  int *v = el->GetVertices();
9645  int nv = el->GetNVertices();
9646  for (int j = 0; j < nv; j++)
9647  {
9648  v[j] = v2v[v[j]];
9649  }
9650  }
9651  for (int i = 0; i < GetNBE(); i++)
9652  {
9653  Element *el = GetBdrElement(i);
9654  int *v = el->GetVertices();
9655  int nv = el->GetNVertices();
9656  for (int j = 0; j < nv; j++)
9657  {
9658  v[j] = v2v[v[j]];
9659  }
9660  }
9661  DeleteTables();
9662  if (Dim > 1)
9663  {
9664  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
9665  el_to_edge = new Table;
9666  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
9667  }
9668  if (Dim > 2)
9669  {
9670  // generate el_to_face, be_to_face
9671  GetElementToFaceTable();
9672  }
9673  // Update faces and faces_info
9674  GenerateFaces();
9675  if (Nodes)
9676  {
9677  Nodes->FESpace()->Update();
9678  Nodes->Update();
9679  int s = 0;
9680  for (int i = 0; i < GetNE(); i++)
9681  {
9682  Nodes->FESpace()->GetElementVDofs(i, vdofs);
9683  Nodes->SetSubVector(vdofs, &nodes_by_element(s));
9684  s += vdofs.Size();
9685  }
9686  }
9687 }
9688 
9690 {
9691  if (NURBSext || ncmesh) { return; }
9692 
9693  SetState(Mesh::NORMAL);
9694 
9695  int num_bdr_elem = 0;
9696  int new_bel_to_edge_nnz = 0;
9697  for (int i = 0; i < GetNBE(); i++)
9698  {
9699  if (FaceIsInterior(GetBdrElementEdgeIndex(i)))
9700  {
9701  FreeElement(boundary[i]);
9702  }
9703  else
9704  {
9705  num_bdr_elem++;
9706  if (Dim == 3)
9707  {
9708  new_bel_to_edge_nnz += bel_to_edge->RowSize(i);
9709  }
9710  }
9711  }
9712 
9713  if (num_bdr_elem == GetNBE()) { return; }
9714 
9715  Array<Element *> new_boundary(num_bdr_elem);
9716  Array<int> new_be_to_edge, new_be_to_face;
9717  Table *new_bel_to_edge = NULL;
9718  new_boundary.SetSize(0);
9719  if (Dim == 2)
9720  {
9721  new_be_to_edge.Reserve(num_bdr_elem);
9722  }
9723  else if (Dim == 3)
9724  {
9725  new_be_to_face.Reserve(num_bdr_elem);
9726  new_bel_to_edge = new Table;
9727  new_bel_to_edge->SetDims(num_bdr_elem, new_bel_to_edge_nnz);
9728  }
9729  for (int i = 0; i < GetNBE(); i++)
9730  {
9731  if (!FaceIsInterior(GetBdrElementEdgeIndex(i)))
9732  {
9733  new_boundary.Append(boundary[i]);
9734  if (Dim == 2)
9735  {
9736  new_be_to_edge.Append(be_to_edge[i]);
9737  }
9738  else if (Dim == 3)
9739  {
9740  int row = new_be_to_face.Size();
9741  new_be_to_face.Append(be_to_face[i]);
9742  int *e = bel_to_edge->GetRow(i);
9743  int ne = bel_to_edge->RowSize(i);
9744  int *new_e = new_bel_to_edge->GetRow(row);
9745  for (int j = 0; j < ne; j++)
9746  {
9747  new_e[j] = e[j];
9748  }
9749  new_bel_to_edge->GetI()[row+1] = new_bel_to_edge->GetI()[row] + ne;
9750  }
9751  }
9752  }
9753 
9754  NumOfBdrElements = new_boundary.Size();
9755  mfem::Swap(boundary, new_boundary);
9756 
9757  if (Dim == 2)
9758  {
9759  mfem::Swap(be_to_edge, new_be_to_edge);
9760  }
9761  else if (Dim == 3)
9762  {
9763  mfem::Swap(be_to_face, new_be_to_face);
9764  delete bel_to_edge;
9765  bel_to_edge = new_bel_to_edge;
9766  }
9767 
9768  Array<int> attribs(num_bdr_elem);
9769  for (int i = 0; i < attribs.Size(); i++)
9770  {
9771  attribs[i] = GetBdrAttribute(i);
9772  }
9773  attribs.Sort();
9774  attribs.Unique();
9775  bdr_attributes.DeleteAll();
9776  attribs.Copy(bdr_attributes);
9777 }
9778 
9780 {
9781 #ifdef MFEM_USE_MEMALLOC
9782  if (E)
9783  switch (E->GetType())
9784  {
9785  case Element::TETRAHEDRON: TetMemory.Free((Tetrahedron *)E); break;
9786  case Element::BISECTED: BEMemory.Free((BisectedElement *)E); break;
9787  default: delete E; break;
9788  }
9789 #else
9790  delete E;
9791 #endif
9792 }
9793 
9795 {
9796  int i;
9797 
9798  SetState(Mesh::NORMAL);
9799 
9800  if (own_nodes) { delete Nodes; }
9801 
9802  delete ncmesh;
9803 
9804  delete NURBSext;
9805 
9806  for (i = 0; i < NumOfElements; i++)
9807  {
9808  FreeElement(elements[i]);
9809  }
9810 
9811  for (i = 0; i < NumOfBdrElements; i++)
9812  {
9813  FreeElement(boundary[i]);
9814  }
9815 
9816  for (i = 0; i < faces.Size(); i++)
9817  {
9818  FreeElement(faces[i]);
9819  }
9820 
9821  DeleteTables();
9822 }
9823 
9824 std::ostream &operator<<(std::ostream &out, const Mesh &mesh)
9825 {
9826  mesh.Print(out);
9827  return out;
9828 }
9829 
9830 
9832  const double _s)
9833  : VectorCoefficient(dim), n(_n), s(_s), tip(p, dim-1)
9834 {
9835 }
9836 
9838  const IntegrationPoint &ip)
9839 {
9840  V.SetSize(vdim);
9841  T.Transform(ip, tip);
9842  V(0) = p[0];
9843  if (vdim == 2)
9844  {
9845  V(1) = s * ((ip.y + layer) / n);
9846  }
9847  else
9848  {
9849  V(1) = p[1];
9850  V(2) = s * ((ip.z + layer) / n);
9851  }
9852 }
9853 
9854 
9855 Mesh *Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
9856 {
9857  if (mesh->Dimension() != 1)
9858  {
9859  cerr << "Extrude1D : Not a 1D mesh!" << endl;
9860  mfem_error();
9861  }
9862 
9863  int nvy = (closed) ? (ny) : (ny + 1);
9864  int nvt = mesh->GetNV() * nvy;
9865 
9866  Mesh *mesh2d;
9867 
9868  if (closed)
9869  {
9870  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny, mesh->GetNBE()*ny);
9871  }
9872  else
9873  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny,
9874  mesh->GetNBE()*ny+2*mesh->GetNE());
9875 
9876  // vertices
9877  double vc[2];
9878  for (int i = 0; i < mesh->GetNV(); i++)
9879  {
9880  vc[0] = mesh->GetVertex(i)[0];
9881  for (int j = 0; j < nvy; j++)
9882  {
9883  vc[1] = sy * (double(j) / ny);
9884  mesh2d->AddVertex(vc);
9885  }
9886  }
9887  // elements
9888  Array<int> vert;
9889  for (int i = 0; i < mesh->GetNE(); i++)
9890  {
9891  const Element *elem = mesh->GetElement(i);
9892  elem->GetVertices(vert);
9893  const int attr = elem->GetAttribute();
9894  for (int j = 0; j < ny; j++)
9895  {
9896  int qv[4];
9897  qv[0] = vert[0] * nvy + j;
9898  qv[1] = vert[1] * nvy + j;
9899  qv[2] = vert[1] * nvy + (j + 1) % nvy;
9900  qv[3] = vert[0] * nvy + (j + 1) % nvy;
9901 
9902  mesh2d->AddQuad(qv, attr);
9903  }
9904  }
9905  // 2D boundary from the 1D boundary
9906  for (int i = 0; i < mesh->GetNBE(); i++)
9907  {
9908  const Element *elem = mesh->GetBdrElement(i);
9909  elem->GetVertices(vert);
9910  const int attr = elem->GetAttribute();
9911  for (int j = 0; j < ny; j++)
9912  {
9913  int sv[2];
9914  sv[0] = vert[0] * nvy + j;
9915  sv[1] = vert[0] * nvy + (j + 1) % nvy;
9916 
9917  if (attr%2)
9918  {
9919  Swap<int>(sv[0], sv[1]);
9920  }
9921 
9922  mesh2d->AddBdrSegment(sv, attr);
9923  }
9924  }
9925 
9926  if (!closed)
9927  {
9928  // 2D boundary from the 1D elements (bottom + top)
9929  int nba = (mesh->bdr_attributes.Size() > 0 ?
9930  mesh->bdr_attributes.Max() : 0);
9931  for (int i = 0; i < mesh->GetNE(); i++)
9932  {
9933  const Element *elem = mesh->GetElement(i);
9934  elem->GetVertices(vert);
9935  const int attr = nba + elem->GetAttribute();
9936  int sv[2];
9937  sv[0] = vert[0] * nvy;
9938  sv[1] = vert[1] * nvy;
9939 
9940  mesh2d->AddBdrSegment(sv, attr);
9941 
9942  sv[0] = vert[1] * nvy + ny;
9943  sv[1] = vert[0] * nvy + ny;
9944 
9945  mesh2d->AddBdrSegment(sv, attr);
9946  }
9947  }
9948 
9949  mesh2d->FinalizeQuadMesh(1, 0, false);
9950 
9951  GridFunction *nodes = mesh->GetNodes();
9952  if (nodes)
9953  {
9954  // duplicate the fec of the 1D mesh so that it can be deleted safely
9955  // along with its nodes, fes and fec
9956  FiniteElementCollection *fec2d = NULL;
9957  FiniteElementSpace *fes2d;
9958  const char *name = nodes->FESpace()->FEColl()->Name();
9959  string cname = name;
9960  if (cname == "Linear")
9961  {
9962  fec2d = new LinearFECollection;
9963  }
9964  else if (cname == "Quadratic")
9965  {
9966  fec2d = new QuadraticFECollection;
9967  }
9968  else if (cname == "Cubic")
9969  {
9970  fec2d = new CubicFECollection;
9971  }
9972  else if (!strncmp(name, "H1_", 3))
9973  {
9974  fec2d = new H1_FECollection(atoi(name + 7), 2);
9975  }
9976  else if (!strncmp(name, "L2_T", 4))
9977  {
9978  fec2d = new L2_FECollection(atoi(name + 10), 2, atoi(name + 4));
9979  }
9980  else if (!strncmp(name, "L2_", 3))
9981  {
9982  fec2d = new L2_FECollection(atoi(name + 7), 2);
9983  }
9984  else
9985  {
9986  delete mesh2d;
9987  cerr << "Extrude1D : The mesh uses unknown FE collection : "
9988  << cname << endl;
9989  mfem_error();
9990  }
9991  fes2d = new FiniteElementSpace(mesh2d, fec2d, 2);
9992  mesh2d->SetNodalFESpace(fes2d);
9993  GridFunction *nodes2d = mesh2d->GetNodes();
9994  nodes2d->MakeOwner(fec2d);
9995 
9996  NodeExtrudeCoefficient ecoeff(2, ny, sy);
9997  Vector lnodes;
9998  Array<int> vdofs2d;
9999  for (int i = 0; i < mesh->GetNE(); i++)
10000  {
10002  for (int j = ny-1; j >= 0; j--)
10003  {
10004  fes2d->GetElementVDofs(i*ny+j, vdofs2d);
10005  lnodes.SetSize(vdofs2d.Size());
10006  ecoeff.SetLayer(j);
10007  fes2d->GetFE(i*ny+j)->Project(ecoeff, T, lnodes);
10008  nodes2d->SetSubVector(vdofs2d, lnodes);
10009  }
10010  }
10011  }
10012  return mesh2d;
10013 }
10014 
10015 }
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:228
Abstract class for Finite Elements.
Definition: fe.hpp:44
void AddHex(const int *vi, int attr=1)
Definition: mesh.cpp:884
int GetOrder() const
Definition: fe_coll.hpp:232
Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
Definition: fe_coll.hpp:217
int Size() const
For backward compatibility define Size to be synonym of Width()
Definition: densemat.hpp:68
void SetState(int s)
Change the mesh state to NORMAL, TWO_LEVEL_COARSE, TWO_LEVEL_FINE.
Definition: mesh.cpp:7397
std::ostream & operator<<(std::ostream &out, const Mesh &mesh)
Definition: mesh.cpp:9824
int Size() const
Logical size of the array.
Definition: array.hpp:109
void GetFaceEdges(int i, Array< int > &, Array< int > &) const
Definition: mesh.cpp:4116
void PrintSurfaces(const Table &Aface_face, std::ostream &out) const
Print set of disjoint surfaces:
Definition: mesh.cpp:9327
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:4418
int * CartesianPartitioning(int nxyz[])
Definition: mesh.cpp:5023
ElementTransformation * Face
Definition: eltrans.hpp:119
int * GetJ()
Definition: table.hpp:108
Class for integration rule.
Definition: intrules.hpp:83
void UpdateOrder(int Order)
Change the order of the collection.
Definition: fe_coll.hpp:235
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:479
void ScaleElements(double sf)
Definition: mesh.cpp:9461
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:27
int DofToVDof(int dof, int vd, int ndofs=-1) const
Definition: fespace.cpp:116
void Unique()
Definition: array.hpp:193
Table * GetEdgeVertexTable() const
Returns the edge-to-vertex Table (3D)
Definition: mesh.cpp:4186
void GetBdrElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of bdr element i.
Definition: mesh.cpp:4084
void FreeElement(Element *E)
Definition: mesh.cpp:9779
void GetFaceInfos(int Face, int *Inf1, int *Inf2)
Definition: mesh.cpp:740
void SetVertices(const Vector &vert_coord)
Definition: mesh.cpp:5784
virtual Element * Duplicate(Mesh *m) const =0
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Definition: intrules.cpp:235
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:4148
void METIS_PartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:72
virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip)
Definition: mesh.cpp:9837
float real_t
Definition: mesh.cpp:5006
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:74
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Definition: fe.cpp:75
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
void AddHexAsTets(const int *vi, int attr=1)
Definition: mesh.cpp:889
void GetFaceElements(int Face, int *Elem1, int *Elem2)
Definition: mesh.cpp:734
Array< Element * > boundary
Definition: mesh.hpp:70
void JacToPerfJac(int GeomType, const DenseMatrix &J, DenseMatrix &PJ) const
Definition: geom.cpp:428
int * GeneratePartitioning(int nparts, int part_method=1)
Definition: mesh.cpp:5068
void BisectTetTrans(DenseMatrix &pointmat, Tetrahedron *tet, int child)
Definition: mesh.cpp:7886
int own_nodes
Definition: mesh.hpp:119
void MoveVertices(const Vector &displacements)
Definition: mesh.cpp:5764
void SetSize(int s)
Resizes the vector if the new size is different.
Definition: vector.hpp:259
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:457
void GetLocalPtToSegTransformation(IsoparametricTransformation &, int)
Used in GetFaceElementTransformations (...)
Definition: mesh.cpp:424
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:161
void PrintWithPartitioning(int *partitioning, std::ostream &out, int elem_attr=0) const
Definition: mesh.cpp:8843
void MakeOwner(FiniteElementCollection *_fec)
Make the GridFunction the owner of &#39;fec&#39; and &#39;fes&#39;.
Definition: gridfunc.hpp:70
double Det() const
Calculates the determinant of the matrix (for 2x2 or 3x3 matrices)
Definition: densemat.cpp:416
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
Definition: mesh.cpp:5868
int NumOfEdges
Definition: mesh.hpp:54
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:124
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Definition: mesh.cpp:5882
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:445
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols.
Definition: operator.hpp:41
void GetElementFaces(int i, Array< int > &, Array< int > &) const
Return the indices and the orientations of all faces of element i.
Definition: mesh.cpp:4281
void SetDims(int rows, int nnz)
Definition: table.cpp:132
void DegreeElevate(int t)
Definition: mesh.cpp:3497
int Push(int a, int b)
Definition: table.hpp:224
void SetIntPoint(const IntegrationPoint *ip)
Definition: eltrans.hpp:33
void Copy(Array &copy) const
Create a copy of the current array.
Definition: array.hpp:160
RefinedGeometry * Refine(int Geom, int Times, int ETimes=1)
Definition: geom.cpp:465
void AddTri(const int *vi, int attr=1)
Definition: mesh.cpp:856
int WantTwoLevelState
Definition: mesh.hpp:56
int Push(int r, int c, int f)
Definition: stable3d.cpp:65
void DeleteTables()
Definition: mesh.cpp:764
Piecewise-(bi)linear continuous finite elements.
Definition: fe_coll.hpp:260
Data type dense matrix using column-major storage.
Definition: densemat.hpp:22
GridFunction * Nodes
Definition: mesh.hpp:118
int Size() const
Returns the size of the vector.
Definition: vector.hpp:84
int NumOfElements
Definition: mesh.hpp:53
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:179
Mesh * Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
Extrude a 1D mesh.
Definition: mesh.cpp:9855
void Transform(void(*f)(const Vector &, Vector &))
Definition: mesh.cpp:9531
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:4370
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:454
void BisectTriTrans(DenseMatrix &pointmat, Triangle *tri, int child)
Definition: mesh.cpp:7862
void GenerateBoundaryElements()
Definition: mesh.cpp:938
void DeleteCoarseTables()
Definition: mesh.cpp:784
Data type for vertex.
Definition: vertex.hpp:21
void GetElementLocalToGlobal(Array< int > &lelem_elem)
Definition: nurbs.cpp:2281
void SetMeshGen()
Definition: mesh.cpp:2219
ElementTransformation * GetFineElemTrans(int i, int j)
Definition: mesh.cpp:7978
virtual void Transform(const IntegrationPoint &, Vector &)
Definition: eltrans.cpp:129
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:3924
Data type quadrilateral element.
void GetVertices(Vector &vert_coord) const
Definition: mesh.cpp:5773
virtual ~Mesh()
Destroys mesh.
Definition: mesh.cpp:9794
void AddBdrSegment(const int *vi, int attr=1)
Definition: mesh.cpp:908
const IntegrationPoint & GetCenter(int GeomType)
Definition: geom.hpp:51
void GetVertexLocalToGlobal(Array< int > &lvert_vert)
Definition: nurbs.cpp:2271
void CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition: mesh.cpp:3972
void RemoveInternalBoundaries()
Definition: mesh.cpp:9689
NURBSExtension * GetNURBSext()
Definition: fespace.hpp:142
FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition: mesh.cpp:557
int Size_of_connections() const
Definition: table.hpp:92
Array< Element * > faces
Definition: mesh.hpp:71
const IntegrationRule * GetVertices(int GeomType)
Definition: geom.cpp:172
void FinalizeHexMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Definition: mesh.cpp:1620
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:4487
void MarkTriMeshForRefinement()
Definition: mesh.cpp:1255
void skip_comment_lines(std::istream &is, const char comment_char)
Definition: mesh.cpp:2249
int GetGeometryType() const
Definition: element.hpp:50
void DeleteAll()
Delete whole array.
Definition: array.hpp:455
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:96
int master
master number (in Mesh numbering)
Definition: ncmesh.hpp:117
int idxtype
Definition: mesh.cpp:4994
Array< NCFaceInfo > nc_faces_info
Definition: mesh.hpp:95
Element * ReadElement(std::istream &)
Definition: mesh.cpp:2201
void KnotInsert(Array< KnotVector * > &kv)
Definition: mesh.cpp:3468
int GetFineElemPath(int i, int j)
Definition: mesh.cpp:7937
Element * NewElement(int geom)
Definition: mesh.cpp:2152
Table * el_to_face
Definition: mesh.hpp:98
void GetEdgeTransformation(int i, IsoparametricTransformation *EdTr)
Definition: mesh.cpp:369
void MarkForRefinement()
Definition: mesh.cpp:1240
void RefineAtVertex(const Vertex &vert, int levels, double eps=0.0, int nonconforming=-1)
Refine elements sharing the specified vertex, &#39;levels&#39; times.
Definition: mesh.cpp:6961
static const int tet_faces[4][3]
Definition: mesh.hpp:125
Element * CoarseElem
Definition: element.hpp:102
ElementTransformation * GetBdrElementTransformation(int i)
Returns the transformation defining the i-th boundary element.
Definition: mesh.cpp:246
template void SortPairs< int, int >(Pair< int, int > *, int)
void AddVertex(const double *)
Definition: mesh.cpp:845
void PrintTopo(std::ostream &out, const Array< int > &e_to_k) const
Definition: mesh.cpp:8406
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:3755
void Load(std::istream &input, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition: mesh.cpp:2262
Piecewise-(bi)cubic continuous finite elements.
Definition: fe_coll.hpp:327
double Weight() const
Definition: densemat.cpp:445
PointFiniteElement PointFE
Definition: point.cpp:30
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: segment.cpp:40
void GetElementJacobian(int i, DenseMatrix &J)
Definition: mesh.cpp:35
Data type hexahedron element.
Definition: hexahedron.hpp:22
Geometry Geometries
Definition: geom.cpp:443
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:231
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:193
void MoveNodes(const Vector &displacements)
Definition: mesh.cpp:5832
void GetEdgeOrdering(DSTable &v_to_v, Array< int > &order)
Definition: mesh.cpp:1270
int dim
Definition: ex3.cpp:48
IntegrationRules IntRules(0)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:292
int idx_t
Definition: mesh.cpp:5005
void FinalizeTriMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Definition: mesh.cpp:992
void UpdateNURBS()
Definition: mesh.cpp:3519
Symmetric 3D Table.
Definition: stable3d.hpp:28
static const int quad_orientations[8][4]
Definition: mesh.hpp:129
void FinalizeTetMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Definition: mesh.cpp:1582
void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
Definition: mesh.cpp:5426
void AddBdrQuadAsTriangles(const int *vi, int attr=1)
Definition: mesh.cpp:923
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows.
Definition: operator.hpp:35
void AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
Definition: mesh.cpp:4616
int local
local number within &#39;element&#39;
Definition: ncmesh.hpp:96
void SetAttributes()
Definition: mesh.cpp:796
int Append(const T &el)
Append element to array, resize if necessary.
Definition: array.hpp:368
void MarkTetMeshForRefinement()
Definition: mesh.cpp:1296
int State
Definition: mesh.hpp:56
void GetFaceTransformation(int i, IsoparametricTransformation *FTr)
Definition: mesh.cpp:280
void CreateRefinementFlag(int refinement_edges[2], int type, int flag=0)
Definition: tetrahedron.cpp:40
void GetLocalSegToTriTransformation(IsoparametricTransformation &loc, int i)
Definition: mesh.cpp:438
void AddQuadFaceElement(int lf, int gf, int el, int v0, int v1, int v2, int v3)
Definition: mesh.cpp:4667
std::vector< Master > masters
Definition: ncmesh.hpp:127
TriLinear3DFiniteElement HexahedronFE
Definition: hexahedron.cpp:68
int GetRefinementType(int i)
For a given coarse element i returns its refinement type.
Definition: mesh.cpp:7675
void AddConnection(int r, int c)
Definition: table.hpp:74
static FiniteElement * GetTransformationFEforElementType(int)
Definition: mesh.cpp:157
void LoadPatchTopo(std::istream &input, Array< int > &edge_to_knot)
Read NURBS patch/macro-element mesh.
Definition: mesh.cpp:3582
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:4841
void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Definition: mesh.cpp:3736
void Make2D(int nx, int ny, Element::Type type, int generate_edges, double sx, double sy)
Definition: mesh.cpp:1837
int MeshGenerator()
Truegrid or NetGen?
Definition: mesh.hpp:447
Type
Constants for the classes derived from Element.
Definition: element.hpp:37
T Max() const
Definition: array.cpp:90
void GetBdrPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:4434
void InitTables()
Definition: mesh.cpp:758
virtual void GetElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:1100
void CheckDisplacements(const Vector &displacements, double &tmax)
Definition: mesh.cpp:5687
void CheckElementOrientation(bool fix_it=true)
Check the orientation of the elements.
Definition: mesh.cpp:3770
NURBSExtension * StealNURBSext()
Definition: fespace.cpp:1008
const IntegrationRule & GetNodes() const
Definition: fe.hpp:113
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:122
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
Definition: table.cpp:385
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:914
void SetLayer(const int l)
Definition: mesh.hpp:879
int GetAttribute() const
Return element&#39;s attribute.
Definition: element.hpp:80
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:4512
virtual void SetVertices(const int *ind)
Set the indices the element according to the input.
Definition: element.hpp:129
int GetElementType(int i) const
Returns the type of element i.
Definition: mesh.cpp:4382
Data type triangle element.
Definition: triangle.hpp:23
Element * FirstChild
Definition: element.hpp:102
const Element * GetElement(int i) const
Definition: mesh.hpp:482
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Definition: triangle.cpp:48
void GetLocalQuadToHexTransformation(IsoparametricTransformation &loc, int i)
Used in GetFaceElementTransformations (...)
Definition: mesh.cpp:536
IntegrationRule RefPts
Definition: geom.hpp:80
static int State
Definition: element.hpp:100
void Sort()
Sorts the array. This requires operator&lt; to be defined for T.
Definition: array.hpp:189
virtual double Weight()=0
int GetVDim()
Returns dimension of the vector.
void Init()
Definition: mesh.cpp:746
void SetNodalFESpace(FiniteElementSpace *nfes)
Definition: mesh.cpp:3719
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:86
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:154
A class for non-conforming AMR on higher-order hexahedral, quadrilateral or triangular meshes...
Definition: ncmesh.hpp:63
FaceElementTransformations * GetBdrFaceTransformations(int BdrElemNo)
Definition: mesh.cpp:708
void SetData(double *d)
Definition: vector.hpp:67
static const char * Name[NumGeom]
Definition: geom.hpp:36
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:270
int Dimension() const
Definition: mesh.hpp:475
virtual void ReorientTetMesh()
Definition: mesh.cpp:4914
int NumOfBdrElements
Definition: mesh.hpp:53
Table * el_to_edge
Definition: mesh.hpp:97
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: triangle.cpp:125
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:6293
int METIS_SetDefaultOptions(idx_t *options)
int GetBdrElementType(int i) const
Returns the type of boundary element i.
Definition: mesh.cpp:4401
void FindPartitioningComponents(Table &elem_elem, const Array< int > &partitioning, Array< int > &component, Array< int > &num_comp)
Definition: mesh.cpp:5298
void GetGeckoElementReordering(Array< int > &ordering)
Definition: mesh.cpp:1049
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
int GetGeomType() const
Returns the geometry type:
Definition: fe.hpp:85
int GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:176
double GetElementSize(int i, int type=0)
Definition: mesh.cpp:43
int SpaceDimension() const
Definition: mesh.hpp:476
void GetBdrElementFace(int i, int *, int *) const
Return the index and the orientation of the face of bdr element i. (3D)
Definition: mesh.cpp:4319
void CheckPartitioning(int *partitioning)
Definition: mesh.cpp:5369
virtual void Print(std::ostream &out=std::cout) const
Print the mesh to the given stream using the default MFEM mesh format.
Definition: mesh.cpp:8332
void PrintElementsWithPartitioning(int *partitioning, std::ostream &out, int interior_faces=0)
Definition: mesh.cpp:8953
void AddPointFaceElement(int lf, int gf, int el)
Used in GenerateFaces()
Definition: mesh.cpp:4599
void Make1D(int n, double sx=1.0)
Creates a 1D mesh for the interval [0,sx] divided into n equal intervals.
Definition: mesh.cpp:1987
double * Data() const
Returns vector of the elements.
Definition: densemat.hpp:77
int GetNumFineElems(int i)
Definition: mesh.cpp:7569
bool IsSlaveFace(const FaceInfo &fi)
Definition: mesh.cpp:690
void Swap(Array< T > &, Array< T > &)
Definition: array.hpp:314
Array< int > bdr_attributes
Definition: mesh.hpp:140
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:6674
void PrintVTK(std::ostream &out)
Print the mesh in VTK format (linear and quadratic meshes only).
Definition: mesh.cpp:8448
Table * el_to_el
Definition: mesh.hpp:99
void SetCoarseElem(Element *ce)
Definition: element.hpp:111
MemAlloc< BisectedElement, 1024 > BEMemory
int GetBisectionHierarchy(Element *E)
Definition: mesh.cpp:7636
virtual void Update()
Definition: fespace.cpp:1511
int SpaceDimension() const
Definition: ncmesh.hpp:79
std::vector< Slave > slaves
Definition: ncmesh.hpp:128
Abstract finite element space.
Definition: fespace.hpp:62
int GetDof() const
Returns the degrees of freedom in the FE space.
Definition: fe.hpp:88
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition: mesh.cpp:9580
static void PrintElement(const Element *, std::ostream &)
Definition: mesh.cpp:2213
virtual void NURBSUniformRefinement()
Refine NURBS mesh.
Definition: mesh.cpp:3487
void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
static void GetElementArrayEdgeTable(const Array< Element * > &elem_array, const DSTable &v_to_v, Table &el_to_edge)
Definition: mesh.cpp:4465
void PrintCharacteristics(Vector *Vh=NULL, Vector *Vk=NULL, std::ostream &out=std::cout)
Definition: mesh.cpp:86
void AddAColumnInRow(int r)
Definition: table.hpp:71
void mfem_error(const char *msg)
Definition: error.cpp:23
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition: mesh.hpp:701
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
Definition: array.hpp:323
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
Definition: mesh.cpp:1322
static const int edges[12][2]
Definition: hexahedron.hpp:28
void SetSubVector(const Array< int > &dofs, const Vector &elemvect)
Definition: vector.cpp:493
int FindRoots(const Vector &z, Vector &x)
Definition: mesh.cpp:5506
void AddQuad(const int *vi, int attr=1)
Definition: mesh.cpp:866
Array< Vertex > vertices
Definition: mesh.hpp:69
int Push4(int r, int c, int f, int t)
Definition: stable3d.cpp:136
void Save(std::ostream &out)
Prints array to stream out.
Definition: array.cpp:80
Helper struct for defining a connectivity table, see Table::MakeFromList.
Definition: table.hpp:24
virtual void QuadUniformRefinement()
Refine quadrilateral mesh.
Definition: mesh.cpp:5919
virtual void HexUniformRefinement()
Refine hexahedral mesh.
Definition: mesh.cpp:6068
Linear3DFiniteElement TetrahedronFE
void Swap(Mesh &other, bool non_geometry=false)
Definition: mesh.cpp:6783
Array< Element * > elements
Definition: mesh.hpp:66
const Table & ElementToElementTable()
Definition: mesh.cpp:4551
double GetLength(int i, int j) const
Return the length of the segment from node i to node j.
Definition: mesh.cpp:4450
void ShiftUpI()
Definition: table.cpp:107
Linear2DFiniteElement TriangleFE
Definition: triangle.cpp:134
void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
int meshgen
Definition: mesh.hpp:59
Table * bel_to_edge
Definition: mesh.hpp:101
virtual int * DofOrderForOrientation(int GeomType, int Or) const =0
void AddBdrTriangle(const int *vi, int attr=1)
Definition: mesh.cpp:913
static FiniteElementCollection * New(const char *name)
Definition: fe_coll.cpp:44
Table * GetFaceToElementTable() const
Definition: mesh.cpp:4247
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
void GetLocalTriToTetTransformation(IsoparametricTransformation &loc, int i)
Used in GetFaceElementTransformations (...)
Definition: mesh.cpp:513
NURBSExtension * NURBSext
Definition: mesh.hpp:142
int GetNV() const
Definition: mesh.hpp:451
void AddBdrQuad(const int *vi, int attr=1)
Definition: mesh.cpp:918
Array< int > be_to_edge
Definition: mesh.hpp:100
virtual const char * Name() const
Definition: fe_coll.hpp:36
const Table & ElementToFaceTable() const
Definition: mesh.cpp:4581
Class for integration point with weight.
Definition: intrules.hpp:25
void RandomRefinement(int levels, int frac=2, bool aniso=false, int nonconforming=-1, int nc_limit=-1, int seed=0)
Refine each element with 1/frac probability, repeat &#39;levels&#39; times.
Definition: mesh.cpp:6938
void UniformRefinement()
Definition: mesh.cpp:6827
Element * ReadElementWithoutAttr(std::istream &)
Definition: mesh.cpp:2172
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Definition: mesh.cpp:4062
void AddTriangle(const int *vi, int attr=1)
Definition: mesh.cpp:861
static const int hex_faces[6][4]
Definition: mesh.hpp:126
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: mesh.cpp:173
void GetLocalSegToQuadTransformation(IsoparametricTransformation &loc, int i)
Definition: mesh.cpp:461
const FiniteElementSpace * GetNodalFESpace()
Definition: mesh.cpp:3731
Table * face_edge
Definition: mesh.hpp:103
void FinalizeQuadMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Definition: mesh.cpp:1020
NodeExtrudeCoefficient(const int dim, const int _n, const double _s)
Definition: mesh.cpp:9831
void ReorderElements(const Array< int > &ordering, bool reorder_vertices=true)
Definition: mesh.cpp:1094
void MakeJ()
Definition: table.cpp:84
Table * edge_vertex
Definition: mesh.hpp:104
void SetFE(const FiniteElement *FE)
Definition: eltrans.hpp:79
void ApplySlaveTransformation(IsoparametricTransformation &transf, const FaceInfo &fi)
Definition: mesh.cpp:695
void Destroy()
Destroy a vector.
Definition: vector.hpp:278
void FindTMax(Vector &c, Vector &x, double &tmax, const double factor, const int Dim)
Definition: mesh.cpp:5653
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement associated with i&#39;th element.
Definition: fespace.cpp:1199
void GetMeshComponents(Array< mfem::Vertex > &vertices, Array< mfem::Element * > &elements, Array< mfem::Element * > &boundary) const
Return the basic Mesh arrays for the current finest level.
Definition: ncmesh.cpp:1344
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
Definition: densemat.cpp:1654
Array< FaceInfo > faces_info
Definition: mesh.hpp:94
virtual int GetNVertices() const =0
void SetAttribute(const int attr)
Set element&#39;s attribute.
Definition: element.hpp:83
void ProjectCoefficient(Coefficient &coeff)
Definition: gridfunc.cpp:1140
STable3D * GetFacesTable()
Definition: mesh.cpp:4806
Piecewise-(bi)quadratic continuous finite elements.
Definition: fe_coll.hpp:283
void Make3D(int nx, int ny, int nz, Element::Type type, int generate_edges, double sx, double sy, double sz)
Definition: mesh.cpp:1649
int Dimension() const
Definition: ncmesh.hpp:78
NCMesh * ncmesh
Definition: mesh.hpp:143
static void PrintElementWithoutAttr(const Element *, std::ostream &)
Definition: mesh.cpp:2189
int GetFineElem(int i, int j)
Definition: mesh.cpp:7751
int Dim
Definition: mesh.hpp:50
void EnsureNCMesh()
Definition: mesh.cpp:6929
double kappa
Definition: ex3.cpp:47
void DofsToVDofs(Array< int > &dofs) const
Definition: fespace.cpp:35
Vector data type.
Definition: vector.hpp:33
Data type point element.
Definition: point.hpp:22
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:178
virtual void Transform(const IntegrationPoint &, Vector &)=0
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:5844
int GetFaceBaseGeometry(int i) const
Definition: mesh.cpp:4348
void AverageVertices(int *indexes, int n, int result)
Definition: mesh.cpp:5892
int NumberOfEntries() const
Definition: table.hpp:223
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:3880
void SetNode(int i, const double *coord)
Definition: mesh.cpp:5812
void GetNode(int i, double *coord)
Definition: mesh.cpp:5793
int * GetI()
Definition: table.hpp:107
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:54
void XYZ_VectorFunction(const Vector &p, Vector &v)
Definition: mesh.cpp:3682
void GenerateFaces()
Definition: mesh.cpp:4688
void GetElementColoring(Array< int > &colors, int el0=0)
Definition: mesh.cpp:8768
int spaceDim
Definition: mesh.hpp:51
void AddTet(const int *vi, int attr=1)
Definition: mesh.cpp:871
virtual const DenseMatrix & Jacobian()=0
Table * GetFaceEdgeTable() const
Returns the face-to-edge Table (3D)
Definition: mesh.cpp:4158
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag)
Definition: tetrahedron.cpp:22
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
Definition: mesh.cpp:1364
void SetNodes(const Vector &node_coord)
Definition: mesh.cpp:5856
virtual int GetRefinementFlag()
Definition: tetrahedron.hpp:54
int RowSize(int i) const
Definition: table.hpp:102
virtual int DofForGeometry(int GeomType) const =0
void SetNodalGridFunction(GridFunction *nodes, bool make_owner=false)
Definition: mesh.cpp:3725
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition: densemat.hpp:71
int NumOfVertices
Definition: mesh.hpp:53
void ScaleSubdomains(double sf)
Definition: mesh.cpp:9391
Array< int > be_to_face
Definition: mesh.hpp:102
virtual void PrintXG(std::ostream &out=std::cout) const
Print the mesh to the given stream using Netgen/Truegrid format.
Definition: mesh.cpp:8168
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
Definition: mesh.cpp:6741
int NumberOfRows() const
Definition: table.hpp:222
void Bisection(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:6991
virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const =0
int index
Mesh number.
Definition: ncmesh.hpp:95
BiLinear2DFiniteElement QuadrilateralFE
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:6864
Abstract data type element.
Definition: element.hpp:27
int GetAttribute(int i) const
Return the attribute of element i.
Definition: mesh.hpp:646
void AddTriangleFaceElement(int lf, int gf, int el, int v0, int v1, int v2)
Definition: mesh.cpp:4646
const Table & ElementToEdgeTable() const
Definition: mesh.cpp:4590
Data type line segment element.
Definition: segment.hpp:22
Linear1DFiniteElement SegmentFE
Definition: segment.cpp:49
int NumberOfElements()
Definition: stable3d.hpp:51
void GenerateNCFaceInfo()
Definition: mesh.cpp:4757
Array< int > RefGeoms
Definition: geom.hpp:81
double GetElementVolume(int i)
Definition: mesh.cpp:70
Array< int > attributes
Definition: mesh.hpp:139
void InitMesh(int _Dim, int _spaceDim, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Definition: mesh.cpp:827
Table * GetVertexToElementTable()
The returned Table must be destroyed by the caller.
Definition: mesh.cpp:4212
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:486
virtual int GetType() const =0
Returns element&#39;s type.
DenseMatrix point_matrix
position within the master
Definition: ncmesh.hpp:118
void UpdateNodes()
Update the nodes of a curved mesh after refinement.
Definition: mesh.cpp:5913
Arbitrary order &quot;L2-conforming&quot; discontinuous finite elements.
Definition: fe_coll.hpp:95
static const int tri_orientations[6][3]
Definition: mesh.hpp:128
Class used to extrude the nodes of a mesh.
Definition: mesh.hpp:871
int NumOfFaces
Definition: mesh.hpp:54