MFEM  v4.5.2
Finite element discretization library
mesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
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 #include "../general/binaryio.hpp"
18 #include "../general/text.hpp"
19 #include "../general/device.hpp"
20 #include "../general/tic_toc.hpp"
21 #include "../general/gecko.hpp"
22 #include "../fem/quadinterpolator.hpp"
23 
24 #include <iostream>
25 #include <sstream>
26 #include <fstream>
27 #include <limits>
28 #include <cmath>
29 #include <cstring>
30 #include <ctime>
31 #include <functional>
32 #include <map>
33 #include <set>
34 
35 // Include the METIS header, if using version 5. If using METIS 4, the needed
36 // declarations are inlined below, i.e. no header is needed.
37 #if defined(MFEM_USE_METIS) && defined(MFEM_USE_METIS_5)
38 #include "metis.h"
39 #endif
40 
41 // METIS 4 prototypes
42 #if defined(MFEM_USE_METIS) && !defined(MFEM_USE_METIS_5)
43 typedef int idx_t;
44 typedef int idxtype;
45 extern "C" {
47  int*, int*, int*, int*, int*, idxtype*);
49  int*, int*, int*, int*, int*, idxtype*);
51  int*, int*, int*, int*, int*, idxtype*);
52 }
53 #endif
54 
55 using namespace std;
56 
57 namespace mfem
58 {
59 
60 void Mesh::GetElementJacobian(int i, DenseMatrix &J)
61 {
62  Geometry::Type geom = GetElementBaseGeometry(i);
63  ElementTransformation *eltransf = GetElementTransformation(i);
64  eltransf->SetIntPoint(&Geometries.GetCenter(geom));
65  Geometries.JacToPerfJac(geom, eltransf->Jacobian(), J);
66 }
67 
68 void Mesh::GetElementCenter(int i, Vector &center)
69 {
70  center.SetSize(spaceDim);
71  int geom = GetElementBaseGeometry(i);
72  ElementTransformation *eltransf = GetElementTransformation(i);
73  eltransf->Transform(Geometries.GetCenter(geom), center);
74 }
75 
76 double Mesh::GetElementSize(ElementTransformation *T, int type)
77 {
78  DenseMatrix J(spaceDim, Dim);
79 
80  Geometry::Type geom = T->GetGeometryType();
81  T->SetIntPoint(&Geometries.GetCenter(geom));
82  Geometries.JacToPerfJac(geom, T->Jacobian(), J);
83 
84  if (type == 0)
85  {
86  return pow(fabs(J.Weight()), 1./Dim);
87  }
88  else if (type == 1)
89  {
90  return J.CalcSingularvalue(Dim-1); // h_min
91  }
92  else
93  {
94  return J.CalcSingularvalue(0); // h_max
95  }
96 }
97 
98 double Mesh::GetElementSize(int i, int type)
99 {
100  return GetElementSize(GetElementTransformation(i), type);
101 }
102 
103 double Mesh::GetElementSize(int i, const Vector &dir)
104 {
105  DenseMatrix J(spaceDim, Dim);
106  Vector d_hat(Dim);
107  GetElementJacobian(i, J);
108  J.MultTranspose(dir, d_hat);
109  return sqrt((d_hat * d_hat) / (dir * dir));
110 }
111 
112 double Mesh::GetElementVolume(int i)
113 {
114  ElementTransformation *et = GetElementTransformation(i);
115  const IntegrationRule &ir = IntRules.Get(GetElementBaseGeometry(i),
116  et->OrderJ());
117  double volume = 0.0;
118  for (int j = 0; j < ir.GetNPoints(); j++)
119  {
120  const IntegrationPoint &ip = ir.IntPoint(j);
121  et->SetIntPoint(&ip);
122  volume += ip.weight * et->Weight();
123  }
124 
125  return volume;
126 }
127 
128 // Similar to VisualizationSceneSolution3d::FindNewBox in GLVis
129 void Mesh::GetBoundingBox(Vector &min, Vector &max, int ref)
130 {
131  min.SetSize(spaceDim);
132  max.SetSize(spaceDim);
133 
134  for (int d = 0; d < spaceDim; d++)
135  {
136  min(d) = infinity();
137  max(d) = -infinity();
138  }
139 
140  if (Nodes == NULL)
141  {
142  double *coord;
143  for (int i = 0; i < NumOfVertices; i++)
144  {
145  coord = GetVertex(i);
146  for (int d = 0; d < spaceDim; d++)
147  {
148  if (coord[d] < min(d)) { min(d) = coord[d]; }
149  if (coord[d] > max(d)) { max(d) = coord[d]; }
150  }
151  }
152  }
153  else
154  {
155  const bool use_boundary = false; // make this a parameter?
156  int ne = use_boundary ? GetNBE() : GetNE();
157  int fn, fo;
158  DenseMatrix pointmat;
159  RefinedGeometry *RefG;
160  IntegrationRule eir;
163 
164  for (int i = 0; i < ne; i++)
165  {
166  if (use_boundary)
167  {
168  GetBdrElementFace(i, &fn, &fo);
169  RefG = GlobGeometryRefiner.Refine(GetFaceGeometry(fn), ref);
170  Tr = GetFaceElementTransformations(fn, 5);
171  eir.SetSize(RefG->RefPts.GetNPoints());
172  Tr->Loc1.Transform(RefG->RefPts, eir);
173  Tr->Elem1->Transform(eir, pointmat);
174  }
175  else
176  {
177  T = GetElementTransformation(i);
178  RefG = GlobGeometryRefiner.Refine(GetElementBaseGeometry(i), ref);
179  T->Transform(RefG->RefPts, pointmat);
180  }
181  for (int j = 0; j < pointmat.Width(); j++)
182  {
183  for (int d = 0; d < pointmat.Height(); d++)
184  {
185  if (pointmat(d,j) < min(d)) { min(d) = pointmat(d,j); }
186  if (pointmat(d,j) > max(d)) { max(d) = pointmat(d,j); }
187  }
188  }
189  }
190  }
191 }
192 
193 void Mesh::GetCharacteristics(double &h_min, double &h_max,
194  double &kappa_min, double &kappa_max,
195  Vector *Vh, Vector *Vk)
196 {
197  int i, dim, sdim;
198  DenseMatrix J;
199  double h, kappa;
200 
201  dim = Dimension();
202  sdim = SpaceDimension();
203 
204  if (Vh) { Vh->SetSize(NumOfElements); }
205  if (Vk) { Vk->SetSize(NumOfElements); }
206 
207  h_min = kappa_min = infinity();
208  h_max = kappa_max = -h_min;
209  if (dim == 0) { if (Vh) { *Vh = 1.0; } if (Vk) {*Vk = 1.0; } return; }
210  J.SetSize(sdim, dim);
211  for (i = 0; i < NumOfElements; i++)
212  {
213  GetElementJacobian(i, J);
214  h = pow(fabs(J.Weight()), 1.0/double(dim));
215  kappa = (dim == sdim) ?
216  J.CalcSingularvalue(0) / J.CalcSingularvalue(dim-1) : -1.0;
217  if (Vh) { (*Vh)(i) = h; }
218  if (Vk) { (*Vk)(i) = kappa; }
219 
220  if (h < h_min) { h_min = h; }
221  if (h > h_max) { h_max = h; }
222  if (kappa < kappa_min) { kappa_min = kappa; }
223  if (kappa > kappa_max) { kappa_max = kappa; }
224  }
225 }
226 
227 // static method
228 void Mesh::PrintElementsByGeometry(int dim,
229  const Array<int> &num_elems_by_geom,
230  std::ostream &os)
231 {
232  for (int g = Geometry::DimStart[dim], first = 1;
233  g < Geometry::DimStart[dim+1]; g++)
234  {
235  if (!num_elems_by_geom[g]) { continue; }
236  if (!first) { os << " + "; }
237  else { first = 0; }
238  os << num_elems_by_geom[g] << ' ' << Geometry::Name[g] << "(s)";
239  }
240 }
241 
242 void Mesh::PrintCharacteristics(Vector *Vh, Vector *Vk, std::ostream &os)
243 {
244  double h_min, h_max, kappa_min, kappa_max;
245 
246  os << "Mesh Characteristics:";
247 
248  this->GetCharacteristics(h_min, h_max, kappa_min, kappa_max, Vh, Vk);
249 
250  Array<int> num_elems_by_geom(Geometry::NumGeom);
251  num_elems_by_geom = 0;
252  for (int i = 0; i < GetNE(); i++)
253  {
254  num_elems_by_geom[GetElementBaseGeometry(i)]++;
255  }
256 
257  os << '\n'
258  << "Dimension : " << Dimension() << '\n'
259  << "Space dimension : " << SpaceDimension();
260  if (Dim == 0)
261  {
262  os << '\n'
263  << "Number of vertices : " << GetNV() << '\n'
264  << "Number of elements : " << GetNE() << '\n'
265  << "Number of bdr elem : " << GetNBE() << '\n';
266  }
267  else if (Dim == 1)
268  {
269  os << '\n'
270  << "Number of vertices : " << GetNV() << '\n'
271  << "Number of elements : " << GetNE() << '\n'
272  << "Number of bdr elem : " << GetNBE() << '\n'
273  << "h_min : " << h_min << '\n'
274  << "h_max : " << h_max << '\n';
275  }
276  else if (Dim == 2)
277  {
278  os << '\n'
279  << "Number of vertices : " << GetNV() << '\n'
280  << "Number of edges : " << GetNEdges() << '\n'
281  << "Number of elements : " << GetNE() << " -- ";
282  PrintElementsByGeometry(2, num_elems_by_geom, os);
283  os << '\n'
284  << "Number of bdr elem : " << GetNBE() << '\n'
285  << "Euler Number : " << EulerNumber2D() << '\n'
286  << "h_min : " << h_min << '\n'
287  << "h_max : " << h_max << '\n'
288  << "kappa_min : " << kappa_min << '\n'
289  << "kappa_max : " << kappa_max << '\n';
290  }
291  else
292  {
293  Array<int> num_bdr_elems_by_geom(Geometry::NumGeom);
294  num_bdr_elems_by_geom = 0;
295  for (int i = 0; i < GetNBE(); i++)
296  {
297  num_bdr_elems_by_geom[GetBdrElementBaseGeometry(i)]++;
298  }
299  Array<int> num_faces_by_geom(Geometry::NumGeom);
300  num_faces_by_geom = 0;
301  for (int i = 0; i < GetNFaces(); i++)
302  {
303  num_faces_by_geom[GetFaceGeometry(i)]++;
304  }
305 
306  os << '\n'
307  << "Number of vertices : " << GetNV() << '\n'
308  << "Number of edges : " << GetNEdges() << '\n'
309  << "Number of faces : " << GetNFaces() << " -- ";
310  PrintElementsByGeometry(Dim-1, num_faces_by_geom, os);
311  os << '\n'
312  << "Number of elements : " << GetNE() << " -- ";
313  PrintElementsByGeometry(Dim, num_elems_by_geom, os);
314  os << '\n'
315  << "Number of bdr elem : " << GetNBE() << " -- ";
316  PrintElementsByGeometry(Dim-1, num_bdr_elems_by_geom, os);
317  os << '\n'
318  << "Euler Number : " << EulerNumber() << '\n'
319  << "h_min : " << h_min << '\n'
320  << "h_max : " << h_max << '\n'
321  << "kappa_min : " << kappa_min << '\n'
322  << "kappa_max : " << kappa_max << '\n';
323  }
324  os << '\n' << std::flush;
325 }
326 
327 FiniteElement *Mesh::GetTransformationFEforElementType(Element::Type ElemType)
328 {
329  switch (ElemType)
330  {
331  case Element::POINT : return &PointFE;
332  case Element::SEGMENT : return &SegmentFE;
333  case Element::TRIANGLE : return &TriangleFE;
334  case Element::QUADRILATERAL : return &QuadrilateralFE;
335  case Element::TETRAHEDRON : return &TetrahedronFE;
336  case Element::HEXAHEDRON : return &HexahedronFE;
337  case Element::WEDGE : return &WedgeFE;
338  case Element::PYRAMID : return &PyramidFE;
339  default:
340  MFEM_ABORT("Unknown element type \"" << ElemType << "\"");
341  break;
342  }
343  MFEM_ABORT("Unknown element type");
344  return NULL;
345 }
346 
347 
348 void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr)
349 {
350  ElTr->Attribute = GetAttribute(i);
351  ElTr->ElementNo = i;
352  ElTr->ElementType = ElementTransformation::ELEMENT;
353  ElTr->mesh = this;
354  ElTr->Reset();
355  if (Nodes == NULL)
356  {
357  GetPointMatrix(i, ElTr->GetPointMat());
358  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
359  }
360  else
361  {
362  DenseMatrix &pm = ElTr->GetPointMat();
363  Array<int> vdofs;
364  Nodes->FESpace()->GetElementVDofs(i, vdofs);
365  Nodes->HostRead();
366  const GridFunction &nodes = *Nodes;
367  int n = vdofs.Size()/spaceDim;
368  pm.SetSize(spaceDim, n);
369  for (int k = 0; k < spaceDim; k++)
370  {
371  for (int j = 0; j < n; j++)
372  {
373  pm(k,j) = nodes(vdofs[n*k+j]);
374  }
375  }
376  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
377  }
378 }
379 
380 void Mesh::GetElementTransformation(int i, const Vector &nodes,
382 {
383  ElTr->Attribute = GetAttribute(i);
384  ElTr->ElementNo = i;
385  ElTr->ElementType = ElementTransformation::ELEMENT;
386  ElTr->mesh = this;
387  DenseMatrix &pm = ElTr->GetPointMat();
388  ElTr->Reset();
389  nodes.HostRead();
390  if (Nodes == NULL)
391  {
392  MFEM_ASSERT(nodes.Size() == spaceDim*GetNV(), "");
393  int nv = elements[i]->GetNVertices();
394  const int *v = elements[i]->GetVertices();
395  int n = vertices.Size();
396  pm.SetSize(spaceDim, nv);
397  for (int k = 0; k < spaceDim; k++)
398  {
399  for (int j = 0; j < nv; j++)
400  {
401  pm(k, j) = nodes(k*n+v[j]);
402  }
403  }
404  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
405  }
406  else
407  {
408  MFEM_ASSERT(nodes.Size() == Nodes->Size(), "");
409  Array<int> vdofs;
410  Nodes->FESpace()->GetElementVDofs(i, vdofs);
411  int n = vdofs.Size()/spaceDim;
412  pm.SetSize(spaceDim, n);
413  for (int k = 0; k < spaceDim; k++)
414  {
415  for (int j = 0; j < n; j++)
416  {
417  pm(k,j) = nodes(vdofs[n*k+j]);
418  }
419  }
420  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
421  }
422 }
423 
424 ElementTransformation *Mesh::GetElementTransformation(int i)
425 {
426  GetElementTransformation(i, &Transformation);
427 
428  return &Transformation;
429 }
430 
431 ElementTransformation *Mesh::GetBdrElementTransformation(int i)
432 {
433  GetBdrElementTransformation(i, &BdrTransformation);
434  return &BdrTransformation;
435 }
436 
437 void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr)
438 {
439  ElTr->Attribute = GetBdrAttribute(i);
440  ElTr->ElementNo = i; // boundary element number
441  ElTr->ElementType = ElementTransformation::BDR_ELEMENT;
442  ElTr->mesh = this;
443  DenseMatrix &pm = ElTr->GetPointMat();
444  ElTr->Reset();
445  if (Nodes == NULL)
446  {
447  GetBdrPointMatrix(i, pm);
448  ElTr->SetFE(GetTransformationFEforElementType(GetBdrElementType(i)));
449  }
450  else
451  {
452  const FiniteElement *bdr_el = Nodes->FESpace()->GetBE(i);
453  Nodes->HostRead();
454  const GridFunction &nodes = *Nodes;
455  if (bdr_el)
456  {
457  Array<int> vdofs;
458  Nodes->FESpace()->GetBdrElementVDofs(i, vdofs);
459  int n = vdofs.Size()/spaceDim;
460  pm.SetSize(spaceDim, n);
461  for (int k = 0; k < spaceDim; k++)
462  {
463  for (int j = 0; j < n; j++)
464  {
465  pm(k,j) = nodes(vdofs[n*k+j]);
466  }
467  }
468  ElTr->SetFE(bdr_el);
469  }
470  else // L2 Nodes (e.g., periodic mesh)
471  {
472  int elem_id, face_info;
473  GetBdrElementAdjacentElement2(i, elem_id, face_info);
474 
475  GetLocalFaceTransformation(GetBdrElementType(i),
476  GetElementType(elem_id),
477  FaceElemTr.Loc1.Transf, face_info);
478  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
479 
480  Geometry::Type face_geom = GetBdrElementBaseGeometry(i);
481  const FiniteElement *face_el =
482  Nodes->FESpace()->GetTraceElement(elem_id, face_geom);
483  MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
484  "Mesh requires nodal Finite Element.");
485  IntegrationRule eir(face_el->GetDof());
486  FaceElemTr.Loc1.Transf.ElementNo = elem_id;
487  FaceElemTr.Loc1.Transf.mesh = this;
488  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
489  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
490  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
491 
492  ElTr->SetFE(face_el);
493  }
494  }
495 }
496 
497 void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr)
498 {
499  FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute();
500  FTr->ElementNo = FaceNo;
501  FTr->ElementType = ElementTransformation::FACE;
502  FTr->mesh = this;
503  DenseMatrix &pm = FTr->GetPointMat();
504  FTr->Reset();
505  if (Nodes == NULL)
506  {
507  const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
508  const int nv = (Dim == 1) ? 1 : faces[FaceNo]->GetNVertices();
509  pm.SetSize(spaceDim, nv);
510  for (int i = 0; i < spaceDim; i++)
511  {
512  for (int j = 0; j < nv; j++)
513  {
514  pm(i, j) = vertices[v[j]](i);
515  }
516  }
517  FTr->SetFE(GetTransformationFEforElementType(GetFaceElementType(FaceNo)));
518  }
519  else // curved mesh
520  {
521  const FiniteElement *face_el = Nodes->FESpace()->GetFaceElement(FaceNo);
522  Nodes->HostRead();
523  const GridFunction &nodes = *Nodes;
524  if (face_el)
525  {
526  Array<int> vdofs;
527  Nodes->FESpace()->GetFaceVDofs(FaceNo, vdofs);
528  int n = vdofs.Size()/spaceDim;
529  pm.SetSize(spaceDim, n);
530  for (int i = 0; i < spaceDim; i++)
531  {
532  for (int j = 0; j < n; j++)
533  {
534  pm(i, j) = nodes(vdofs[n*i+j]);
535  }
536  }
537  FTr->SetFE(face_el);
538  }
539  else // L2 Nodes (e.g., periodic mesh), go through the volume of Elem1
540  {
541  FaceInfo &face_info = faces_info[FaceNo];
542 
543  Geometry::Type face_geom = GetFaceGeometry(FaceNo);
544  Element::Type face_type = GetFaceElementType(FaceNo);
545 
546  GetLocalFaceTransformation(face_type,
547  GetElementType(face_info.Elem1No),
548  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
549  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
550 
551  face_el = Nodes->FESpace()->GetTraceElement(face_info.Elem1No,
552  face_geom);
553  MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
554  "Mesh requires nodal Finite Element.");
555 
556  IntegrationRule eir(face_el->GetDof());
557  FaceElemTr.Loc1.Transf.ElementNo = face_info.Elem1No;
558  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
559  FaceElemTr.Loc1.Transf.mesh = this;
560  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
561  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
562 
563  FTr->SetFE(face_el);
564  }
565  }
566 }
567 
568 ElementTransformation *Mesh::GetFaceTransformation(int FaceNo)
569 {
570  GetFaceTransformation(FaceNo, &FaceTransformation);
571  return &FaceTransformation;
572 }
573 
574 void Mesh::GetEdgeTransformation(int EdgeNo, IsoparametricTransformation *EdTr)
575 {
576  if (Dim == 2)
577  {
578  GetFaceTransformation(EdgeNo, EdTr);
579  return;
580  }
581  if (Dim == 1)
582  {
583  mfem_error("Mesh::GetEdgeTransformation not defined in 1D \n");
584  }
585 
586  EdTr->Attribute = 1;
587  EdTr->ElementNo = EdgeNo;
588  EdTr->ElementType = ElementTransformation::EDGE;
589  EdTr->mesh = this;
590  DenseMatrix &pm = EdTr->GetPointMat();
591  EdTr->Reset();
592  if (Nodes == NULL)
593  {
594  Array<int> v;
595  GetEdgeVertices(EdgeNo, v);
596  const int nv = 2;
597  pm.SetSize(spaceDim, nv);
598  for (int i = 0; i < spaceDim; i++)
599  {
600  for (int j = 0; j < nv; j++)
601  {
602  pm(i, j) = vertices[v[j]](i);
603  }
604  }
605  EdTr->SetFE(GetTransformationFEforElementType(Element::SEGMENT));
606  }
607  else
608  {
609  const FiniteElement *edge_el = Nodes->FESpace()->GetEdgeElement(EdgeNo);
610  Nodes->HostRead();
611  const GridFunction &nodes = *Nodes;
612  if (edge_el)
613  {
614  Array<int> vdofs;
615  Nodes->FESpace()->GetEdgeVDofs(EdgeNo, vdofs);
616  int n = vdofs.Size()/spaceDim;
617  pm.SetSize(spaceDim, n);
618  for (int i = 0; i < spaceDim; i++)
619  {
620  for (int j = 0; j < n; j++)
621  {
622  pm(i, j) = nodes(vdofs[n*i+j]);
623  }
624  }
625  EdTr->SetFE(edge_el);
626  }
627  else
628  {
629  MFEM_ABORT("Not implemented.");
630  }
631  }
632 }
633 
634 ElementTransformation *Mesh::GetEdgeTransformation(int EdgeNo)
635 {
636  GetEdgeTransformation(EdgeNo, &EdgeTransformation);
637  return &EdgeTransformation;
638 }
639 
640 
641 void Mesh::GetLocalPtToSegTransformation(
642  IsoparametricTransformation &Transf, int i)
643 {
644  const IntegrationRule *SegVert;
645  DenseMatrix &locpm = Transf.GetPointMat();
646  Transf.Reset();
647 
648  Transf.SetFE(&PointFE);
649  SegVert = Geometries.GetVertices(Geometry::SEGMENT);
650  locpm.SetSize(1, 1);
651  locpm(0, 0) = SegVert->IntPoint(i/64).x;
652  // (i/64) is the local face no. in the segment
653  // (i%64) is the orientation of the point (not used)
654 }
655 
656 void Mesh::GetLocalSegToTriTransformation(
657  IsoparametricTransformation &Transf, int i)
658 {
659  const int *tv, *so;
660  const IntegrationRule *TriVert;
661  DenseMatrix &locpm = Transf.GetPointMat();
662  Transf.Reset();
663 
664  Transf.SetFE(&SegmentFE);
665  tv = tri_t::Edges[i/64]; // (i/64) is the local face no. in the triangle
666  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
667  TriVert = Geometries.GetVertices(Geometry::TRIANGLE);
668  locpm.SetSize(2, 2);
669  for (int j = 0; j < 2; j++)
670  {
671  locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x;
672  locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y;
673  }
674 }
675 
676 void Mesh::GetLocalSegToQuadTransformation(
677  IsoparametricTransformation &Transf, int i)
678 {
679  const int *qv, *so;
680  const IntegrationRule *QuadVert;
681  DenseMatrix &locpm = Transf.GetPointMat();
682  Transf.Reset();
683 
684  Transf.SetFE(&SegmentFE);
685  qv = quad_t::Edges[i/64]; // (i/64) is the local face no. in the quad
686  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
687  QuadVert = Geometries.GetVertices(Geometry::SQUARE);
688  locpm.SetSize(2, 2);
689  for (int j = 0; j < 2; j++)
690  {
691  locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x;
692  locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y;
693  }
694 }
695 
696 void Mesh::GetLocalTriToTetTransformation(
697  IsoparametricTransformation &Transf, int i)
698 {
699  DenseMatrix &locpm = Transf.GetPointMat();
700  Transf.Reset();
701 
702  Transf.SetFE(&TriangleFE);
703  // (i/64) is the local face no. in the tet
704  const int *tv = tet_t::FaceVert[i/64];
705  // (i%64) is the orientation of the tetrahedron face
706  // w.r.t. the face element
707  const int *to = tri_t::Orient[i%64];
708  const IntegrationRule *TetVert =
709  Geometries.GetVertices(Geometry::TETRAHEDRON);
710  locpm.SetSize(3, 3);
711  for (int j = 0; j < 3; j++)
712  {
713  const IntegrationPoint &vert = TetVert->IntPoint(tv[to[j]]);
714  locpm(0, j) = vert.x;
715  locpm(1, j) = vert.y;
716  locpm(2, j) = vert.z;
717  }
718 }
719 
720 void Mesh::GetLocalTriToWdgTransformation(
721  IsoparametricTransformation &Transf, int i)
722 {
723  DenseMatrix &locpm = Transf.GetPointMat();
724  Transf.Reset();
725 
726  Transf.SetFE(&TriangleFE);
727  // (i/64) is the local face no. in the pri
728  MFEM_VERIFY(i < 128, "Local face index " << i/64
729  << " is not a triangular face of a wedge.");
730  const int *pv = pri_t::FaceVert[i/64];
731  // (i%64) is the orientation of the wedge face
732  // w.r.t. the face element
733  const int *to = tri_t::Orient[i%64];
734  const IntegrationRule *PriVert =
735  Geometries.GetVertices(Geometry::PRISM);
736  locpm.SetSize(3, 3);
737  for (int j = 0; j < 3; j++)
738  {
739  const IntegrationPoint &vert = PriVert->IntPoint(pv[to[j]]);
740  locpm(0, j) = vert.x;
741  locpm(1, j) = vert.y;
742  locpm(2, j) = vert.z;
743  }
744 }
745 
746 void Mesh::GetLocalTriToPyrTransformation(
747  IsoparametricTransformation &Transf, int i)
748 {
749  DenseMatrix &locpm = Transf.GetPointMat();
750 
751  Transf.SetFE(&TriangleFE);
752  // (i/64) is the local face no. in the pyr
753  MFEM_VERIFY(i >= 64, "Local face index " << i/64
754  << " is not a triangular face of a pyramid.");
755  const int *pv = pyr_t::FaceVert[i/64];
756  // (i%64) is the orientation of the pyramid face
757  // w.r.t. the face element
758  const int *to = tri_t::Orient[i%64];
759  const IntegrationRule *PyrVert =
760  Geometries.GetVertices(Geometry::PYRAMID);
761  locpm.SetSize(3, 3);
762  for (int j = 0; j < 3; j++)
763  {
764  const IntegrationPoint &vert = PyrVert->IntPoint(pv[to[j]]);
765  locpm(0, j) = vert.x;
766  locpm(1, j) = vert.y;
767  locpm(2, j) = vert.z;
768  }
769 }
770 
771 void Mesh::GetLocalQuadToHexTransformation(
772  IsoparametricTransformation &Transf, int i)
773 {
774  DenseMatrix &locpm = Transf.GetPointMat();
775  Transf.Reset();
776 
777  Transf.SetFE(&QuadrilateralFE);
778  // (i/64) is the local face no. in the hex
779  const int *hv = hex_t::FaceVert[i/64];
780  // (i%64) is the orientation of the quad
781  const int *qo = quad_t::Orient[i%64];
782  const IntegrationRule *HexVert = Geometries.GetVertices(Geometry::CUBE);
783  locpm.SetSize(3, 4);
784  for (int j = 0; j < 4; j++)
785  {
786  const IntegrationPoint &vert = HexVert->IntPoint(hv[qo[j]]);
787  locpm(0, j) = vert.x;
788  locpm(1, j) = vert.y;
789  locpm(2, j) = vert.z;
790  }
791 }
792 
793 void Mesh::GetLocalQuadToWdgTransformation(
794  IsoparametricTransformation &Transf, int i)
795 {
796  DenseMatrix &locpm = Transf.GetPointMat();
797  Transf.Reset();
798 
799  Transf.SetFE(&QuadrilateralFE);
800  // (i/64) is the local face no. in the pri
801  MFEM_VERIFY(i >= 128, "Local face index " << i/64
802  << " is not a quadrilateral face of a wedge.");
803  const int *pv = pri_t::FaceVert[i/64];
804  // (i%64) is the orientation of the quad
805  const int *qo = quad_t::Orient[i%64];
806  const IntegrationRule *PriVert = Geometries.GetVertices(Geometry::PRISM);
807  locpm.SetSize(3, 4);
808  for (int j = 0; j < 4; j++)
809  {
810  const IntegrationPoint &vert = PriVert->IntPoint(pv[qo[j]]);
811  locpm(0, j) = vert.x;
812  locpm(1, j) = vert.y;
813  locpm(2, j) = vert.z;
814  }
815 }
816 
817 void Mesh::GetLocalQuadToPyrTransformation(
818  IsoparametricTransformation &Transf, int i)
819 {
820  DenseMatrix &locpm = Transf.GetPointMat();
821 
822  Transf.SetFE(&QuadrilateralFE);
823  // (i/64) is the local face no. in the pyr
824  MFEM_VERIFY(i < 64, "Local face index " << i/64
825  << " is not a quadrilateral face of a pyramid.");
826  const int *pv = pyr_t::FaceVert[i/64];
827  // (i%64) is the orientation of the quad
828  const int *qo = quad_t::Orient[i%64];
829  const IntegrationRule *PyrVert = Geometries.GetVertices(Geometry::PYRAMID);
830  locpm.SetSize(3, 4);
831  for (int j = 0; j < 4; j++)
832  {
833  const IntegrationPoint &vert = PyrVert->IntPoint(pv[qo[j]]);
834  locpm(0, j) = vert.x;
835  locpm(1, j) = vert.y;
836  locpm(2, j) = vert.z;
837  }
838 }
839 
840 const GeometricFactors* Mesh::GetGeometricFactors(const IntegrationRule& ir,
841  const int flags,
842  MemoryType d_mt)
843 {
844  for (int i = 0; i < geom_factors.Size(); i++)
845  {
846  GeometricFactors *gf = geom_factors[i];
847  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags)
848  {
849  return gf;
850  }
851  }
852 
853  this->EnsureNodes();
854 
855  GeometricFactors *gf = new GeometricFactors(this, ir, flags, d_mt);
856  geom_factors.Append(gf);
857  return gf;
858 }
859 
860 const FaceGeometricFactors* Mesh::GetFaceGeometricFactors(
861  const IntegrationRule& ir,
862  const int flags, FaceType type, MemoryType d_mt)
863 {
864  for (int i = 0; i < face_geom_factors.Size(); i++)
865  {
866  FaceGeometricFactors *gf = face_geom_factors[i];
867  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags &&
868  gf->type==type)
869  {
870  return gf;
871  }
872  }
873 
874  this->EnsureNodes();
875 
876  FaceGeometricFactors *gf = new FaceGeometricFactors(this, ir, flags, type,
877  d_mt);
878  face_geom_factors.Append(gf);
879  return gf;
880 }
881 
882 void Mesh::DeleteGeometricFactors()
883 {
884  for (int i = 0; i < geom_factors.Size(); i++)
885  {
886  delete geom_factors[i];
887  }
888  geom_factors.SetSize(0);
889  for (int i = 0; i < face_geom_factors.Size(); i++)
890  {
891  delete face_geom_factors[i];
892  }
893  face_geom_factors.SetSize(0);
894 }
895 
896 void Mesh::GetLocalFaceTransformation(
897  int face_type, int elem_type, IsoparametricTransformation &Transf, int info)
898 {
899  switch (face_type)
900  {
901  case Element::POINT:
902  GetLocalPtToSegTransformation(Transf, info);
903  break;
904 
905  case Element::SEGMENT:
906  if (elem_type == Element::TRIANGLE)
907  {
908  GetLocalSegToTriTransformation(Transf, info);
909  }
910  else
911  {
912  MFEM_ASSERT(elem_type == Element::QUADRILATERAL, "");
913  GetLocalSegToQuadTransformation(Transf, info);
914  }
915  break;
916 
917  case Element::TRIANGLE:
918  if (elem_type == Element::TETRAHEDRON)
919  {
920  GetLocalTriToTetTransformation(Transf, info);
921  }
922  else if (elem_type == Element::WEDGE)
923  {
924  GetLocalTriToWdgTransformation(Transf, info);
925  }
926  else if (elem_type == Element::PYRAMID)
927  {
928  GetLocalTriToPyrTransformation(Transf, info);
929  }
930  else
931  {
932  MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
933  "face type " << face_type
934  << " and element type " << elem_type << "\n");
935  }
936  break;
937 
938  case Element::QUADRILATERAL:
939  if (elem_type == Element::HEXAHEDRON)
940  {
941  GetLocalQuadToHexTransformation(Transf, info);
942  }
943  else if (elem_type == Element::WEDGE)
944  {
945  GetLocalQuadToWdgTransformation(Transf, info);
946  }
947  else if (elem_type == Element::PYRAMID)
948  {
949  GetLocalQuadToPyrTransformation(Transf, info);
950  }
951  else
952  {
953  MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
954  "face type " << face_type
955  << " and element type " << elem_type << "\n");
956  }
957  break;
958  }
959 }
960 
961 FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo,
962  int mask)
963 {
964  FaceInfo &face_info = faces_info[FaceNo];
965 
966  int cmask = 0;
967  FaceElemTr.SetConfigurationMask(cmask);
968  FaceElemTr.Elem1 = NULL;
969  FaceElemTr.Elem2 = NULL;
970 
971  // setup the transformation for the first element
972  FaceElemTr.Elem1No = face_info.Elem1No;
973  if (mask & FaceElementTransformations::HAVE_ELEM1)
974  {
975  GetElementTransformation(FaceElemTr.Elem1No, &Transformation);
976  FaceElemTr.Elem1 = &Transformation;
977  cmask |= 1;
978  }
979 
980  // setup the transformation for the second element
981  // return NULL in the Elem2 field if there's no second element, i.e.
982  // the face is on the "boundary"
983  FaceElemTr.Elem2No = face_info.Elem2No;
984  if ((mask & FaceElementTransformations::HAVE_ELEM2) &&
985  FaceElemTr.Elem2No >= 0)
986  {
987 #ifdef MFEM_DEBUG
988  if (NURBSext && (mask & FaceElementTransformations::HAVE_ELEM1))
989  { MFEM_ABORT("NURBS mesh not supported!"); }
990 #endif
991  GetElementTransformation(FaceElemTr.Elem2No, &Transformation2);
992  FaceElemTr.Elem2 = &Transformation2;
993  cmask |= 2;
994  }
995 
996  // setup the face transformation
997  if (mask & FaceElementTransformations::HAVE_FACE)
998  {
999  GetFaceTransformation(FaceNo, &FaceElemTr);
1000  cmask |= 16;
1001  }
1002  else
1003  {
1004  FaceElemTr.SetGeometryType(GetFaceGeometry(FaceNo));
1005  }
1006 
1007  // setup Loc1 & Loc2
1008  int face_type = GetFaceElementType(FaceNo);
1009  if (mask & FaceElementTransformations::HAVE_LOC1)
1010  {
1011  int elem_type = GetElementType(face_info.Elem1No);
1012  GetLocalFaceTransformation(face_type, elem_type,
1013  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
1014  cmask |= 4;
1015  }
1016  if ((mask & FaceElementTransformations::HAVE_LOC2) &&
1017  FaceElemTr.Elem2No >= 0)
1018  {
1019  int elem_type = GetElementType(face_info.Elem2No);
1020  GetLocalFaceTransformation(face_type, elem_type,
1021  FaceElemTr.Loc2.Transf, face_info.Elem2Inf);
1022 
1023  // NC meshes: prepend slave edge/face transformation to Loc2
1024  if (Nonconforming() && IsSlaveFace(face_info))
1025  {
1026  ApplyLocalSlaveTransformation(FaceElemTr, face_info, false);
1027  }
1028  cmask |= 8;
1029  }
1030 
1031  FaceElemTr.SetConfigurationMask(cmask);
1032 
1033  // This check can be useful for internal debugging, however it will fail on
1034  // periodic boundary faces, so we keep it disabled in general.
1035 #if 0
1036 #ifdef MFEM_DEBUG
1037  double dist = FaceElemTr.CheckConsistency();
1038  if (dist >= 1e-12)
1039  {
1040  mfem::out << "\nInternal error: face id = " << FaceNo
1041  << ", dist = " << dist << '\n';
1042  FaceElemTr.CheckConsistency(1); // print coordinates
1043  MFEM_ABORT("internal error");
1044  }
1045 #endif
1046 #endif
1047 
1048  return &FaceElemTr;
1049 }
1050 
1051 bool Mesh::IsSlaveFace(const FaceInfo &fi) const
1052 {
1053  return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
1054 }
1055 
1056 void Mesh::ApplyLocalSlaveTransformation(FaceElementTransformations &FT,
1057  const FaceInfo &fi, bool is_ghost)
1058 {
1059 #ifdef MFEM_THREAD_SAFE
1060  DenseMatrix composition;
1061 #else
1062  static DenseMatrix composition;
1063 #endif
1064  MFEM_ASSERT(fi.NCFace >= 0, "");
1065  MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error");
1066  if (!is_ghost)
1067  {
1068  // side 1 -> child side, side 2 -> parent side
1070  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1071  // In 2D, we need to flip the point matrix since it is aligned with the
1072  // parent side.
1073  if (Dim == 2)
1074  {
1075  // swap points (columns) 0 and 1
1076  std::swap(composition(0,0), composition(0,1));
1077  std::swap(composition(1,0), composition(1,1));
1078  }
1079  LT.SetPointMat(composition);
1080  }
1081  else // is_ghost == true
1082  {
1083  // side 1 -> parent side, side 2 -> child side
1085  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1086  // In 2D, there is no need to flip the point matrix since it is already
1087  // aligned with the parent side, see also ParNCMesh::GetFaceNeighbors.
1088  // In 3D the point matrix was flipped during construction in
1089  // ParNCMesh::GetFaceNeighbors and due to that it is already aligned with
1090  // the parent side.
1091  LT.SetPointMat(composition);
1092  }
1093 }
1094 
1095 FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
1096 {
1098  int fn = GetBdrFace(BdrElemNo);
1099 
1100  // Check if the face is interior, shared, or nonconforming.
1101  if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
1102  {
1103  return NULL;
1104  }
1105  tr = GetFaceElementTransformations(fn, 21);
1106  tr->Attribute = boundary[BdrElemNo]->GetAttribute();
1107  tr->ElementNo = BdrElemNo;
1108  tr->ElementType = ElementTransformation::BDR_FACE;
1109  tr->mesh = this;
1110  return tr;
1111 }
1112 
1113 int Mesh::GetBdrFace(int BdrElemNo) const
1114 {
1115  int fn;
1116  if (Dim == 3)
1117  {
1118  fn = be_to_face[BdrElemNo];
1119  }
1120  else if (Dim == 2)
1121  {
1122  fn = be_to_edge[BdrElemNo];
1123  }
1124  else
1125  {
1126  fn = boundary[BdrElemNo]->GetVertices()[0];
1127  }
1128  return fn;
1129 }
1130 
1131 Mesh::FaceInformation Mesh::GetFaceInformation(int f) const
1132 {
1133  FaceInformation face;
1134  int e1, e2;
1135  int inf1, inf2;
1136  int ncface;
1137  GetFaceElements(f, &e1, &e2);
1138  GetFaceInfos(f, &inf1, &inf2, &ncface);
1139  face.element[0].index = e1;
1140  face.element[0].location = ElementLocation::Local;
1141  face.element[0].orientation = inf1%64;
1142  face.element[0].local_face_id = inf1/64;
1143  face.element[1].local_face_id = inf2/64;
1144  face.ncface = ncface;
1145  face.point_matrix = nullptr;
1146  // The following figures out face.location, face.conformity,
1147  // face.element[1].index, and face.element[1].orientation.
1148  if (f < GetNumFaces()) // Non-ghost face
1149  {
1150  if (e2>=0)
1151  {
1152  if (ncface==-1)
1153  {
1154  face.tag = FaceInfoTag::LocalConforming;
1155  face.topology = FaceTopology::Conforming;
1156  face.element[1].location = ElementLocation::Local;
1157  face.element[0].conformity = ElementConformity::Coincident;
1158  face.element[1].conformity = ElementConformity::Coincident;
1159  face.element[1].index = e2;
1160  face.element[1].orientation = inf2%64;
1161  }
1162  else // ncface >= 0
1163  {
1164  face.tag = FaceInfoTag::LocalSlaveNonconforming;
1165  face.topology = FaceTopology::Nonconforming;
1166  face.element[1].location = ElementLocation::Local;
1167  face.element[0].conformity = ElementConformity::Coincident;
1168  face.element[1].conformity = ElementConformity::Superset;
1169  face.element[1].index = e2;
1170  MFEM_ASSERT(inf2%64==0, "unexpected slave face orientation.");
1171  face.element[1].orientation = inf2%64;
1172  face.point_matrix = nc_faces_info[ncface].PointMatrix;
1173  }
1174  }
1175  else // e2<0
1176  {
1177  if (ncface==-1)
1178  {
1179  if (inf2<0)
1180  {
1181  face.tag = FaceInfoTag::Boundary;
1182  face.topology = FaceTopology::Boundary;
1183  face.element[1].location = ElementLocation::NA;
1184  face.element[0].conformity = ElementConformity::Coincident;
1185  face.element[1].conformity = ElementConformity::NA;
1186  face.element[1].index = -1;
1187  face.element[1].orientation = -1;
1188  }
1189  else // inf2 >= 0
1190  {
1191  face.tag = FaceInfoTag::SharedConforming;
1192  face.topology = FaceTopology::Conforming;
1193  face.element[0].conformity = ElementConformity::Coincident;
1194  face.element[1].conformity = ElementConformity::Coincident;
1195  face.element[1].location = ElementLocation::FaceNbr;
1196  face.element[1].index = -1 - e2;
1197  face.element[1].orientation = inf2%64;
1198  }
1199  }
1200  else // ncface >= 0
1201  {
1202  if (inf2 < 0)
1203  {
1204  face.tag = FaceInfoTag::MasterNonconforming;
1205  face.topology = FaceTopology::Nonconforming;
1206  face.element[1].location = ElementLocation::NA;
1207  face.element[0].conformity = ElementConformity::Coincident;
1208  face.element[1].conformity = ElementConformity::Subset;
1209  face.element[1].index = -1;
1210  face.element[1].orientation = -1;
1211  }
1212  else
1213  {
1214  face.tag = FaceInfoTag::SharedSlaveNonconforming;
1215  face.topology = FaceTopology::Nonconforming;
1216  face.element[1].location = ElementLocation::FaceNbr;
1217  face.element[0].conformity = ElementConformity::Coincident;
1218  face.element[1].conformity = ElementConformity::Superset;
1219  face.element[1].index = -1 - e2;
1220  face.element[1].orientation = inf2%64;
1221  }
1222  face.point_matrix = nc_faces_info[ncface].PointMatrix;
1223  }
1224  }
1225  }
1226  else // Ghost face
1227  {
1228  if (e1==-1)
1229  {
1230  face.tag = FaceInfoTag::GhostMaster;
1231  face.topology = FaceTopology::NA;
1232  face.element[1].location = ElementLocation::NA;
1233  face.element[0].conformity = ElementConformity::NA;
1234  face.element[1].conformity = ElementConformity::NA;
1235  face.element[1].index = -1;
1236  face.element[1].orientation = -1;
1237  }
1238  else
1239  {
1240  face.tag = FaceInfoTag::GhostSlave;
1241  face.topology = FaceTopology::Nonconforming;
1242  face.element[1].location = ElementLocation::FaceNbr;
1243  face.element[0].conformity = ElementConformity::Superset;
1244  face.element[1].conformity = ElementConformity::Coincident;
1245  face.element[1].index = -1 - e2;
1246  face.element[1].orientation = inf2%64;
1247  face.point_matrix = nc_faces_info[ncface].PointMatrix;
1248  }
1249  }
1250  return face;
1251 }
1252 
1253 Mesh::FaceInformation::operator Mesh::FaceInfo() const
1254 {
1255  FaceInfo res {-1, -1, -1, -1, -1};
1256  switch (tag)
1257  {
1258  case FaceInfoTag::LocalConforming:
1259  res.Elem1No = element[0].index;
1260  res.Elem2No = element[1].index;
1261  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1262  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1263  res.NCFace = ncface;
1264  break;
1265  case FaceInfoTag::LocalSlaveNonconforming:
1266  res.Elem1No = element[0].index;
1267  res.Elem2No = element[1].index;
1268  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1269  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1270  res.NCFace = ncface;
1271  break;
1272  case FaceInfoTag::Boundary:
1273  res.Elem1No = element[0].index;
1274  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1275  break;
1276  case FaceInfoTag::SharedConforming:
1277  res.Elem1No = element[0].index;
1278  res.Elem2No = -1 - element[1].index;
1279  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1280  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1281  break;
1282  case FaceInfoTag::MasterNonconforming:
1283  res.Elem1No = element[0].index;
1284  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1285  break;
1286  case FaceInfoTag::SharedSlaveNonconforming:
1287  res.Elem1No = element[0].index;
1288  res.Elem2No = -1 - element[1].index;
1289  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1290  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1291  break;
1292  case FaceInfoTag::GhostMaster:
1293  break;
1294  case FaceInfoTag::GhostSlave:
1295  res.Elem1No = element[0].index;
1296  res.Elem2No = -1 - element[1].index;
1297  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1298  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1299  break;
1300  }
1301  return res;
1302 }
1303 
1304 std::ostream& operator<<(std::ostream& os, const Mesh::FaceInformation& info)
1305 {
1306  os << "face topology=";
1307  switch (info.topology)
1308  {
1309  case Mesh::FaceTopology::Boundary:
1310  os << "Boundary";
1311  break;
1312  case Mesh::FaceTopology::Conforming:
1313  os << "Conforming";
1314  break;
1315  case Mesh::FaceTopology::Nonconforming:
1316  os << "Non-conforming";
1317  break;
1318  case Mesh::FaceTopology::NA:
1319  os << "NA";
1320  break;
1321  }
1322  os << "element[0].location=";
1323  switch (info.element[0].location)
1324  {
1325  case Mesh::ElementLocation::Local:
1326  os << "Local";
1327  break;
1328  case Mesh::ElementLocation::FaceNbr:
1329  os << "FaceNbr";
1330  break;
1331  case Mesh::ElementLocation::NA:
1332  os << "NA";
1333  break;
1334  }
1335  os << std::endl;
1336  os << "element[1].location=";
1337  switch (info.element[1].location)
1338  {
1339  case Mesh::ElementLocation::Local:
1340  os << "Local";
1341  break;
1342  case Mesh::ElementLocation::FaceNbr:
1343  os << "FaceNbr";
1344  break;
1345  case Mesh::ElementLocation::NA:
1346  os << "NA";
1347  break;
1348  }
1349  os << std::endl;
1350  os << "element[0].conformity=";
1351  switch (info.element[0].conformity)
1352  {
1353  case Mesh::ElementConformity::Coincident:
1354  os << "Coincident";
1355  break;
1356  case Mesh::ElementConformity::Superset:
1357  os << "Superset";
1358  break;
1359  case Mesh::ElementConformity::Subset:
1360  os << "Subset";
1361  break;
1362  case Mesh::ElementConformity::NA:
1363  os << "NA";
1364  break;
1365  }
1366  os << std::endl;
1367  os << "element[1].conformity=";
1368  switch (info.element[1].conformity)
1369  {
1370  case Mesh::ElementConformity::Coincident:
1371  os << "Coincident";
1372  break;
1373  case Mesh::ElementConformity::Superset:
1374  os << "Superset";
1375  break;
1376  case Mesh::ElementConformity::Subset:
1377  os << "Subset";
1378  break;
1379  case Mesh::ElementConformity::NA:
1380  os << "NA";
1381  break;
1382  }
1383  os << std::endl;
1384  os << "element[0].index=" << info.element[0].index << std::endl
1385  << "element[1].index=" << info.element[1].index << std::endl
1386  << "element[0].local_face_id=" << info.element[0].local_face_id << std::endl
1387  << "element[1].local_face_id=" << info.element[1].local_face_id << std::endl
1388  << "element[0].orientation=" << info.element[0].orientation << std::endl
1389  << "element[1].orientation=" << info.element[1].orientation << std::endl
1390  << "ncface=" << info.ncface << std::endl;
1391  return os;
1392 }
1393 
1394 void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2) const
1395 {
1396  *Elem1 = faces_info[Face].Elem1No;
1397  *Elem2 = faces_info[Face].Elem2No;
1398 }
1399 
1400 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const
1401 {
1402  *Inf1 = faces_info[Face].Elem1Inf;
1403  *Inf2 = faces_info[Face].Elem2Inf;
1404 }
1405 
1406 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2, int *NCFace) const
1407 {
1408  *Inf1 = faces_info[Face].Elem1Inf;
1409  *Inf2 = faces_info[Face].Elem2Inf;
1410  *NCFace = faces_info[Face].NCFace;
1411 }
1412 
1413 Geometry::Type Mesh::GetFaceGeometry(int Face) const
1414 {
1415  switch (Dim)
1416  {
1417  case 1: return Geometry::POINT;
1418  case 2: return Geometry::SEGMENT;
1419  case 3:
1420  if (Face < NumOfFaces) // local (non-ghost) face
1421  {
1422  return faces[Face]->GetGeometryType();
1423  }
1424  // ghost face
1425  const int nc_face_id = faces_info[Face].NCFace;
1426  MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported");
1427  return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType();
1428  }
1429  return Geometry::INVALID;
1430 }
1431 
1432 Element::Type Mesh::GetFaceElementType(int Face) const
1433 {
1434  return (Dim == 1) ? Element::POINT : faces[Face]->GetType();
1435 }
1436 
1437 Array<int> Mesh::GetFaceToBdrElMap() const
1438 {
1439  Array<int> face_to_be(NumOfFaces);
1440  face_to_be = -1;
1441  for (int i = 0; i < NumOfBdrElements; i++)
1442  {
1443  face_to_be[GetBdrElementEdgeIndex(i)] = i;
1444  }
1445  return face_to_be;
1446 }
1447 
1448 void Mesh::Init()
1449 {
1450  // in order of declaration:
1451  Dim = spaceDim = 0;
1452  NumOfVertices = -1;
1453  NumOfElements = NumOfBdrElements = 0;
1454  NumOfEdges = NumOfFaces = 0;
1455  nbInteriorFaces = -1;
1456  nbBoundaryFaces = -1;
1457  meshgen = mesh_geoms = 0;
1458  sequence = 0;
1459  Nodes = NULL;
1460  own_nodes = 1;
1461  NURBSext = NULL;
1462  ncmesh = NULL;
1463  last_operation = Mesh::NONE;
1464 }
1465 
1466 void Mesh::InitTables()
1467 {
1468  el_to_edge =
1469  el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
1470  face_to_elem = NULL;
1471 }
1472 
1473 void Mesh::SetEmpty()
1474 {
1475  Init();
1476  InitTables();
1477 }
1478 
1479 void Mesh::DestroyTables()
1480 {
1481  delete el_to_edge;
1482  delete el_to_face;
1483  delete el_to_el;
1484  DeleteGeometricFactors();
1485 
1486  if (Dim == 3)
1487  {
1488  delete bel_to_edge;
1489  }
1490 
1491  delete face_edge;
1492  delete edge_vertex;
1493 
1494  delete face_to_elem;
1495  face_to_elem = NULL;
1496 }
1497 
1498 void Mesh::DestroyPointers()
1499 {
1500  if (own_nodes) { delete Nodes; }
1501 
1502  delete ncmesh;
1503 
1504  delete NURBSext;
1505 
1506  for (int i = 0; i < NumOfElements; i++)
1507  {
1508  FreeElement(elements[i]);
1509  }
1510 
1511  for (int i = 0; i < NumOfBdrElements; i++)
1512  {
1513  FreeElement(boundary[i]);
1514  }
1515 
1516  for (int i = 0; i < faces.Size(); i++)
1517  {
1518  FreeElement(faces[i]);
1519  }
1520 
1521  DestroyTables();
1522 }
1523 
1524 void Mesh::Destroy()
1525 {
1526  DestroyPointers();
1527 
1528  elements.DeleteAll();
1529  vertices.DeleteAll();
1530  boundary.DeleteAll();
1531  faces.DeleteAll();
1532  faces_info.DeleteAll();
1533  nc_faces_info.DeleteAll();
1534  be_to_edge.DeleteAll();
1535  be_to_face.DeleteAll();
1536 
1537  // TODO:
1538  // IsoparametricTransformations
1539  // Transformation, Transformation2, BdrTransformation, FaceTransformation,
1540  // EdgeTransformation;
1541  // FaceElementTransformations FaceElemTr;
1542 
1543  CoarseFineTr.Clear();
1544 
1545 #ifdef MFEM_USE_MEMALLOC
1546  TetMemory.Clear();
1547 #endif
1548 
1549  attributes.DeleteAll();
1550  bdr_attributes.DeleteAll();
1551 }
1552 
1553 void Mesh::ResetLazyData()
1554 {
1555  delete el_to_el; el_to_el = NULL;
1556  delete face_edge; face_edge = NULL;
1557  delete face_to_elem; face_to_elem = NULL;
1558  delete edge_vertex; edge_vertex = NULL;
1559  DeleteGeometricFactors();
1560  nbInteriorFaces = -1;
1561  nbBoundaryFaces = -1;
1562 }
1563 
1564 void Mesh::SetAttributes()
1565 {
1566  Array<int> attribs;
1567 
1568  attribs.SetSize(GetNBE());
1569  for (int i = 0; i < attribs.Size(); i++)
1570  {
1571  attribs[i] = GetBdrAttribute(i);
1572  }
1573  attribs.Sort();
1574  attribs.Unique();
1575  attribs.Copy(bdr_attributes);
1576  if (bdr_attributes.Size() > 0 && bdr_attributes[0] <= 0)
1577  {
1578  MFEM_WARNING("Non-positive attributes on the boundary!");
1579  }
1580 
1581  attribs.SetSize(GetNE());
1582  for (int i = 0; i < attribs.Size(); i++)
1583  {
1584  attribs[i] = GetAttribute(i);
1585  }
1586  attribs.Sort();
1587  attribs.Unique();
1588  attribs.Copy(attributes);
1589  if (attributes.Size() > 0 && attributes[0] <= 0)
1590  {
1591  MFEM_WARNING("Non-positive attributes in the domain!");
1592  }
1593 }
1594 
1595 void Mesh::InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
1596 {
1597  SetEmpty();
1598 
1599  Dim = Dim_;
1600  spaceDim = spaceDim_;
1601 
1602  NumOfVertices = 0;
1603  vertices.SetSize(NVert); // just allocate space for vertices
1604 
1605  NumOfElements = 0;
1606  elements.SetSize(NElem); // just allocate space for Element *
1607 
1608  NumOfBdrElements = 0;
1609  boundary.SetSize(NBdrElem); // just allocate space for Element *
1610 }
1611 
1612 template<typename T>
1613 static void CheckEnlarge(Array<T> &array, int size)
1614 {
1615  if (size >= array.Size()) { array.SetSize(size + 1); }
1616 }
1617 
1618 int Mesh::AddVertex(double x, double y, double z)
1619 {
1620  CheckEnlarge(vertices, NumOfVertices);
1621  double *v = vertices[NumOfVertices]();
1622  v[0] = x;
1623  v[1] = y;
1624  v[2] = z;
1625  return NumOfVertices++;
1626 }
1627 
1628 int Mesh::AddVertex(const double *coords)
1629 {
1630  CheckEnlarge(vertices, NumOfVertices);
1631  vertices[NumOfVertices].SetCoords(spaceDim, coords);
1632  return NumOfVertices++;
1633 }
1634 
1635 int Mesh::AddVertex(const Vector &coords)
1636 {
1637  MFEM_ASSERT(coords.Size() >= spaceDim,
1638  "invalid 'coords' size: " << coords.Size());
1639  return AddVertex(coords.GetData());
1640 }
1641 
1642 void Mesh::AddVertexParents(int i, int p1, int p2)
1643 {
1644  tmp_vertex_parents.Append(Triple<int, int, int>(i, p1, p2));
1645 
1646  // if vertex coordinates are defined, make sure the hanging vertex has the
1647  // correct position
1648  if (i < vertices.Size())
1649  {
1650  double *vi = vertices[i](), *vp1 = vertices[p1](), *vp2 = vertices[p2]();
1651  for (int j = 0; j < 3; j++)
1652  {
1653  vi[j] = (vp1[j] + vp2[j]) * 0.5;
1654  }
1655  }
1656 }
1657 
1658 int Mesh::AddSegment(int v1, int v2, int attr)
1659 {
1660  CheckEnlarge(elements, NumOfElements);
1661  elements[NumOfElements] = new Segment(v1, v2, attr);
1662  return NumOfElements++;
1663 }
1664 
1665 int Mesh::AddSegment(const int *vi, int attr)
1666 {
1667  CheckEnlarge(elements, NumOfElements);
1668  elements[NumOfElements] = new Segment(vi, attr);
1669  return NumOfElements++;
1670 }
1671 
1672 int Mesh::AddTriangle(int v1, int v2, int v3, int attr)
1673 {
1674  CheckEnlarge(elements, NumOfElements);
1675  elements[NumOfElements] = new Triangle(v1, v2, v3, attr);
1676  return NumOfElements++;
1677 }
1678 
1679 int Mesh::AddTriangle(const int *vi, int attr)
1680 {
1681  CheckEnlarge(elements, NumOfElements);
1682  elements[NumOfElements] = new Triangle(vi, attr);
1683  return NumOfElements++;
1684 }
1685 
1686 int Mesh::AddQuad(int v1, int v2, int v3, int v4, int attr)
1687 {
1688  CheckEnlarge(elements, NumOfElements);
1689  elements[NumOfElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1690  return NumOfElements++;
1691 }
1692 
1693 int Mesh::AddQuad(const int *vi, int attr)
1694 {
1695  CheckEnlarge(elements, NumOfElements);
1696  elements[NumOfElements] = new Quadrilateral(vi, attr);
1697  return NumOfElements++;
1698 }
1699 
1700 int Mesh::AddTet(int v1, int v2, int v3, int v4, int attr)
1701 {
1702  int vi[4] = {v1, v2, v3, v4};
1703  return AddTet(vi, attr);
1704 }
1705 
1706 int Mesh::AddTet(const int *vi, int attr)
1707 {
1708  CheckEnlarge(elements, NumOfElements);
1709 #ifdef MFEM_USE_MEMALLOC
1710  Tetrahedron *tet;
1711  tet = TetMemory.Alloc();
1712  tet->SetVertices(vi);
1713  tet->SetAttribute(attr);
1714  elements[NumOfElements] = tet;
1715 #else
1716  elements[NumOfElements] = new Tetrahedron(vi, attr);
1717 #endif
1718  return NumOfElements++;
1719 }
1720 
1721 int Mesh::AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr)
1722 {
1723  CheckEnlarge(elements, NumOfElements);
1724  elements[NumOfElements] = new Wedge(v1, v2, v3, v4, v5, v6, attr);
1725  return NumOfElements++;
1726 }
1727 
1728 int Mesh::AddWedge(const int *vi, int attr)
1729 {
1730  CheckEnlarge(elements, NumOfElements);
1731  elements[NumOfElements] = new Wedge(vi, attr);
1732  return NumOfElements++;
1733 }
1734 
1735 int Mesh::AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr)
1736 {
1737  CheckEnlarge(elements, NumOfElements);
1738  elements[NumOfElements] = new Pyramid(v1, v2, v3, v4, v5, attr);
1739  return NumOfElements++;
1740 }
1741 
1742 int Mesh::AddPyramid(const int *vi, int attr)
1743 {
1744  CheckEnlarge(elements, NumOfElements);
1745  elements[NumOfElements] = new Pyramid(vi, attr);
1746  return NumOfElements++;
1747 }
1748 
1749 int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
1750  int attr)
1751 {
1752  CheckEnlarge(elements, NumOfElements);
1753  elements[NumOfElements] =
1754  new Hexahedron(v1, v2, v3, v4, v5, v6, v7, v8, attr);
1755  return NumOfElements++;
1756 }
1757 
1758 int Mesh::AddHex(const int *vi, int attr)
1759 {
1760  CheckEnlarge(elements, NumOfElements);
1761  elements[NumOfElements] = new Hexahedron(vi, attr);
1762  return NumOfElements++;
1763 }
1764 
1765 void Mesh::AddHexAsTets(const int *vi, int attr)
1766 {
1767  static const int hex_to_tet[6][4] =
1768  {
1769  { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
1770  { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
1771  };
1772  int ti[4];
1773 
1774  for (int i = 0; i < 6; i++)
1775  {
1776  for (int j = 0; j < 4; j++)
1777  {
1778  ti[j] = vi[hex_to_tet[i][j]];
1779  }
1780  AddTet(ti, attr);
1781  }
1782 }
1783 
1784 void Mesh::AddHexAsWedges(const int *vi, int attr)
1785 {
1786  static const int hex_to_wdg[2][6] =
1787  {
1788  { 0, 1, 2, 4, 5, 6 }, { 0, 2, 3, 4, 6, 7 }
1789  };
1790  int ti[6];
1791 
1792  for (int i = 0; i < 2; i++)
1793  {
1794  for (int j = 0; j < 6; j++)
1795  {
1796  ti[j] = vi[hex_to_wdg[i][j]];
1797  }
1798  AddWedge(ti, attr);
1799  }
1800 }
1801 
1802 void Mesh::AddHexAsPyramids(const int *vi, int attr)
1803 {
1804  static const int hex_to_pyr[6][5] =
1805  {
1806  { 0, 1, 2, 3, 8 }, { 0, 4, 5, 1, 8 }, { 1, 5, 6, 2, 8 },
1807  { 2, 6, 7, 3, 8 }, { 3, 7, 4, 0, 8 }, { 7, 6, 5, 4, 8 }
1808  };
1809  int ti[5];
1810 
1811  for (int i = 0; i < 6; i++)
1812  {
1813  for (int j = 0; j < 5; j++)
1814  {
1815  ti[j] = vi[hex_to_pyr[i][j]];
1816  }
1817  AddPyramid(ti, attr);
1818  }
1819 }
1820 
1821 int Mesh::AddElement(Element *elem)
1822 {
1823  CheckEnlarge(elements, NumOfElements);
1824  elements[NumOfElements] = elem;
1825  return NumOfElements++;
1826 }
1827 
1828 int Mesh::AddBdrElement(Element *elem)
1829 {
1830  CheckEnlarge(boundary, NumOfBdrElements);
1831  boundary[NumOfBdrElements] = elem;
1832  return NumOfBdrElements++;
1833 }
1834 
1835 int Mesh::AddBdrSegment(int v1, int v2, int attr)
1836 {
1837  CheckEnlarge(boundary, NumOfBdrElements);
1838  boundary[NumOfBdrElements] = new Segment(v1, v2, attr);
1839  return NumOfBdrElements++;
1840 }
1841 
1842 int Mesh::AddBdrSegment(const int *vi, int attr)
1843 {
1844  CheckEnlarge(boundary, NumOfBdrElements);
1845  boundary[NumOfBdrElements] = new Segment(vi, attr);
1846  return NumOfBdrElements++;
1847 }
1848 
1849 int Mesh::AddBdrTriangle(int v1, int v2, int v3, int attr)
1850 {
1851  CheckEnlarge(boundary, NumOfBdrElements);
1852  boundary[NumOfBdrElements] = new Triangle(v1, v2, v3, attr);
1853  return NumOfBdrElements++;
1854 }
1855 
1856 int Mesh::AddBdrTriangle(const int *vi, int attr)
1857 {
1858  CheckEnlarge(boundary, NumOfBdrElements);
1859  boundary[NumOfBdrElements] = new Triangle(vi, attr);
1860  return NumOfBdrElements++;
1861 }
1862 
1863 int Mesh::AddBdrQuad(int v1, int v2, int v3, int v4, int attr)
1864 {
1865  CheckEnlarge(boundary, NumOfBdrElements);
1866  boundary[NumOfBdrElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1867  return NumOfBdrElements++;
1868 }
1869 
1870 int Mesh::AddBdrQuad(const int *vi, int attr)
1871 {
1872  CheckEnlarge(boundary, NumOfBdrElements);
1873  boundary[NumOfBdrElements] = new Quadrilateral(vi, attr);
1874  return NumOfBdrElements++;
1875 }
1876 
1877 void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
1878 {
1879  static const int quad_to_tri[2][3] = { { 0, 1, 2 }, { 0, 2, 3 } };
1880  int ti[3];
1881 
1882  for (int i = 0; i < 2; i++)
1883  {
1884  for (int j = 0; j < 3; j++)
1885  {
1886  ti[j] = vi[quad_to_tri[i][j]];
1887  }
1888  AddBdrTriangle(ti, attr);
1889  }
1890 }
1891 
1892 int Mesh::AddBdrPoint(int v, int attr)
1893 {
1894  CheckEnlarge(boundary, NumOfBdrElements);
1895  boundary[NumOfBdrElements] = new Point(&v, attr);
1896  return NumOfBdrElements++;
1897 }
1898 
1899 void Mesh::GenerateBoundaryElements()
1900 {
1901  int i, j;
1902  Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
1903 
1904  // GenerateFaces();
1905 
1906  for (i = 0; i < boundary.Size(); i++)
1907  {
1908  FreeElement(boundary[i]);
1909  }
1910 
1911  if (Dim == 3)
1912  {
1913  delete bel_to_edge;
1914  bel_to_edge = NULL;
1915  }
1916 
1917  // count the 'NumOfBdrElements'
1918  NumOfBdrElements = 0;
1919  for (i = 0; i < faces_info.Size(); i++)
1920  {
1921  if (faces_info[i].Elem2No < 0) { NumOfBdrElements++; }
1922  }
1923 
1924  boundary.SetSize(NumOfBdrElements);
1925  be2face.SetSize(NumOfBdrElements);
1926  for (j = i = 0; i < faces_info.Size(); i++)
1927  {
1928  if (faces_info[i].Elem2No < 0)
1929  {
1930  boundary[j] = faces[i]->Duplicate(this);
1931  be2face[j++] = i;
1932  }
1933  }
1934  // In 3D, 'bel_to_edge' is destroyed but it's not updated.
1935 }
1936 
1937 void Mesh::FinalizeCheck()
1938 {
1939  MFEM_VERIFY(vertices.Size() == NumOfVertices ||
1940  vertices.Size() == 0,
1941  "incorrect number of vertices: preallocated: " << vertices.Size()
1942  << ", actually added: " << NumOfVertices);
1943  MFEM_VERIFY(elements.Size() == NumOfElements,
1944  "incorrect number of elements: preallocated: " << elements.Size()
1945  << ", actually added: " << NumOfElements);
1946  MFEM_VERIFY(boundary.Size() == NumOfBdrElements,
1947  "incorrect number of boundary elements: preallocated: "
1948  << boundary.Size() << ", actually added: " << NumOfBdrElements);
1949 }
1950 
1951 void Mesh::FinalizeTriMesh(int generate_edges, int refine, bool fix_orientation)
1952 {
1953  FinalizeCheck();
1954  CheckElementOrientation(fix_orientation);
1955 
1956  if (refine)
1957  {
1958  MarkTriMeshForRefinement();
1959  }
1960 
1961  if (generate_edges)
1962  {
1963  el_to_edge = new Table;
1964  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1965  GenerateFaces();
1966  CheckBdrElementOrientation();
1967  }
1968  else
1969  {
1970  NumOfEdges = 0;
1971  }
1972 
1973  NumOfFaces = 0;
1974 
1975  SetAttributes();
1976 
1977  SetMeshGen();
1978 }
1979 
1980 void Mesh::FinalizeQuadMesh(int generate_edges, int refine,
1981  bool fix_orientation)
1982 {
1983  FinalizeCheck();
1984  if (fix_orientation)
1985  {
1986  CheckElementOrientation(fix_orientation);
1987  }
1988 
1989  if (generate_edges)
1990  {
1991  el_to_edge = new Table;
1992  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1993  GenerateFaces();
1994  CheckBdrElementOrientation();
1995  }
1996  else
1997  {
1998  NumOfEdges = 0;
1999  }
2000 
2001  NumOfFaces = 0;
2002 
2003  SetAttributes();
2004 
2005  SetMeshGen();
2006 }
2007 
2008 
2009 class GeckoProgress : public Gecko::Progress
2010 {
2011  double limit;
2012  mutable StopWatch sw;
2013 public:
2014  GeckoProgress(double limit) : limit(limit) { sw.Start(); }
2015  virtual bool quit() const { return limit > 0 && sw.UserTime() > limit; }
2016 };
2017 
2018 class GeckoVerboseProgress : public GeckoProgress
2019 {
2020  using Float = Gecko::Float;
2021  using Graph = Gecko::Graph;
2022  using uint = Gecko::uint;
2023 public:
2024  GeckoVerboseProgress(double limit) : GeckoProgress(limit) {}
2025 
2026  virtual void beginorder(const Graph* graph, Float cost) const
2027  { mfem::out << "Begin Gecko ordering, cost = " << cost << std::endl; }
2028  virtual void endorder(const Graph* graph, Float cost) const
2029  { mfem::out << "End ordering, cost = " << cost << std::endl; }
2030 
2031  virtual void beginiter(const Graph* graph,
2032  uint iter, uint maxiter, uint window) const
2033  {
2034  mfem::out << "Iteration " << iter << "/" << maxiter << ", window "
2035  << window << std::flush;
2036  }
2037  virtual void enditer(const Graph* graph, Float mincost, Float cost) const
2038  { mfem::out << ", cost = " << cost << endl; }
2039 };
2040 
2041 
2042 double Mesh::GetGeckoElementOrdering(Array<int> &ordering,
2043  int iterations, int window,
2044  int period, int seed, bool verbose,
2045  double time_limit)
2046 {
2047  Gecko::Graph graph;
2048  Gecko::FunctionalGeometric functional; // edge product cost
2049 
2050  GeckoProgress progress(time_limit);
2051  GeckoVerboseProgress vprogress(time_limit);
2052 
2053  // insert elements as nodes in the graph
2054  for (int elemid = 0; elemid < GetNE(); ++elemid)
2055  {
2056  graph.insert_node();
2057  }
2058 
2059  // insert graph edges for element neighbors
2060  // NOTE: indices in Gecko are 1 based hence the +1 on insertion
2061  const Table &my_el_to_el = ElementToElementTable();
2062  for (int elemid = 0; elemid < GetNE(); ++elemid)
2063  {
2064  const int *neighid = my_el_to_el.GetRow(elemid);
2065  for (int i = 0; i < my_el_to_el.RowSize(elemid); ++i)
2066  {
2067  graph.insert_arc(elemid + 1, neighid[i] + 1);
2068  }
2069  }
2070 
2071  // get the ordering from Gecko and copy it into the Array<int>
2072  graph.order(&functional, iterations, window, period, seed,
2073  verbose ? &vprogress : &progress);
2074 
2075  ordering.SetSize(GetNE());
2076  Gecko::Node::Index NE = GetNE();
2077  for (Gecko::Node::Index gnodeid = 1; gnodeid <= NE; ++gnodeid)
2078  {
2079  ordering[gnodeid - 1] = graph.rank(gnodeid);
2080  }
2081 
2082  return graph.cost();
2083 }
2084 
2085 
2086 struct HilbertCmp
2087 {
2088  int coord;
2089  bool dir;
2090  const Array<double> &points;
2091  double mid;
2092 
2093  HilbertCmp(int coord, bool dir, const Array<double> &points, double mid)
2094  : coord(coord), dir(dir), points(points), mid(mid) {}
2095 
2096  bool operator()(int i) const
2097  {
2098  return (points[3*i + coord] < mid) != dir;
2099  }
2100 };
2101 
2102 static void HilbertSort2D(int coord1, // major coordinate to sort points by
2103  bool dir1, // sort coord1 ascending/descending?
2104  bool dir2, // sort coord2 ascending/descending?
2105  const Array<double> &points, int *beg, int *end,
2106  double xmin, double ymin, double xmax, double ymax)
2107 {
2108  if (end - beg <= 1) { return; }
2109 
2110  double xmid = (xmin + xmax)*0.5;
2111  double ymid = (ymin + ymax)*0.5;
2112 
2113  int coord2 = (coord1 + 1) % 2; // the 'other' coordinate
2114 
2115  // sort (partition) points into four quadrants
2116  int *p0 = beg, *p4 = end;
2117  int *p2 = std::partition(p0, p4, HilbertCmp(coord1, dir1, points, xmid));
2118  int *p1 = std::partition(p0, p2, HilbertCmp(coord2, dir2, points, ymid));
2119  int *p3 = std::partition(p2, p4, HilbertCmp(coord2, !dir2, points, ymid));
2120 
2121  if (p1 != p4)
2122  {
2123  HilbertSort2D(coord2, dir2, dir1, points, p0, p1,
2124  ymin, xmin, ymid, xmid);
2125  }
2126  if (p1 != p0 || p2 != p4)
2127  {
2128  HilbertSort2D(coord1, dir1, dir2, points, p1, p2,
2129  xmin, ymid, xmid, ymax);
2130  }
2131  if (p2 != p0 || p3 != p4)
2132  {
2133  HilbertSort2D(coord1, dir1, dir2, points, p2, p3,
2134  xmid, ymid, xmax, ymax);
2135  }
2136  if (p3 != p0)
2137  {
2138  HilbertSort2D(coord2, !dir2, !dir1, points, p3, p4,
2139  ymid, xmax, ymin, xmid);
2140  }
2141 }
2142 
2143 static void HilbertSort3D(int coord1, bool dir1, bool dir2, bool dir3,
2144  const Array<double> &points, int *beg, int *end,
2145  double xmin, double ymin, double zmin,
2146  double xmax, double ymax, double zmax)
2147 {
2148  if (end - beg <= 1) { return; }
2149 
2150  double xmid = (xmin + xmax)*0.5;
2151  double ymid = (ymin + ymax)*0.5;
2152  double zmid = (zmin + zmax)*0.5;
2153 
2154  int coord2 = (coord1 + 1) % 3;
2155  int coord3 = (coord1 + 2) % 3;
2156 
2157  // sort (partition) points into eight octants
2158  int *p0 = beg, *p8 = end;
2159  int *p4 = std::partition(p0, p8, HilbertCmp(coord1, dir1, points, xmid));
2160  int *p2 = std::partition(p0, p4, HilbertCmp(coord2, dir2, points, ymid));
2161  int *p6 = std::partition(p4, p8, HilbertCmp(coord2, !dir2, points, ymid));
2162  int *p1 = std::partition(p0, p2, HilbertCmp(coord3, dir3, points, zmid));
2163  int *p3 = std::partition(p2, p4, HilbertCmp(coord3, !dir3, points, zmid));
2164  int *p5 = std::partition(p4, p6, HilbertCmp(coord3, dir3, points, zmid));
2165  int *p7 = std::partition(p6, p8, HilbertCmp(coord3, !dir3, points, zmid));
2166 
2167  if (p1 != p8)
2168  {
2169  HilbertSort3D(coord3, dir3, dir1, dir2, points, p0, p1,
2170  zmin, xmin, ymin, zmid, xmid, ymid);
2171  }
2172  if (p1 != p0 || p2 != p8)
2173  {
2174  HilbertSort3D(coord2, dir2, dir3, dir1, points, p1, p2,
2175  ymin, zmid, xmin, ymid, zmax, xmid);
2176  }
2177  if (p2 != p0 || p3 != p8)
2178  {
2179  HilbertSort3D(coord2, dir2, dir3, dir1, points, p2, p3,
2180  ymid, zmid, xmin, ymax, zmax, xmid);
2181  }
2182  if (p3 != p0 || p4 != p8)
2183  {
2184  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p3, p4,
2185  xmin, ymax, zmid, xmid, ymid, zmin);
2186  }
2187  if (p4 != p0 || p5 != p8)
2188  {
2189  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p4, p5,
2190  xmid, ymax, zmid, xmax, ymid, zmin);
2191  }
2192  if (p5 != p0 || p6 != p8)
2193  {
2194  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p5, p6,
2195  ymax, zmid, xmax, ymid, zmax, xmid);
2196  }
2197  if (p6 != p0 || p7 != p8)
2198  {
2199  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p6, p7,
2200  ymid, zmid, xmax, ymin, zmax, xmid);
2201  }
2202  if (p7 != p0)
2203  {
2204  HilbertSort3D(coord3, !dir3, !dir1, dir2, points, p7, p8,
2205  zmid, xmax, ymin, zmin, xmid, ymid);
2206  }
2207 }
2208 
2209 void Mesh::GetHilbertElementOrdering(Array<int> &ordering)
2210 {
2211  MFEM_VERIFY(spaceDim <= 3, "");
2212 
2213  Vector min, max, center;
2214  GetBoundingBox(min, max);
2215 
2216  Array<int> indices(GetNE());
2217  Array<double> points(3*GetNE());
2218 
2219  if (spaceDim < 3) { points = 0.0; }
2220 
2221  // calculate element centers
2222  for (int i = 0; i < GetNE(); i++)
2223  {
2224  GetElementCenter(i, center);
2225  for (int j = 0; j < spaceDim; j++)
2226  {
2227  points[3*i + j] = center(j);
2228  }
2229  indices[i] = i;
2230  }
2231 
2232  if (spaceDim == 1)
2233  {
2234  indices.Sort([&](int a, int b)
2235  { return points[3*a] < points[3*b]; });
2236  }
2237  else if (spaceDim == 2)
2238  {
2239  // recursively partition the points in 2D
2240  HilbertSort2D(0, false, false,
2241  points, indices.begin(), indices.end(),
2242  min(0), min(1), max(0), max(1));
2243  }
2244  else
2245  {
2246  // recursively partition the points in 3D
2247  HilbertSort3D(0, false, false, false,
2248  points, indices.begin(), indices.end(),
2249  min(0), min(1), min(2), max(0), max(1), max(2));
2250  }
2251 
2252  // return ordering in the format required by ReorderElements
2253  ordering.SetSize(GetNE());
2254  for (int i = 0; i < GetNE(); i++)
2255  {
2256  ordering[indices[i]] = i;
2257  }
2258 }
2259 
2260 
2261 void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
2262 {
2263  if (NURBSext)
2264  {
2265  MFEM_WARNING("element reordering of NURBS meshes is not supported.");
2266  return;
2267  }
2268  if (ncmesh)
2269  {
2270  MFEM_WARNING("element reordering of non-conforming meshes is not"
2271  " supported.");
2272  return;
2273  }
2274  MFEM_VERIFY(ordering.Size() == GetNE(), "invalid reordering array.")
2275 
2276  // Data members that need to be updated:
2277 
2278  // - elements - reorder of the pointers and the vertex ids if reordering
2279  // the vertices
2280  // - vertices - if reordering the vertices
2281  // - boundary - update the vertex ids, if reordering the vertices
2282  // - faces - regenerate
2283  // - faces_info - regenerate
2284 
2285  // Deleted by DeleteTables():
2286  // - el_to_edge - rebuild in 2D and 3D only
2287  // - el_to_face - rebuild in 3D only
2288  // - bel_to_edge - rebuild in 3D only
2289  // - el_to_el - no need to rebuild
2290  // - face_edge - no need to rebuild
2291  // - edge_vertex - no need to rebuild
2292  // - geom_factors - no need to rebuild
2293 
2294  // - be_to_edge - 2D only
2295  // - be_to_face - 3D only
2296 
2297  // - Nodes
2298 
2299  // Save the locations of the Nodes so we can rebuild them later
2300  Array<Vector*> old_elem_node_vals;
2301  FiniteElementSpace *nodes_fes = NULL;
2302  if (Nodes)
2303  {
2304  old_elem_node_vals.SetSize(GetNE());
2305  nodes_fes = Nodes->FESpace();
2306  Array<int> old_dofs;
2307  Vector vals;
2308  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2309  {
2310  nodes_fes->GetElementVDofs(old_elid, old_dofs);
2311  Nodes->GetSubVector(old_dofs, vals);
2312  old_elem_node_vals[old_elid] = new Vector(vals);
2313  }
2314  }
2315 
2316  // Get the newly ordered elements
2317  Array<Element *> new_elements(GetNE());
2318  for (int old_elid = 0; old_elid < ordering.Size(); ++old_elid)
2319  {
2320  int new_elid = ordering[old_elid];
2321  new_elements[new_elid] = elements[old_elid];
2322  }
2323  mfem::Swap(elements, new_elements);
2324  new_elements.DeleteAll();
2325 
2326  if (reorder_vertices)
2327  {
2328  // Get the new vertex ordering permutation vectors and fill the new
2329  // vertices
2330  Array<int> vertex_ordering(GetNV());
2331  vertex_ordering = -1;
2332  Array<Vertex> new_vertices(GetNV());
2333  int new_vertex_ind = 0;
2334  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2335  {
2336  int *elem_vert = elements[new_elid]->GetVertices();
2337  int nv = elements[new_elid]->GetNVertices();
2338  for (int vi = 0; vi < nv; ++vi)
2339  {
2340  int old_vertex_ind = elem_vert[vi];
2341  if (vertex_ordering[old_vertex_ind] == -1)
2342  {
2343  vertex_ordering[old_vertex_ind] = new_vertex_ind;
2344  new_vertices[new_vertex_ind] = vertices[old_vertex_ind];
2345  new_vertex_ind++;
2346  }
2347  }
2348  }
2349  mfem::Swap(vertices, new_vertices);
2350  new_vertices.DeleteAll();
2351 
2352  // Replace the vertex ids in the elements with the reordered vertex
2353  // numbers
2354  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2355  {
2356  int *elem_vert = elements[new_elid]->GetVertices();
2357  int nv = elements[new_elid]->GetNVertices();
2358  for (int vi = 0; vi < nv; ++vi)
2359  {
2360  elem_vert[vi] = vertex_ordering[elem_vert[vi]];
2361  }
2362  }
2363 
2364  // Replace the vertex ids in the boundary with reordered vertex numbers
2365  for (int belid = 0; belid < GetNBE(); ++belid)
2366  {
2367  int *be_vert = boundary[belid]->GetVertices();
2368  int nv = boundary[belid]->GetNVertices();
2369  for (int vi = 0; vi < nv; ++vi)
2370  {
2371  be_vert[vi] = vertex_ordering[be_vert[vi]];
2372  }
2373  }
2374  }
2375 
2376  // Destroy tables that need to be rebuild
2377  DeleteTables();
2378 
2379  if (Dim > 1)
2380  {
2381  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
2382  el_to_edge = new Table;
2383  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2384  }
2385  if (Dim > 2)
2386  {
2387  // generate el_to_face, be_to_face
2388  GetElementToFaceTable();
2389  }
2390  // Update faces and faces_info
2391  GenerateFaces();
2392 
2393  // Build the nodes from the saved locations if they were around before
2394  if (Nodes)
2395  {
2396  // To force FE space update, we need to increase 'sequence':
2397  sequence++;
2398  last_operation = Mesh::NONE;
2399  nodes_fes->Update(false); // want_transform = false
2400  Nodes->Update(); // just needed to update Nodes->sequence
2401  Array<int> new_dofs;
2402  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2403  {
2404  int new_elid = ordering[old_elid];
2405  nodes_fes->GetElementVDofs(new_elid, new_dofs);
2406  Nodes->SetSubVector(new_dofs, *(old_elem_node_vals[old_elid]));
2407  delete old_elem_node_vals[old_elid];
2408  }
2409  }
2410 }
2411 
2412 
2413 void Mesh::MarkForRefinement()
2414 {
2415  if (meshgen & 1)
2416  {
2417  if (Dim == 2)
2418  {
2419  MarkTriMeshForRefinement();
2420  }
2421  else if (Dim == 3)
2422  {
2423  DSTable v_to_v(NumOfVertices);
2424  GetVertexToVertexTable(v_to_v);
2425  MarkTetMeshForRefinement(v_to_v);
2426  }
2427  }
2428 }
2429 
2430 void Mesh::MarkTriMeshForRefinement()
2431 {
2432  // Mark the longest triangle edge by rotating the indices so that
2433  // vertex 0 - vertex 1 is the longest edge in the triangle.
2434  DenseMatrix pmat;
2435  for (int i = 0; i < NumOfElements; i++)
2436  {
2437  if (elements[i]->GetType() == Element::TRIANGLE)
2438  {
2439  GetPointMatrix(i, pmat);
2440  static_cast<Triangle*>(elements[i])->MarkEdge(pmat);
2441  }
2442  }
2443 }
2444 
2445 void Mesh::GetEdgeOrdering(DSTable &v_to_v, Array<int> &order)
2446 {
2447  NumOfEdges = v_to_v.NumberOfEntries();
2448  order.SetSize(NumOfEdges);
2449  Array<Pair<double, int> > length_idx(NumOfEdges);
2450 
2451  for (int i = 0; i < NumOfVertices; i++)
2452  {
2453  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
2454  {
2455  int j = it.Index();
2456  length_idx[j].one = GetLength(i, it.Column());
2457  length_idx[j].two = j;
2458  }
2459  }
2460 
2461  // Sort by increasing edge-length.
2462  length_idx.Sort();
2463 
2464  for (int i = 0; i < NumOfEdges; i++)
2465  {
2466  order[length_idx[i].two] = i;
2467  }
2468 }
2469 
2470 void Mesh::MarkTetMeshForRefinement(DSTable &v_to_v)
2471 {
2472  // Mark the longest tetrahedral edge by rotating the indices so that
2473  // vertex 0 - vertex 1 is the longest edge in the element.
2474  Array<int> order;
2475  GetEdgeOrdering(v_to_v, order);
2476 
2477  for (int i = 0; i < NumOfElements; i++)
2478  {
2479  if (elements[i]->GetType() == Element::TETRAHEDRON)
2480  {
2481  elements[i]->MarkEdge(v_to_v, order);
2482  }
2483  }
2484  for (int i = 0; i < NumOfBdrElements; i++)
2485  {
2486  if (boundary[i]->GetType() == Element::TRIANGLE)
2487  {
2488  boundary[i]->MarkEdge(v_to_v, order);
2489  }
2490  }
2491 }
2492 
2493 void Mesh::PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
2494 {
2495  if (*old_v_to_v && *old_elem_vert)
2496  {
2497  return;
2498  }
2499 
2500  FiniteElementSpace *fes = Nodes->FESpace();
2501 
2502  if (*old_v_to_v == NULL)
2503  {
2504  bool need_v_to_v = false;
2505  Array<int> dofs;
2506  for (int i = 0; i < GetNEdges(); i++)
2507  {
2508  // Since edge indices may change, we need to permute edge interior dofs
2509  // any time an edge index changes and there is at least one dof on that
2510  // edge.
2511  fes->GetEdgeInteriorDofs(i, dofs);
2512  if (dofs.Size() > 0)
2513  {
2514  need_v_to_v = true;
2515  break;
2516  }
2517  }
2518  if (need_v_to_v)
2519  {
2520  *old_v_to_v = new DSTable(NumOfVertices);
2521  GetVertexToVertexTable(*(*old_v_to_v));
2522  }
2523  }
2524  if (*old_elem_vert == NULL)
2525  {
2526  bool need_elem_vert = false;
2527  Array<int> dofs;
2528  for (int i = 0; i < GetNE(); i++)
2529  {
2530  // Since element indices do not change, we need to permute element
2531  // interior dofs only when there are at least 2 interior dofs in an
2532  // element (assuming the nodal dofs are non-directional).
2533  fes->GetElementInteriorDofs(i, dofs);
2534  if (dofs.Size() > 1)
2535  {
2536  need_elem_vert = true;
2537  break;
2538  }
2539  }
2540  if (need_elem_vert)
2541  {
2542  *old_elem_vert = new Table;
2543  (*old_elem_vert)->MakeI(GetNE());
2544  for (int i = 0; i < GetNE(); i++)
2545  {
2546  (*old_elem_vert)->AddColumnsInRow(i, elements[i]->GetNVertices());
2547  }
2548  (*old_elem_vert)->MakeJ();
2549  for (int i = 0; i < GetNE(); i++)
2550  {
2551  (*old_elem_vert)->AddConnections(i, elements[i]->GetVertices(),
2552  elements[i]->GetNVertices());
2553  }
2554  (*old_elem_vert)->ShiftUpI();
2555  }
2556  }
2557 }
2558 
2559 void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
2560 {
2561  FiniteElementSpace *fes = Nodes->FESpace();
2562  const FiniteElementCollection *fec = fes->FEColl();
2563  Array<int> old_dofs, new_dofs;
2564 
2565  // assuming that all edges have the same number of dofs
2566  if (NumOfEdges) { fes->GetEdgeInteriorDofs(0, old_dofs); }
2567  const int num_edge_dofs = old_dofs.Size();
2568 
2569  // Save the original nodes
2570  const Vector onodes = *Nodes;
2571 
2572  // vertex dofs do not need to be moved
2573  fes->GetVertexDofs(0, old_dofs);
2574  int offset = NumOfVertices * old_dofs.Size();
2575 
2576  // edge dofs:
2577  // edge enumeration may be different but edge orientation is the same
2578  if (num_edge_dofs > 0)
2579  {
2580  DSTable new_v_to_v(NumOfVertices);
2581  GetVertexToVertexTable(new_v_to_v);
2582 
2583  for (int i = 0; i < NumOfVertices; i++)
2584  {
2585  for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it)
2586  {
2587  const int old_i = (*old_v_to_v)(i, it.Column());
2588  const int new_i = it.Index();
2589  if (new_i == old_i) { continue; }
2590 
2591  old_dofs.SetSize(num_edge_dofs);
2592  new_dofs.SetSize(num_edge_dofs);
2593  for (int j = 0; j < num_edge_dofs; j++)
2594  {
2595  old_dofs[j] = offset + old_i * num_edge_dofs + j;
2596  new_dofs[j] = offset + new_i * num_edge_dofs + j;
2597  }
2598  fes->DofsToVDofs(old_dofs);
2599  fes->DofsToVDofs(new_dofs);
2600  for (int j = 0; j < old_dofs.Size(); j++)
2601  {
2602  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2603  }
2604  }
2605  }
2606  offset += NumOfEdges * num_edge_dofs;
2607  }
2608 
2609  // face dofs:
2610  // both enumeration and orientation of the faces may be different
2611  if (fes->GetNFDofs() > 0)
2612  {
2613  // generate the old face-vertex table using the unmodified 'faces'
2614  Table old_face_vertex;
2615  old_face_vertex.MakeI(NumOfFaces);
2616  for (int i = 0; i < NumOfFaces; i++)
2617  {
2618  old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices());
2619  }
2620  old_face_vertex.MakeJ();
2621  for (int i = 0; i < NumOfFaces; i++)
2622  old_face_vertex.AddConnections(i, faces[i]->GetVertices(),
2623  faces[i]->GetNVertices());
2624  old_face_vertex.ShiftUpI();
2625 
2626  // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info'
2627  STable3D *faces_tbl = GetElementToFaceTable(1);
2628  GenerateFaces();
2629 
2630  // compute the new face dof offsets
2631  Array<int> new_fdofs(NumOfFaces+1);
2632  new_fdofs[0] = 0;
2633  for (int i = 0; i < NumOfFaces; i++) // i = old face index
2634  {
2635  const int *old_v = old_face_vertex.GetRow(i);
2636  int new_i; // new face index
2637  switch (old_face_vertex.RowSize(i))
2638  {
2639  case 3:
2640  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2641  break;
2642  case 4:
2643  default:
2644  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2645  break;
2646  }
2647  fes->GetFaceInteriorDofs(i, old_dofs);
2648  new_fdofs[new_i+1] = old_dofs.Size();
2649  }
2650  new_fdofs.PartialSum();
2651 
2652  // loop over the old face numbers
2653  for (int i = 0; i < NumOfFaces; i++)
2654  {
2655  const int *old_v = old_face_vertex.GetRow(i), *new_v;
2656  const int *dof_ord;
2657  int new_i, new_or;
2658  switch (old_face_vertex.RowSize(i))
2659  {
2660  case 3:
2661  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2662  new_v = faces[new_i]->GetVertices();
2663  new_or = GetTriOrientation(old_v, new_v);
2664  dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, new_or);
2665  break;
2666  case 4:
2667  default:
2668  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2669  new_v = faces[new_i]->GetVertices();
2670  new_or = GetQuadOrientation(old_v, new_v);
2671  dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, new_or);
2672  break;
2673  }
2674 
2675  fes->GetFaceInteriorDofs(i, old_dofs);
2676  new_dofs.SetSize(old_dofs.Size());
2677  for (int j = 0; j < old_dofs.Size(); j++)
2678  {
2679  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2680  const int old_j = dof_ord[j];
2681  new_dofs[old_j] = offset + new_fdofs[new_i] + j;
2682  }
2683  fes->DofsToVDofs(old_dofs);
2684  fes->DofsToVDofs(new_dofs);
2685  for (int j = 0; j < old_dofs.Size(); j++)
2686  {
2687  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2688  }
2689  }
2690 
2691  offset += fes->GetNFDofs();
2692  delete faces_tbl;
2693  }
2694 
2695  // element dofs:
2696  // element orientation may be different
2697  if (old_elem_vert) // have elements with 2 or more dofs
2698  {
2699  // matters when the 'fec' is
2700  // (this code is executed only for triangles/tets)
2701  // - Pk on triangles, k >= 4
2702  // - Qk on quads, k >= 3
2703  // - Pk on tets, k >= 5
2704  // - Qk on hexes, k >= 3
2705  // - DG spaces
2706  // - ...
2707 
2708  // loop over all elements
2709  for (int i = 0; i < GetNE(); i++)
2710  {
2711  const int *old_v = old_elem_vert->GetRow(i);
2712  const int *new_v = elements[i]->GetVertices();
2713  const int *dof_ord;
2714  int new_or;
2715  const Geometry::Type geom = elements[i]->GetGeometryType();
2716  switch (geom)
2717  {
2718  case Geometry::SEGMENT:
2719  new_or = (old_v[0] == new_v[0]) ? +1 : -1;
2720  break;
2721  case Geometry::TRIANGLE:
2722  new_or = GetTriOrientation(old_v, new_v);
2723  break;
2724  case Geometry::SQUARE:
2725  new_or = GetQuadOrientation(old_v, new_v);
2726  break;
2727  case Geometry::TETRAHEDRON:
2728  new_or = GetTetOrientation(old_v, new_v);
2729  break;
2730  default:
2731  new_or = 0;
2732  MFEM_ABORT(Geometry::Name[geom] << " elements (" << fec->Name()
2733  << " FE collection) are not supported yet!");
2734  break;
2735  }
2736  dof_ord = fec->DofOrderForOrientation(geom, new_or);
2737  MFEM_VERIFY(dof_ord != NULL,
2738  "FE collection '" << fec->Name()
2739  << "' does not define reordering for "
2740  << Geometry::Name[geom] << " elements!");
2741  fes->GetElementInteriorDofs(i, old_dofs);
2742  new_dofs.SetSize(old_dofs.Size());
2743  for (int j = 0; j < new_dofs.Size(); j++)
2744  {
2745  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2746  const int old_j = dof_ord[j];
2747  new_dofs[old_j] = offset + j;
2748  }
2749  offset += new_dofs.Size();
2750  fes->DofsToVDofs(old_dofs);
2751  fes->DofsToVDofs(new_dofs);
2752  for (int j = 0; j < old_dofs.Size(); j++)
2753  {
2754  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2755  }
2756  }
2757  }
2758 
2759  // Update Tables, faces, etc
2760  if (Dim > 2)
2761  {
2762  if (fes->GetNFDofs() == 0)
2763  {
2764  // needed for FE spaces that have face dofs, even if
2765  // the 'Nodes' do not have face dofs.
2766  GetElementToFaceTable();
2767  GenerateFaces();
2768  }
2769  CheckBdrElementOrientation();
2770  }
2771  if (el_to_edge)
2772  {
2773  // update 'el_to_edge', 'be_to_edge' (2D), 'bel_to_edge' (3D)
2774  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2775  if (Dim == 2)
2776  {
2777  // update 'faces' and 'faces_info'
2778  GenerateFaces();
2779  CheckBdrElementOrientation();
2780  }
2781  }
2782  // To force FE space update, we need to increase 'sequence':
2783  sequence++;
2784  last_operation = Mesh::NONE;
2785  fes->Update(false); // want_transform = false
2786  Nodes->Update(); // just needed to update Nodes->sequence
2787 }
2788 
2789 void Mesh::FinalizeTetMesh(int generate_edges, int refine, bool fix_orientation)
2790 {
2791  FinalizeCheck();
2792  CheckElementOrientation(fix_orientation);
2793 
2794  if (NumOfBdrElements == 0)
2795  {
2796  GetElementToFaceTable();
2797  GenerateFaces();
2798  GenerateBoundaryElements();
2799  }
2800 
2801  if (refine)
2802  {
2803  DSTable v_to_v(NumOfVertices);
2804  GetVertexToVertexTable(v_to_v);
2805  MarkTetMeshForRefinement(v_to_v);
2806  }
2807 
2808  GetElementToFaceTable();
2809  GenerateFaces();
2810 
2811  CheckBdrElementOrientation();
2812 
2813  if (generate_edges == 1)
2814  {
2815  el_to_edge = new Table;
2816  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2817  }
2818  else
2819  {
2820  el_to_edge = NULL; // Not really necessary -- InitTables was called
2821  bel_to_edge = NULL;
2822  NumOfEdges = 0;
2823  }
2824 
2825  SetAttributes();
2826 
2827  SetMeshGen();
2828 }
2829 
2830 void Mesh::FinalizeWedgeMesh(int generate_edges, int refine,
2831  bool fix_orientation)
2832 {
2833  FinalizeCheck();
2834  CheckElementOrientation(fix_orientation);
2835 
2836  if (NumOfBdrElements == 0)
2837  {
2838  GetElementToFaceTable();
2839  GenerateFaces();
2840  GenerateBoundaryElements();
2841  }
2842 
2843  GetElementToFaceTable();
2844  GenerateFaces();
2845 
2846  CheckBdrElementOrientation();
2847 
2848  if (generate_edges == 1)
2849  {
2850  el_to_edge = new Table;
2851  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2852  }
2853  else
2854  {
2855  el_to_edge = NULL; // Not really necessary -- InitTables was called
2856  bel_to_edge = NULL;
2857  NumOfEdges = 0;
2858  }
2859 
2860  SetAttributes();
2861 
2862  SetMeshGen();
2863 }
2864 
2865 void Mesh::FinalizeHexMesh(int generate_edges, int refine, bool fix_orientation)
2866 {
2867  FinalizeCheck();
2868  CheckElementOrientation(fix_orientation);
2869 
2870  GetElementToFaceTable();
2871  GenerateFaces();
2872 
2873  if (NumOfBdrElements == 0)
2874  {
2875  GenerateBoundaryElements();
2876  }
2877 
2878  CheckBdrElementOrientation();
2879 
2880  if (generate_edges)
2881  {
2882  el_to_edge = new Table;
2883  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2884  }
2885  else
2886  {
2887  NumOfEdges = 0;
2888  }
2889 
2890  SetAttributes();
2891 
2892  SetMeshGen();
2893 }
2894 
2895 void Mesh::FinalizeMesh(int refine, bool fix_orientation)
2896 {
2897  FinalizeTopology();
2898 
2899  Finalize(refine, fix_orientation);
2900 }
2901 
2902 void Mesh::FinalizeTopology(bool generate_bdr)
2903 {
2904  // Requirements: the following should be defined:
2905  // 1) Dim
2906  // 2) NumOfElements, elements
2907  // 3) NumOfBdrElements, boundary
2908  // 4) NumOfVertices
2909  // Optional:
2910  // 2) ncmesh may be defined
2911  // 3) el_to_edge may be allocated (it will be re-computed)
2912 
2913  FinalizeCheck();
2914  bool generate_edges = true;
2915 
2916  if (spaceDim == 0) { spaceDim = Dim; }
2917  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
2918 
2919  // if the user defined any hanging nodes (see AddVertexParent),
2920  // we're initializing a non-conforming mesh
2921  if (tmp_vertex_parents.Size())
2922  {
2923  MFEM_VERIFY(ncmesh == NULL, "");
2924  ncmesh = new NCMesh(this);
2925 
2926  // we need to recreate the Mesh because NCMesh reorders the vertices
2927  // (see NCMesh::UpdateVertices())
2928  InitFromNCMesh(*ncmesh);
2929  ncmesh->OnMeshUpdated(this);
2930  GenerateNCFaceInfo();
2931 
2932  SetAttributes();
2933 
2934  tmp_vertex_parents.DeleteAll();
2935  return;
2936  }
2937 
2938  // set the mesh type: 'meshgen', ...
2939  SetMeshGen();
2940 
2941  // generate the faces
2942  if (Dim > 2)
2943  {
2944  GetElementToFaceTable();
2945  GenerateFaces();
2946  if (NumOfBdrElements == 0 && generate_bdr)
2947  {
2948  GenerateBoundaryElements();
2949  GetElementToFaceTable(); // update be_to_face
2950  }
2951  }
2952  else
2953  {
2954  NumOfFaces = 0;
2955  }
2956 
2957  // generate edges if requested
2958  if (Dim > 1 && generate_edges)
2959  {
2960  // el_to_edge may already be allocated (P2 VTK meshes)
2961  if (!el_to_edge) { el_to_edge = new Table; }
2962  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2963  if (Dim == 2)
2964  {
2965  GenerateFaces(); // 'Faces' in 2D refers to the edges
2966  if (NumOfBdrElements == 0 && generate_bdr)
2967  {
2968  GenerateBoundaryElements();
2969  }
2970  }
2971  }
2972  else
2973  {
2974  NumOfEdges = 0;
2975  }
2976 
2977  if (Dim == 1)
2978  {
2979  GenerateFaces();
2980  }
2981 
2982  if (ncmesh)
2983  {
2984  // tell NCMesh the numbering of edges/faces
2985  ncmesh->OnMeshUpdated(this);
2986 
2987  // update faces_info with NC relations
2988  GenerateNCFaceInfo();
2989  }
2990 
2991  // generate the arrays 'attributes' and 'bdr_attributes'
2992  SetAttributes();
2993 }
2994 
2995 void Mesh::Finalize(bool refine, bool fix_orientation)
2996 {
2997  if (NURBSext || ncmesh)
2998  {
2999  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
3000  MFEM_ASSERT(CheckBdrElementOrientation() == 0, "");
3001  return;
3002  }
3003 
3004  // Requirements:
3005  // 1) FinalizeTopology() or equivalent was called
3006  // 2) if (Nodes == NULL), vertices must be defined
3007  // 3) if (Nodes != NULL), Nodes must be defined
3008 
3009  const bool check_orientation = true; // for regular elements, not boundary
3010  const bool curved = (Nodes != NULL);
3011  const bool may_change_topology =
3012  ( refine && (Dim > 1 && (meshgen & 1)) ) ||
3013  ( check_orientation && fix_orientation &&
3014  (Dim == 2 || (Dim == 3 && (meshgen & 1))) );
3015 
3016  DSTable *old_v_to_v = NULL;
3017  Table *old_elem_vert = NULL;
3018 
3019  if (curved && may_change_topology)
3020  {
3021  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
3022  }
3023 
3024  if (check_orientation)
3025  {
3026  // check and optionally fix element orientation
3027  CheckElementOrientation(fix_orientation);
3028  }
3029  if (refine)
3030  {
3031  MarkForRefinement(); // may change topology!
3032  }
3033 
3034  if (may_change_topology)
3035  {
3036  if (curved)
3037  {
3038  DoNodeReorder(old_v_to_v, old_elem_vert); // updates the mesh topology
3039  delete old_elem_vert;
3040  delete old_v_to_v;
3041  }
3042  else
3043  {
3044  FinalizeTopology(); // Re-computes some data unnecessarily.
3045  }
3046 
3047  // TODO: maybe introduce Mesh::NODE_REORDER operation and FESpace::
3048  // NodeReorderMatrix and do Nodes->Update() instead of DoNodeReorder?
3049  }
3050 
3051  // check and fix boundary element orientation
3052  CheckBdrElementOrientation();
3053 
3054 #ifdef MFEM_DEBUG
3055  // For non-orientable surfaces/manifolds, the check below will fail, so we
3056  // only perform it when Dim == spaceDim.
3057  if (Dim >= 2 && Dim == spaceDim)
3058  {
3059  const int num_faces = GetNumFaces();
3060  for (int i = 0; i < num_faces; i++)
3061  {
3062  MFEM_VERIFY(faces_info[i].Elem2No < 0 ||
3063  faces_info[i].Elem2Inf%2 != 0, "Invalid mesh topology."
3064  " Interior face with incompatible orientations.");
3065  }
3066  }
3067 #endif
3068 }
3069 
3070 void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
3071  double sx, double sy, double sz, bool sfc_ordering)
3072 {
3073  int x, y, z;
3074 
3075  int NVert, NElem, NBdrElem;
3076 
3077  NVert = (nx+1) * (ny+1) * (nz+1);
3078  NElem = nx * ny * nz;
3079  NBdrElem = 2*(nx*ny+nx*nz+ny*nz);
3080  if (type == Element::TETRAHEDRON)
3081  {
3082  NElem *= 6;
3083  NBdrElem *= 2;
3084  }
3085  else if (type == Element::WEDGE)
3086  {
3087  NElem *= 2;
3088  NBdrElem += 2*nx*ny;
3089  }
3090  else if (type == Element::PYRAMID)
3091  {
3092  NElem *= 6;
3093  NVert += nx * ny * nz;
3094  }
3095 
3096  InitMesh(3, 3, NVert, NElem, NBdrElem);
3097 
3098  double coord[3];
3099  int ind[9];
3100 
3101  // Sets vertices and the corresponding coordinates
3102  for (z = 0; z <= nz; z++)
3103  {
3104  coord[2] = ((double) z / nz) * sz;
3105  for (y = 0; y <= ny; y++)
3106  {
3107  coord[1] = ((double) y / ny) * sy;
3108  for (x = 0; x <= nx; x++)
3109  {
3110  coord[0] = ((double) x / nx) * sx;
3111  AddVertex(coord);
3112  }
3113  }
3114  }
3115  if (type == Element::PYRAMID)
3116  {
3117  for (z = 0; z < nz; z++)
3118  {
3119  coord[2] = (((double) z + 0.5) / nz) * sz;
3120  for (y = 0; y < ny; y++)
3121  {
3122  coord[1] = (((double) y + 0.5 ) / ny) * sy;
3123  for (x = 0; x < nx; x++)
3124  {
3125  coord[0] = (((double) x + 0.5 ) / nx) * sx;
3126  AddVertex(coord);
3127  }
3128  }
3129  }
3130  }
3131 
3132 #define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
3133 #define VTXP(XC, YC, ZC) ((nx+1)*(ny+1)*(nz+1)+(XC)+((YC)+(ZC)*ny)*nx)
3134 
3135  // Sets elements and the corresponding indices of vertices
3136  if (sfc_ordering && type == Element::HEXAHEDRON)
3137  {
3138  Array<int> sfc;
3139  NCMesh::GridSfcOrdering3D(nx, ny, nz, sfc);
3140  MFEM_VERIFY(sfc.Size() == 3*nx*ny*nz, "");
3141 
3142  for (int k = 0; k < nx*ny*nz; k++)
3143  {
3144  x = sfc[3*k + 0];
3145  y = sfc[3*k + 1];
3146  z = sfc[3*k + 2];
3147 
3148  // *INDENT-OFF*
3149  ind[0] = VTX(x , y , z );
3150  ind[1] = VTX(x+1, y , z );
3151  ind[2] = VTX(x+1, y+1, z );
3152  ind[3] = VTX(x , y+1, z );
3153  ind[4] = VTX(x , y , z+1);
3154  ind[5] = VTX(x+1, y , z+1);
3155  ind[6] = VTX(x+1, y+1, z+1);
3156  ind[7] = VTX(x , y+1, z+1);
3157  // *INDENT-ON*
3158 
3159  AddHex(ind, 1);
3160  }
3161  }
3162  else
3163  {
3164  for (z = 0; z < nz; z++)
3165  {
3166  for (y = 0; y < ny; y++)
3167  {
3168  for (x = 0; x < nx; x++)
3169  {
3170  // *INDENT-OFF*
3171  ind[0] = VTX(x , y , z );
3172  ind[1] = VTX(x+1, y , z );
3173  ind[2] = VTX(x+1, y+1, z );
3174  ind[3] = VTX(x , y+1, z );
3175  ind[4] = VTX(x , y , z+1);
3176  ind[5] = VTX(x+1, y , z+1);
3177  ind[6] = VTX(x+1, y+1, z+1);
3178  ind[7] = VTX( x, y+1, z+1);
3179  // *INDENT-ON*
3180  if (type == Element::TETRAHEDRON)
3181  {
3182  AddHexAsTets(ind, 1);
3183  }
3184  else if (type == Element::WEDGE)
3185  {
3186  AddHexAsWedges(ind, 1);
3187  }
3188  else if (type == Element::PYRAMID)
3189  {
3190  ind[8] = VTXP(x, y, z);
3191  AddHexAsPyramids(ind, 1);
3192  }
3193  else
3194  {
3195  AddHex(ind, 1);
3196  }
3197  }
3198  }
3199  }
3200  }
3201 
3202  // Sets boundary elements and the corresponding indices of vertices
3203  // bottom, bdr. attribute 1
3204  for (y = 0; y < ny; y++)
3205  {
3206  for (x = 0; x < nx; x++)
3207  {
3208  // *INDENT-OFF*
3209  ind[0] = VTX(x , y , 0);
3210  ind[1] = VTX(x , y+1, 0);
3211  ind[2] = VTX(x+1, y+1, 0);
3212  ind[3] = VTX(x+1, y , 0);
3213  // *INDENT-ON*
3214  if (type == Element::TETRAHEDRON)
3215  {
3216  AddBdrQuadAsTriangles(ind, 1);
3217  }
3218  else if (type == Element::WEDGE)
3219  {
3220  AddBdrQuadAsTriangles(ind, 1);
3221  }
3222  else
3223  {
3224  AddBdrQuad(ind, 1);
3225  }
3226  }
3227  }
3228  // top, bdr. attribute 6
3229  for (y = 0; y < ny; y++)
3230  {
3231  for (x = 0; x < nx; x++)
3232  {
3233  // *INDENT-OFF*
3234  ind[0] = VTX(x , y , nz);
3235  ind[1] = VTX(x+1, y , nz);
3236  ind[2] = VTX(x+1, y+1, nz);
3237  ind[3] = VTX(x , y+1, nz);
3238  // *INDENT-ON*
3239  if (type == Element::TETRAHEDRON)
3240  {
3241  AddBdrQuadAsTriangles(ind, 6);
3242  }
3243  else if (type == Element::WEDGE)
3244  {
3245  AddBdrQuadAsTriangles(ind, 6);
3246  }
3247  else
3248  {
3249  AddBdrQuad(ind, 6);
3250  }
3251  }
3252  }
3253  // left, bdr. attribute 5
3254  for (z = 0; z < nz; z++)
3255  {
3256  for (y = 0; y < ny; y++)
3257  {
3258  // *INDENT-OFF*
3259  ind[0] = VTX(0 , y , z );
3260  ind[1] = VTX(0 , y , z+1);
3261  ind[2] = VTX(0 , y+1, z+1);
3262  ind[3] = VTX(0 , y+1, z );
3263  // *INDENT-ON*
3264  if (type == Element::TETRAHEDRON)
3265  {
3266  AddBdrQuadAsTriangles(ind, 5);
3267  }
3268  else
3269  {
3270  AddBdrQuad(ind, 5);
3271  }
3272  }
3273  }
3274  // right, bdr. attribute 3
3275  for (z = 0; z < nz; z++)
3276  {
3277  for (y = 0; y < ny; y++)
3278  {
3279  // *INDENT-OFF*
3280  ind[0] = VTX(nx, y , z );
3281  ind[1] = VTX(nx, y+1, z );
3282  ind[2] = VTX(nx, y+1, z+1);
3283  ind[3] = VTX(nx, y , z+1);
3284  // *INDENT-ON*
3285  if (type == Element::TETRAHEDRON)
3286  {
3287  AddBdrQuadAsTriangles(ind, 3);
3288  }
3289  else
3290  {
3291  AddBdrQuad(ind, 3);
3292  }
3293  }
3294  }
3295  // front, bdr. attribute 2
3296  for (x = 0; x < nx; x++)
3297  {
3298  for (z = 0; z < nz; z++)
3299  {
3300  // *INDENT-OFF*
3301  ind[0] = VTX(x , 0, z );
3302  ind[1] = VTX(x+1, 0, z );
3303  ind[2] = VTX(x+1, 0, z+1);
3304  ind[3] = VTX(x , 0, z+1);
3305  // *INDENT-ON*
3306  if (type == Element::TETRAHEDRON)
3307  {
3308  AddBdrQuadAsTriangles(ind, 2);
3309  }
3310  else
3311  {
3312  AddBdrQuad(ind, 2);
3313  }
3314  }
3315  }
3316  // back, bdr. attribute 4
3317  for (x = 0; x < nx; x++)
3318  {
3319  for (z = 0; z < nz; z++)
3320  {
3321  // *INDENT-OFF*
3322  ind[0] = VTX(x , ny, z );
3323  ind[1] = VTX(x , ny, z+1);
3324  ind[2] = VTX(x+1, ny, z+1);
3325  ind[3] = VTX(x+1, ny, z );
3326  // *INDENT-ON*
3327  if (type == Element::TETRAHEDRON)
3328  {
3329  AddBdrQuadAsTriangles(ind, 4);
3330  }
3331  else
3332  {
3333  AddBdrQuad(ind, 4);
3334  }
3335  }
3336  }
3337 
3338 #undef VTX
3339 
3340 #if 0
3341  ofstream test_stream("debug.mesh");
3342  Print(test_stream);
3343  test_stream.close();
3344 #endif
3345 
3346  FinalizeTopology();
3347 
3348  // Finalize(...) can be called after this method, if needed
3349 }
3350 
3351 void Mesh::Make2D(int nx, int ny, Element::Type type,
3352  double sx, double sy,
3353  bool generate_edges, bool sfc_ordering)
3354 {
3355  int i, j, k;
3356 
3357  SetEmpty();
3358 
3359  Dim = spaceDim = 2;
3360 
3361  // Creates quadrilateral mesh
3362  if (type == Element::QUADRILATERAL)
3363  {
3364  NumOfVertices = (nx+1) * (ny+1);
3365  NumOfElements = nx * ny;
3366  NumOfBdrElements = 2 * nx + 2 * ny;
3367 
3368  vertices.SetSize(NumOfVertices);
3369  elements.SetSize(NumOfElements);
3370  boundary.SetSize(NumOfBdrElements);
3371 
3372  double cx, cy;
3373  int ind[4];
3374 
3375  // Sets vertices and the corresponding coordinates
3376  k = 0;
3377  for (j = 0; j < ny+1; j++)
3378  {
3379  cy = ((double) j / ny) * sy;
3380  for (i = 0; i < nx+1; i++)
3381  {
3382  cx = ((double) i / nx) * sx;
3383  vertices[k](0) = cx;
3384  vertices[k](1) = cy;
3385  k++;
3386  }
3387  }
3388 
3389  // Sets elements and the corresponding indices of vertices
3390  if (sfc_ordering)
3391  {
3392  Array<int> sfc;
3393  NCMesh::GridSfcOrdering2D(nx, ny, sfc);
3394  MFEM_VERIFY(sfc.Size() == 2*nx*ny, "");
3395 
3396  for (k = 0; k < nx*ny; k++)
3397  {
3398  i = sfc[2*k + 0];
3399  j = sfc[2*k + 1];
3400  ind[0] = i + j*(nx+1);
3401  ind[1] = i + 1 +j*(nx+1);
3402  ind[2] = i + 1 + (j+1)*(nx+1);
3403  ind[3] = i + (j+1)*(nx+1);
3404  elements[k] = new Quadrilateral(ind);
3405  }
3406  }
3407  else
3408  {
3409  k = 0;
3410  for (j = 0; j < ny; j++)
3411  {
3412  for (i = 0; i < nx; i++)
3413  {
3414  ind[0] = i + j*(nx+1);
3415  ind[1] = i + 1 +j*(nx+1);
3416  ind[2] = i + 1 + (j+1)*(nx+1);
3417  ind[3] = i + (j+1)*(nx+1);
3418  elements[k] = new Quadrilateral(ind);
3419  k++;
3420  }
3421  }
3422  }
3423 
3424  // Sets boundary elements and the corresponding indices of vertices
3425  int m = (nx+1)*ny;
3426  for (i = 0; i < nx; i++)
3427  {
3428  boundary[i] = new Segment(i, i+1, 1);
3429  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3430  }
3431  m = nx+1;
3432  for (j = 0; j < ny; j++)
3433  {
3434  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3435  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3436  }
3437  }
3438  // Creates triangular mesh
3439  else if (type == Element::TRIANGLE)
3440  {
3441  NumOfVertices = (nx+1) * (ny+1);
3442  NumOfElements = 2 * nx * ny;
3443  NumOfBdrElements = 2 * nx + 2 * ny;
3444 
3445  vertices.SetSize(NumOfVertices);
3446  elements.SetSize(NumOfElements);
3447  boundary.SetSize(NumOfBdrElements);
3448 
3449  double cx, cy;
3450  int ind[3];
3451 
3452  // Sets vertices and the corresponding coordinates
3453  k = 0;
3454  for (j = 0; j < ny+1; j++)
3455  {
3456  cy = ((double) j / ny) * sy;
3457  for (i = 0; i < nx+1; i++)
3458  {
3459  cx = ((double) i / nx) * sx;
3460  vertices[k](0) = cx;
3461  vertices[k](1) = cy;
3462  k++;
3463  }
3464  }
3465 
3466  // Sets the elements and the corresponding indices of vertices
3467  k = 0;
3468  for (j = 0; j < ny; j++)
3469  {
3470  for (i = 0; i < nx; i++)
3471  {
3472  ind[0] = i + j*(nx+1);
3473  ind[1] = i + 1 + (j+1)*(nx+1);
3474  ind[2] = i + (j+1)*(nx+1);
3475  elements[k] = new Triangle(ind);
3476  k++;
3477  ind[1] = i + 1 + j*(nx+1);
3478  ind[2] = i + 1 + (j+1)*(nx+1);
3479  elements[k] = new Triangle(ind);
3480  k++;
3481  }
3482  }
3483 
3484  // Sets boundary elements and the corresponding indices of vertices
3485  int m = (nx+1)*ny;
3486  for (i = 0; i < nx; i++)
3487  {
3488  boundary[i] = new Segment(i, i+1, 1);
3489  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3490  }
3491  m = nx+1;
3492  for (j = 0; j < ny; j++)
3493  {
3494  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3495  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3496  }
3497 
3498  // MarkTriMeshForRefinement(); // done in Finalize(...)
3499  }
3500  else
3501  {
3502  MFEM_ABORT("Unsupported element type.");
3503  }
3504 
3505  SetMeshGen();
3506  CheckElementOrientation();
3507 
3508  if (generate_edges == 1)
3509  {
3510  el_to_edge = new Table;
3511  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3512  GenerateFaces();
3513  CheckBdrElementOrientation();
3514  }
3515  else
3516  {
3517  NumOfEdges = 0;
3518  }
3519 
3520  NumOfFaces = 0;
3521 
3522  attributes.Append(1);
3523  bdr_attributes.Append(1); bdr_attributes.Append(2);
3524  bdr_attributes.Append(3); bdr_attributes.Append(4);
3525 
3526  // Finalize(...) can be called after this method, if needed
3527 }
3528 
3529 void Mesh::Make1D(int n, double sx)
3530 {
3531  int j, ind[1];
3532 
3533  SetEmpty();
3534 
3535  Dim = 1;
3536  spaceDim = 1;
3537 
3538  NumOfVertices = n + 1;
3539  NumOfElements = n;
3540  NumOfBdrElements = 2;
3541  vertices.SetSize(NumOfVertices);
3542  elements.SetSize(NumOfElements);
3543  boundary.SetSize(NumOfBdrElements);
3544 
3545  // Sets vertices and the corresponding coordinates
3546  for (j = 0; j < n+1; j++)
3547  {
3548  vertices[j](0) = ((double) j / n) * sx;
3549  }
3550 
3551  // Sets elements and the corresponding indices of vertices
3552  for (j = 0; j < n; j++)
3553  {
3554  elements[j] = new Segment(j, j+1, 1);
3555  }
3556 
3557  // Sets the boundary elements
3558  ind[0] = 0;
3559  boundary[0] = new Point(ind, 1);
3560  ind[0] = n;
3561  boundary[1] = new Point(ind, 2);
3562 
3563  NumOfEdges = 0;
3564  NumOfFaces = 0;
3565 
3566  SetMeshGen();
3567  GenerateFaces();
3568 
3569  attributes.Append(1);
3570  bdr_attributes.Append(1); bdr_attributes.Append(2);
3571 }
3572 
3573 Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
3574 {
3575  Dim = mesh.Dim;
3576  spaceDim = mesh.spaceDim;
3577 
3578  NumOfVertices = mesh.NumOfVertices;
3579  NumOfElements = mesh.NumOfElements;
3580  NumOfBdrElements = mesh.NumOfBdrElements;
3581  NumOfEdges = mesh.NumOfEdges;
3582  NumOfFaces = mesh.NumOfFaces;
3583  nbInteriorFaces = mesh.nbInteriorFaces;
3584  nbBoundaryFaces = mesh.nbBoundaryFaces;
3585 
3586  meshgen = mesh.meshgen;
3587  mesh_geoms = mesh.mesh_geoms;
3588 
3589  // Create the new Mesh instance without a record of its refinement history
3590  sequence = 0;
3591  last_operation = Mesh::NONE;
3592 
3593  // Duplicate the elements
3594  elements.SetSize(NumOfElements);
3595  for (int i = 0; i < NumOfElements; i++)
3596  {
3597  elements[i] = mesh.elements[i]->Duplicate(this);
3598  }
3599 
3600  // Copy the vertices
3601  mesh.vertices.Copy(vertices);
3602 
3603  // Duplicate the boundary
3604  boundary.SetSize(NumOfBdrElements);
3605  for (int i = 0; i < NumOfBdrElements; i++)
3606  {
3607  boundary[i] = mesh.boundary[i]->Duplicate(this);
3608  }
3609 
3610  // Copy the element-to-face Table, el_to_face
3611  el_to_face = (mesh.el_to_face) ? new Table(*mesh.el_to_face) : NULL;
3612 
3613  // Copy the boundary-to-face Array, be_to_face.
3614  mesh.be_to_face.Copy(be_to_face);
3615 
3616  // Copy the element-to-edge Table, el_to_edge
3617  el_to_edge = (mesh.el_to_edge) ? new Table(*mesh.el_to_edge) : NULL;
3618 
3619  // Copy the boundary-to-edge Table, bel_to_edge (3D)
3620  bel_to_edge = (mesh.bel_to_edge) ? new Table(*mesh.bel_to_edge) : NULL;
3621 
3622  // Copy the boundary-to-edge Array, be_to_edge (2D)
3623  mesh.be_to_edge.Copy(be_to_edge);
3624 
3625  // Duplicate the faces and faces_info.
3626  faces.SetSize(mesh.faces.Size());
3627  for (int i = 0; i < faces.Size(); i++)
3628  {
3629  Element *face = mesh.faces[i]; // in 1D the faces are NULL
3630  faces[i] = (face) ? face->Duplicate(this) : NULL;
3631  }
3632  mesh.faces_info.Copy(faces_info);
3633  mesh.nc_faces_info.Copy(nc_faces_info);
3634 
3635  // Do NOT copy the element-to-element Table, el_to_el
3636  el_to_el = NULL;
3637 
3638  // Do NOT copy the face-to-edge Table, face_edge
3639  face_edge = NULL;
3640  face_to_elem = NULL;
3641 
3642  // Copy the edge-to-vertex Table, edge_vertex
3643  edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
3644 
3645  // Copy the attributes and bdr_attributes
3646  mesh.attributes.Copy(attributes);
3647  mesh.bdr_attributes.Copy(bdr_attributes);
3648 
3649  // Deep copy the NURBSExtension.
3650 #ifdef MFEM_USE_MPI
3651  ParNURBSExtension *pNURBSext =
3652  dynamic_cast<ParNURBSExtension *>(mesh.NURBSext);
3653  if (pNURBSext)
3654  {
3655  NURBSext = new ParNURBSExtension(*pNURBSext);
3656  }
3657  else
3658 #endif
3659  {
3660  NURBSext = mesh.NURBSext ? new NURBSExtension(*mesh.NURBSext) : NULL;
3661  }
3662 
3663  // Deep copy the NCMesh.
3664 #ifdef MFEM_USE_MPI
3665  if (dynamic_cast<const ParMesh*>(&mesh))
3666  {
3667  ncmesh = NULL; // skip; will be done in ParMesh copy ctor
3668  }
3669  else
3670 #endif
3671  {
3672  ncmesh = mesh.ncmesh ? new NCMesh(*mesh.ncmesh) : NULL;
3673  }
3674 
3675  // Duplicate the Nodes, including the FiniteElementCollection and the
3676  // FiniteElementSpace
3677  if (mesh.Nodes && copy_nodes)
3678  {
3679  FiniteElementSpace *fes = mesh.Nodes->FESpace();
3680  const FiniteElementCollection *fec = fes->FEColl();
3681  FiniteElementCollection *fec_copy =
3682  FiniteElementCollection::New(fec->Name());
3683  FiniteElementSpace *fes_copy =
3684  new FiniteElementSpace(*fes, this, fec_copy);
3685  Nodes = new GridFunction(fes_copy);
3686  Nodes->MakeOwner(fec_copy);
3687  *Nodes = *mesh.Nodes;
3688  own_nodes = 1;
3689  }
3690  else
3691  {
3692  Nodes = mesh.Nodes;
3693  own_nodes = 0;
3694  }
3695 }
3696 
3697 Mesh::Mesh(Mesh &&mesh) : Mesh()
3698 {
3699  Swap(mesh, true);
3700 }
3701 
3703 {
3704  Swap(mesh, true);
3705  return *this;
3706 }
3707 
3708 Mesh Mesh::LoadFromFile(const char *filename, int generate_edges, int refine,
3709  bool fix_orientation)
3710 {
3711  Mesh mesh;
3712  named_ifgzstream imesh(filename);
3713  if (!imesh) { MFEM_ABORT("Mesh file not found: " << filename << '\n'); }
3714  else { mesh.Load(imesh, generate_edges, refine, fix_orientation); }
3715  return mesh;
3716 }
3717 
3718 Mesh Mesh::MakeCartesian1D(int n, double sx)
3719 {
3720  Mesh mesh;
3721  mesh.Make1D(n, sx);
3722  // mesh.Finalize(); not needed in this case
3723  return mesh;
3724 }
3725 
3727  int nx, int ny, Element::Type type, bool generate_edges,
3728  double sx, double sy, bool sfc_ordering)
3729 {
3730  Mesh mesh;
3731  mesh.Make2D(nx, ny, type, sx, sy, generate_edges, sfc_ordering);
3732  mesh.Finalize(true); // refine = true
3733  return mesh;
3734 }
3735 
3737  int nx, int ny, int nz, Element::Type type,
3738  double sx, double sy, double sz, bool sfc_ordering)
3739 {
3740  Mesh mesh;
3741  mesh.Make3D(nx, ny, nz, type, sx, sy, sz, sfc_ordering);
3742  mesh.Finalize(true); // refine = true
3743  return mesh;
3744 }
3745 
3746 Mesh Mesh::MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
3747 {
3748  Mesh mesh;
3749  Array<int> ref_factors(orig_mesh.GetNE());
3750  ref_factors = ref_factor;
3751  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3752  return mesh;
3753 }
3754 
3755 Mesh Mesh::MakeRefined(Mesh &orig_mesh, const Array<int> &ref_factors,
3756  int ref_type)
3757 {
3758  Mesh mesh;
3759  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3760  return mesh;
3761 }
3762 
3763 Mesh::Mesh(const char *filename, int generate_edges, int refine,
3764  bool fix_orientation)
3765 {
3766  // Initialization as in the default constructor
3767  SetEmpty();
3768 
3769  named_ifgzstream imesh(filename);
3770  if (!imesh)
3771  {
3772  // Abort with an error message.
3773  MFEM_ABORT("Mesh file not found: " << filename << '\n');
3774  }
3775  else
3776  {
3777  Load(imesh, generate_edges, refine, fix_orientation);
3778  }
3779 }
3780 
3781 Mesh::Mesh(std::istream &input, int generate_edges, int refine,
3782  bool fix_orientation)
3783 {
3784  SetEmpty();
3785  Load(input, generate_edges, refine, fix_orientation);
3786 }
3787 
3788 void Mesh::ChangeVertexDataOwnership(double *vertex_data, int len_vertex_data,
3789  bool zerocopy)
3790 {
3791  // A dimension of 3 is now required since we use mfem::Vertex objects as PODs
3792  // and these object have a hardcoded double[3] entry
3793  MFEM_VERIFY(len_vertex_data >= NumOfVertices * 3,
3794  "Not enough vertices in external array : "
3795  "len_vertex_data = "<< len_vertex_data << ", "
3796  "NumOfVertices * 3 = " << NumOfVertices * 3);
3797  // Allow multiple calls to this method with the same vertex_data
3798  if (vertex_data == (double *)(vertices.GetData()))
3799  {
3800  MFEM_ASSERT(!vertices.OwnsData(), "invalid ownership");
3801  return;
3802  }
3803  if (!zerocopy)
3804  {
3805  memcpy(vertex_data, vertices.GetData(),
3806  NumOfVertices * 3 * sizeof(double));
3807  }
3808  // Vertex is POD double[3]
3809  vertices.MakeRef(reinterpret_cast<Vertex*>(vertex_data), NumOfVertices);
3810 }
3811 
3812 Mesh::Mesh(double *vertices_, int num_vertices,
3813  int *element_indices, Geometry::Type element_type,
3814  int *element_attributes, int num_elements,
3815  int *boundary_indices, Geometry::Type boundary_type,
3816  int *boundary_attributes, int num_boundary_elements,
3817  int dimension, int space_dimension)
3818 {
3819  if (space_dimension == -1)
3820  {
3821  space_dimension = dimension;
3822  }
3823 
3824  InitMesh(dimension, space_dimension, /*num_vertices*/ 0, num_elements,
3825  num_boundary_elements);
3826 
3827  int element_index_stride = Geometry::NumVerts[element_type];
3828  int boundary_index_stride = num_boundary_elements > 0 ?
3829  Geometry::NumVerts[boundary_type] : 0;
3830 
3831  // assuming Vertex is POD
3832  vertices.MakeRef(reinterpret_cast<Vertex*>(vertices_), num_vertices);
3833  NumOfVertices = num_vertices;
3834 
3835  for (int i = 0; i < num_elements; i++)
3836  {
3837  elements[i] = NewElement(element_type);
3838  elements[i]->SetVertices(element_indices + i * element_index_stride);
3839  elements[i]->SetAttribute(element_attributes[i]);
3840  }
3841  NumOfElements = num_elements;
3842 
3843  for (int i = 0; i < num_boundary_elements; i++)
3844  {
3845  boundary[i] = NewElement(boundary_type);
3846  boundary[i]->SetVertices(boundary_indices + i * boundary_index_stride);
3847  boundary[i]->SetAttribute(boundary_attributes[i]);
3848  }
3849  NumOfBdrElements = num_boundary_elements;
3850 
3851  FinalizeTopology();
3852 }
3853 
3855 {
3856  switch (geom)
3857  {
3858  case Geometry::POINT: return (new Point);
3859  case Geometry::SEGMENT: return (new Segment);
3860  case Geometry::TRIANGLE: return (new Triangle);
3861  case Geometry::SQUARE: return (new Quadrilateral);
3862  case Geometry::TETRAHEDRON:
3863 #ifdef MFEM_USE_MEMALLOC
3864  return TetMemory.Alloc();
3865 #else
3866  return (new Tetrahedron);
3867 #endif
3868  case Geometry::CUBE: return (new Hexahedron);
3869  case Geometry::PRISM: return (new Wedge);
3870  case Geometry::PYRAMID: return (new Pyramid);
3871  default:
3872  MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
3873  }
3874 
3875  return NULL;
3876 }
3877 
3879 {
3880  int geom, nv, *v;
3881  Element *el;
3882 
3883  input >> geom;
3884  el = NewElement(geom);
3885  MFEM_VERIFY(el, "Unsupported element type: " << geom);
3886  nv = el->GetNVertices();
3887  v = el->GetVertices();
3888  for (int i = 0; i < nv; i++)
3889  {
3890  input >> v[i];
3891  }
3892 
3893  return el;
3894 }
3895 
3896 void Mesh::PrintElementWithoutAttr(const Element *el, std::ostream &os)
3897 {
3898  os << el->GetGeometryType();
3899  const int nv = el->GetNVertices();
3900  const int *v = el->GetVertices();
3901  for (int j = 0; j < nv; j++)
3902  {
3903  os << ' ' << v[j];
3904  }
3905  os << '\n';
3906 }
3907 
3908 Element *Mesh::ReadElement(std::istream &input)
3909 {
3910  int attr;
3911  Element *el;
3912 
3913  input >> attr;
3914  el = ReadElementWithoutAttr(input);
3915  el->SetAttribute(attr);
3916 
3917  return el;
3918 }
3919 
3920 void Mesh::PrintElement(const Element *el, std::ostream &os)
3921 {
3922  os << el->GetAttribute() << ' ';
3923  PrintElementWithoutAttr(el, os);
3924 }
3925 
3927 {
3928  meshgen = mesh_geoms = 0;
3929  for (int i = 0; i < NumOfElements; i++)
3930  {
3931  const Element::Type type = GetElement(i)->GetType();
3932  switch (type)
3933  {
3934  case Element::TETRAHEDRON:
3936  case Element::TRIANGLE:
3937  mesh_geoms |= (1 << Geometry::TRIANGLE);
3938  case Element::SEGMENT:
3939  mesh_geoms |= (1 << Geometry::SEGMENT);
3940  case Element::POINT:
3941  mesh_geoms |= (1 << Geometry::POINT);
3942  meshgen |= 1;
3943  break;
3944 
3945  case Element::HEXAHEDRON:
3946  mesh_geoms |= (1 << Geometry::CUBE);
3948  mesh_geoms |= (1 << Geometry::SQUARE);
3949  mesh_geoms |= (1 << Geometry::SEGMENT);
3950  mesh_geoms |= (1 << Geometry::POINT);
3951  meshgen |= 2;
3952  break;
3953 
3954  case Element::WEDGE:
3955  mesh_geoms |= (1 << Geometry::PRISM);
3956  mesh_geoms |= (1 << Geometry::SQUARE);
3957  mesh_geoms |= (1 << Geometry::TRIANGLE);
3958  mesh_geoms |= (1 << Geometry::SEGMENT);
3959  mesh_geoms |= (1 << Geometry::POINT);
3960  meshgen |= 4;
3961  break;
3962 
3963  case Element::PYRAMID:
3964  mesh_geoms |= (1 << Geometry::PYRAMID);
3965  mesh_geoms |= (1 << Geometry::SQUARE);
3966  mesh_geoms |= (1 << Geometry::TRIANGLE);
3967  mesh_geoms |= (1 << Geometry::SEGMENT);
3968  mesh_geoms |= (1 << Geometry::POINT);
3969  meshgen |= 8;
3970  break;
3971 
3972  default:
3973  MFEM_ABORT("invalid element type: " << type);
3974  break;
3975  }
3976  }
3977 }
3978 
3979 void Mesh::Loader(std::istream &input, int generate_edges,
3980  std::string parse_tag)
3981 {
3982  int curved = 0, read_gf = 1;
3983  bool finalize_topo = true;
3984 
3985  if (!input)
3986  {
3987  MFEM_ABORT("Input stream is not open");
3988  }
3989 
3990  Clear();
3991 
3992  string mesh_type;
3993  input >> ws;
3994  getline(input, mesh_type);
3995  filter_dos(mesh_type);
3996 
3997  // MFEM's conforming mesh formats
3998  int mfem_version = 0;
3999  if (mesh_type == "MFEM mesh v1.0") { mfem_version = 10; } // serial
4000  else if (mesh_type == "MFEM mesh v1.2") { mfem_version = 12; } // parallel
4001 
4002  // MFEM nonconforming mesh format
4003  // (NOTE: previous v1.1 is now under this branch for backward compatibility)
4004  int mfem_nc_version = 0;
4005  if (mesh_type == "MFEM NC mesh v1.0") { mfem_nc_version = 10; }
4006  else if (mesh_type == "MFEM mesh v1.1") { mfem_nc_version = 1 /*legacy*/; }
4007 
4008  if (mfem_version)
4009  {
4010  // Formats mfem_v12 and newer have a tag indicating the end of the mesh
4011  // section in the stream. A user provided parse tag can also be provided
4012  // via the arguments. For example, if this is called from parallel mesh
4013  // object, it can indicate to read until parallel mesh section begins.
4014  if (mfem_version == 12 && parse_tag.empty())
4015  {
4016  parse_tag = "mfem_mesh_end";
4017  }
4018  ReadMFEMMesh(input, mfem_version, curved);
4019  }
4020  else if (mfem_nc_version)
4021  {
4022  MFEM_ASSERT(ncmesh == NULL, "internal error");
4023  int is_nc = 1;
4024 
4025 #ifdef MFEM_USE_MPI
4026  ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
4027  if (pmesh)
4028  {
4029  MFEM_VERIFY(mfem_nc_version >= 10,
4030  "Legacy nonconforming format (MFEM mesh v1.1) cannot be "
4031  "used to load a parallel nonconforming mesh, sorry.");
4032 
4033  ncmesh = new ParNCMesh(pmesh->GetComm(),
4034  input, mfem_nc_version, curved, is_nc);
4035  }
4036  else
4037 #endif
4038  {
4039  ncmesh = new NCMesh(input, mfem_nc_version, curved, is_nc);
4040  }
4042 
4043  if (!is_nc)
4044  {
4045  // special case for backward compatibility with MFEM <=4.2:
4046  // if the "vertex_parents" section is missing in the v1.1 format,
4047  // the mesh is treated as conforming
4048  delete ncmesh;
4049  ncmesh = NULL;
4050  }
4051  }
4052  else if (mesh_type == "linemesh") // 1D mesh
4053  {
4054  ReadLineMesh(input);
4055  }
4056  else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2")
4057  {
4058  if (mesh_type == "curved_areamesh2")
4059  {
4060  curved = 1;
4061  }
4062  ReadNetgen2DMesh(input, curved);
4063  }
4064  else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format")
4065  {
4066  ReadNetgen3DMesh(input);
4067  }
4068  else if (mesh_type == "TrueGrid")
4069  {
4070  ReadTrueGridMesh(input);
4071  }
4072  else if (mesh_type.rfind("# vtk DataFile Version") == 0)
4073  {
4074  int major_vtk_version = mesh_type[mesh_type.length()-3] - '0';
4075  // int minor_vtk_version = mesh_type[mesh_type.length()-1] - '0';
4076  MFEM_VERIFY(major_vtk_version >= 2 && major_vtk_version <= 4,
4077  "Unsupported VTK format");
4078  ReadVTKMesh(input, curved, read_gf, finalize_topo);
4079  }
4080  else if (mesh_type.rfind("<VTKFile ") == 0 || mesh_type.rfind("<?xml") == 0)
4081  {
4082  ReadXML_VTKMesh(input, curved, read_gf, finalize_topo, mesh_type);
4083  }
4084  else if (mesh_type == "MFEM NURBS mesh v1.0")
4085  {
4086  ReadNURBSMesh(input, curved, read_gf);
4087  }
4088  else if (mesh_type == "MFEM INLINE mesh v1.0")
4089  {
4090  ReadInlineMesh(input, generate_edges);
4091  return; // done with inline mesh construction
4092  }
4093  else if (mesh_type == "$MeshFormat") // Gmsh
4094  {
4095  ReadGmshMesh(input, curved, read_gf);
4096  }
4097  else if
4098  ((mesh_type.size() > 2 &&
4099  mesh_type[0] == 'C' && mesh_type[1] == 'D' && mesh_type[2] == 'F') ||
4100  (mesh_type.size() > 3 &&
4101  mesh_type[1] == 'H' && mesh_type[2] == 'D' && mesh_type[3] == 'F'))
4102  {
4103  named_ifgzstream *mesh_input = dynamic_cast<named_ifgzstream *>(&input);
4104  if (mesh_input)
4105  {
4106 #ifdef MFEM_USE_NETCDF
4107  ReadCubit(mesh_input->filename.c_str(), curved, read_gf);
4108 #else
4109  MFEM_ABORT("NetCDF support requires configuration with"
4110  " MFEM_USE_NETCDF=YES");
4111  return;
4112 #endif
4113  }
4114  else
4115  {
4116  MFEM_ABORT("Can not determine Cubit mesh filename!"
4117  " Use mfem::named_ifgzstream for input.");
4118  return;
4119  }
4120  }
4121  else
4122  {
4123  MFEM_ABORT("Unknown input mesh format: " << mesh_type);
4124  return;
4125  }
4126 
4127  // at this point the following should be defined:
4128  // 1) Dim
4129  // 2) NumOfElements, elements
4130  // 3) NumOfBdrElements, boundary
4131  // 4) NumOfVertices, with allocated space in vertices
4132  // 5) curved
4133  // 5a) if curved == 0, vertices must be defined
4134  // 5b) if curved != 0 and read_gf != 0,
4135  // 'input' must point to a GridFunction
4136  // 5c) if curved != 0 and read_gf == 0,
4137  // vertices and Nodes must be defined
4138  // optional:
4139  // 1) el_to_edge may be allocated (as in the case of P2 VTK meshes)
4140  // 2) ncmesh may be allocated
4141 
4142  // FinalizeTopology() will:
4143  // - assume that generate_edges is true
4144  // - assume that refine is false
4145  // - does not check the orientation of regular and boundary elements
4146  if (finalize_topo)
4147  {
4148  // don't generate any boundary elements, especially in parallel
4149  bool generate_bdr = false;
4150 
4151  FinalizeTopology(generate_bdr);
4152  }
4153 
4154  if (curved && read_gf)
4155  {
4156  Nodes = new GridFunction(this, input);
4157 
4158  own_nodes = 1;
4159  spaceDim = Nodes->VectorDim();
4160  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
4161 
4162  // Set vertex coordinates from the 'Nodes'
4164  }
4165 
4166  // If a parse tag was supplied, keep reading the stream until the tag is
4167  // encountered.
4168  if (mfem_version == 12)
4169  {
4170  string line;
4171  do
4172  {
4173  skip_comment_lines(input, '#');
4174  MFEM_VERIFY(input.good(), "Required mesh-end tag not found");
4175  getline(input, line);
4176  filter_dos(line);
4177  // mfem v1.2 may not have parse_tag in it, e.g. if trying to read a
4178  // serial mfem v1.2 mesh as parallel with "mfem_serial_mesh_end" as
4179  // parse_tag. That's why, regardless of parse_tag, we stop reading if
4180  // we find "mfem_mesh_end" which is required by mfem v1.2 format.
4181  if (line == "mfem_mesh_end") { break; }
4182  }
4183  while (line != parse_tag);
4184  }
4185  else if (mfem_nc_version >= 10)
4186  {
4187  string ident;
4188  skip_comment_lines(input, '#');
4189  input >> ident;
4190  MFEM_VERIFY(ident == "mfem_mesh_end",
4191  "invalid mesh: end of file tag not found");
4192  }
4193 
4194  // Finalize(...) should be called after this, if needed.
4195 }
4196 
4197 Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
4198 {
4199  int i, j, ie, ib, iv, *v, nv;
4200  Element *el;
4201  Mesh *m;
4202 
4203  SetEmpty();
4204 
4205  Dim = mesh_array[0]->Dimension();
4206  spaceDim = mesh_array[0]->SpaceDimension();
4207 
4208  if (mesh_array[0]->NURBSext)
4209  {
4210  // assuming the pieces form a partition of a NURBS mesh
4211  NURBSext = new NURBSExtension(mesh_array, num_pieces);
4212 
4215 
4217 
4218  // NumOfBdrElements = NURBSext->GetNBE();
4219  // NURBSext->GetBdrElementTopo(boundary);
4220 
4221  Array<int> lvert_vert, lelem_elem;
4222 
4223  // Here, for visualization purposes, we copy the boundary elements from
4224  // the individual pieces which include the interior boundaries. This
4225  // creates 'boundary' array that is different from the one generated by
4226  // the NURBSExtension which, in particular, makes the boundary-dof table
4227  // invalid. This, in turn, causes GetBdrElementTransformation to not
4228  // function properly.
4229  NumOfBdrElements = 0;
4230  for (i = 0; i < num_pieces; i++)
4231  {
4232  NumOfBdrElements += mesh_array[i]->GetNBE();
4233  }
4234  boundary.SetSize(NumOfBdrElements);
4235  vertices.SetSize(NumOfVertices);
4236  ib = 0;
4237  for (i = 0; i < num_pieces; i++)
4238  {
4239  m = mesh_array[i];
4240  m->NURBSext->GetVertexLocalToGlobal(lvert_vert);
4241  m->NURBSext->GetElementLocalToGlobal(lelem_elem);
4242  // copy the element attributes
4243  for (j = 0; j < m->GetNE(); j++)
4244  {
4245  elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j));
4246  }
4247  // copy the boundary
4248  for (j = 0; j < m->GetNBE(); j++)
4249  {
4250  el = m->GetBdrElement(j)->Duplicate(this);
4251  v = el->GetVertices();
4252  nv = el->GetNVertices();
4253  for (int k = 0; k < nv; k++)
4254  {
4255  v[k] = lvert_vert[v[k]];
4256  }
4257  boundary[ib++] = el;
4258  }
4259  // copy the vertices
4260  for (j = 0; j < m->GetNV(); j++)
4261  {
4262  vertices[lvert_vert[j]].SetCoords(m->SpaceDimension(),
4263  m->GetVertex(j));
4264  }
4265  }
4266  }
4267  else // not a NURBS mesh
4268  {
4269  NumOfElements = 0;
4270  NumOfBdrElements = 0;
4271  NumOfVertices = 0;
4272  for (i = 0; i < num_pieces; i++)
4273  {
4274  m = mesh_array[i];
4275  NumOfElements += m->GetNE();
4276  NumOfBdrElements += m->GetNBE();
4277  NumOfVertices += m->GetNV();
4278  }
4279  elements.SetSize(NumOfElements);
4280  boundary.SetSize(NumOfBdrElements);
4281  vertices.SetSize(NumOfVertices);
4282  ie = ib = iv = 0;
4283  for (i = 0; i < num_pieces; i++)
4284  {
4285  m = mesh_array[i];
4286  // copy the elements
4287  for (j = 0; j < m->GetNE(); j++)
4288  {
4289  el = m->GetElement(j)->Duplicate(this);
4290  v = el->GetVertices();
4291  nv = el->GetNVertices();
4292  for (int k = 0; k < nv; k++)
4293  {
4294  v[k] += iv;
4295  }
4296  elements[ie++] = el;
4297  }
4298  // copy the boundary elements
4299  for (j = 0; j < m->GetNBE(); j++)
4300  {
4301  el = m->GetBdrElement(j)->Duplicate(this);
4302  v = el->GetVertices();
4303  nv = el->GetNVertices();
4304  for (int k = 0; k < nv; k++)
4305  {
4306  v[k] += iv;
4307  }
4308  boundary[ib++] = el;
4309  }
4310  // copy the vertices
4311  for (j = 0; j < m->GetNV(); j++)
4312  {
4313  vertices[iv++].SetCoords(m->SpaceDimension(), m->GetVertex(j));
4314  }
4315  }
4316  }
4317 
4318  FinalizeTopology();
4319 
4320  // copy the nodes (curvilinear meshes)
4321  GridFunction *g = mesh_array[0]->GetNodes();
4322  if (g)
4323  {
4324  Array<GridFunction *> gf_array(num_pieces);
4325  for (i = 0; i < num_pieces; i++)
4326  {
4327  gf_array[i] = mesh_array[i]->GetNodes();
4328  }
4329  Nodes = new GridFunction(this, gf_array, num_pieces);
4330  own_nodes = 1;
4331  }
4332 
4333 #ifdef MFEM_DEBUG
4334  CheckElementOrientation(false);
4336 #endif
4337 }
4338 
4339 Mesh::Mesh(Mesh *orig_mesh, int ref_factor, int ref_type)
4340 {
4341  Array<int> ref_factors(orig_mesh->GetNE());
4342  ref_factors = ref_factor;
4343  MakeRefined_(*orig_mesh, ref_factors, ref_type);
4344 }
4345 
4346 void Mesh::MakeRefined_(Mesh &orig_mesh, const Array<int> ref_factors,
4347  int ref_type)
4348 {
4349  SetEmpty();
4350  Dim = orig_mesh.Dimension();
4351  spaceDim = orig_mesh.SpaceDimension();
4352 
4353  int orig_ne = orig_mesh.GetNE();
4354  MFEM_VERIFY(ref_factors.Size() == orig_ne && orig_ne > 0,
4355  "Number of refinement factors must equal number of elements")
4356  MFEM_VERIFY(ref_factors.Min() >= 1, "Refinement factor must be >= 1");
4357  const int q_type = BasisType::GetQuadrature1D(ref_type);
4358  MFEM_VERIFY(Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid,
4359  "Invalid refinement type. Must use closed basis type.");
4360 
4361  int min_ref = ref_factors.Min();
4362  int max_ref = ref_factors.Max();
4363 
4364  bool var_order = (min_ref != max_ref);
4365 
4366  // variable order space can only be constructed over an NC mesh
4367  if (var_order) { orig_mesh.EnsureNCMesh(true); }
4368 
4369  // Construct a scalar H1 FE space of order ref_factor and use its dofs as
4370  // the indices of the new, refined vertices.
4371  H1_FECollection rfec(min_ref, Dim, ref_type);
4372  FiniteElementSpace rfes(&orig_mesh, &rfec);
4373 
4374  if (var_order)
4375  {
4376  rfes.SetRelaxedHpConformity(false);
4377  for (int i = 0; i < orig_ne; i++)
4378  {
4379  rfes.SetElementOrder(i, ref_factors[i]);
4380  }
4381  rfes.Update(false);
4382  }
4383 
4384  // Set the number of vertices, set the actual coordinates later
4385  NumOfVertices = rfes.GetNDofs();
4386  vertices.SetSize(NumOfVertices);
4387 
4388  Array<int> rdofs;
4389  DenseMatrix phys_pts;
4390 
4391  GeometryRefiner refiner;
4392  refiner.SetType(q_type);
4393 
4394  // Add refined elements and set vertex coordinates
4395  for (int el = 0; el < orig_ne; el++)
4396  {
4397  Geometry::Type geom = orig_mesh.GetElementGeometry(el);
4398  int attrib = orig_mesh.GetAttribute(el);
4399  int nvert = Geometry::NumVerts[geom];
4400  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el]);
4401 
4402  rfes.GetElementDofs(el, rdofs);
4403  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4404  const FiniteElement *rfe = rfes.GetFE(el);
4405  orig_mesh.GetElementTransformation(el)->Transform(rfe->GetNodes(),
4406  phys_pts);
4407  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[el]);
4408  for (int i = 0; i < phys_pts.Width(); i++)
4409  {
4410  vertices[rdofs[i]].SetCoords(spaceDim, phys_pts.GetColumn(i));
4411  }
4412  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4413  {
4414  Element *elem = NewElement(geom);
4415  elem->SetAttribute(attrib);
4416  int *v = elem->GetVertices();
4417  for (int k = 0; k < nvert; k++)
4418  {
4419  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4420  v[k] = rdofs[c2h_map[cid]];
4421  }
4422  AddElement(elem);
4423  }
4424  }
4425 
4426  if (Dim > 2)
4427  {
4428  GetElementToFaceTable(false);
4429  GenerateFaces();
4430  }
4431 
4432  // Add refined boundary elements
4433  for (int el = 0; el < orig_mesh.GetNBE(); el++)
4434  {
4435  int i, info;
4436  orig_mesh.GetBdrElementAdjacentElement(el, i, info);
4437  Geometry::Type geom = orig_mesh.GetBdrElementBaseGeometry(el);
4438  int attrib = orig_mesh.GetBdrAttribute(el);
4439  int nvert = Geometry::NumVerts[geom];
4440  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[i]);
4441 
4442  rfes.GetBdrElementDofs(el, rdofs);
4443  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4444  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[i]);
4445  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4446  {
4447  Element *elem = NewElement(geom);
4448  elem->SetAttribute(attrib);
4449  int *v = elem->GetVertices();
4450  for (int k = 0; k < nvert; k++)
4451  {
4452  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4453  v[k] = rdofs[c2h_map[cid]];
4454  }
4455  AddBdrElement(elem);
4456  }
4457  }
4458  FinalizeTopology(false);
4459  sequence = orig_mesh.GetSequence() + 1;
4461 
4462  // Set up the nodes of the new mesh (if the original mesh has nodes). The new
4463  // mesh is always straight-sided (i.e. degree 1 finite element space), but
4464  // the nodes are required for e.g. periodic meshes.
4465  if (orig_mesh.GetNodes())
4466  {
4467  bool discont = orig_mesh.GetNodalFESpace()->IsDGSpace();
4468  Ordering::Type dof_ordering = orig_mesh.GetNodalFESpace()->GetOrdering();
4469  Mesh::SetCurvature(1, discont, spaceDim, dof_ordering);
4470  FiniteElementSpace *nodal_fes = Nodes->FESpace();
4471  const FiniteElementCollection *nodal_fec = nodal_fes->FEColl();
4472  H1_FECollection vertex_fec(1, Dim);
4473  Array<int> dofs;
4474  int el_counter = 0;
4475  for (int iel = 0; iel < orig_ne; iel++)
4476  {
4477  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(iel);
4478  int nvert = Geometry::NumVerts[geom];
4479  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[iel]);
4480  rfes.GetElementDofs(iel, rdofs);
4481  const FiniteElement *rfe = rfes.GetFE(iel);
4482  orig_mesh.GetElementTransformation(iel)->Transform(rfe->GetNodes(),
4483  phys_pts);
4484  const int *node_map = NULL;
4485  const H1_FECollection *h1_fec =
4486  dynamic_cast<const H1_FECollection *>(nodal_fec);
4487  if (h1_fec != NULL) { node_map = h1_fec->GetDofMap(geom); }
4488  const int *vertex_map = vertex_fec.GetDofMap(geom);
4489  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[iel]);
4490  for (int jel = 0; jel < RG.RefGeoms.Size()/nvert; jel++)
4491  {
4492  nodal_fes->GetElementVDofs(el_counter++, dofs);
4493  for (int iv_lex=0; iv_lex<nvert; ++iv_lex)
4494  {
4495  // convert from lexicographic to vertex index
4496  int iv = vertex_map[iv_lex];
4497  // index of vertex of current element in phys_pts matrix
4498  int pt_idx = c2h_map[RG.RefGeoms[iv+nvert*jel]];
4499  // index of current vertex into DOF array
4500  int node_idx = node_map ? node_map[iv_lex] : iv_lex;
4501  for (int d=0; d<spaceDim; ++d)
4502  {
4503  (*Nodes)[dofs[node_idx + d*nvert]] = phys_pts(d,pt_idx);
4504  }
4505  }
4506  }
4507  }
4508  }
4509 
4510  // Setup the data for the coarse-fine refinement transformations
4511  CoarseFineTr.embeddings.SetSize(GetNE());
4512  // First, compute total number of point matrices that we need per geometry
4513  // and the offsets into that array
4514  using GeomRef = std::pair<Geometry::Type, int>;
4515  std::map<GeomRef, int> point_matrices_offsets;
4516  int n_point_matrices[Geometry::NumGeom] = {}; // initialize to zero
4517  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4518  {
4519  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4520  // Have we seen this pair of (goemetry, refinement level) before?
4521  GeomRef id(geom, ref_factors[el_coarse]);
4522  if (point_matrices_offsets.find(id) == point_matrices_offsets.end())
4523  {
4524  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el_coarse]);
4525  int nvert = Geometry::NumVerts[geom];
4526  int nref_el = RG.RefGeoms.Size()/nvert;
4527  // If not, then store the offset and add to the size required
4528  point_matrices_offsets[id] = n_point_matrices[geom];
4529  n_point_matrices[geom] += nref_el;
4530  }
4531  }
4532 
4533  // Set up the sizes
4534  for (int geom = 0; geom < Geometry::NumGeom; ++geom)
4535  {
4536  int nmatrices = n_point_matrices[geom];
4537  int nvert = Geometry::NumVerts[geom];
4538  CoarseFineTr.point_matrices[geom].SetSize(Dim, nvert, nmatrices);
4539  }
4540 
4541  // Compute the point matrices and embeddings
4542  int el_fine = 0;
4543  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4544  {
4545  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4546  int ref = ref_factors[el_coarse];
4547  int offset = point_matrices_offsets[GeomRef(geom, ref)];
4548  int nvert = Geometry::NumVerts[geom];
4549  RefinedGeometry &RG = *refiner.Refine(geom, ref);
4550  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4551  {
4552  DenseMatrix &Pj = CoarseFineTr.point_matrices[geom](offset + j);
4553  for (int k = 0; k < nvert; k++)
4554  {
4555  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4556  const IntegrationPoint &ip = RG.RefPts[cid];
4557  ip.Get(Pj.GetColumn(k), Dim);
4558  }
4559 
4560  Embedding &emb = CoarseFineTr.embeddings[el_fine];
4561  emb.parent = el_coarse;
4562  emb.matrix = offset + j;
4563  ++el_fine;
4564  }
4565  }
4566 
4567  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4568 
4569  // The check below is disabled because is fails for parallel meshes with
4570  // interior "boundary" element that, when such "boundary" element is between
4571  // two elements on different processors.
4572  // MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4573 }
4574 
4575 Mesh Mesh::MakeSimplicial(const Mesh &orig_mesh)
4576 {
4577  Mesh mesh;
4578  mesh.MakeSimplicial_(orig_mesh, NULL);
4579  return mesh;
4580 }
4581 
4582 void Mesh::MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
4583 {
4584  MFEM_VERIFY(const_cast<Mesh&>(orig_mesh).CheckElementOrientation(false) == 0,
4585  "Mesh::MakeSimplicial requires a properly oriented input mesh");
4586  MFEM_VERIFY(orig_mesh.Conforming(),
4587  "Mesh::MakeSimplicial does not support non-conforming meshes.")
4588 
4589  int dim = orig_mesh.Dimension();
4590  int sdim = orig_mesh.SpaceDimension();
4591 
4592  if (dim == 1)
4593  {
4594  Mesh copy(orig_mesh);
4595  Swap(copy, true);
4596  return;
4597  }
4598 
4599  int nv = orig_mesh.GetNV();
4600  int ne = orig_mesh.GetNE();
4601  int nbe = orig_mesh.GetNBE();
4602 
4603  static int num_subdivisions[Geometry::NUM_GEOMETRIES];
4604  num_subdivisions[Geometry::POINT] = 1;
4605  num_subdivisions[Geometry::SEGMENT] = 1;
4606  num_subdivisions[Geometry::TRIANGLE] = 1;
4607  num_subdivisions[Geometry::TETRAHEDRON] = 1;
4608  num_subdivisions[Geometry::SQUARE] = 2;
4609  num_subdivisions[Geometry::PRISM] = 3;
4610  num_subdivisions[Geometry::CUBE] = 6;
4611  // NOTE: some hexes may be subdivided into only 5 tets, so this is an
4612  // estimate only. The actual number of created tets may be less, so the
4613  // elements array will need to be shrunk after mesh creation.
4614  int new_ne = 0, new_nbe = 0;
4615  for (int i=0; i<ne; ++i)
4616  {
4617  new_ne += num_subdivisions[orig_mesh.GetElementBaseGeometry(i)];
4618  }
4619  for (int i=0; i<nbe; ++i)
4620  {
4621  new_nbe += num_subdivisions[orig_mesh.GetBdrElementBaseGeometry(i)];
4622  }
4623 
4624  InitMesh(dim, sdim, nv, new_ne, new_nbe);
4625 
4626  // Vertices of the new mesh are same as the original mesh
4627  NumOfVertices = nv;
4628  for (int i=0; i<nv; ++i)
4629  {
4630  vertices[i].SetCoords(dim, orig_mesh.vertices[i]());
4631  }
4632 
4633  // We need a global vertex numbering to identify which diagonals to split
4634  // (quad faces are split using the diagonal originating from the smallest
4635  // global vertex number). Use the supplied global numbering, if it is
4636  // non-NULL, otherwise use the local numbering.
4637  Array<int> vglobal_id;
4638  if (vglobal == NULL)
4639  {
4640  vglobal_id.SetSize(nv);
4641  for (int i=0; i<nv; ++i) { vglobal_id[i] = i; }
4642  vglobal = vglobal_id.GetData();
4643  }
4644 
4645  constexpr int nv_tri = 3, nv_quad = 4, nv_tet = 4, nv_prism = 6, nv_hex = 8;
4646  constexpr int quad_ntris = 2, prism_ntets = 3;
4647  static const int quad_trimap[2][nv_tri*quad_ntris] =
4648  {
4649  {
4650  0, 0,
4651  1, 2,
4652  2, 3
4653  },{
4654  0, 1,
4655  1, 2,
4656  3, 3
4657  }
4658  };
4659  static const int prism_rot[nv_prism*nv_prism] =
4660  {
4661  0, 1, 2, 3, 4, 5,
4662  1, 2, 0, 4, 5, 3,
4663  2, 0, 1, 5, 3, 4,
4664  3, 5, 4, 0, 2, 1,
4665  4, 3, 5, 1, 0, 2,
4666  5, 4, 3, 2, 1, 0
4667  };
4668  static const int prism_f[nv_quad] = {1, 2, 5, 4};
4669  static const int prism_tetmaps[2][nv_prism*prism_ntets] =
4670  {
4671  {
4672  0, 0, 0,
4673  1, 1, 4,
4674  2, 5, 5,
4675  5, 4, 3
4676  },{
4677  0, 0, 0,
4678  1, 4, 4,
4679  2, 2, 5,
4680  4, 5, 3
4681  }
4682  };
4683  static const int hex_rot[nv_hex*nv_hex] =
4684  {
4685  0, 1, 2, 3, 4, 5, 6, 7,
4686  1, 0, 4, 5, 2, 3, 7, 6,
4687  2, 1, 5, 6, 3, 0, 4, 7,
4688  3, 0, 1, 2, 7, 4, 5, 6,
4689  4, 0, 3, 7, 5, 1, 2, 6,
4690  5, 1, 0, 4, 6, 2, 3, 7,
4691  6, 2, 1, 5, 7, 3, 0, 4,
4692  7, 3, 2, 6, 4, 0, 1, 5
4693  };
4694  static const int hex_f0[nv_quad] = {1, 2, 6, 5};
4695  static const int hex_f1[nv_quad] = {2, 3, 7, 6};
4696  static const int hex_f2[nv_quad] = {4, 5, 6, 7};
4697  static const int num_rot[8] = {0, 1, 2, 0, 0, 2, 1, 0};
4698  static const int hex_tetmap0[nv_tet*5] =
4699  {
4700  0, 0, 0, 0, 2,
4701  1, 2, 2, 5, 7,
4702  2, 7, 3, 7, 5,
4703  5, 5, 7, 4, 6
4704  };
4705  static const int hex_tetmap1[nv_tet*6] =
4706  {
4707  0, 0, 1, 0, 0, 1,
4708  5, 1, 6, 7, 7, 7,
4709  7, 7, 7, 2, 1, 6,
4710  4, 5, 5, 3, 2, 2
4711  };
4712  static const int hex_tetmap2[nv_tet*6] =
4713  {
4714  0, 0, 0, 0, 0, 0,
4715  4, 3, 7, 1, 3, 6,
4716  5, 7, 4, 2, 6, 5,
4717  6, 6, 6, 5, 2, 2
4718  };
4719  static const int hex_tetmap3[nv_tet*6] =
4720  {
4721  0, 0, 0, 0, 1, 1,
4722  2, 3, 7, 5, 5, 6,
4723  3, 7, 4, 6, 6, 2,
4724  6, 6, 6, 4, 0, 0
4725  };
4726  static const int *hex_tetmaps[4] =
4727  {
4728  hex_tetmap0, hex_tetmap1, hex_tetmap2, hex_tetmap3
4729  };
4730 
4731  auto find_min = [](const int*a, int n) { return std::min_element(a,a+n)-a; };
4732 
4733  for (int i=0; i<ne; ++i)
4734  {
4735  const int *v = orig_mesh.elements[i]->GetVertices();
4736  const int attrib = orig_mesh.GetAttribute(i);
4737  const Geometry::Type orig_geom = orig_mesh.GetElementBaseGeometry(i);
4738 
4739  if (num_subdivisions[orig_geom] == 1)
4740  {
4741  // (num_subdivisions[orig_geom] == 1) implies that the element does
4742  // not need to be further split (it is either a segment, triangle,
4743  // or tetrahedron), and so it is left unchanged.
4744  Element *e = NewElement(orig_geom);
4745  e->SetAttribute(attrib);
4746  e->SetVertices(v);
4747  AddElement(e);
4748  }
4749  else if (orig_geom == Geometry::SQUARE)
4750  {
4751  for (int itri=0; itri<quad_ntris; ++itri)
4752  {
4754  e->SetAttribute(attrib);
4755  int *v2 = e->GetVertices();
4756  for (int iv=0; iv<nv_tri; ++iv)
4757  {
4758  v2[iv] = v[quad_trimap[0][itri + iv*quad_ntris]];
4759  }
4760  AddElement(e);
4761  }
4762  }
4763  else if (orig_geom == Geometry::PRISM)
4764  {
4765  int vg[nv_prism];
4766  for (int iv=0; iv<nv_prism; ++iv) { vg[iv] = vglobal[v[iv]]; }
4767  // Rotate the vertices of the prism so that the smallest vertex index
4768  // is in the first place
4769  int irot = find_min(vg, nv_prism);
4770  for (int iv=0; iv<nv_prism; ++iv)
4771  {
4772  int jv = prism_rot[iv + irot*nv_prism];
4773  vg[iv] = v[jv];
4774  }
4775  // Two cases according to which diagonal splits third quad face
4776  int q[nv_quad];
4777  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[prism_f[iv]]]; }
4778  int j = find_min(q, nv_quad);
4779  const int *tetmap = (j == 0 || j == 2) ? prism_tetmaps[0] : prism_tetmaps[1];
4780  for (int itet=0; itet<prism_ntets; ++itet)
4781  {
4783  e->SetAttribute(attrib);
4784  int *v2 = e->GetVertices();
4785  for (int iv=0; iv<nv_tet; ++iv)
4786  {
4787  v2[iv] = vg[tetmap[itet + iv*prism_ntets]];
4788  }
4789  AddElement(e);
4790  }
4791  }
4792  else if (orig_geom == Geometry::CUBE)
4793  {
4794  int vg[nv_hex];
4795  for (int iv=0; iv<nv_hex; ++iv) { vg[iv] = vglobal[v[iv]]; }
4796 
4797  // Rotate the vertices of the hex so that the smallest vertex index is
4798  // in the first place
4799  int irot = find_min(vg, nv_hex);
4800  for (int iv=0; iv<nv_hex; ++iv)
4801  {
4802  int jv = hex_rot[iv + irot*nv_hex];
4803  vg[iv] = v[jv];
4804  }
4805 
4806  int q[nv_quad];
4807  // Bitmask is three binary digits, each digit is 1 if the diagonal of
4808  // the corresponding face goes through the 7th vertex, and 0 if not.
4809  int bitmask = 0;
4810  int j;
4811  // First quad face
4812  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f0[iv]]]; }
4813  j = find_min(q, nv_quad);
4814  if (j == 0 || j == 2) { bitmask += 4; }
4815  // Second quad face
4816  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f1[iv]]]; }
4817  j = find_min(q, nv_quad);
4818  if (j == 1 || j == 3) { bitmask += 2; }
4819  // Third quad face
4820  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f2[iv]]]; }
4821  j = find_min(q, nv_quad);
4822  if (j == 0 || j == 2) { bitmask += 1; }
4823 
4824  // Apply rotations
4825  int nrot = num_rot[bitmask];
4826  for (int k=0; k<nrot; ++k)
4827  {
4828  int vtemp;
4829  vtemp = vg[1];
4830  vg[1] = vg[4];
4831  vg[4] = vg[3];
4832  vg[3] = vtemp;
4833  vtemp = vg[5];
4834  vg[5] = vg[7];
4835  vg[7] = vg[2];
4836  vg[2] = vtemp;
4837  }
4838 
4839  // Sum up nonzero bits in bitmask
4840  int ndiags = ((bitmask&4) >> 2) + ((bitmask&2) >> 1) + (bitmask&1);
4841  int ntets = (ndiags == 0) ? 5 : 6;
4842  const int *tetmap = hex_tetmaps[ndiags];
4843  for (int itet=0; itet<ntets; ++itet)
4844  {
4846  e->SetAttribute(attrib);
4847  int *v2 = e->GetVertices();
4848  for (int iv=0; iv<nv_tet; ++iv)
4849  {
4850  v2[iv] = vg[tetmap[itet + iv*ntets]];
4851  }
4852  AddElement(e);
4853  }
4854  }
4855  }
4856  // In 3D, shrink the element array because some hexes have only 5 tets
4857  if (dim == 3) { elements.SetSize(NumOfElements); }
4858 
4859  for (int i=0; i<nbe; ++i)
4860  {
4861  const int *v = orig_mesh.boundary[i]->GetVertices();
4862  const int attrib = orig_mesh.GetBdrAttribute(i);
4863  const Geometry::Type orig_geom = orig_mesh.GetBdrElementBaseGeometry(i);
4864  if (num_subdivisions[orig_geom] == 1)
4865  {
4866  Element *be = NewElement(orig_geom);
4867  be->SetAttribute(attrib);
4868  be->SetVertices(v);
4869  AddBdrElement(be);
4870  }
4871  else if (orig_geom == Geometry::SQUARE)
4872  {
4873  int vg[nv_quad];
4874  for (int iv=0; iv<nv_quad; ++iv) { vg[iv] = vglobal[v[iv]]; }
4875  // Split quad according the smallest (global) vertex
4876  int iv_min = find_min(vg, nv_quad);
4877  int isplit = (iv_min == 0 || iv_min == 2) ? 0 : 1;
4878  for (int itri=0; itri<quad_ntris; ++itri)
4879  {
4881  be->SetAttribute(attrib);
4882  int *v2 = be->GetVertices();
4883  for (int iv=0; iv<nv_tri; ++iv)
4884  {
4885  v2[iv] = v[quad_trimap[isplit][itri + iv*quad_ntris]];
4886  }
4887  AddBdrElement(be);
4888  }
4889  }
4890  else
4891  {
4892  MFEM_ABORT("Unreachable");
4893  }
4894  }
4895 
4896  FinalizeTopology(false);
4897  sequence = orig_mesh.GetSequence();
4898  last_operation = orig_mesh.last_operation;
4899 
4900  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4901  MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4902 }
4903 
4904 Mesh Mesh::MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v)
4905 {
4906  Mesh periodic_mesh(orig_mesh, true); // Make a copy of the original mesh
4907  const FiniteElementSpace *nodal_fes = orig_mesh.GetNodalFESpace();
4908  int nodal_order = nodal_fes ? nodal_fes->GetMaxElementOrder() : 1;
4909  periodic_mesh.SetCurvature(nodal_order, true);
4910 
4911  // renumber element vertices
4912  for (int i = 0; i < periodic_mesh.GetNE(); i++)
4913  {
4914  Element *el = periodic_mesh.GetElement(i);
4915  int *v = el->GetVertices();
4916  int nv = el->GetNVertices();
4917  for (int j = 0; j < nv; j++)
4918  {
4919  v[j] = v2v[v[j]];
4920  }
4921  }
4922  // renumber boundary element vertices
4923  for (int i = 0; i < periodic_mesh.GetNBE(); i++)
4924  {
4925  Element *el = periodic_mesh.GetBdrElement(i);
4926  int *v = el->GetVertices();
4927  int nv = el->GetNVertices();
4928  for (int j = 0; j < nv; j++)
4929  {
4930  v[j] = v2v[v[j]];
4931  }
4932  }
4933 
4934  periodic_mesh.RemoveUnusedVertices();
4935  return periodic_mesh;
4936 }
4937 
4939  const std::vector<Vector> &translations, double tol) const
4940 {
4941  int sdim = SpaceDimension();
4942 
4943  Vector coord(sdim), at(sdim), dx(sdim);
4944  Vector xMax(sdim), xMin(sdim), xDiff(sdim);
4945  xMax = xMin = xDiff = 0.0;
4946 
4947  // Get a list of all vertices on the boundary
4948  set<int> bdr_v;
4949  for (int be = 0; be < GetNBE(); be++)
4950  {
4951  Array<int> dofs;
4952  GetBdrElementVertices(be,dofs);
4953 
4954  for (int i = 0; i < dofs.Size(); i++)
4955  {
4956  bdr_v.insert(dofs[i]);
4957 
4958  coord = GetVertex(dofs[i]);
4959  for (int j = 0; j < sdim; j++)
4960  {
4961  xMax[j] = max(xMax[j], coord[j]);
4962  xMin[j] = min(xMin[j], coord[j]);
4963  }
4964  }
4965  }
4966  add(xMax, -1.0, xMin, xDiff);
4967  double dia = xDiff.Norml2(); // compute mesh diameter
4968 
4969  // We now identify coincident vertices. Several originally distinct vertices
4970  // may become coincident under the periodic mapping. One of these vertices
4971  // will be identified as the "primary" vertex, and all other coincident
4972  // vertices will be considered as "replicas".
4973 
4974  // replica2primary[v] is the index of the primary vertex of replica `v`
4975  map<int, int> replica2primary;
4976  // primary2replicas[v] is a set of indices of replicas of primary vertex `v`
4977  map<int, set<int>> primary2replicas;
4978 
4979  // We begin with the assumption that all vertices are primary, and that there
4980  // are no replicas.
4981  for (int v : bdr_v) { primary2replicas[v]; }
4982 
4983  // Make `r` and all of `r`'s replicas be replicas of `p`. Delete `r` from the
4984  // list of primary vertices.
4985  auto make_replica = [&replica2primary, &primary2replicas](int r, int p)
4986  {
4987  if (r == p) { return; }
4988  primary2replicas[p].insert(r);
4989  replica2primary[r] = p;
4990  for (int s : primary2replicas[r])
4991  {
4992  primary2replicas[p].insert(s);
4993  replica2primary[s] = p;
4994  }
4995  primary2replicas.erase(r);
4996  };
4997 
4998  for (unsigned int i = 0; i < translations.size(); i++)
4999  {
5000  for (int vi : bdr_v)
5001  {
5002  coord = GetVertex(vi);
5003  add(coord, translations[i], at);
5004 
5005  for (int vj : bdr_v)
5006  {
5007  coord = GetVertex(vj);
5008  add(at, -1.0, coord, dx);
5009  if (dx.Norml2() > dia*tol) { continue; }
5010 
5011  // The two vertices vi and vj are coincident.
5012 
5013  // Are vertices `vi` and `vj` already primary?
5014  bool pi = primary2replicas.find(vi) != primary2replicas.end();
5015  bool pj = primary2replicas.find(vj) != primary2replicas.end();
5016 
5017  if (pi && pj)
5018  {
5019  // Both vertices are currently primary
5020  // Demote `vj` to be a replica of `vi`
5021  make_replica(vj, vi);
5022  }
5023  else if (pi && !pj)
5024  {
5025  // `vi` is primary and `vj` is a replica
5026  int owner_of_vj = replica2primary[vj];
5027  // Make `vi` and its replicas be replicas of `vj`'s owner
5028  make_replica(vi, owner_of_vj);
5029  }
5030  else if (!pi && pj)
5031  {
5032  // `vi` is currently a replica and `vj` is currently primary
5033  // Make `vj` and its replicas be replicas of `vi`'s owner
5034  int owner_of_vi = replica2primary[vi];
5035  make_replica(vj, owner_of_vi);
5036  }
5037  else
5038  {
5039  // Both vertices are currently replicas
5040  // Make `vj`'s owner and all of its owner's replicas be replicas
5041  // of `vi`'s owner
5042  int owner_of_vi = replica2primary[vi];
5043  int owner_of_vj = replica2primary[vj];
5044  make_replica(owner_of_vj, owner_of_vi);
5045  }
5046  break;
5047  }
5048  }
5049  }
5050 
5051  std::vector<int> v2v(GetNV());
5052  for (size_t i = 0; i < v2v.size(); i++)
5053  {
5054  v2v[i] = i;
5055  }
5056  for (auto &&r2p : replica2primary)
5057  {
5058  v2v[r2p.first] = r2p.second;
5059  }
5060  return v2v;
5061 }
5062 
5064 {
5065  if (NURBSext == NULL)
5066  {
5067  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5068  }
5069 
5070  if (kv.Size() != NURBSext->GetNKV())
5071  {
5072  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5073  }
5074 
5076 
5077  NURBSext->KnotInsert(kv);
5078 
5079  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5080  sequence++;
5081 
5082  UpdateNURBS();
5083 }
5084 
5086 {
5087  if (NURBSext == NULL)
5088  {
5089  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5090  }
5091 
5092  if (kv.Size() != NURBSext->GetNKV())
5093  {
5094  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5095  }
5096 
5098 
5099  NURBSext->KnotInsert(kv);
5100 
5101  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5102  sequence++;
5103 
5104  UpdateNURBS();
5105 }
5106 
5108 {
5109  // do not check for NURBSext since this method is protected
5111 
5113 
5114  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5115  sequence++;
5116 
5117  UpdateNURBS();
5118 }
5119 
5120 void Mesh::DegreeElevate(int rel_degree, int degree)
5121 {
5122  if (NURBSext == NULL)
5123  {
5124  mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!");
5125  }
5126 
5128 
5129  NURBSext->DegreeElevate(rel_degree, degree);
5130 
5131  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5132  sequence++;
5133 
5134  UpdateNURBS();
5135 }
5136 
5138 {
5139  ResetLazyData();
5140 
5142 
5143  Dim = NURBSext->Dimension();
5144  spaceDim = Dim;
5145 
5146  if (NumOfElements != NURBSext->GetNE())
5147  {
5148  for (int i = 0; i < elements.Size(); i++)
5149  {
5150  FreeElement(elements[i]);
5151  }
5154  }
5155 
5156  if (NumOfBdrElements != NURBSext->GetNBE())
5157  {
5158  for (int i = 0; i < boundary.Size(); i++)
5159  {
5160  FreeElement(boundary[i]);
5161  }
5164  }
5165 
5166  Nodes->FESpace()->Update();
5167  Nodes->Update();
5169 
5170  if (NumOfVertices != NURBSext->GetNV())
5171  {
5173  vertices.SetSize(NumOfVertices);
5174  int vd = Nodes->VectorDim();
5175  for (int i = 0; i < vd; i++)
5176  {
5177  Vector vert_val;
5178  Nodes->GetNodalValues(vert_val, i+1);
5179  for (int j = 0; j < NumOfVertices; j++)
5180  {
5181  vertices[j](i) = vert_val(j);
5182  }
5183  }
5184  }
5185 
5186  if (el_to_edge)
5187  {
5189  if (Dim == 2)
5190  {
5191  GenerateFaces();
5192  }
5193  }
5194 
5195  if (el_to_face)
5196  {
5198  GenerateFaces();
5199  }
5200 }
5201 
5202 void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot)
5203 {
5204  SetEmpty();
5205 
5206  // Read MFEM NURBS mesh v1.0 format
5207  string ident;
5208 
5209  skip_comment_lines(input, '#');
5210 
5211  input >> ident; // 'dimension'
5212  input >> Dim;
5213  spaceDim = Dim;
5214 
5215  skip_comment_lines(input, '#');
5216 
5217  input >> ident; // 'elements'
5218  input >> NumOfElements;
5219  elements.SetSize(NumOfElements);
5220  for (int j = 0; j < NumOfElements; j++)
5221  {
5222  elements[j] = ReadElement(input);
5223  }
5224 
5225  skip_comment_lines(input, '#');
5226 
5227  input >> ident; // 'boundary'
5228  input >> NumOfBdrElements;
5229  boundary.SetSize(NumOfBdrElements);
5230  for (int j = 0; j < NumOfBdrElements; j++)
5231  {
5232  boundary[j] = ReadElement(input);
5233  }
5234 
5235  skip_comment_lines(input, '#');
5236 
5237  input >> ident; // 'edges'
5238  input >> NumOfEdges;
5239  edge_vertex = new Table(NumOfEdges, 2);
5240  edge_to_knot.SetSize(NumOfEdges);
5241  for (int j = 0; j < NumOfEdges; j++)
5242  {
5243  int *v = edge_vertex->GetRow(j);
5244  input >> edge_to_knot[j] >> v[0] >> v[1];
5245  if (v[0] > v[1])
5246  {
5247  edge_to_knot[j] = -1 - edge_to_knot[j];
5248  }
5249  }
5250 
5251  skip_comment_lines(input, '#');
5252 
5253  input >> ident; // 'vertices'
5254  input >> NumOfVertices;
5255  vertices.SetSize(0);
5256 
5257  FinalizeTopology();
5258  CheckBdrElementOrientation(); // check and fix boundary element orientation
5259 }
5260 
5262 {
5263  if (p.Size() >= v.Size())
5264  {
5265  for (int d = 0; d < v.Size(); d++)
5266  {
5267  v(d) = p(d);
5268  }
5269  }
5270  else
5271  {
5272  int d;
5273  for (d = 0; d < p.Size(); d++)
5274  {
5275  v(d) = p(d);
5276  }
5277  for ( ; d < v.Size(); d++)
5278  {
5279  v(d) = 0.0;
5280  }
5281  }
5282 }
5283 
5284 void Mesh::GetNodes(GridFunction &nodes) const
5285 {
5286  if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
5287  {
5288  const int newSpaceDim = nodes.FESpace()->GetVDim();
5290  nodes.ProjectCoefficient(xyz);
5291  }
5292  else
5293  {
5294  nodes = *Nodes;
5295  }
5296 }
5297 
5299 {
5300  GridFunction *nodes = new GridFunction(nfes);
5301  SetNodalGridFunction(nodes, true);
5302 }
5303 
5305 {
5306  if (Nodes)
5307  {
5309  if (dynamic_cast<const H1_FECollection*>(fec)
5310  || dynamic_cast<const L2_FECollection*>(fec))
5311  {
5312  return;
5313  }
5314  else // Mesh using a legacy FE_Collection
5315  {
5316  const int order = GetNodalFESpace()->GetElementOrder(0);
5317  if (NURBSext)
5318  {
5319 #ifndef MFEM_USE_MPI
5320  const bool warn = true;
5321 #else
5322  ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
5323  const bool warn = !pmesh || pmesh->GetMyRank() == 0;
5324 #endif
5325  if (warn)
5326  {
5327  MFEM_WARNING("converting NURBS mesh to order " << order <<
5328  " H1-continuous mesh!\n "
5329  "If this is the desired behavior, you can silence"
5330  " this warning by converting\n "
5331  "the NURBS mesh to high-order mesh in advance by"
5332  " calling the method\n "
5333  "Mesh::SetCurvature().");
5334  }
5335  }
5336  SetCurvature(order, false, -1, Ordering::byVDIM);
5337  }
5338  }
5339  else // First order H1 mesh
5340  {
5341  SetCurvature(1, false, -1, Ordering::byVDIM);
5342  }
5343 }
5344 
5345 void Mesh::SetNodalGridFunction(GridFunction *nodes, bool make_owner)
5346 {
5347  GetNodes(*nodes);
5348  NewNodes(*nodes, make_owner);
5349 }
5350 
5352 {
5353  return ((Nodes) ? Nodes->FESpace() : NULL);
5354 }
5355 
5356 void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
5357 {
5358  space_dim = (space_dim == -1) ? spaceDim : space_dim;
5360  if (discont)
5361  {
5362  const int type = 1; // Gauss-Lobatto points
5363  nfec = new L2_FECollection(order, Dim, type);
5364  }
5365  else
5366  {
5367  nfec = new H1_FECollection(order, Dim);
5368  }
5369  FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
5370  ordering);
5371  SetNodalFESpace(nfes);
5372  Nodes->MakeOwner(nfec);
5373 }
5374 
5376 {
5377  MFEM_ASSERT(nodes != NULL, "");
5378  for (int i = 0; i < spaceDim; i++)
5379  {
5380  Vector vert_val;
5381  nodes->GetNodalValues(vert_val, i+1);
5382  for (int j = 0; j < NumOfVertices; j++)
5383  {
5384  vertices[j](i) = vert_val(j);
5385  }
5386  }
5387 }
5388 
5390 {
5391  switch (Dim)
5392  {
5393  case 1: return GetNV();
5394  case 2: return GetNEdges();
5395  case 3: return GetNFaces();
5396  }
5397  return 0;
5398 }
5399 
5401 {
5402  return faces_info.Size();
5403 }
5404 
5406 {
5407  const bool isInt = type==FaceType::Interior;
5408  int &nf = isInt ? nbInteriorFaces : nbBoundaryFaces;
5409  if (nf<0)
5410  {
5411  nf = 0;
5412  for (int f = 0; f < GetNumFacesWithGhost(); ++f)
5413  {
5415  if ( face.IsOfFaceType(type) )
5416  {
5417  if (face.IsNonconformingCoarse())
5418  {
5419  // We don't count nonconforming coarse faces.
5420  continue;
5421  }
5422  nf++;
5423  }
5424  }
5425  }
5426  return nf;
5427 }
5428 
5429 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5430 static const char *fixed_or_not[] = { "fixed", "NOT FIXED" };
5431 #endif
5432 
5434 {
5435  int i, j, k, wo = 0, fo = 0;
5436  double *v[4];
5437 
5438  if (Dim == 2 && spaceDim == 2)
5439  {
5440  DenseMatrix J(2, 2);
5441 
5442  for (i = 0; i < NumOfElements; i++)
5443  {
5444  int *vi = elements[i]->GetVertices();
5445  if (Nodes == NULL)
5446  {
5447  for (j = 0; j < 3; j++)
5448  {
5449  v[j] = vertices[vi[j]]();
5450  }
5451  for (j = 0; j < 2; j++)
5452  for (k = 0; k < 2; k++)
5453  {
5454  J(j, k) = v[j+1][k] - v[0][k];
5455  }
5456  }
5457  else
5458  {
5459  // only check the Jacobian at the center of the element
5460  GetElementJacobian(i, J);
5461  }
5462  if (J.Det() < 0.0)
5463  {
5464  if (fix_it)
5465  {
5466  switch (GetElementType(i))
5467  {
5468  case Element::TRIANGLE:
5469  mfem::Swap(vi[0], vi[1]);
5470  break;
5472  mfem::Swap(vi[1], vi[3]);
5473  break;
5474  default:
5475  MFEM_ABORT("Invalid 2D element type \""
5476  << GetElementType(i) << "\"");
5477  break;
5478  }
5479  fo++;
5480  }
5481  wo++;
5482  }
5483  }
5484  }
5485 
5486  if (Dim == 3)
5487  {
5488  DenseMatrix J(3, 3);
5489 
5490  for (i = 0; i < NumOfElements; i++)
5491  {
5492  int *vi = elements[i]->GetVertices();
5493  switch (GetElementType(i))
5494  {
5495  case Element::TETRAHEDRON:
5496  if (Nodes == NULL)
5497  {
5498  for (j = 0; j < 4; j++)
5499  {
5500  v[j] = vertices[vi[j]]();
5501  }
5502  for (j = 0; j < 3; j++)
5503  for (k = 0; k < 3; k++)
5504  {
5505  J(j, k) = v[j+1][k] - v[0][k];
5506  }
5507  }
5508  else
5509  {
5510  // only check the Jacobian at the center of the element
5511  GetElementJacobian(i, J);
5512  }
5513  if (J.Det() < 0.0)
5514  {
5515  wo++;
5516  if (fix_it)
5517  {
5518  mfem::Swap(vi[0], vi[1]);
5519  fo++;
5520  }
5521  }
5522  break;
5523 
5524  case Element::WEDGE:
5525  // only check the Jacobian at the center of the element
5526  GetElementJacobian(i, J);
5527  if (J.Det() < 0.0)
5528  {
5529  wo++;
5530  if (fix_it)
5531  {
5532  // how?
5533  }
5534  }
5535  break;
5536 
5537  case Element::PYRAMID:
5538  // only check the Jacobian at the center of the element
5539  GetElementJacobian(i, J);
5540  if (J.Det() < 0.0)
5541  {
5542  wo++;
5543  if (fix_it)
5544  {
5545  // how?
5546  }
5547  }
5548  break;
5549 
5550  case Element::HEXAHEDRON:
5551  // only check the Jacobian at the center of the element
5552  GetElementJacobian(i, J);
5553  if (J.Det() < 0.0)
5554  {
5555  wo++;
5556  if (fix_it)
5557  {
5558  // how?
5559  }
5560  }
5561  break;
5562 
5563  default:
5564  MFEM_ABORT("Invalid 3D element type \""
5565  << GetElementType(i) << "\"");
5566  break;
5567  }
5568  }
5569  }
5570 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5571  if (wo > 0)
5572  {
5573  mfem::out << "Elements with wrong orientation: " << wo << " / "
5574  << NumOfElements << " (" << fixed_or_not[(wo == fo) ? 0 : 1]
5575  << ")" << endl;
5576  }
5577 #endif
5578  return wo;
5579 }
5580 
5581 int Mesh::GetTriOrientation(const int *base, const int *test)
5582 {
5583  // Static method.
5584  // This function computes the index 'j' of the permutation that transforms
5585  // test into base: test[tri_orientation[j][i]]=base[i].
5586  // tri_orientation = Geometry::Constants<Geometry::TRIANGLE>::Orient
5587  int orient;
5588 
5589  if (test[0] == base[0])
5590  if (test[1] == base[1])
5591  {
5592  orient = 0; // (0, 1, 2)
5593  }
5594  else
5595  {
5596  orient = 5; // (0, 2, 1)
5597  }
5598  else if (test[0] == base[1])
5599  if (test[1] == base[0])
5600  {
5601  orient = 1; // (1, 0, 2)
5602  }
5603  else
5604  {
5605  orient = 2; // (1, 2, 0)
5606  }
5607  else // test[0] == base[2]
5608  if (test[1] == base[0])
5609  {
5610  orient = 4; // (2, 0, 1)
5611  }
5612  else
5613  {
5614  orient = 3; // (2, 1, 0)
5615  }
5616 
5617 #ifdef MFEM_DEBUG
5618  const int *aor = tri_t::Orient[orient];
5619  for (int j = 0; j < 3; j++)
5620  if (test[aor[j]] != base[j])
5621  {
5622  mfem_error("Mesh::GetTriOrientation(...)");
5623  }
5624 #endif
5625 
5626  return orient;
5627 }
5628 
5629 int Mesh::GetQuadOrientation(const int *base, const int *test)
5630 {
5631  int i;
5632 
5633  for (i = 0; i < 4; i++)
5634  if (test[i] == base[0])
5635  {
5636  break;
5637  }
5638 
5639 #ifdef MFEM_DEBUG
5640  int orient;
5641  if (test[(i+1)%4] == base[1])
5642  {
5643  orient = 2*i;
5644  }
5645  else
5646  {
5647  orient = 2*i+1;
5648  }
5649  const int *aor = quad_t::Orient[orient];
5650  for (int j = 0; j < 4; j++)
5651  if (test[aor[j]] != base[j])
5652  {
5653  mfem::err << "Mesh::GetQuadOrientation(...)" << endl;
5654  mfem::err << " base = [";
5655  for (int k = 0; k < 4; k++)
5656  {
5657  mfem::err << " " << base[k];
5658  }
5659  mfem::err << " ]\n test = [";
5660  for (int k = 0; k < 4; k++)
5661  {
5662  mfem::err << " " << test[k];
5663  }
5664  mfem::err << " ]" << endl;
5665  mfem_error();
5666  }
5667 #endif
5668 
5669  if (test[(i+1)%4] == base[1])
5670  {
5671  return 2*i;
5672  }
5673 
5674  return 2*i+1;
5675 }
5676 
5677 int Mesh::GetTetOrientation(const int *base, const int *test)
5678 {
5679  // Static method.
5680  // This function computes the index 'j' of the permutation that transforms
5681  // test into base: test[tet_orientation[j][i]]=base[i].
5682  // tet_orientation = Geometry::Constants<Geometry::TETRAHEDRON>::Orient
5683  int orient;
5684 
5685  if (test[0] == base[0])
5686  if (test[1] == base[1])
5687  if (test[2] == base[2])
5688  {
5689  orient = 0; // (0, 1, 2, 3)
5690  }
5691  else
5692  {
5693  orient = 1; // (0, 1, 3, 2)
5694  }
5695  else if (test[2] == base[1])
5696  if (test[3] == base[2])
5697  {
5698  orient = 2; // (0, 2, 3, 1)
5699  }
5700  else
5701  {
5702  orient = 3; // (0, 2, 1, 3)
5703  }
5704  else // test[3] == base[1]
5705  if (test[1] == base[2])
5706  {
5707  orient = 4; // (0, 3, 1, 2)
5708  }
5709  else
5710  {
5711  orient = 5; // (0, 3, 2, 1)
5712  }
5713  else if (test[1] == base[0])
5714  if (test[2] == base[1])
5715  if (test[0] == base[2])
5716  {
5717  orient = 6; // (1, 2, 0, 3)
5718  }
5719  else
5720  {
5721  orient = 7; // (1, 2, 3, 0)
5722  }
5723  else if (test[3] == base[1])
5724  if (test[2] == base[2])
5725  {
5726  orient = 8; // (1, 3, 2, 0)
5727  }
5728  else
5729  {
5730  orient = 9; // (1, 3, 0, 2)
5731  }
5732  else // test[0] == base[1]
5733  if (test[3] == base[2])
5734  {
5735  orient = 10; // (1, 0, 3, 2)
5736  }
5737  else
5738  {
5739  orient = 11; // (1, 0, 2, 3)
5740  }
5741  else if (test[2] == base[0])
5742  if (test[3] == base[1])
5743  if (test[0] == base[2])
5744  {
5745  orient = 12; // (2, 3, 0, 1)
5746  }
5747  else
5748  {
5749  orient = 13; // (2, 3, 1, 0)
5750  }
5751  else if (test[0] == base[1])
5752  if (test[1] == base[2])
5753  {
5754  orient = 14; // (2, 0, 1, 3)
5755  }
5756  else
5757  {
5758  orient = 15; // (2, 0, 3, 1)
5759  }
5760  else // test[1] == base[1]
5761  if (test[3] == base[2])
5762  {
5763  orient = 16; // (2, 1, 3, 0)
5764  }
5765  else
5766  {
5767  orient = 17; // (2, 1, 0, 3)
5768  }
5769  else // (test[3] == base[0])
5770  if (test[0] == base[1])
5771  if (test[2] == base[2])
5772  {
5773  orient = 18; // (3, 0, 2, 1)
5774  }
5775  else
5776  {
5777  orient = 19; // (3, 0, 1, 2)
5778  }
5779  else if (test[1] == base[1])
5780  if (test[0] == base[2])
5781  {
5782  orient = 20; // (3, 1, 0, 2)
5783  }
5784  else
5785  {
5786  orient = 21; // (3, 1, 2, 0)
5787  }
5788  else // test[2] == base[1]
5789  if (test[1] == base[2])
5790  {
5791  orient = 22; // (3, 2, 1, 0)
5792  }
5793  else
5794  {
5795  orient = 23; // (3, 2, 0, 1)
5796  }
5797 
5798 #ifdef MFEM_DEBUG
5799  const int *aor = tet_t::Orient[orient];
5800  for (int j = 0; j < 4; j++)
5801  if (test[aor[j]] != base[j])
5802  {
5803  mfem_error("Mesh::GetTetOrientation(...)");
5804  }
5805 #endif
5806 
5807  return orient;
5808 }
5809 
5811 {
5812  int wo = 0; // count wrong orientations
5813 
5814  if (Dim == 2)
5815  {
5816  if (el_to_edge == NULL) // edges were not generated
5817  {
5818  el_to_edge = new Table;
5820  GenerateFaces(); // 'Faces' in 2D refers to the edges
5821  }
5822  for (int i = 0; i < NumOfBdrElements; i++)
5823  {
5824  if (faces_info[be_to_edge[i]].Elem2No < 0) // boundary face
5825  {
5826  int *bv = boundary[i]->GetVertices();
5827  int *fv = faces[be_to_edge[i]]->GetVertices();
5828  if (bv[0] != fv[0])
5829  {
5830  if (fix_it)
5831  {
5832  mfem::Swap<int>(bv[0], bv[1]);
5833  }
5834  wo++;
5835  }
5836  }
5837  }
5838  }
5839 
5840  if (Dim == 3)
5841  {
5842  for (int i = 0; i < NumOfBdrElements; i++)
5843  {
5844  const int fi = be_to_face[i];
5845 
5846  if (faces_info[fi].Elem2No >= 0) { continue; }
5847 
5848  // boundary face
5849  int *bv = boundary[i]->GetVertices();
5850  // Make sure the 'faces' are generated:
5851  MFEM_ASSERT(fi < faces.Size(), "internal error");
5852  const int *fv = faces[fi]->GetVertices();
5853  int orientation; // orientation of the bdr. elem. w.r.t. the
5854  // corresponding face element (that's the base)
5855  const Element::Type bdr_type = GetBdrElementType(i);
5856  switch (bdr_type)
5857  {
5858  case Element::TRIANGLE:
5859  {
5860  orientation = GetTriOrientation(fv, bv);
5861  break;
5862  }
5864  {
5865  orientation = GetQuadOrientation(fv, bv);
5866  break;
5867  }
5868  default:
5869  MFEM_ABORT("Invalid 2D boundary element type \""
5870  << bdr_type << "\"");
5871  orientation = 0; // suppress a warning
5872  break;
5873  }
5874 
5875  if (orientation % 2 == 0) { continue; }
5876  wo++;
5877  if (!fix_it) { continue; }
5878 
5879  switch (bdr_type)
5880  {
5881  case Element::TRIANGLE:
5882  {
5883  // swap vertices 0 and 1 so that we don't change the marked edge:
5884  // (0,1,2) -> (1,0,2)
5885  mfem::Swap<int>(bv[0], bv[1]);
5886  if (bel_to_edge)
5887  {
5888  int *be = bel_to_edge->GetRow(i);
5889  mfem::Swap<int>(be[1], be[2]);
5890  }
5891  break;
5892  }
5894  {
5895  mfem::Swap<int>(bv[0], bv[2]);
5896  if (bel_to_edge)
5897  {
5898  int *be = bel_to_edge->GetRow(i);
5899  mfem::Swap<int>(be[0], be[1]);
5900  mfem::Swap<int>(be[2], be[3]);
5901  }
5902  break;
5903  }
5904  default: // unreachable
5905  break;
5906  }
5907  }
5908  }
5909  // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5910 #ifdef MFEM_DEBUG
5911  if (wo > 0)
5912  {
5913  mfem::out << "Boundary elements with wrong orientation: " << wo << " / "
5914  << NumOfBdrElements << " (" << fixed_or_not[fix_it ? 0 : 1]
5915  << ")" << endl;
5916  }
5917 #endif
5918  return wo;
5919 }
5920 
5922 {
5923  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
5924  int num_geoms = 0;
5925  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
5926  {
5927  if (HasGeometry(Geometry::Type(g))) { num_geoms++; }
5928  }
5929  return num_geoms;
5930 }
5931 
5933 {
5934  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
5935  el_geoms.SetSize(0);
5936  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
5937  {
5938  if (HasGeometry(Geometry::Type(g)))
5939  {
5940  el_geoms.Append(Geometry::Type(g));
5941  }
5942  }
5943 }
5944 
5945 void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const
5946 {
5947  if (el_to_edge)
5948  {
5949  el_to_edge->GetRow(i, edges);
5950  }
5951  else
5952  {
5953  mfem_error("Mesh::GetElementEdges(...) element to edge table "
5954  "is not generated.");
5955  }
5956 
5957  const int *v = elements[i]->GetVertices();
5958  const int ne = elements[i]->GetNEdges();
5959  cor.SetSize(ne);
5960  for (int j = 0; j < ne; j++)
5961  {
5962  const int *e = elements[i]->GetEdgeVertices(j);
5963  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5964  }
5965 }
5966 
5967 void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const
5968 {
5969  if (Dim == 2)
5970  {
5971  edges.SetSize(1);
5972  cor.SetSize(1);
5973  edges[0] = be_to_edge[i];
5974  const int *v = boundary[i]->GetVertices();
5975  cor[0] = (v[0] < v[1]) ? (1) : (-1);
5976  }
5977  else if (Dim == 3)
5978  {
5979  if (bel_to_edge)
5980  {
5981  bel_to_edge->GetRow(i, edges);
5982  }
5983  else
5984  {
5985  mfem_error("Mesh::GetBdrElementEdges(...)");
5986  }
5987 
5988  const int *v = boundary[i]->GetVertices();
5989  const int ne = boundary[i]->GetNEdges();
5990  cor.SetSize(ne);
5991  for (int j = 0; j < ne; j++)
5992  {
5993  const int *e = boundary[i]->GetEdgeVertices(j);
5994  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5995  }
5996  }
5997 }
5998 
5999 void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const
6000 {
6001  if (Dim == 2)
6002  {
6003  edges.SetSize(1);
6004  edges[0] = i;
6005  o.SetSize(1);
6006  const int *v = faces[i]->GetVertices();
6007  o[0] = (v[0] < v[1]) ? (1) : (-1);
6008  }
6009 
6010  if (Dim != 3)
6011  {
6012  return;
6013  }
6014 
6015  GetFaceEdgeTable(); // generate face_edge Table (if not generated)
6016 
6017  face_edge->GetRow(i, edges);
6018 
6019  const int *v = faces[i]->GetVertices();
6020  const int ne = faces[i]->GetNEdges();
6021  o.SetSize(ne);
6022  for (int j = 0; j < ne; j++)
6023  {
6024  const int *e = faces[i]->GetEdgeVertices(j);
6025  o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
6026  }
6027 }
6028 
6029 void Mesh::GetEdgeVertices(int i, Array<int> &vert) const
6030 {
6031  // the two vertices are sorted: vert[0] < vert[1]
6032  // this is consistent with the global edge orientation
6033  // generate edge_vertex Table (if not generated)
6034  if (!edge_vertex) { GetEdgeVertexTable(); }
6035  edge_vertex->GetRow(i, vert);
6036 }
6037 
6039 {
6040  if (face_edge)
6041  {
6042  return face_edge;
6043  }
6044 
6045  if (Dim != 3)
6046  {
6047  return NULL;
6048  }
6049 
6050 #ifdef MFEM_DEBUG
6051  if (faces.Size() != NumOfFaces)
6052  {
6053  mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!");
6054  }
6055 #endif
6056 
6057  DSTable v_to_v(NumOfVertices);
6058  GetVertexToVertexTable(v_to_v);
6059 
6060  face_edge = new Table;
6062 
6063  return (face_edge);
6064 }
6065 
6067 {
6068  if (edge_vertex)
6069  {
6070  return edge_vertex;
6071  }
6072 
6073  DSTable v_to_v(NumOfVertices);
6074  GetVertexToVertexTable(v_to_v);
6075 
6076  int nedges = v_to_v.NumberOfEntries();
6077  edge_vertex = new Table(nedges, 2);
6078  for (int i = 0; i < NumOfVertices; i++)
6079  {
6080  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
6081  {
6082  int j = it.Index();
6083  edge_vertex->Push(j, i);
6084  edge_vertex->Push(j, it.Column());
6085  }
6086  }
6087  edge_vertex->Finalize();
6088 
6089  return edge_vertex;
6090 }
6091 
6093 {
6094  int i, j, nv, *v;
6095 
6096  Table *vert_elem = new Table;
6097 
6098  vert_elem->MakeI(NumOfVertices);
6099 
6100  for (i = 0; i < NumOfElements; i++)
6101  {
6102  nv = elements[i]->GetNVertices();
6103  v = elements[i]->GetVertices();
6104  for (j = 0; j < nv; j++)
6105  {
6106  vert_elem->AddAColumnInRow(v[j]);
6107  }
6108  }
6109 
6110  vert_elem->MakeJ();
6111 
6112  for (i = 0; i < NumOfElements; i++)
6113  {
6114  nv = elements[i]->GetNVertices();
6115  v = elements[i]->GetVertices();
6116  for (j = 0; j < nv; j++)
6117  {
6118  vert_elem->AddConnection(v[j], i);
6119  }
6120  }
6121 
6122  vert_elem->ShiftUpI();
6123 
6124  return vert_elem;
6125 }
6126 
6128 {
6129  Table *face_elem = new Table;
6130 
6131  face_elem->MakeI(faces_info.Size());
6132 
6133  for (int i = 0; i < faces_info.Size(); i++)
6134  {
6135  if (faces_info[i].Elem2No >= 0)
6136  {
6137  face_elem->AddColumnsInRow(i, 2);
6138  }
6139  else
6140  {
6141  face_elem->AddAColumnInRow(i);
6142  }
6143  }
6144 
6145  face_elem->MakeJ();
6146 
6147  for (int i = 0; i < faces_info.Size(); i++)
6148  {
6149  face_elem->AddConnection(i, faces_info[i].Elem1No);
6150  if (faces_info[i].Elem2No >= 0)
6151  {
6152  face_elem->AddConnection(i, faces_info[i].Elem2No);
6153  }
6154  }
6155 
6156  face_elem->ShiftUpI();
6157 
6158  return face_elem;
6159 }
6160 
6161 void Mesh::GetElementFaces(int i, Array<int> &el_faces, Array<int> &ori) const
6162 {
6163  MFEM_VERIFY(el_to_face != NULL, "el_to_face not generated");
6164 
6165  el_to_face->GetRow(i, el_faces);
6166 
6167  int n = el_faces.Size();
6168  ori.SetSize(n);
6169 
6170  for (int j = 0; j < n; j++)
6171  {
6172  if (faces_info[el_faces[j]].Elem1No == i)
6173  {
6174  ori[j] = faces_info[el_faces[j]].Elem1Inf % 64;
6175  }
6176  else
6177  {
6178  MFEM_ASSERT(faces_info[el_faces[j]].Elem2No == i, "internal error");
6179  ori[j] = faces_info[el_faces[j]].Elem2Inf % 64;
6180  }
6181  }
6182 }
6183 
6185 {
6186  if (face_to_elem == NULL)
6187  {
6189  }
6190 
6191  Array<int> elem_faces;
6192  Array<int> ori;
6193  GetElementFaces(elem, elem_faces, ori);
6194 
6195  Array<int> nghb;
6196  for (auto f : elem_faces)
6197  {
6198  Array<int> row;
6199  face_to_elem->GetRow(f, row);
6200  for (auto r : row)
6201  {
6202  nghb.Append(r);
6203  }
6204  }
6205 
6206  nghb.Sort();
6207  nghb.Unique();
6208 
6209  return nghb;
6210 }
6211 
6212 void Mesh::GetBdrElementFace(int i, int *f, int *o) const
6213 {
6214  const int *bv, *fv;
6215 
6216  *f = be_to_face[i];
6217  bv = boundary[i]->GetVertices();
6218  fv = faces[be_to_face[i]]->GetVertices();
6219 
6220  // find the orientation of the bdr. elem. w.r.t.
6221  // the corresponding face element (that's the base)
6222  switch (GetBdrElementType(i))
6223  {
6224  case Element::TRIANGLE:
6225  *o = GetTriOrientation(fv, bv);
6226  break;
6228  *o = GetQuadOrientation(fv, bv);
6229  break;
6230  default:
6231  MFEM_ABORT("invalid geometry");
6232  }
6233 }
6234 
6236 {
6237  switch (Dim)
6238  {
6239  case 1: return boundary[i]->GetVertices()[0];
6240  case 2: return be_to_edge[i];
6241  case 3: return be_to_face[i];
6242  default: MFEM_ABORT("invalid dimension!");
6243  }
6244  return -1;
6245 }
6246 
6247 void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
6248 {
6249  int fid = GetBdrElementEdgeIndex(bdr_el);
6250 
6251  const FaceInfo &fi = faces_info[fid];
6252  MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
6253 
6254  const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
6255  const int *bv = boundary[bdr_el]->GetVertices();
6256  int ori;
6257  switch (GetBdrElementGeometry(bdr_el))
6258  {
6259  case Geometry::POINT: ori = 0; break;
6260  case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
6261  case Geometry::TRIANGLE: ori = GetTriOrientation(fv, bv); break;
6262  case Geometry::SQUARE: ori = GetQuadOrientation(fv, bv); break;
6263  default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
6264  }
6265  el = fi.Elem1No;
6266  info = fi.Elem1Inf + ori;
6267 }
6268 
6269 void Mesh::GetBdrElementAdjacentElement2(int bdr_el, int &el, int &info) const
6270 {
6271  int fid = GetBdrElementEdgeIndex(bdr_el);
6272 
6273  const FaceInfo &fi = faces_info[fid];
6274  MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
6275 
6276  const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
6277  const int *bv = boundary[bdr_el]->GetVertices();
6278  int ori;
6279  switch (GetBdrElementGeometry(bdr_el))
6280  {
6281  case Geometry::POINT: ori = 0; break;
6282  case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
6283  case Geometry::TRIANGLE: ori = GetTriOrientation(bv, fv); break;
6284  case Geometry::SQUARE: ori = GetQuadOrientation(bv, fv); break;
6285  default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
6286  }
6287  el = fi.Elem1No;
6288  info = fi.Elem1Inf + ori;
6289 }
6290 
6292 {
6293  return elements[i]->GetType();
6294 }
6295 
6297 {
6298  return boundary[i]->GetType();
6299 }
6300 
6301 void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const
6302 {
6303  int k, j, nv;
6304  const int *v;
6305 
6306  v = elements[i]->GetVertices();
6307  nv = elements[i]->GetNVertices();
6308 
6309  pointmat.SetSize(spaceDim, nv);
6310  for (k = 0; k < spaceDim; k++)
6311  {
6312  for (j = 0; j < nv; j++)
6313  {
6314  pointmat(k, j) = vertices[v[j]](k);
6315  }
6316  }
6317 }
6318 
6319 void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const
6320 {
6321  int k, j, nv;
6322  const int *v;
6323 
6324  v = boundary[i]->GetVertices();
6325  nv = boundary[i]->GetNVertices();
6326 
6327  pointmat.SetSize(spaceDim, nv);
6328  for (k = 0; k < spaceDim; k++)
6329  for (j = 0; j < nv; j++)
6330  {
6331  pointmat(k, j) = vertices[v[j]](k);
6332  }
6333 }
6334 
6335 double Mesh::GetLength(int i, int j) const
6336 {
6337  const double *vi = vertices[i]();
6338  const double *vj = vertices[j]();
6339  double length = 0.;
6340 
6341  for (int k = 0; k < spaceDim; k++)
6342  {
6343  length += (vi[k]-vj[k])*(vi[k]-vj[k]);
6344  }
6345 
6346  return sqrt(length);
6347 }
6348 
6349 // static method
6351  const DSTable &v_to_v, Table &el_to_edge)
6352 {
6353  el_to_edge.MakeI(elem_array.Size());
6354  for (int i = 0; i < elem_array.Size(); i++)
6355  {
6356  el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges());
6357  }
6358  el_to_edge.MakeJ();
6359  for (int i = 0; i < elem_array.Size(); i++)
6360  {
6361  const int *v = elem_array[i]->GetVertices();
6362  const int ne = elem_array[i]->GetNEdges();
6363  for (int j = 0; j < ne; j++)
6364  {
6365  const int *e = elem_array[i]->GetEdgeVertices(j);
6366  el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]]));
6367  }
6368  }
6369  el_to_edge.ShiftUpI();
6370 }
6371 
6373 {
6374  if (edge_vertex)
6375  {
6376  for (int i = 0; i < edge_vertex->Size(); i++)
6377  {
6378  const int *v = edge_vertex->GetRow(i);
6379  v_to_v.Push(v[0], v[1]);
6380  }
6381  }
6382  else
6383  {
6384  for (int i = 0; i < NumOfElements; i++)
6385  {
6386  const int *v = elements[i]->GetVertices();
6387  const int ne = elements[i]->GetNEdges();
6388  for (int j = 0; j < ne; j++)
6389  {
6390  const int *e = elements[i]->GetEdgeVertices(j);
6391  v_to_v.Push(v[e[0]], v[e[1]]);
6392  }
6393  }
6394  }
6395 }
6396 
6398 {
6399  int i, NumberOfEdges;
6400 
6401  DSTable v_to_v(NumOfVertices);
6402  GetVertexToVertexTable(v_to_v);
6403 
6404  NumberOfEdges = v_to_v.NumberOfEntries();
6405 
6406  // Fill the element to edge table
6407  GetElementArrayEdgeTable(elements, v_to_v, e_to_f);
6408 
6409  if (Dim == 2)
6410  {
6411  // Initialize the indices for the boundary elements.
6412  be_to_f.SetSize(NumOfBdrElements);
6413  for (i = 0; i < NumOfBdrElements; i++)
6414  {
6415  const int *v = boundary[i]->GetVertices();
6416  be_to_f[i] = v_to_v(v[0], v[1]);
6417  }
6418  }
6419  else if (Dim == 3)
6420  {
6421  if (bel_to_edge == NULL)
6422  {
6423  bel_to_edge = new Table;
6424  }
6426  }
6427  else
6428  {
6429  mfem_error("1D GetElementToEdgeTable is not yet implemented.");
6430  }
6431 
6432  // Return the number of edges
6433  return NumberOfEdges;
6434 }
6435 
6437 {
6438  if (el_to_el)
6439  {
6440  return *el_to_el;
6441  }
6442 
6443  // Note that, for ParNCMeshes, faces_info will contain also the ghost faces
6444  MFEM_ASSERT(faces_info.Size() >= GetNumFaces(), "faces were not generated!");
6445 
6446  Array<Connection> conn;
6447  conn.Reserve(2*faces_info.Size());
6448 
6449  for (int i = 0; i < faces_info.Size(); i++)
6450  {
6451  const FaceInfo &fi = faces_info[i];
6452  if (fi.Elem2No >= 0)
6453  {
6454  conn.Append(Connection(fi.Elem1No, fi.Elem2No));
6455  conn.Append(Connection(fi.Elem2No, fi.Elem1No));
6456  }
6457  else if (fi.Elem2Inf >= 0)
6458  {
6459  int nbr_elem_idx = NumOfElements - 1 - fi.Elem2No;
6460  conn.Append(Connection(fi.Elem1No, nbr_elem_idx));
6461  conn.Append(Connection(nbr_elem_idx, fi.Elem1No));
6462  }
6463  }
6464 
6465  conn.Sort();
6466  conn.Unique();
6467  el_to_el = new Table(NumOfElements, conn);
6468 
6469  return *el_to_el;
6470 }
6471 
6473 {
6474  if (el_to_face == NULL)
6475  {
6476  mfem_error("Mesh::ElementToFaceTable()");
6477  }
6478  return *el_to_face;
6479 }
6480 
6482 {
6483  if (el_to_edge == NULL)
6484  {
6485  mfem_error("Mesh::ElementToEdgeTable()");
6486  }
6487  return *el_to_edge;
6488 }
6489 
6490 void Mesh::AddPointFaceElement(int lf, int gf, int el)
6491 {
6492  if (faces_info[gf].Elem1No == -1) // this will be elem1
6493  {
6494  // faces[gf] = new Point(&gf);
6495  faces_info[gf].Elem1No = el;
6496  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6497  faces_info[gf].Elem2No = -1; // in case there's no other side
6498  faces_info[gf].Elem2Inf = -1; // face is not shared
6499  }
6500  else // this will be elem2
6501  {
6502  /* WARNING: Without the following check the mesh faces_info data structure
6503  may contain unreliable data. Normally, the order in which elements are
6504  processed could swap which elements appear as Elem1No and Elem2No. In
6505  branched meshes, where more than two elements can meet at a given node,
6506  the indices stored in Elem1No and Elem2No will be the first and last,
6507  respectively, elements found which touch a given node. This can lead to
6508  inconsistencies in any algorithms which rely on this data structure. To
6509  properly support branched meshes this data structure should be extended
6510  to support multiple elements per face. */
6511  /*
6512  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6513  "Interior point found connecting 1D elements "
6514  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6515  << " and " << el << ".");
6516  */
6517  faces_info[gf].Elem2No = el;
6518  faces_info[gf].Elem2Inf = 64 * lf + 1;
6519  }
6520 }
6521 
6522 void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
6523 {
6524  if (faces[gf] == NULL) // this will be elem1
6525  {
6526  faces[gf] = new Segment(v0, v1);
6527  faces_info[gf].Elem1No = el;
6528  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6529  faces_info[gf].Elem2No = -1; // in case there's no other side
6530  faces_info[gf].Elem2Inf = -1; // face is not shared
6531  }
6532  else // this will be elem2
6533  {
6534  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6535  "Interior edge found between 2D elements "
6536  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6537  << " and " << el << ".");
6538  int *v = faces[gf]->GetVertices();
6539  faces_info[gf].Elem2No = el;
6540  if ( v[1] == v0 && v[0] == v1 )
6541  {
6542  faces_info[gf].Elem2Inf = 64 * lf + 1;
6543  }
6544  else if ( v[0] == v0 && v[1] == v1 )
6545  {
6546  // Temporarily allow even edge orientations: see the remark in
6547  // AddTriangleFaceElement().
6548  // Also, in a non-orientable surface mesh, the orientation will be even
6549  // for edges that connect elements with opposite orientations.
6550  faces_info[gf].Elem2Inf = 64 * lf;
6551  }
6552  else
6553  {
6554  MFEM_ABORT("internal error");
6555  }
6556  }
6557 }
6558 
6559 void Mesh::AddTriangleFaceElement(int lf, int gf, int el,
6560  int v0, int v1, int v2)
6561 {
6562  if (faces[gf] == NULL) // this will be elem1
6563  {
6564  faces[gf] = new Triangle(v0, v1, v2);
6565  faces_info[gf].Elem1No = el;
6566  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6567  faces_info[gf].Elem2No = -1; // in case there's no other side
6568  faces_info[gf].Elem2Inf = -1; // face is not shared
6569  }
6570  else // this will be elem2
6571  {
6572  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6573  "Interior triangular face found connecting elements "
6574  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6575  << " and " << el << ".");
6576  int orientation, vv[3] = { v0, v1, v2 };
6577  orientation = GetTriOrientation(faces[gf]->GetVertices(), vv);
6578  // In a valid mesh, we should have (orientation % 2 != 0), however, if
6579  // one of the adjacent elements has wrong orientation, both face
6580  // orientations can be even, until the element orientations are fixed.
6581  // MFEM_ASSERT(orientation % 2 != 0, "");
6582  faces_info[gf].Elem2No = el;
6583  faces_info[gf].Elem2Inf = 64 * lf + orientation;
6584  }
6585 }
6586 
6587 void Mesh::AddQuadFaceElement(int lf, int gf, int el,
6588  int v0, int v1, int v2, int v3)
6589 {
6590  if (faces_info[gf].Elem1No < 0) // this will be elem1
6591  {
6592  faces[gf] = new Quadrilateral(v0, v1, v2, v3);
6593  faces_info[gf].Elem1No = el;
6594  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6595  faces_info[gf].Elem2No = -1; // in case there's no other side
6596  faces_info[gf].Elem2Inf = -1; // face is not shared
6597  }
6598  else // this will be elem2
6599  {
6600  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6601  "Interior quadrilateral face found connecting elements "
6602  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6603  << " and " << el << ".");
6604  int vv[4] = { v0, v1, v2, v3 };
6605  int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv);
6606  // Temporarily allow even face orientations: see the remark in
6607  // AddTriangleFaceElement().
6608  // MFEM_ASSERT(oo % 2 != 0, "");
6609  faces_info[gf].Elem2No = el;
6610  faces_info[gf].Elem2Inf = 64 * lf + oo;
6611  }
6612 }
6613 
6615 {
6616  int i, nfaces = GetNumFaces();
6617 
6618  for (i = 0; i < faces.Size(); i++)
6619  {
6620  FreeElement(faces[i]);
6621  }
6622 
6623  // (re)generate the interior faces and the info for them
6624  faces.SetSize(nfaces);
6625  faces_info.SetSize(nfaces);
6626  for (i = 0; i < nfaces; i++)
6627  {
6628  faces[i] = NULL;
6629  faces_info[i].Elem1No = -1;
6630  faces_info[i].NCFace = -1;
6631  }
6632  for (i = 0; i < NumOfElements; i++)
6633  {
6634  const int *v = elements[i]->GetVertices();
6635  const int *ef;
6636  if (Dim == 1)
6637  {
6638  AddPointFaceElement(0, v[0], i);
6639  AddPointFaceElement(1, v[1], i);
6640  }
6641  else if (Dim == 2)
6642  {
6643  ef = el_to_edge->GetRow(i);
6644  const int ne = elements[i]->GetNEdges();
6645  for (int j = 0; j < ne; j++)
6646  {
6647  const int *e = elements[i]->GetEdgeVertices(j);
6648  AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]);
6649  }
6650  }
6651  else
6652  {
6653  ef = el_to_face->GetRow(i);
6654  switch (GetElementType(i))
6655  {
6656  case Element::TETRAHEDRON:
6657  {
6658  for (int j = 0; j < 4; j++)
6659  {
6660  const int *fv = tet_t::FaceVert[j];
6661  AddTriangleFaceElement(j, ef[j], i,
6662  v[fv[0]], v[fv[1]], v[fv[2]]);
6663  }
6664  break;
6665  }
6666  case Element::WEDGE:
6667  {
6668  for (int j = 0; j < 2; j++)
6669  {
6670  const int *fv = pri_t::FaceVert[j];
6671  AddTriangleFaceElement(j, ef[j], i,
6672  v[fv[0]], v[fv[1]], v[fv[2]]);
6673  }
6674  for (int j = 2; j < 5; j++)
6675  {
6676  const int *fv = pri_t::FaceVert[j];
6677  AddQuadFaceElement(j, ef[j], i,
6678  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6679  }
6680  break;
6681  }
6682  case Element::PYRAMID:
6683  {
6684  for (int j = 0; j < 1; j++)
6685  {
6686  const int *fv = pyr_t::FaceVert[j];
6687  AddQuadFaceElement(j, ef[j], i,
6688  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6689  }
6690  for (int j = 1; j < 5; j++)
6691  {
6692  const int *fv = pyr_t::FaceVert[j];
6693  AddTriangleFaceElement(j, ef[j], i,
6694  v[fv[0]], v[fv[1]], v[fv[2]]);
6695  }
6696  break;
6697  }
6698  case Element::HEXAHEDRON:
6699  {
6700  for (int j = 0; j < 6; j++)
6701  {
6702  const int *fv = hex_t::FaceVert[j];
6703  AddQuadFaceElement(j, ef[j], i,
6704  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6705  }
6706  break;
6707  }
6708  default:
6709  MFEM_ABORT("Unexpected type of Element.");
6710  }
6711  }
6712  }
6713 }
6714 
6716 {
6717  MFEM_VERIFY(ncmesh, "missing NCMesh.");
6718 
6719  for (int i = 0; i < faces_info.Size(); i++)
6720  {
6721  faces_info[i].NCFace = -1;
6722  }
6723 
6724  const NCMesh::NCList &list =
6725  (Dim == 2) ? ncmesh->GetEdgeList() : ncmesh->GetFaceList();
6726 
6727  nc_faces_info.SetSize(0);
6728  nc_faces_info.Reserve(list.masters.Size() + list.slaves.Size());
6729 
6730  int nfaces = GetNumFaces();
6731 
6732  // add records for master faces
6733  for (int i = 0; i < list.masters.Size(); i++)
6734  {
6735  const NCMesh::Master &master = list.masters[i];
6736  if (master.index >= nfaces) { continue; }
6737 
6738  FaceInfo &master_fi = faces_info[master.index];
6739  master_fi.NCFace = nc_faces_info.Size();
6740  nc_faces_info.Append(NCFaceInfo(false, master.local, NULL));
6741  // NOTE: one of the unused members stores local face no. to be used below
6742  MFEM_ASSERT(master_fi.Elem2No == -1, "internal error");
6743  MFEM_ASSERT(master_fi.Elem2Inf == -1, "internal error");
6744  }
6745 
6746  // add records for slave faces
6747  for (int i = 0; i < list.slaves.Size(); i++)
6748  {
6749  const NCMesh::Slave &slave = list.slaves[i];
6750 
6751  if (slave.index < 0 || // degenerate slave face
6752  slave.index >= nfaces || // ghost slave
6753  slave.master >= nfaces) // has ghost master
6754  {
6755  continue;
6756  }
6757 
6758  FaceInfo &slave_fi = faces_info[slave.index];
6759  FaceInfo &master_fi = faces_info[slave.master];
6760  NCFaceInfo &master_nc = nc_faces_info[master_fi.NCFace];
6761 
6762  slave_fi.NCFace = nc_faces_info.Size();
6763  slave_fi.Elem2No = master_fi.Elem1No;
6764  slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
6765  // NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
6766  // matrix. In 2D, the point matrix has the orientation of the parent
6767  // edge, so its columns need to be flipped when applying it, see
6768  // ApplyLocalSlaveTransformation.
6769 
6770  nc_faces_info.Append(
6771  NCFaceInfo(true, slave.master,
6772  list.point_matrices[slave.geom][slave.matrix]));
6773  }
6774 }
6775 
6777 {
6778  STable3D *faces_tbl = new STable3D(NumOfVertices);
6779  for (int i = 0; i < NumOfElements; i++)
6780  {
6781  const int *v = elements[i]->GetVertices();
6782  switch (GetElementType(i))
6783  {
6784  case Element::TETRAHEDRON:
6785  {
6786  for (int j = 0; j < 4; j++)
6787  {
6788  const int *fv = tet_t::FaceVert[j];
6789  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6790  }
6791  break;
6792  }
6793  case Element::PYRAMID:
6794  {
6795  for (int j = 0; j < 1; j++)
6796  {
6797  const int *fv = pyr_t::FaceVert[j];
6798  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6799  }
6800  for (int j = 1; j < 5; j++)
6801  {
6802  const int *fv = pyr_t::FaceVert[j];
6803  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6804  }
6805  break;
6806  }
6807  case Element::WEDGE:
6808  {
6809  for (int j = 0; j < 2; j++)
6810  {
6811  const int *fv = pri_t::FaceVert[j];
6812  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6813  }
6814  for (int j = 2; j < 5; j++)
6815  {
6816  const int *fv = pri_t::FaceVert[j];
6817  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6818  }
6819  break;
6820  }
6821  case Element::HEXAHEDRON:
6822  {
6823  // find the face by the vertices with the smallest 3 numbers
6824  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
6825  for (int j = 0; j < 6; j++)
6826  {
6827  const int *fv = hex_t::FaceVert[j];
6828  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6829  }
6830  break;
6831  }
6832  default:
6833  MFEM_ABORT("Unexpected type of Element.");
6834  }
6835  }
6836  return faces_tbl;
6837 }
6838 
6840 {
6841  int i, *v;
6842  STable3D *faces_tbl;
6843 
6844  if (el_to_face != NULL)
6845  {
6846  delete el_to_face;
6847  }
6848  el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra
6849  faces_tbl = new STable3D(NumOfVertices);
6850  for (i = 0; i < NumOfElements; i++)
6851  {
6852  v = elements[i]->GetVertices();
6853  switch (GetElementType(i))
6854  {
6855  case Element::TETRAHEDRON:
6856  {
6857  for (int j = 0; j < 4; j++)
6858  {
6859  const int *fv = tet_t::FaceVert[j];
6860  el_to_face->Push(
6861  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6862  }
6863  break;
6864  }
6865  case Element::WEDGE:
6866  {
6867  for (int j = 0; j < 2; j++)
6868  {
6869  const int *fv = pri_t::FaceVert[j];
6870  el_to_face->Push(
6871  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6872  }
6873  for (int j = 2; j < 5; j++)
6874  {
6875  const int *fv = pri_t::FaceVert[j];
6876  el_to_face->Push(
6877  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6878  }
6879  break;
6880  }
6881  case Element::PYRAMID:
6882  {
6883  for (int j = 0; j < 1; j++)
6884  {
6885  const int *fv = pyr_t::FaceVert[j];
6886  el_to_face->Push(
6887  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6888  }
6889  for (int j = 1; j < 5; j++)
6890  {
6891  const int *fv = pyr_t::FaceVert[j];
6892  el_to_face->Push(
6893  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6894  }
6895  break;
6896  }
6897  case Element::HEXAHEDRON:
6898  {
6899  // find the face by the vertices with the smallest 3 numbers
6900  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
6901  for (int j = 0; j < 6; j++)
6902  {
6903  const int *fv = hex_t::FaceVert[j];
6904  el_to_face->Push(
6905  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6906  }
6907  break;
6908  }
6909  default:
6910  MFEM_ABORT("Unexpected type of Element.");
6911  }
6912  }
6913  el_to_face->Finalize();
6914  NumOfFaces = faces_tbl->NumberOfElements();
6916  for (i = 0; i < NumOfBdrElements; i++)
6917  {
6918  v = boundary[i]->GetVertices();
6919  switch (GetBdrElementType(i))
6920  {
6921  case Element::TRIANGLE:
6922  {
6923  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]);
6924  break;
6925  }
6927  {
6928  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
6929  break;
6930  }
6931  default:
6932  MFEM_ABORT("Unexpected type of boundary Element.");
6933  }
6934  }
6935 
6936  if (ret_ftbl)
6937  {
6938  return faces_tbl;
6939  }
6940  delete faces_tbl;
6941  return NULL;
6942 }
6943 
6944 // shift cyclically 3 integers so that the smallest is first
6945 static inline
6946 void Rotate3(int &a, int &b, int &c)
6947 {
6948  if (a < b)
6949  {
6950  if (a > c)
6951  {
6952  ShiftRight(a, b, c);
6953  }
6954  }
6955  else
6956  {
6957  if (b < c)
6958  {
6959  ShiftRight(c, b, a);
6960  }
6961  else
6962  {
6963  ShiftRight(a, b, c);
6964  }
6965  }
6966 }
6967 
6969 {
6970  if (Dim != 3 || !(meshgen & 1))
6971  {
6972  return;
6973  }
6974 
6975  ResetLazyData();
6976 
6977  DSTable *old_v_to_v = NULL;
6978  Table *old_elem_vert = NULL;
6979 
6980  if (Nodes)
6981  {
6982  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
6983  }
6984 
6985  for (int i = 0; i < NumOfElements; i++)
6986  {
6988  {
6989  int *v = elements[i]->GetVertices();
6990 
6991  Rotate3(v[0], v[1], v[2]);
6992  if (v[0] < v[3])
6993  {
6994  Rotate3(v[1], v[2], v[3]);
6995  }
6996  else
6997  {
6998  ShiftRight(v[0], v[1], v[3]);
6999  }
7000  }
7001  }
7002 
7003  for (int i = 0; i < NumOfBdrElements; i++)
7004  {
7006  {
7007  int *v = boundary[i]->GetVertices();
7008 
7009  Rotate3(v[0], v[1], v[2]);
7010  }
7011  }
7012 
7013  if (!Nodes)
7014  {
7016  GenerateFaces();
7017  if (el_to_edge)
7018  {
7020  }
7021  }
7022  else
7023  {
7024  DoNodeReorder(old_v_to_v, old_elem_vert);
7025  delete old_elem_vert;
7026  delete old_v_to_v;
7027  }
7028 }
7029 
7031 {
7032  int *partitioning;
7033  double pmin[3] = { infinity(), infinity(), infinity() };
7034  double pmax[3] = { -infinity(), -infinity(), -infinity() };
7035  // find a bounding box using the vertices
7036  for (int vi = 0; vi < NumOfVertices; vi++)
7037  {
7038  const double *p = vertices[vi]();
7039  for (int i = 0; i < spaceDim; i++)
7040  {
7041  if (p[i] < pmin[i]) { pmin[i] = p[i]; }
7042  if (p[i] > pmax[i]) { pmax[i] = p[i]; }
7043  }
7044  }
7045 
7046  partitioning = new int[NumOfElements];
7047 
7048  // determine the partitioning using the centers of the elements
7049  double ppt[3];
7050  Vector pt(ppt, spaceDim);
7051  for (int el = 0; el < NumOfElements; el++)
7052  {
7053  GetElementTransformation(el)->Transform(
7055  int part = 0;
7056  for (int i = spaceDim-1; i >= 0; i--)
7057  {
7058  int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i])));
7059  if (idx < 0) { idx = 0; }
7060  if (idx >= nxyz[i]) { idx = nxyz[i]-1; }
7061  part = part * nxyz[i] + idx;
7062  }
7063  partitioning[el] = part;
7064  }
7065 
7066  return partitioning;
7067 }
7068 
7069 void FindPartitioningComponents(Table &elem_elem,
7070  const Array<int> &partitioning,
7071  Array<int> &component,
7072  Array<int> &num_comp);
7073 
7074 int *Mesh::GeneratePartitioning(int nparts, int part_method)
7075 {
7076 #ifdef MFEM_USE_METIS
7077 
7078  int print_messages = 1;
7079  // If running in parallel, print messages only from rank 0.
7080 #ifdef MFEM_USE_MPI
7081  int init_flag, fin_flag;
7082  MPI_Initialized(&init_flag);
7083  MPI_Finalized(&fin_flag);
7084  if (init_flag && !fin_flag)
7085  {
7086  int rank;
7087  MPI_Comm_rank(GetGlobalMPI_Comm(), &rank);
7088  if (rank != 0) { print_messages = 0; }
7089  }
7090 #endif
7091 
7092  int i, *partitioning;
7093 
7095 
7096  partitioning = new int[NumOfElements];
7097 
7098  if (nparts == 1)
7099  {
7100  for (i = 0; i < NumOfElements; i++)
7101  {
7102  partitioning[i] = 0;
7103  }
7104  }
7105  else if (NumOfElements <= nparts)
7106  {
7107  for (i = 0; i < NumOfElements; i++)
7108  {
7109  partitioning[i] = i;
7110  }
7111  }
7112  else
7113  {
7114  idx_t *I, *J, n;
7115 #ifndef MFEM_USE_METIS_5
7116  idx_t wgtflag = 0;
7117  idx_t numflag = 0;
7118  idx_t options[5];
7119 #else
7120  idx_t ncon = 1;
7121  idx_t errflag;
7122  idx_t options[40];
7123 #endif
7124  idx_t edgecut;
7125 
7126  // In case METIS have been compiled with 64bit indices
7127  bool freedata = false;
7128  idx_t mparts = (idx_t) nparts;
7129  idx_t *mpartitioning;
7130 
7131  n = NumOfElements;
7132  if (sizeof(idx_t) == sizeof(int))
7133  {
7134  I = (idx_t*) el_to_el->GetI();
7135  J = (idx_t*) el_to_el->GetJ();
7136  mpartitioning = (idx_t*) partitioning;
7137  }
7138  else
7139  {
7140  int *iI = el_to_el->GetI();
7141  int *iJ = el_to_el->GetJ();
7142  int m = iI[n];
7143  I = new idx_t[n+1];
7144  J = new idx_t[m];
7145  for (int k = 0; k < n+1; k++) { I[k] = iI[k]; }
7146  for (int k = 0; k < m; k++) { J[k] = iJ[k]; }
7147  mpartitioning = new idx_t[n];
7148  freedata = true;
7149  }
7150 #ifndef MFEM_USE_METIS_5
7151  options[0] = 0;
7152 #else
7153  METIS_SetDefaultOptions(options);
7154  options[METIS_OPTION_CONTIG] = 1; // set METIS_OPTION_CONTIG
7155  // If the mesh is disconnected, disable METIS_OPTION_CONTIG.
7156  {
7157  Array<int> part(partitioning, NumOfElements);
7158  part = 0; // single part for the whole mesh
7159  Array<int> component; // size will be set to num. elem.
7160  Array<int> num_comp; // size will be set to num. parts (1)
7161  FindPartitioningComponents(*el_to_el, part, component, num_comp);
7162  if (num_comp[0] > 1) { options[METIS_OPTION_CONTIG] = 0; }
7163  }
7164 #endif
7165 
7166  // Sort the neighbor lists
7167  if (part_method >= 0 && part_method <= 2)
7168  {
7169  for (i = 0; i < n; i++)
7170  {
7171  // Sort in increasing order.
7172  // std::sort(J+I[i], J+I[i+1]);
7173 
7174  // Sort in decreasing order, as in previous versions of MFEM.
7175  std::sort(J+I[i], J+I[i+1], std::greater<idx_t>());
7176  }
7177  }
7178 
7179  // This function should be used to partition a graph into a small
7180  // number of partitions (less than 8).
7181  if (part_method == 0 || part_method == 3)
7182  {
7183 #ifndef MFEM_USE_METIS_5
7185  I,
7186  J,
7187  NULL,
7188  NULL,
7189  &wgtflag,
7190  &numflag,
7191  &mparts,
7192  options,
7193  &edgecut,
7194  mpartitioning);
7195 #else
7196  errflag = METIS_PartGraphRecursive(&n,
7197  &ncon,
7198  I,
7199  J,
7200  NULL,
7201  NULL,
7202  NULL,
7203  &mparts,
7204  NULL,
7205  NULL,
7206  options,
7207  &edgecut,
7208  mpartitioning);
7209  if (errflag != 1)
7210  {
7211  mfem_error("Mesh::GeneratePartitioning: "
7212  " error in METIS_PartGraphRecursive!");
7213  }
7214 #endif
7215  }
7216 
7217  // This function should be used to partition a graph into a large
7218  // number of partitions (greater than 8).
7219  if (part_method == 1 || part_method == 4)
7220  {
7221 #ifndef MFEM_USE_METIS_5
7223  I,
7224  J,
7225  NULL,
7226  NULL,
7227  &wgtflag,
7228  &numflag,
7229  &mparts,
7230  options,
7231  &edgecut,
7232  mpartitioning);
7233 #else
7234  errflag = METIS_PartGraphKway(&n,
7235  &ncon,
7236  I,
7237  J,
7238  NULL,
7239  NULL,
7240  NULL,
7241  &mparts,
7242  NULL,
7243  NULL,
7244  options,
7245  &edgecut,
7246  mpartitioning);
7247  if (errflag != 1)
7248  {
7249  mfem_error("Mesh::GeneratePartitioning: "
7250  " error in METIS_PartGraphKway!");
7251  }
7252 #endif
7253  }
7254 
7255  // The objective of this partitioning is to minimize the total
7256  // communication volume
7257  if (part_method == 2 || part_method == 5)
7258  {
7259 #ifndef MFEM_USE_METIS_5
7261  I,
7262  J,
7263  NULL,
7264  NULL,
7265  &wgtflag,
7266  &numflag,
7267  &mparts,
7268  options,
7269  &edgecut,
7270  mpartitioning);
7271 #else
7272  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
7273  errflag = METIS_PartGraphKway(&n,
7274  &ncon,
7275  I,
7276  J,
7277  NULL,
7278  NULL,
7279  NULL,
7280  &mparts,
7281  NULL,
7282  NULL,
7283  options,
7284  &edgecut,
7285  mpartitioning);
7286  if (errflag != 1)
7287  {
7288  mfem_error("Mesh::GeneratePartitioning: "
7289  " error in METIS_PartGraphKway!");
7290  }
7291 #endif
7292  }
7293 
7294 #ifdef MFEM_DEBUG
7295  if (print_messages)
7296  {
7297  mfem::out << "Mesh::GeneratePartitioning(...): edgecut = "
7298  << edgecut << endl;
7299  }
7300 #endif
7301  nparts = (int) mparts;
7302  if (mpartitioning != (idx_t*)partitioning)
7303  {
7304  for (int k = 0; k<NumOfElements; k++)
7305  {
7306  partitioning[k] = mpartitioning[k];
7307  }
7308  }
7309  if (freedata)
7310  {
7311  delete[] I;
7312  delete[] J;
7313  delete[] mpartitioning;
7314  }
7315  }
7316 
7317  delete el_to_el;
7318  el_to_el = NULL;
7319 
7320  // Check for empty partitionings (a "feature" in METIS)
7321  if (nparts > 1 && NumOfElements > nparts)
7322  {
7323  Array< Pair<int,int> > psize(nparts);
7324  int empty_parts;
7325 
7326  // Count how many elements are in each partition, and store the result in
7327  // psize, where psize[i].one is the number of elements, and psize[i].two
7328  // is partition index. Keep track of the number of empty parts.
7329  auto count_partition_elements = [&]()
7330  {
7331  for (i = 0; i < nparts; i++)
7332  {
7333  psize[i].one = 0;
7334  psize[i].two = i;
7335  }
7336 
7337  for (i = 0; i < NumOfElements; i++)
7338  {
7339  psize[partitioning[i]].one++;
7340  }
7341 
7342  empty_parts = 0;
7343  for (i = 0; i < nparts; i++)
7344  {
7345  if (psize[i].one == 0) { empty_parts++; }
7346  }
7347  };
7348 
7349  count_partition_elements();
7350 
7351  // This code just split the largest partitionings in two.
7352  // Do we need to replace it with something better?
7353  while (empty_parts)
7354  {
7355  if (print_messages)
7356  {
7357  mfem::err << "Mesh::GeneratePartitioning(...): METIS returned "
7358  << empty_parts << " empty parts!"
7359  << " Applying a simple fix ..." << endl;
7360  }
7361 
7362  SortPairs<int,int>(psize, nparts);
7363 
7364  for (i = nparts-1; i > nparts-1-empty_parts; i--)
7365  {
7366  psize[i].one /= 2;
7367  }
7368 
7369  for (int j = 0; j < NumOfElements; j++)
7370  {
7371  for (i = nparts-1; i > nparts-1-empty_parts; i--)
7372  {
7373  if (psize[i].one == 0 || partitioning[j] != psize[i].two)
7374  {
7375  continue;
7376  }
7377  else
7378  {
7379  partitioning[j] = psize[nparts-1-i].two;
7380  psize[i].one--;
7381  }
7382  }
7383  }
7384 
7385  // Check for empty partitionings again
7386  count_partition_elements();
7387  }
7388  }
7389 
7390  return partitioning;
7391 
7392 #else
7393 
7394  mfem_error("Mesh::GeneratePartitioning(...): "
7395  "MFEM was compiled without Metis.");
7396 
7397  return NULL;
7398 
7399 #endif
7400 }
7401 
7402 /* required: 0 <= partitioning[i] < num_part */
7404  const Array<int> &partitioning,
7405  Array<int> &component,
7406  Array<int> &num_comp)
7407 {
7408  int i, j, k;
7409  int num_elem, *i_elem_elem, *j_elem_elem;
7410 
7411  num_elem = elem_elem.Size();
7412  i_elem_elem = elem_elem.GetI();
7413  j_elem_elem = elem_elem.GetJ();
7414 
7415  component.SetSize(num_elem);
7416 
7417  Array<int> elem_stack(num_elem);
7418  int stack_p, stack_top_p, elem;
7419  int num_part;
7420 
7421  num_part = -1;
7422  for (i = 0; i < num_elem; i++)
7423  {
7424  if (partitioning[i] > num_part)
7425  {
7426  num_part = partitioning[i];
7427  }
7428  component[i] = -1;
7429  }
7430  num_part++;
7431 
7432  num_comp.SetSize(num_part);
7433  for (i = 0; i < num_part; i++)
7434  {
7435  num_comp[i] = 0;
7436  }
7437 
7438  stack_p = 0;
7439  stack_top_p = 0; // points to the first unused element in the stack
7440  for (elem = 0; elem < num_elem; elem++)
7441  {
7442  if (component[elem] >= 0)
7443  {
7444  continue;
7445  }
7446 
7447  component[elem] = num_comp[partitioning[elem]]++;
7448 
7449  elem_stack[stack_top_p++] = elem;
7450 
7451  for ( ; stack_p < stack_top_p; stack_p++)
7452  {
7453  i = elem_stack[stack_p];
7454  for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++)
7455  {
7456  k = j_elem_elem[j];
7457  if (partitioning[k] == partitioning[i])
7458  {
7459  if (component[k] < 0)
7460  {
7461  component[k] = component[i];
7462  elem_stack[stack_top_p++] = k;
7463  }
7464  else if (component[k] != component[i])
7465  {
7466  mfem_error("FindPartitioningComponents");
7467  }
7468  }
7469  }
7470  }
7471  }
7472 }
7473 
7474 void Mesh::CheckPartitioning(int *partitioning_)
7475 {
7476  int i, n_empty, n_mcomp;
7477  Array<int> component, num_comp;
7478  const Array<int> partitioning(partitioning_, GetNE());
7479 
7481 
7482  FindPartitioningComponents(*el_to_el, partitioning, component, num_comp);
7483 
7484  n_empty = n_mcomp = 0;
7485  for (i = 0; i < num_comp.Size(); i++)
7486  if (num_comp[i] == 0)
7487  {
7488  n_empty++;
7489  }
7490  else if (num_comp[i] > 1)
7491  {
7492  n_mcomp++;
7493  }
7494 
7495  if (n_empty > 0)
7496  {
7497  mfem::out << "Mesh::CheckPartitioning(...) :\n"
7498  << "The following subdomains are empty :\n";
7499  for (i = 0; i < num_comp.Size(); i++)
7500  if (num_comp[i] == 0)
7501  {
7502  mfem::out << ' ' << i;
7503  }
7504  mfem::out << endl;
7505  }
7506  if (n_mcomp > 0)
7507  {
7508  mfem::out << "Mesh::CheckPartitioning(...) :\n"
7509  << "The following subdomains are NOT connected :\n";
7510  for (i = 0; i < num_comp.Size(); i++)
7511  if (num_comp[i] > 1)
7512  {
7513  mfem::out << ' ' << i;
7514  }
7515  mfem::out << endl;
7516  }
7517  if (n_empty == 0 && n_mcomp == 0)
7518  mfem::out << "Mesh::CheckPartitioning(...) : "
7519  "All subdomains are connected." << endl;
7520 
7521  if (el_to_el)
7522  {
7523  delete el_to_el;
7524  }
7525  el_to_el = NULL;
7526 }
7527 
7528 // compute the coefficients of the polynomial in t:
7529 // c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B)
7530 // where A, B are (d x d), d=2,3
7531 void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
7532 {
7533  const double *a = A.Data();
7534  const double *b = B.Data();
7535 
7536  c.SetSize(A.Width()+1);
7537  switch (A.Width())
7538  {
7539  case 2:
7540  {
7541  // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ |b0 b2|
7542  // |a1 a3| + \ |a1 b3| |b1 a3| / * t + |b1 b3| * t^2
7543  c(0) = a[0]*a[3]-a[1]*a[2];
7544  c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2];
7545  c(2) = b[0]*b[3]-b[1]*b[2];
7546  }
7547  break;
7548 
7549  case 3:
7550  {
7551  /* |a0 a3 a6|
7552  * det(A+t*B) = |a1 a4 a7| +
7553  * |a2 a5 a8|
7554 
7555  * / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \
7556  * + | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t +
7557  * \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| /
7558 
7559  * / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \
7560  * + | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 +
7561  * \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| /
7562 
7563  * |b0 b3 b6|
7564  * + |b1 b4 b7| * t^3
7565  * |b2 b5 b8| */
7566  c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) +
7567  a[1] * (a[5] * a[6] - a[3] * a[8]) +
7568  a[2] * (a[3] * a[7] - a[4] * a[6]));
7569 
7570  c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) +
7571  b[1] * (a[5] * a[6] - a[3] * a[8]) +
7572  b[2] * (a[3] * a[7] - a[4] * a[6]) +
7573 
7574  a[0] * (b[4] * a[8] - b[5] * a[7]) +
7575  a[1] * (b[5] * a[6] - b[3] * a[8]) +
7576  a[2] * (b[3] * a[7] - b[4] * a[6]) +
7577 
7578  a[0] * (a[4] * b[8] - a[5] * b[7]) +
7579  a[1] * (a[5] * b[6] - a[3] * b[8]) +
7580  a[2] * (a[3] * b[7] - a[4] * b[6]));
7581 
7582  c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) +
7583  a[1] * (b[5] * b[6] - b[3] * b[8]) +
7584  a[2] * (b[3] * b[7] - b[4] * b[6]) +
7585 
7586  b[0] * (a[4] * b[8] - a[5] * b[7]) +
7587  b[1] * (a[5] * b[6] - a[3] * b[8]) +
7588  b[2] * (a[3] * b[7] - a[4] * b[6]) +
7589 
7590  b[0] * (b[4] * a[8] - b[5] * a[7]) +
7591  b[1] * (b[5] * a[6] - b[3] * a[8]) +
7592  b[2] * (b[3] * a[7] - b[4] * a[6]));
7593 
7594  c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) +
7595  b[1] * (b[5] * b[6] - b[3] * b[8]) +
7596  b[2] * (b[3] * b[7] - b[4] * b[6]));
7597  }
7598  break;
7599 
7600  default:
7601  mfem_error("DetOfLinComb(...)");
7602  }
7603 }
7604 
7605 // compute the real roots of
7606 // z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3;
7607 // the roots are returned in x, sorted in increasing order;
7608 // it is assumed that x is at least of size d;
7609 // return the number of roots counting multiplicity;
7610 // return -1 if all z(i) are 0.
7611 int FindRoots(const Vector &z, Vector &x)
7612 {
7613  int d = z.Size()-1;
7614  if (d > 3 || d < 0)
7615  {
7616  mfem_error("FindRoots(...)");
7617  }
7618 
7619  while (z(d) == 0.0)
7620  {
7621  if (d == 0)
7622  {
7623  return (-1);
7624  }
7625  d--;
7626  }
7627  switch (d)
7628  {
7629  case 0:
7630  {
7631  return 0;
7632  }
7633 
7634  case 1:
7635  {
7636  x(0) = -z(0)/z(1);
7637  return 1;
7638  }
7639 
7640  case 2:
7641  {
7642  double a = z(2), b = z(1), c = z(0);
7643  double D = b*b-4*a*c;
7644  if (D < 0.0)
7645  {
7646  return 0;
7647  }
7648  if (D == 0.0)
7649  {
7650  x(0) = x(1) = -0.5 * b / a;
7651  return 2; // root with multiplicity 2
7652  }
7653  if (b == 0.0)
7654  {
7655  x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a));
7656  return 2;
7657  }
7658  else
7659  {
7660  double t;
7661  if (b > 0.0)
7662  {
7663  t = -0.5 * (b + sqrt(D));
7664  }
7665  else
7666  {
7667  t = -0.5 * (b - sqrt(D));
7668  }
7669  x(0) = t / a;
7670  x(1) = c / t;
7671  if (x(0) > x(1))
7672  {
7673  Swap<double>(x(0), x(1));
7674  }
7675  return 2;
7676  }
7677  }
7678 
7679  case 3:
7680  {
7681  double a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3);
7682 
7683  // find the real roots of x^3 + a x^2 + b x + c = 0
7684  double Q = (a * a - 3 * b) / 9;
7685  double R = (2 * a * a * a - 9 * a * b + 27 * c) / 54;
7686  double Q3 = Q * Q * Q;
7687  double R2 = R * R;
7688 
7689  if (R2 == Q3)
7690  {
7691  if (Q == 0)
7692  {
7693  x(0) = x(1) = x(2) = - a / 3;
7694  }
7695  else
7696  {
7697  double sqrtQ = sqrt(Q);
7698 
7699  if (R > 0)
7700  {
7701  x(0) = -2 * sqrtQ - a / 3;
7702  x(1) = x(2) = sqrtQ - a / 3;
7703  }
7704  else
7705  {
7706  x(0) = x(1) = - sqrtQ - a / 3;
7707  x(2) = 2 * sqrtQ - a / 3;
7708  }
7709  }
7710  return 3;
7711  }
7712  else if (R2 < Q3)
7713  {
7714  double theta = acos(R / sqrt(Q3));
7715  double A = -2 * sqrt(Q);
7716  double x0, x1, x2;
7717  x0 = A * cos(theta / 3) - a / 3;
7718  x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3;
7719  x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3;
7720 
7721  /* Sort x0, x1, x2 */
7722  if (x0 > x1)
7723  {
7724  Swap<double>(x0, x1);
7725  }
7726  if (x1 > x2)
7727  {
7728  Swap<double>(x1, x2);
7729  if (x0 > x1)
7730  {
7731  Swap<double>(x0, x1);
7732  }
7733  }
7734  x(0) = x0;
7735  x(1) = x1;
7736  x(2) = x2;
7737  return 3;
7738  }
7739  else
7740  {
7741  double A;
7742  if (R >= 0.0)
7743  {
7744  A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0);
7745  }
7746  else
7747  {
7748  A = pow(sqrt(R2 - Q3) - R, 1.0/3.0);
7749  }
7750  x(0) = A + Q / A - a / 3;
7751  return 1;
7752  }
7753  }
7754  }
7755  return 0;
7756 }
7757 
7758 void FindTMax(Vector &c, Vector &x, double &tmax,
7759  const double factor, const int Dim)
7760 {
7761  const double c0 = c(0);
7762  c(0) = c0 * (1.0 - pow(factor, -Dim));
7763  int nr = FindRoots(c, x);
7764  for (int j = 0; j < nr; j++)
7765  {
7766  if (x(j) > tmax)
7767  {
7768  break;
7769  }
7770  if (x(j) >= 0.0)
7771  {
7772  tmax = x(j);
7773  break;
7774  }
7775  }
7776  c(0) = c0 * (1.0 - pow(factor, Dim));
7777  nr = FindRoots(c, x);
7778  for (int j = 0; j < nr; j++)
7779  {
7780  if (x(j) > tmax)
7781  {
7782  break;
7783  }
7784  if (x(j) >= 0.0)
7785  {
7786  tmax = x(j);
7787  break;
7788  }
7789  }
7790 }
7791 
7792 void Mesh::CheckDisplacements(const Vector &displacements, double &tmax)
7793 {
7794  int nvs = vertices.Size();
7795  DenseMatrix P, V, DS, PDS(spaceDim), VDS(spaceDim);
7796  Vector c(spaceDim+1), x(spaceDim);
7797  const double factor = 2.0;
7798 
7799  // check for tangling assuming constant speed
7800  if (tmax < 1.0)
7801  {
7802  tmax = 1.0;
7803  }
7804  for (int i = 0; i < NumOfElements; i++)
7805  {
7806  Element *el = elements[i];
7807  int nv = el->GetNVertices();
7808  int *v = el->GetVertices();
7809  P.SetSize(spaceDim, nv);
7810  V.SetSize(spaceDim, nv);
7811  for (int j = 0; j < spaceDim; j++)
7812  for (int k = 0; k < nv; k++)
7813  {
7814  P(j, k) = vertices[v[k]](j);
7815  V(j, k) = displacements(v[k]+j*nvs);
7816  }
7817  DS.SetSize(nv, spaceDim);
7818  const FiniteElement *fe =
7820  // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1
7821  switch (el->GetType())
7822  {
7823  case Element::TRIANGLE:
7824  case Element::TETRAHEDRON:
7825  {
7826  // DS is constant
7827  fe->CalcDShape(Geometries.GetCenter(fe->GetGeomType()), DS);
7828  Mult(P, DS, PDS);
7829  Mult(V, DS, VDS);
7830  DetOfLinComb(PDS, VDS, c);
7831  if (c(0) <= 0.0)
7832  {
7833  tmax = 0.0;
7834  }
7835  else
7836  {
7837  FindTMax(c, x, tmax, factor, Dim);
7838  }
7839  }
7840  break;
7841 
7843  {
7844  const IntegrationRule &ir = fe->GetNodes();
7845  for (int j = 0; j < nv; j++)
7846  {
7847  fe->CalcDShape(ir.IntPoint(j), DS);
7848  Mult(P, DS, PDS);
7849  Mult(V, DS, VDS);
7850  DetOfLinComb(PDS, VDS, c);
7851  if (c(0) <= 0.0)
7852  {
7853  tmax = 0.0;
7854  }
7855  else
7856  {
7857  FindTMax(c, x, tmax, factor, Dim);
7858  }
7859  }
7860  }
7861  break;
7862 
7863  default:
7864  mfem_error("Mesh::CheckDisplacements(...)");
7865  }
7866  }
7867 }
7868 
7869 void Mesh::MoveVertices(const Vector &displacements)
7870 {
7871  for (int i = 0, nv = vertices.Size(); i < nv; i++)
7872  for (int j = 0; j < spaceDim; j++)
7873  {
7874  vertices[i](j) += displacements(j*nv+i);
7875  }
7876 }
7877 
7878 void Mesh::GetVertices(Vector &vert_coord) const
7879 {
7880  int nv = vertices.Size();
7881  vert_coord.SetSize(nv*spaceDim);
7882  for (int i = 0; i < nv; i++)
7883  for (int j = 0; j < spaceDim; j++)
7884  {
7885  vert_coord(j*nv+i) = vertices[i](j);
7886  }
7887 }
7888 
7889 void Mesh::SetVertices(const Vector &vert_coord)
7890 {
7891  for (int i = 0, nv = vertices.Size(); i < nv; i++)
7892  for (int j = 0; j < spaceDim; j++)
7893  {
7894  vertices[i](j) = vert_coord(j*nv+i);
7895  }
7896 }
7897 
7898 void Mesh::GetNode(int i, double *coord) const
7899 {
7900  if (Nodes)
7901  {
7902  FiniteElementSpace *fes = Nodes->FESpace();
7903  for (int j = 0; j < spaceDim; j++)
7904  {
7905  coord[j] = (*Nodes)(fes->DofToVDof(i, j));
7906  }
7907  }
7908  else
7909  {
7910  for (int j = 0; j < spaceDim; j++)
7911  {
7912  coord[j] = vertices[i](j);
7913  }
7914  }
7915 }
7916 
7917 void Mesh::SetNode(int i, const double *coord)
7918 {
7919  if (Nodes)
7920  {
7921  FiniteElementSpace *fes = Nodes->FESpace();
7922  for (int j = 0; j < spaceDim; j++)
7923  {
7924  (*Nodes)(fes->DofToVDof(i, j)) = coord[j];
7925  }
7926  }
7927  else
7928  {
7929  for (int j = 0; j < spaceDim; j++)
7930  {
7931  vertices[i](j) = coord[j];
7932  }
7933 
7934  }
7935 }
7936 
7937 void Mesh::MoveNodes(const Vector &displacements)
7938 {
7939  if (Nodes)
7940  {
7941  (*Nodes) += displacements;
7942  }
7943  else
7944  {
7945  MoveVertices(displacements);
7946  }
7947 }
7948 
7949 void Mesh::GetNodes(Vector &node_coord) const
7950 {
7951  if (Nodes)
7952  {
7953  node_coord = (*Nodes);
7954  }
7955  else
7956  {
7957  GetVertices(node_coord);
7958  }
7959 }
7960 
7961 void Mesh::SetNodes(const Vector &node_coord)
7962 {
7963  if (Nodes)
7964  {
7965  (*Nodes) = node_coord;
7966  }
7967  else
7968  {
7969  SetVertices(node_coord);
7970  }
7971 
7972  // Invalidate the old geometric factors
7973  NodesUpdated();
7974 }
7975 
7976 void Mesh::NewNodes(GridFunction &nodes, bool make_owner)
7977 {
7978  if (own_nodes) { delete Nodes; }
7979  Nodes = &nodes;
7980  spaceDim = Nodes->FESpace()->GetVDim();
7981  own_nodes = (int)make_owner;
7982 
7983  if (NURBSext != nodes.FESpace()->GetNURBSext())
7984  {
7985  delete NURBSext;
7986  NURBSext = nodes.FESpace()->StealNURBSext();
7987  }
7988 
7989  if (ncmesh)
7990  {
7992  }
7993 
7994  // Invalidate the old geometric factors
7995  NodesUpdated();
7996 }
7997 
7998 void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_)
7999 {
8000  mfem::Swap<GridFunction*>(Nodes, nodes);
8001  mfem::Swap<int>(own_nodes, own_nodes_);
8002  // TODO:
8003  // if (nodes)
8004  // nodes->FESpace()->MakeNURBSextOwner();
8005  // NURBSext = (Nodes) ? Nodes->FESpace()->StealNURBSext() : NULL;
8006 
8007  // Invalidate the old geometric factors
8008  NodesUpdated();
8009 }
8010 
8011 void Mesh::AverageVertices(const int *indexes, int n, int result)
8012 {
8013  int j, k;
8014 
8015  for (k = 0; k < spaceDim; k++)
8016  {
8017  vertices[result](k) = vertices[indexes[0]](k);
8018  }
8019 
8020  for (j = 1; j < n; j++)
8021  for (k = 0; k < spaceDim; k++)
8022  {
8023  vertices[result](k) += vertices[indexes[j]](k);
8024  }
8025 
8026  for (k = 0; k < spaceDim; k++)
8027  {
8028  vertices[result](k) *= (1.0 / n);
8029  }
8030 }
8031 
8033 {
8034  if (Nodes)
8035  {
8036  Nodes->FESpace()->Update();
8037  Nodes->Update();
8038 
8039  // update vertex coordinates for compatibility (e.g., GetVertex())
8041 
8042  // Invalidate the old geometric factors
8043  NodesUpdated();
8044  }
8045 }
8046 
8047 void Mesh::UniformRefinement2D_base(bool update_nodes)
8048 {
8049  ResetLazyData();
8050 
8051  if (el_to_edge == NULL)
8052  {
8053  el_to_edge = new Table;
8055  }
8056 
8057  int quad_counter = 0;
8058  for (int i = 0; i < NumOfElements; i++)
8059  {
8060  if (elements[i]->GetType() == Element::QUADRILATERAL)
8061  {
8062  quad_counter++;
8063  }
8064  }
8065 
8066  const int oedge = NumOfVertices;
8067  const int oelem = oedge + NumOfEdges;
8068 
8069  Array<Element*> new_elements;
8070  Array<Element*> new_boundary;
8071 
8072  vertices.SetSize(oelem + quad_counter);
8073  new_elements.SetSize(4 * NumOfElements);
8074  quad_counter = 0;
8075 
8076  for (int i = 0, j = 0; i < NumOfElements; i++)
8077  {
8078  const Element::Type el_type = elements[i]->GetType();
8079  const int attr = elements[i]->GetAttribute();
8080  int *v = elements[i]->GetVertices();
8081  const int *e = el_to_edge->GetRow(i);
8082  int vv[2];
8083 
8084  if (el_type == Element::TRIANGLE)
8085  {
8086  for (int ei = 0; ei < 3; ei++)
8087  {
8088  for (int k = 0; k < 2; k++)
8089  {
8090  vv[k] = v[tri_t::Edges[ei][k]];
8091  }
8092  AverageVertices(vv, 2, oedge+e[ei]);
8093  }
8094 
8095  new_elements[j++] =
8096  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
8097  new_elements[j++] =
8098  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
8099  new_elements[j++] =
8100  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
8101  new_elements[j++] =
8102  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
8103  }
8104  else if (el_type == Element::QUADRILATERAL)
8105  {
8106  const int qe = quad_counter;
8107  quad_counter++;
8108  AverageVertices(v, 4, oelem+qe);
8109 
8110  for (int ei = 0; ei < 4; ei++)
8111  {
8112  for (int k = 0; k < 2; k++)
8113  {
8114  vv[k] = v[quad_t::Edges[ei][k]];
8115  }
8116  AverageVertices(vv, 2, oedge+e[ei]);
8117  }
8118 
8119  new_elements[j++] =
8120  new Quadrilateral(v[0], oedge+e[0], oelem+qe, oedge+e[3], attr);
8121  new_elements[j++] =
8122  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oelem+qe, attr);
8123  new_elements[j++] =
8124  new Quadrilateral(oelem+qe, oedge+e[1], v[2], oedge+e[2], attr);
8125  new_elements[j++] =
8126  new Quadrilateral(oedge+e[3], oelem+qe, oedge+e[2], v[3], attr);
8127  }
8128  else
8129  {
8130  MFEM_ABORT("unknown element type: " << el_type);
8131  }
8132  FreeElement(elements[i]);
8133  }
8134  mfem::Swap(elements, new_elements);
8135 
8136  // refine boundary elements
8137  new_boundary.SetSize(2 * NumOfBdrElements);
8138  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
8139  {
8140  const int attr = boundary[i]->GetAttribute();
8141  int *v = boundary[i]->GetVertices();
8142 
8143  new_boundary[j++] = new Segment(v[0], oedge+be_to_edge[i], attr);
8144  new_boundary[j++] = new Segment(oedge+be_to_edge[i], v[1], attr);
8145 
8146  FreeElement(boundary[i]);
8147  }
8148  mfem::Swap(boundary, new_boundary);
8149 
8150  static const double A = 0.0, B = 0.5, C = 1.0;
8151  static double tri_children[2*3*4] =
8152  {
8153  A,A, B,A, A,B,
8154  B,B, A,B, B,A,
8155  B,A, C,A, B,B,
8156  A,B, B,B, A,C
8157  };
8158  static double quad_children[2*4*4] =
8159  {
8160  A,A, B,A, B,B, A,B, // lower-left
8161  B,A, C,A, C,B, B,B, // lower-right
8162  B,B, C,B, C,C, B,C, // upper-right
8163  A,B, B,B, B,C, A,C // upper-left
8164  };
8165 
8167  .UseExternalData(tri_children, 2, 3, 4);
8169  .UseExternalData(quad_children, 2, 4, 4);
8170  CoarseFineTr.embeddings.SetSize(elements.Size());
8171 
8172  for (int i = 0; i < elements.Size(); i++)
8173  {
8174  Embedding &emb = CoarseFineTr.embeddings[i];
8175  emb.parent = i / 4;
8176  emb.matrix = i % 4;
8177  }
8178 
8179  NumOfVertices = vertices.Size();
8182  NumOfFaces = 0;
8183 
8185  GenerateFaces();
8186 
8188  sequence++;
8189 
8190  if (update_nodes) { UpdateNodes(); }
8191 
8192 #ifdef MFEM_DEBUG
8193  if (!Nodes || update_nodes)
8194  {
8195  CheckElementOrientation(false);
8196  }
8198 #endif
8199 }
8200 
8201 static inline double sqr(const double &x)
8202 {
8203  return x*x;
8204 }
8205 
8207  bool update_nodes)
8208 {
8209  ResetLazyData();
8210 
8211  if (el_to_edge == NULL)
8212  {
8213  el_to_edge = new Table;
8215  }
8216 
8217  if (el_to_face == NULL)
8218  {
8220  }
8221 
8222  Array<int> f2qf_loc;
8223  Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
8224  f2qf.SetSize(0);
8225 
8226  int NumOfQuadFaces = 0;
8228  {
8230  {
8231  f2qf.SetSize(faces.Size());
8232  for (int i = 0; i < faces.Size(); i++)
8233  {
8234  if (faces[i]->GetType() == Element::QUADRILATERAL)
8235  {
8236  f2qf[i] = NumOfQuadFaces;
8237  NumOfQuadFaces++;
8238  }
8239  }
8240  }
8241  else
8242  {
8243  NumOfQuadFaces = faces.Size();
8244  }
8245  }
8246 
8247  int hex_counter = 0;
8249  {
8250  for (int i = 0; i < elements.Size(); i++)
8251  {
8252  if (elements[i]->GetType() == Element::HEXAHEDRON)
8253  {
8254  hex_counter++;
8255  }
8256  }
8257  }
8258 
8259  int pyr_counter = 0;
8261  {
8262  for (int i = 0; i < elements.Size(); i++)
8263  {
8264  if (elements[i]->GetType() == Element::PYRAMID)
8265  {
8266  pyr_counter++;
8267  }
8268  }
8269  }
8270 
8271  // Map from edge-index to vertex-index, needed for ReorientTetMesh() for
8272  // parallel meshes.
8273  // Note: with the removal of ReorientTetMesh() this may no longer
8274  // be needed. Unfortunately, it's hard to be sure.
8275  Array<int> e2v;
8277  {
8278  e2v.SetSize(NumOfEdges);
8279 
8280  DSTable *v_to_v_ptr = v_to_v_p;
8281  if (!v_to_v_p)
8282  {
8283  v_to_v_ptr = new DSTable(NumOfVertices);
8284  GetVertexToVertexTable(*v_to_v_ptr);
8285  }
8286 
8287  Array<Pair<int,int> > J_v2v(NumOfEdges); // (second vertex id, edge id)
8288  J_v2v.SetSize(0);
8289  for (int i = 0; i < NumOfVertices; i++)
8290  {
8291  Pair<int,int> *row_start = J_v2v.end();
8292  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
8293  {
8294  J_v2v.Append(Pair<int,int>(it.Column(), it.Index()));
8295  }
8296  std::sort(row_start, J_v2v.end());
8297  }
8298 
8299  for (int i = 0; i < J_v2v.Size(); i++)
8300  {
8301  e2v[J_v2v[i].two] = i;
8302  }
8303 
8304  if (!v_to_v_p)
8305  {
8306  delete v_to_v_ptr;
8307  }
8308  else
8309  {
8310  for (int i = 0; i < NumOfVertices; i++)
8311  {
8312  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
8313  {
8314  it.SetIndex(e2v[it.Index()]);
8315  }
8316  }
8317  }
8318  }
8319 
8320  // Offsets for new vertices from edges, faces (quads only), and elements
8321  // (hexes only); each of these entities generates one new vertex.
8322  const int oedge = NumOfVertices;
8323  const int oface = oedge + NumOfEdges;
8324  const int oelem = oface + NumOfQuadFaces;
8325 
8326  Array<Element*> new_elements;
8327  Array<Element*> new_boundary;
8328 
8329  vertices.SetSize(oelem + hex_counter);
8330  new_elements.SetSize(8 * NumOfElements + 2 * pyr_counter);
8331  CoarseFineTr.embeddings.SetSize(new_elements.Size());
8332 
8333  hex_counter = 0;
8334  for (int i = 0, j = 0; i < NumOfElements; i++)
8335  {
8336  const Element::Type el_type = elements[i]->GetType();
8337  const int attr = elements[i]->GetAttribute();
8338  int *v = elements[i]->GetVertices();
8339  const int *e = el_to_edge->GetRow(i);
8340  int vv[4], ev[12];
8341 
8342  if (e2v.Size())
8343  {
8344  const int ne = el_to_edge->RowSize(i);
8345  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
8346  e = ev;
8347  }
8348 
8349  switch (el_type)
8350  {
8351  case Element::TETRAHEDRON:
8352  {
8353  for (int ei = 0; ei < 6; ei++)
8354  {
8355  for (int k = 0; k < 2; k++)
8356  {
8357  vv[k] = v[tet_t::Edges[ei][k]];
8358  }
8359  AverageVertices(vv, 2, oedge+e[ei]);
8360  }
8361 
8362  // Algorithm for choosing refinement type:
8363  // 0: smallest octahedron diagonal
8364  // 1: best aspect ratio
8365  const int rt_algo = 1;
8366  // Refinement type:
8367  // 0: (v0,v1)-(v2,v3), 1: (v0,v2)-(v1,v3), 2: (v0,v3)-(v1,v2)
8368  // 0: e0-e5, 1: e1-e4, 2: e2-e3
8369  int rt;
8371  T->SetIntPoint(&Geometries.GetCenter(Geometry::TETRAHEDRON));
8372  const DenseMatrix &J = T->Jacobian();
8373  if (rt_algo == 0)
8374  {
8375  // smallest octahedron diagonal
8376  double len_sqr, min_len;
8377 
8378  min_len = sqr(J(0,0)-J(0,1)-J(0,2)) +
8379  sqr(J(1,0)-J(1,1)-J(1,2)) +
8380  sqr(J(2,0)-J(2,1)-J(2,2));
8381  rt = 0;
8382 
8383  len_sqr = sqr(J(0,1)-J(0,0)-J(0,2)) +
8384  sqr(J(1,1)-J(1,0)-J(1,2)) +
8385  sqr(J(2,1)-J(2,0)-J(2,2));
8386  if (len_sqr < min_len) { min_len = len_sqr; rt = 1; }
8387 
8388  len_sqr = sqr(J(0,2)-J(0,0)-J(0,1)) +
8389  sqr(J(1,2)-J(1,0)-J(1,1)) +
8390  sqr(J(2,2)-J(2,0)-J(2,1));
8391  if (len_sqr < min_len) { rt = 2; }
8392  }
8393  else
8394  {
8395  // best aspect ratio
8396  double Em_data[18], Js_data[9], Jp_data[9];
8397  DenseMatrix Em(Em_data, 3, 6);
8398  DenseMatrix Js(Js_data, 3, 3), Jp(Jp_data, 3, 3);
8399  double ar1, ar2, kappa, kappa_min;
8400 
8401  for (int s = 0; s < 3; s++)
8402  {
8403  for (int t = 0; t < 3; t++)
8404  {
8405  Em(t,s) = 0.5*J(t,s);
8406  }
8407  }
8408  for (int t = 0; t < 3; t++)
8409  {
8410  Em(t,3) = 0.5*(J(t,0)+J(t,1));
8411  Em(t,4) = 0.5*(J(t,0)+J(t,2));
8412  Em(t,5) = 0.5*(J(t,1)+J(t,2));
8413  }
8414 
8415  // rt = 0; Em: {0,5,1,2}, {0,5,2,4}
8416  for (int t = 0; t < 3; t++)
8417  {
8418  Js(t,0) = Em(t,5)-Em(t,0);
8419  Js(t,1) = Em(t,1)-Em(t,0);
8420  Js(t,2) = Em(t,2)-Em(t,0);
8421  }
8423  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8424  for (int t = 0; t < 3; t++)
8425  {
8426  Js(t,0) = Em(t,5)-Em(t,0);
8427  Js(t,1) = Em(t,2)-Em(t,0);
8428  Js(t,2) = Em(t,4)-Em(t,0);
8429  }
8431  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8432  kappa_min = std::max(ar1, ar2);
8433  rt = 0;
8434 
8435  // rt = 1; Em: {1,0,4,2}, {1,2,4,5}
8436  for (int t = 0; t < 3; t++)
8437  {
8438  Js(t,0) = Em(t,0)-Em(t,1);
8439  Js(t,1) = Em(t,4)-Em(t,1);
8440  Js(t,2) = Em(t,2)-Em(t,1);
8441  }
8443  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8444  for (int t = 0; t < 3; t++)
8445  {
8446  Js(t,0) = Em(t,2)-Em(t,1);
8447  Js(t,1) = Em(t,4)-Em(t,1);
8448  Js(t,2) = Em(t,5)-Em(t,1);
8449  }
8451  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8452  kappa = std::max(ar1, ar2);
8453  if (kappa < kappa_min) { kappa_min = kappa; rt = 1; }
8454 
8455  // rt = 2; Em: {2,0,1,3}, {2,1,5,3}
8456  for (int t = 0; t < 3; t++)
8457  {
8458  Js(t,0) = Em(t,0)-Em(t,2);
8459  Js(t,1) = Em(t,1)-Em(t,2);
8460  Js(t,2) = Em(t,3)-Em(t,2);
8461  }
8463  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8464  for (int t = 0; t < 3; t++)
8465  {
8466  Js(t,0) = Em(t,1)-Em(t,2);
8467  Js(t,1) = Em(t,5)-Em(t,2);
8468  Js(t,2) = Em(t,3)-Em(t,2);
8469  }
8471  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8472  kappa = std::max(ar1, ar2);
8473  if (kappa < kappa_min) { rt = 2; }
8474  }
8475 
8476  static const int mv_all[3][4][4] =
8477  {
8478  { {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1} }, // rt = 0
8479  { {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0} }, // rt = 1
8480  { {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3} } // rt = 2
8481  };
8482  const int (&mv)[4][4] = mv_all[rt];
8483 
8484 #ifndef MFEM_USE_MEMALLOC
8485  new_elements[j+0] =
8486  new Tetrahedron(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
8487  new_elements[j+1] =
8488  new Tetrahedron(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
8489  new_elements[j+2] =
8490  new Tetrahedron(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
8491  new_elements[j+3] =
8492  new Tetrahedron(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
8493 
8494  for (int k = 0; k < 4; k++)
8495  {
8496  new_elements[j+4+k] =
8497  new Tetrahedron(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
8498  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
8499  }
8500 #else
8501  Tetrahedron *tet;
8502  new_elements[j+0] = tet = TetMemory.Alloc();
8503  tet->Init(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
8504 
8505  new_elements[j+1] = tet = TetMemory.Alloc();
8506  tet->Init(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
8507 
8508  new_elements[j+2] = tet = TetMemory.Alloc();
8509  tet->Init(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
8510 
8511  new_elements[j+3] = tet = TetMemory.Alloc();
8512  tet->Init(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
8513 
8514  for (int k = 0; k < 4; k++)
8515  {
8516  new_elements[j+4+k] = tet = TetMemory.Alloc();
8517  tet->Init(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
8518  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
8519  }
8520 #endif
8521  for (int k = 0; k < 4; k++)
8522  {
8523  CoarseFineTr.embeddings[j+k].parent = i;
8524  CoarseFineTr.embeddings[j+k].matrix = k;
8525  }
8526  for (int k = 0; k < 4; k++)
8527  {
8528  CoarseFineTr.embeddings[j+4+k].parent = i;
8529  CoarseFineTr.embeddings[j+4+k].matrix = 4*(rt+1)+k;
8530  }
8531 
8532  j += 8;
8533  }
8534  break;
8535 
8536  case Element::WEDGE:
8537  {
8538  const int *f = el_to_face->GetRow(i);
8539 
8540  for (int fi = 2; fi < 5; fi++)
8541  {
8542  for (int k = 0; k < 4; k++)
8543  {
8544  vv[k] = v[pri_t::FaceVert[fi][k]];
8545  }
8546  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
8547  }
8548 
8549  for (int ei = 0; ei < 9; ei++)
8550  {
8551  for (int k = 0; k < 2; k++)
8552  {
8553  vv[k] = v[pri_t::Edges[ei][k]];
8554  }
8555  AverageVertices(vv, 2, oedge+e[ei]);
8556  }
8557 
8558  const int qf2 = f2qf[f[2]];
8559  const int qf3 = f2qf[f[3]];
8560  const int qf4 = f2qf[f[4]];
8561 
8562  new_elements[j++] =
8563  new Wedge(v[0], oedge+e[0], oedge+e[2],
8564  oedge+e[6], oface+qf2, oface+qf4, attr);
8565 
8566  new_elements[j++] =
8567  new Wedge(oedge+e[1], oedge+e[2], oedge+e[0],
8568  oface+qf3, oface+qf4, oface+qf2, attr);
8569 
8570  new_elements[j++] =
8571  new Wedge(oedge+e[0], v[1], oedge+e[1],
8572  oface+qf2, oedge+e[7], oface+qf3, attr);
8573 
8574  new_elements[j++] =
8575  new Wedge(oedge+e[2], oedge+e[1], v[2],
8576  oface+qf4, oface+qf3, oedge+e[8], attr);
8577 
8578  new_elements[j++] =
8579  new Wedge(oedge+e[6], oface+qf2, oface+qf4,
8580  v[3], oedge+e[3], oedge+e[5], attr);
8581 
8582  new_elements[j++] =
8583  new Wedge(oface+qf3, oface+qf4, oface+qf2,
8584  oedge+e[4], oedge+e[5], oedge+e[3], attr);
8585 
8586  new_elements[j++] =
8587  new Wedge(oface+qf2, oedge+e[7], oface+qf3,
8588  oedge+e[3], v[4], oedge+e[4], attr);
8589 
8590  new_elements[j++] =
8591  new Wedge(oface+qf4, oface+qf3, oedge+e[8],
8592  oedge+e[5], oedge+e[4], v[5], attr);
8593  }
8594  break;
8595 
8596  case Element::PYRAMID:
8597  {
8598  const int *f = el_to_face->GetRow(i);
8599  // pyr_counter++;
8600 
8601  for (int fi = 0; fi < 1; fi++)
8602  {
8603  for (int k = 0; k < 4; k++)
8604  {
8605  vv[k] = v[pyr_t::FaceVert[fi][k]];
8606  }
8607  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
8608  }
8609 
8610  for (int ei = 0; ei < 8; ei++)
8611  {
8612  for (int k = 0; k < 2; k++)
8613  {
8614  vv[k] = v[pyr_t::Edges[ei][k]];
8615  }
8616  AverageVertices(vv, 2, oedge+e[ei]);
8617  }
8618 
8619  const int qf0 = f2qf[f[0]];
8620 
8621  new_elements[j++] =
8622  new Pyramid(v[0], oedge+e[0], oface+qf0,
8623  oedge+e[3], oedge+e[4], attr);
8624 
8625  new_elements[j++] =
8626  new Pyramid(oedge+e[0], v[1], oedge+e[1],
8627  oface+qf0, oedge+e[5], attr);
8628 
8629  new_elements[j++] =
8630  new Pyramid(oface+qf0, oedge+e[1], v[2],
8631  oedge+e[2], oedge+e[6], attr);
8632 
8633  new_elements[j++] =
8634  new Pyramid(oedge+e[3], oface+qf0, oedge+e[2],
8635  v[3], oedge+e[7], attr);
8636 
8637  new_elements[j++] =
8638  new Pyramid(oedge+e[4], oedge+e[5], oedge+e[6],
8639  oedge+e[7], v[4], attr);
8640 
8641  new_elements[j++] =
8642  new Pyramid(oedge+e[7], oedge+e[6], oedge+e[5],
8643  oedge+e[4], oface+qf0, attr);
8644 
8645 #ifndef MFEM_USE_MEMALLOC
8646  new_elements[j++] =
8647  new Tetrahedron(oedge+e[0], oedge+e[4], oedge+e[5],
8648  oface+qf0, attr);
8649 
8650  new_elements[j++] =
8651  new Tetrahedron(oedge+e[1], oedge+e[5], oedge+e[6],
8652  oface+qf0, attr);
8653 
8654  new_elements[j++] =
8655  new Tetrahedron(oedge+e[2], oedge+e[6], oedge+e[7],
8656  oface+qf0, attr);
8657 
8658  new_elements[j++] =
8659  new Tetrahedron(oedge+e[3], oedge+e[7], oedge+e[4],
8660  oface+qf0, attr);
8661 #else
8662  Tetrahedron *tet;
8663  new_elements[j++] = tet = TetMemory.Alloc();
8664  tet->Init(oedge+e[0], oedge+e[4], oedge+e[5],
8665  oface+qf0, attr);
8666 
8667  new_elements[j++] = tet = TetMemory.Alloc();
8668  tet->Init(oedge+e[1], oedge+e[5], oedge+e[6],
8669  oface+qf0, attr);
8670 
8671  new_elements[j++] = tet = TetMemory.Alloc();
8672  tet->Init(oedge+e[2], oedge+e[6], oedge+e[7],
8673  oface+qf0, attr);
8674 
8675  new_elements[j++] = tet = TetMemory.Alloc();
8676  tet->Init(oedge+e[3], oedge+e[7], oedge+e[4],
8677  oface+qf0, attr);
8678 #endif
8679  }
8680  break;
8681 
8682  case Element::HEXAHEDRON:
8683  {
8684  const int *f = el_to_face->GetRow(i);
8685  const int he = hex_counter;
8686  hex_counter++;
8687 
8688  const int *qf;
8689  int qf_data[6];
8690  if (f2qf.Size() == 0)
8691  {
8692  qf = f;
8693  }
8694  else
8695  {
8696  for (int k = 0; k < 6; k++) { qf_data[k] = f2qf[f[k]]; }
8697  qf = qf_data;
8698  }
8699 
8700  AverageVertices(v, 8, oelem+he);
8701 
8702  for (int fi = 0; fi < 6; fi++)
8703  {
8704  for (int k = 0; k < 4; k++)
8705  {
8706  vv[k] = v[hex_t::FaceVert[fi][k]];
8707  }
8708  AverageVertices(vv, 4, oface + qf[fi]);
8709  }
8710 
8711  for (int ei = 0; ei < 12; ei++)
8712  {
8713  for (int k = 0; k < 2; k++)
8714  {
8715  vv[k] = v[hex_t::Edges[ei][k]];
8716  }
8717  AverageVertices(vv, 2, oedge+e[ei]);
8718  }
8719 
8720  new_elements[j++] =
8721  new Hexahedron(v[0], oedge+e[0], oface+qf[0],
8722  oedge+e[3], oedge+e[8], oface+qf[1],
8723  oelem+he, oface+qf[4], attr);
8724  new_elements[j++] =
8725  new Hexahedron(oedge+e[0], v[1], oedge+e[1],
8726  oface+qf[0], oface+qf[1], oedge+e[9],
8727  oface+qf[2], oelem+he, attr);
8728  new_elements[j++] =
8729  new Hexahedron(oface+qf[0], oedge+e[1], v[2],
8730  oedge+e[2], oelem+he, oface+qf[2],
8731  oedge+e[10], oface+qf[3], attr);
8732  new_elements[j++] =
8733  new Hexahedron(oedge+e[3], oface+qf[0], oedge+e[2],
8734  v[3], oface+qf[4], oelem+he,
8735  oface+qf[3], oedge+e[11], attr);
8736  new_elements[j++] =
8737  new Hexahedron(oedge+e[8], oface+qf[1], oelem+he,
8738  oface+qf[4], v[4], oedge+e[4],
8739  oface+qf[5], oedge+e[7], attr);
8740  new_elements[j++] =
8741  new Hexahedron(oface+qf[1], oedge+e[9], oface+qf[2],
8742  oelem+he, oedge+e[4], v[5],
8743  oedge+e[5], oface+qf[5], attr);
8744  new_elements[j++] =
8745  new Hexahedron(oelem+he, oface+qf[2], oedge+e[10],
8746  oface+qf[3], oface+qf[5], oedge+e[5],
8747  v[6], oedge+e[6], attr);
8748  new_elements[j++] =
8749  new Hexahedron(oface+qf[4], oelem+he, oface+qf[3],
8750  oedge+e[11], oedge+e[7], oface+qf[5],
8751  oedge+e[6], v[7], attr);
8752  }
8753  break;
8754 
8755  default:
8756  MFEM_ABORT("Unknown 3D element type \"" << el_type << "\"");
8757  break;
8758  }
8759  FreeElement(elements[i]);
8760  }
8761  mfem::Swap(elements, new_elements);
8762 
8763  // refine boundary elements
8764  new_boundary.SetSize(4 * NumOfBdrElements);
8765  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
8766  {
8767  const Element::Type bdr_el_type = boundary[i]->GetType();
8768  const int attr = boundary[i]->GetAttribute();
8769  int *v = boundary[i]->GetVertices();
8770  const int *e = bel_to_edge->GetRow(i);
8771  int ev[4];
8772 
8773  if (e2v.Size())
8774  {
8775  const int ne = bel_to_edge->RowSize(i);
8776  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
8777  e = ev;
8778  }
8779 
8780  if (bdr_el_type == Element::TRIANGLE)
8781  {
8782  new_boundary[j++] =
8783  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
8784  new_boundary[j++] =
8785  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
8786  new_boundary[j++] =
8787  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
8788  new_boundary[j++] =
8789  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
8790  }
8791  else if (bdr_el_type == Element::QUADRILATERAL)
8792  {
8793  const int qf =
8794  (f2qf.Size() == 0) ? be_to_face[i] : f2qf[be_to_face[i]];
8795 
8796  new_boundary[j++] =
8797  new Quadrilateral(v[0], oedge+e[0], oface+qf, oedge+e[3], attr);
8798  new_boundary[j++] =
8799  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oface+qf, attr);
8800  new_boundary[j++] =
8801  new Quadrilateral(oface+qf, oedge+e[1], v[2], oedge+e[2], attr);
8802  new_boundary[j++] =
8803  new Quadrilateral(oedge+e[3], oface+qf, oedge+e[2], v[3], attr);
8804  }
8805  else
8806  {
8807  MFEM_ABORT("boundary Element is not a triangle or a quad!");
8808  }
8809  FreeElement(boundary[i]);
8810  }
8811  mfem::Swap(boundary, new_boundary);
8812 
8813  static const double A = 0.0, B = 0.5, C = 1.0, D = -1.0;
8814  static double tet_children[3*4*16] =
8815  {
8816  A,A,A, B,A,A, A,B,A, A,A,B,
8817  B,A,A, C,A,A, B,B,A, B,A,B,
8818  A,B,A, B,B,A, A,C,A, A,B,B,
8819  A,A,B, B,A,B, A,B,B, A,A,C,
8820  // edge coordinates:
8821  // 0 -> B,A,A 1 -> A,B,A 2 -> A,A,B
8822  // 3 -> B,B,A 4 -> B,A,B 5 -> A,B,B
8823  // rt = 0: {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1}
8824  B,A,A, A,B,B, A,B,A, A,A,B,
8825  B,A,A, A,B,B, A,A,B, B,A,B,
8826  B,A,A, A,B,B, B,A,B, B,B,A,
8827  B,A,A, A,B,B, B,B,A, A,B,A,
8828  // rt = 1: {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0}
8829  A,B,A, B,A,A, B,A,B, A,A,B,
8830  A,B,A, A,A,B, B,A,B, A,B,B,
8831  A,B,A, A,B,B, B,A,B, B,B,A,
8832  A,B,A, B,B,A, B,A,B, B,A,A,
8833  // rt = 2: {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3}
8834  A,A,B, B,A,A, A,B,A, B,B,A,
8835  A,A,B, A,B,A, A,B,B, B,B,A,
8836  A,A,B, A,B,B, B,A,B, B,B,A,
8837  A,A,B, B,A,B, B,A,A, B,B,A
8838  };
8839  static double pyr_children[3*5*10] =
8840  {
8841  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B,
8842  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B,
8843  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B,
8844  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B,
8845  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C,
8846  A,B,B, B,B,B, B,A,B, A,A,B, B,B,A,
8847  B,A,A, A,A,B, B,A,B, B,B,A, D,D,D,
8848  C,B,A, B,A,B, B,B,B, B,B,A, D,D,D,
8849  B,C,A, B,B,B, A,B,B, B,B,A, D,D,D,
8850  A,B,A, A,B,B, A,A,B, B,B,A, D,D,D
8851  };
8852  static double pri_children[3*6*8] =
8853  {
8854  A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
8855  B,B,A, A,B,A, B,A,A, B,B,B, A,B,B, B,A,B,
8856  B,A,A, C,A,A, B,B,A, B,A,B, C,A,B, B,B,B,
8857  A,B,A, B,B,A, A,C,A, A,B,B, B,B,B, A,C,B,
8858  A,A,B, B,A,B, A,B,B, A,A,C, B,A,C, A,B,C,
8859  B,B,B, A,B,B, B,A,B, B,B,C, A,B,C, B,A,C,
8860  B,A,B, C,A,B, B,B,B, B,A,C, C,A,C, B,B,C,
8861  A,B,B, B,B,B, A,C,B, A,B,C, B,B,C, A,C,C
8862  };
8863  static double hex_children[3*8*8] =
8864  {
8865  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B, B,A,B, B,B,B, A,B,B,
8866  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B, C,A,B, C,B,B, B,B,B,
8867  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B, C,B,B, C,C,B, B,C,B,
8868  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B, B,B,B, B,C,B, A,C,B,
8869  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C, B,A,C, B,B,C, A,B,C,
8870  B,A,B, C,A,B, C,B,B, B,B,B, B,A,C, C,A,C, C,B,C, B,B,C,
8871  B,B,B, C,B,B, C,C,B, B,C,B, B,B,C, C,B,C, C,C,C, B,C,C,
8872  A,B,B, B,B,B, B,C,B, A,C,B, A,B,C, B,B,C, B,C,C, A,C,C
8873  };
8874 
8876  .UseExternalData(tet_children, 3, 4, 16);
8878  .UseExternalData(pyr_children, 3, 5, 10);
8880  .UseExternalData(pri_children, 3, 6, 8);
8882  .UseExternalData(hex_children, 3, 8, 8);
8883 
8884  for (int i = 0; i < elements.Size(); i++)
8885  {
8886  // tetrahedron elements are handled above:
8887  if (elements[i]->GetType() == Element::TETRAHEDRON) { continue; }
8888 
8889  Embedding &emb = CoarseFineTr.embeddings[i];
8890  emb.parent = i / 8;
8891  emb.matrix = i % 8;
8892  }
8893 
8894  NumOfVertices = vertices.Size();
8895  NumOfElements = 8 * NumOfElements + 2 * pyr_counter;
8897 
8899  GenerateFaces();
8900 
8901 #ifdef MFEM_DEBUG
8903 #endif
8904 
8906 
8908  sequence++;
8909 
8910  if (update_nodes) { UpdateNodes(); }
8911 }
8912 
8913 void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
8914 {
8915  int i, j, ind, nedges;
8916  Array<int> v;
8917 
8918  ResetLazyData();
8919 
8920  if (ncmesh)
8921  {
8922  MFEM_ABORT("Local and nonconforming refinements cannot be mixed.");
8923  }
8924 
8926 
8927  if (Dim == 1) // --------------------------------------------------------
8928  {
8929  int cne = NumOfElements, cnv = NumOfVertices;
8930  NumOfVertices += marked_el.Size();
8931  NumOfElements += marked_el.Size();
8932  vertices.SetSize(NumOfVertices);
8933  elements.SetSize(NumOfElements);
8935 
8936  for (j = 0; j < marked_el.Size(); j++)
8937  {
8938  i = marked_el[j];
8939  Segment *c_seg = (Segment *)elements[i];
8940  int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
8941  int new_v = cnv + j, new_e = cne + j;
8942  AverageVertices(vert, 2, new_v);
8943  elements[new_e] = new Segment(new_v, vert[1], attr);
8944  vert[1] = new_v;
8945 
8948  }
8949 
8950  static double seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
8952  UseExternalData(seg_children, 1, 2, 3);
8953 
8954  GenerateFaces();
8955 
8956  } // end of 'if (Dim == 1)'
8957  else if (Dim == 2) // ---------------------------------------------------
8958  {
8959  // 1. Get table of vertex to vertex connections.
8960  DSTable v_to_v(NumOfVertices);
8961  GetVertexToVertexTable(v_to_v);
8962 
8963  // 2. Get edge to element connections in arrays edge1 and edge2
8964  nedges = v_to_v.NumberOfEntries();
8965  int *edge1 = new int[nedges];
8966  int *edge2 = new int[nedges];
8967  int *middle = new int[nedges];
8968 
8969  for (i = 0; i < nedges; i++)
8970  {
8971  edge1[i] = edge2[i] = middle[i] = -1;
8972  }
8973 
8974  for (i = 0; i < NumOfElements; i++)
8975  {
8976  elements[i]->GetVertices(v);
8977  for (j = 1; j < v.Size(); j++)
8978  {
8979  ind = v_to_v(v[j-1], v[j]);
8980  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
8981  }
8982  ind = v_to_v(v[0], v[v.Size()-1]);
8983  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
8984  }
8985 
8986  // 3. Do the red refinement.
8987  for (i = 0; i < marked_el.Size(); i++)
8988  {
8989  RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
8990  }
8991 
8992  // 4. Do the green refinement (to get conforming mesh).
8993  int need_refinement;
8994  do
8995  {
8996  need_refinement = 0;
8997  for (i = 0; i < nedges; i++)
8998  {
8999  if (middle[i] != -1 && edge1[i] != -1)
9000  {
9001  need_refinement = 1;
9002  GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
9003  }
9004  }
9005  }
9006  while (need_refinement == 1);
9007 
9008  // 5. Update the boundary elements.
9009  int v1[2], v2[2], bisect, temp;
9010  temp = NumOfBdrElements;
9011  for (i = 0; i < temp; i++)
9012  {
9013  boundary[i]->GetVertices(v);
9014  bisect = v_to_v(v[0], v[1]);
9015  if (middle[bisect] != -1) // the element was refined (needs updating)
9016  {
9017  if (boundary[i]->GetType() == Element::SEGMENT)
9018  {
9019  v1[0] = v[0]; v1[1] = middle[bisect];
9020  v2[0] = middle[bisect]; v2[1] = v[1];
9021 
9022  boundary[i]->SetVertices(v1);
9023  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
9024  }
9025  else
9026  mfem_error("Only bisection of segment is implemented"
9027  " for bdr elem.");
9028  }
9029  }
9030  NumOfBdrElements = boundary.Size();
9031 
9032  // 6. Free the allocated memory.
9033  delete [] edge1;
9034  delete [] edge2;
9035  delete [] middle;
9036 
9037  if (el_to_edge != NULL)
9038  {
9040  GenerateFaces();
9041  }
9042 
9043  }
9044  else if (Dim == 3) // ---------------------------------------------------
9045  {
9046  // 1. Hash table of vertex to vertex connections corresponding to refined
9047  // edges.
9048  HashTable<Hashed2> v_to_v;
9049 
9050  MFEM_VERIFY(GetNE() == 0 ||
9051  ((Tetrahedron*)elements[0])->GetRefinementFlag() != 0,
9052  "tetrahedral mesh is not marked for refinement:"
9053  " call Finalize(true)");
9054 
9055  // 2. Do the red refinement.
9056  int ii;
9057  switch (type)
9058  {
9059  case 1:
9060  for (i = 0; i < marked_el.Size(); i++)
9061  {
9062  Bisection(marked_el[i], v_to_v);
9063  }
9064  break;
9065  case 2:
9066  for (i = 0; i < marked_el.Size(); i++)
9067  {
9068  Bisection(marked_el[i], v_to_v);
9069 
9070  Bisection(NumOfElements - 1, v_to_v);
9071  Bisection(marked_el[i], v_to_v);
9072  }
9073  break;
9074  case 3:
9075  for (i = 0; i < marked_el.Size(); i++)
9076  {
9077  Bisection(marked_el[i], v_to_v);
9078 
9079  ii = NumOfElements - 1;
9080  Bisection(ii, v_to_v);
9081  Bisection(NumOfElements - 1, v_to_v);
9082  Bisection(ii, v_to_v);
9083 
9084  Bisection(marked_el[i], v_to_v);
9085  Bisection(NumOfElements-1, v_to_v);
9086  Bisection(marked_el[i], v_to_v);
9087  }
9088  break;
9089  }
9090 
9091  // 3. Do the green refinement (to get conforming mesh).
9092  int need_refinement;
9093  // int need_refinement, onoe, max_gen = 0;
9094  do
9095  {
9096  // int redges[2], type, flag;
9097  need_refinement = 0;
9098  // onoe = NumOfElements;
9099  // for (i = 0; i < onoe; i++)
9100  for (i = 0; i < NumOfElements; i++)
9101  {
9102  // ((Tetrahedron *)elements[i])->
9103  // ParseRefinementFlag(redges, type, flag);
9104  // if (flag > max_gen) max_gen = flag;
9105  if (elements[i]->NeedRefinement(v_to_v))
9106  {
9107  need_refinement = 1;
9108  Bisection(i, v_to_v);
9109  }
9110  }
9111  }
9112  while (need_refinement == 1);
9113 
9114  // mfem::out << "Maximum generation: " << max_gen << endl;
9115 
9116  // 4. Update the boundary elements.
9117  do
9118  {
9119  need_refinement = 0;
9120  for (i = 0; i < NumOfBdrElements; i++)
9121  if (boundary[i]->NeedRefinement(v_to_v))
9122  {
9123  need_refinement = 1;
9124  BdrBisection(i, v_to_v);
9125  }
9126  }
9127  while (need_refinement == 1);
9128 
9129  NumOfVertices = vertices.Size();
9130  NumOfBdrElements = boundary.Size();
9131 
9132  // 5. Update element-to-edge and element-to-face relations.
9133  if (el_to_edge != NULL)
9134  {
9136  }
9137  if (el_to_face != NULL)
9138  {
9140  GenerateFaces();
9141  }
9142 
9143  } // end 'if (Dim == 3)'
9144 
9146  sequence++;
9147 
9148  UpdateNodes();
9149 
9150 #ifdef MFEM_DEBUG
9151  CheckElementOrientation(false);
9152 #endif
9153 }
9154 
9156  int nc_limit)
9157 {
9158  MFEM_VERIFY(!NURBSext, "Nonconforming refinement of NURBS meshes is "
9159  "not supported. Project the NURBS to Nodes first.");
9160 
9161  ResetLazyData();
9162 
9163  if (!ncmesh)
9164  {
9165  // start tracking refinement hierarchy
9166  ncmesh = new NCMesh(this);
9167  }
9168 
9169  if (!refinements.Size())
9170  {
9172  return;
9173  }
9174 
9175  // do the refinements
9177  ncmesh->Refine(refinements);
9178 
9179  if (nc_limit > 0)
9180  {
9181  ncmesh->LimitNCLevel(nc_limit);
9182  }
9183 
9184  // create a second mesh containing the finest elements from 'ncmesh'
9185  Mesh* mesh2 = new Mesh(*ncmesh);
9186  ncmesh->OnMeshUpdated(mesh2);
9187 
9188  // now swap the meshes, the second mesh will become the old coarse mesh
9189  // and this mesh will be the new fine mesh
9190  Swap(*mesh2, false);
9191  delete mesh2;
9192 
9194 
9196  sequence++;
9197 
9198  if (Nodes) // update/interpolate curved mesh
9199  {
9200  Nodes->FESpace()->Update();
9201  Nodes->Update();
9202  }
9203 }
9204 
9205 double Mesh::AggregateError(const Array<double> &elem_error,
9206  const int *fine, int nfine, int op)
9207 {
9208  double error = elem_error[fine[0]];
9209 
9210  for (int i = 1; i < nfine; i++)
9211  {
9212  MFEM_VERIFY(fine[i] < elem_error.Size(), "");
9213 
9214  double err_fine = elem_error[fine[i]];
9215  switch (op)
9216  {
9217  case 0: error = std::min(error, err_fine); break;
9218  case 1: error += err_fine; break;
9219  case 2: error = std::max(error, err_fine); break;
9220  }
9221  }
9222  return error;
9223 }
9224 
9226  double threshold, int nc_limit, int op)
9227 {
9228  MFEM_VERIFY(ncmesh, "Only supported for non-conforming meshes.");
9229  MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. "
9230  "Project the NURBS to Nodes first.");
9231 
9232  ResetLazyData();
9233 
9234  const Table &dt = ncmesh->GetDerefinementTable();
9235 
9236  Array<int> level_ok;
9237  if (nc_limit > 0)
9238  {
9239  ncmesh->CheckDerefinementNCLevel(dt, level_ok, nc_limit);
9240  }
9241 
9242  Array<int> derefs;
9243  for (int i = 0; i < dt.Size(); i++)
9244  {
9245  if (nc_limit > 0 && !level_ok[i]) { continue; }
9246 
9247  double error =
9248  AggregateError(elem_error, dt.GetRow(i), dt.RowSize(i), op);
9249 
9250  if (error < threshold) { derefs.Append(i); }
9251  }
9252 
9253  if (!derefs.Size()) { return false; }
9254 
9255  ncmesh->Derefine(derefs);
9256 
9257  Mesh* mesh2 = new Mesh(*ncmesh);
9258  ncmesh->OnMeshUpdated(mesh2);
9259 
9260  Swap(*mesh2, false);
9261  delete mesh2;
9262 
9264 
9266  sequence++;
9267 
9268  UpdateNodes();
9269 
9270  return true;
9271 }
9272 
9273 bool Mesh::DerefineByError(Array<double> &elem_error, double threshold,
9274  int nc_limit, int op)
9275 {
9276  // NOTE: the error array is not const because it will be expanded in parallel
9277  // by ghost element errors
9278  if (Nonconforming())
9279  {
9280  return NonconformingDerefinement(elem_error, threshold, nc_limit, op);
9281  }
9282  else
9283  {
9284  MFEM_ABORT("Derefinement is currently supported for non-conforming "
9285  "meshes only.");
9286  return false;
9287  }
9288 }
9289 
9290 bool Mesh::DerefineByError(const Vector &elem_error, double threshold,
9291  int nc_limit, int op)
9292 {
9293  Array<double> tmp(elem_error.Size());
9294  for (int i = 0; i < tmp.Size(); i++)
9295  {
9296  tmp[i] = elem_error(i);
9297  }
9298  return DerefineByError(tmp, threshold, nc_limit, op);
9299 }
9300 
9301 
9302 void Mesh::InitFromNCMesh(const NCMesh &ncmesh_)
9303 {
9304  Dim = ncmesh_.Dimension();
9305  spaceDim = ncmesh_.SpaceDimension();
9306 
9307  DeleteTables();
9308 
9309  ncmesh_.GetMeshComponents(*this);
9310 
9311  NumOfVertices = vertices.Size();
9312  NumOfElements = elements.Size();
9313  NumOfBdrElements = boundary.Size();
9314 
9315  SetMeshGen(); // set the mesh type: 'meshgen', ...
9316 
9317  NumOfEdges = NumOfFaces = 0;
9319 
9320  if (Dim > 1)
9321  {
9322  el_to_edge = new Table;
9324  }
9325  if (Dim > 2)
9326  {
9328  }
9329  GenerateFaces();
9330 #ifdef MFEM_DEBUG
9332 #endif
9333 
9334  // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
9335  // outside after this method.
9336 }
9337 
9338 Mesh::Mesh(const NCMesh &ncmesh_)
9339 {
9340  Init();
9341  InitTables();
9342  InitFromNCMesh(ncmesh_);
9343  SetAttributes();
9344 }
9345 
9346 void Mesh::Swap(Mesh& other, bool non_geometry)
9347 {
9348  mfem::Swap(Dim, other.Dim);
9349  mfem::Swap(spaceDim, other.spaceDim);
9350 
9356 
9357  mfem::Swap(meshgen, other.meshgen);
9359 
9360  mfem::Swap(elements, other.elements);
9361  mfem::Swap(vertices, other.vertices);
9362  mfem::Swap(boundary, other.boundary);
9363  mfem::Swap(faces, other.faces);
9366 
9369  mfem::Swap(el_to_el, other.el_to_el);
9373  mfem::Swap(face_edge, other.face_edge);
9376 
9379 
9381 
9382 #ifdef MFEM_USE_MEMALLOC
9383  TetMemory.Swap(other.TetMemory);
9384 #endif
9385 
9386  if (non_geometry)
9387  {
9388  mfem::Swap(NURBSext, other.NURBSext);
9389  mfem::Swap(ncmesh, other.ncmesh);
9390 
9391  mfem::Swap(Nodes, other.Nodes);
9392  if (Nodes) { Nodes->FESpace()->UpdateMeshPointer(this); }
9393  if (other.Nodes) { other.Nodes->FESpace()->UpdateMeshPointer(&other); }
9394  mfem::Swap(own_nodes, other.own_nodes);
9395 
9397 
9398  mfem::Swap(sequence, other.sequence);
9400  }
9401 }
9402 
9403 void Mesh::GetElementData(const Array<Element*> &elem_array, int geom,
9404  Array<int> &elem_vtx, Array<int> &attr) const
9405 {
9406  // protected method
9407  const int nv = Geometry::NumVerts[geom];
9408  int num_elems = 0;
9409  for (int i = 0; i < elem_array.Size(); i++)
9410  {
9411  if (elem_array[i]->GetGeometryType() == geom)
9412  {
9413  num_elems++;
9414  }
9415  }
9416  elem_vtx.SetSize(nv*num_elems);
9417  attr.SetSize(num_elems);
9418  elem_vtx.SetSize(0);
9419  attr.SetSize(0);
9420  for (int i = 0; i < elem_array.Size(); i++)
9421  {
9422  Element *el = elem_array[i];
9423  if (el->GetGeometryType() != geom) { continue; }
9424 
9425  Array<int> loc_vtx(el->GetVertices(), nv);
9426  elem_vtx.Append(loc_vtx);
9427  attr.Append(el->GetAttribute());
9428  }
9429 }
9430 
9431 static Array<int>& AllElements(Array<int> &list, int nelem)
9432 {
9433  list.SetSize(nelem);
9434  for (int i = 0; i < nelem; i++) { list[i] = i; }
9435  return list;
9436 }
9437 
9438 void Mesh::UniformRefinement(int ref_algo)
9439 {
9440  Array<int> list;
9441 
9442  if (NURBSext)
9443  {
9445  }
9446  else if (ncmesh)
9447  {
9448  GeneralRefinement(AllElements(list, GetNE()));
9449  }
9450  else if (ref_algo == 1 && meshgen == 1 && Dim == 3)
9451  {
9452  // algorithm "B" for an all-tet mesh
9453  LocalRefinement(AllElements(list, GetNE()));
9454  }
9455  else
9456  {
9457  switch (Dim)
9458  {
9459  case 1: LocalRefinement(AllElements(list, GetNE())); break;
9460  case 2: UniformRefinement2D(); break;
9461  case 3: UniformRefinement3D(); break;
9462  default: MFEM_ABORT("internal error");
9463  }
9464  }
9465 }
9466 
9468  int nonconforming, int nc_limit)
9469 {
9470  if (ncmesh)
9471  {
9472  nonconforming = 1;
9473  }
9474  else if (Dim == 1 || (Dim == 3 && (meshgen & 1)))
9475  {
9476  nonconforming = 0;
9477  }
9478  else if (nonconforming < 0)
9479  {
9480  // determine if nonconforming refinement is suitable
9481  if ((meshgen & 2) || (meshgen & 4) || (meshgen & 8))
9482  {
9483  nonconforming = 1; // tensor product elements and wedges
9484  }
9485  else
9486  {
9487  nonconforming = 0; // simplices
9488  }
9489  }
9490 
9491  if (nonconforming)
9492  {
9493  // non-conforming refinement (hanging nodes)
9494  NonconformingRefinement(refinements, nc_limit);
9495  }
9496  else
9497  {
9498  Array<int> el_to_refine(refinements.Size());
9499  for (int i = 0; i < refinements.Size(); i++)
9500  {
9501  el_to_refine[i] = refinements[i].index;
9502  }
9503 
9504  // infer 'type' of local refinement from first element's 'ref_type'
9505  int type, rt = (refinements.Size() ? refinements[0].ref_type : 7);
9506  if (rt == 1 || rt == 2 || rt == 4)
9507  {
9508  type = 1; // bisection
9509  }
9510  else if (rt == 3 || rt == 5 || rt == 6)
9511  {
9512  type = 2; // quadrisection
9513  }
9514  else
9515  {
9516  type = 3; // octasection
9517  }
9518 
9519  // red-green refinement and bisection, no hanging nodes
9520  LocalRefinement(el_to_refine, type);
9521  }
9522 }
9523 
9524 void Mesh::GeneralRefinement(const Array<int> &el_to_refine, int nonconforming,
9525  int nc_limit)
9526 {
9527  Array<Refinement> refinements(el_to_refine.Size());
9528  for (int i = 0; i < el_to_refine.Size(); i++)
9529  {
9530  refinements[i] = Refinement(el_to_refine[i]);
9531  }
9532  GeneralRefinement(refinements, nonconforming, nc_limit);
9533 }
9534 
9535 void Mesh::EnsureNCMesh(bool simplices_nonconforming)
9536 {
9537  MFEM_VERIFY(!NURBSext, "Cannot convert a NURBS mesh to an NC mesh. "
9538  "Please project the NURBS to Nodes first, with SetCurvature().");
9539 
9540 #ifdef MFEM_USE_MPI
9541  MFEM_VERIFY(ncmesh != NULL || dynamic_cast<const ParMesh*>(this) == NULL,
9542  "Sorry, converting a conforming ParMesh to an NC mesh is "
9543  "not possible.");
9544 #endif
9545 
9546  if (!ncmesh)
9547  {
9548  if ((meshgen & 0x2) /* quads/hexes */ ||
9549  (meshgen & 0x4) /* wedges */ ||
9550  (simplices_nonconforming && (meshgen & 0x1)) /* simplices */)
9551  {
9552  ncmesh = new NCMesh(this);
9553  ncmesh->OnMeshUpdated(this);
9555  }
9556  }
9557 }
9558 
9559 void Mesh::RandomRefinement(double prob, bool aniso, int nonconforming,
9560  int nc_limit)
9561 {
9562  Array<Refinement> refs;
9563  for (int i = 0; i < GetNE(); i++)
9564  {
9565  if ((double) rand() / RAND_MAX < prob)
9566  {
9567  int type = 7;
9568  if (aniso)
9569  {
9570  type = (Dim == 3) ? (rand() % 7 + 1) : (rand() % 3 + 1);
9571  }
9572  refs.Append(Refinement(i, type));
9573  }
9574  }
9575  GeneralRefinement(refs, nonconforming, nc_limit);
9576 }
9577 
9578 void Mesh::RefineAtVertex(const Vertex& vert, double eps, int nonconforming)
9579 {
9580  Array<int> v;
9581  Array<Refinement> refs;
9582  for (int i = 0; i < GetNE(); i++)
9583  {
9584  GetElementVertices(i, v);
9585  bool refine = false;
9586  for (int j = 0; j < v.Size(); j++)
9587  {
9588  double dist = 0.0;
9589  for (int l = 0; l < spaceDim; l++)
9590  {
9591  double d = vert(l) - vertices[v[j]](l);
9592  dist += d*d;
9593  }
9594  if (dist <= eps*eps) { refine = true; break; }
9595  }
9596  if (refine)
9597  {
9598  refs.Append(Refinement(i));
9599  }
9600  }
9601  GeneralRefinement(refs, nonconforming);
9602 }
9603 
9604 bool Mesh::RefineByError(const Array<double> &elem_error, double threshold,
9605  int nonconforming, int nc_limit)
9606 {
9607  MFEM_VERIFY(elem_error.Size() == GetNE(), "");
9608  Array<Refinement> refs;
9609  for (int i = 0; i < GetNE(); i++)
9610  {
9611  if (elem_error[i] > threshold)
9612  {
9613  refs.Append(Refinement(i));
9614  }
9615  }
9616  if (ReduceInt(refs.Size()))
9617  {
9618  GeneralRefinement(refs, nonconforming, nc_limit);
9619  return true;
9620  }
9621  return false;
9622 }
9623 
9624 bool Mesh::RefineByError(const Vector &elem_error, double threshold,
9625  int nonconforming, int nc_limit)
9626 {
9627  Array<double> tmp(const_cast<double*>(elem_error.GetData()),
9628  elem_error.Size());
9629  return RefineByError(tmp, threshold, nonconforming, nc_limit);
9630 }
9631 
9632 
9633 void Mesh::Bisection(int i, const DSTable &v_to_v,
9634  int *edge1, int *edge2, int *middle)
9635 {
9636  int *vert;
9637  int v[2][4], v_new, bisect, t;
9638  Element *el = elements[i];
9639  Vertex V;
9640 
9641  t = el->GetType();
9642  if (t == Element::TRIANGLE)
9643  {
9644  Triangle *tri = (Triangle *) el;
9645 
9646  vert = tri->GetVertices();
9647 
9648  // 1. Get the index for the new vertex in v_new.
9649  bisect = v_to_v(vert[0], vert[1]);
9650  MFEM_ASSERT(bisect >= 0, "");
9651 
9652  if (middle[bisect] == -1)
9653  {
9654  v_new = NumOfVertices++;
9655  for (int d = 0; d < spaceDim; d++)
9656  {
9657  V(d) = 0.5 * (vertices[vert[0]](d) + vertices[vert[1]](d));
9658  }
9659  vertices.Append(V);
9660 
9661  // Put the element that may need refinement (because of this
9662  // bisection) in edge1, or -1 if no more refinement is needed.
9663  if (edge1[bisect] == i)
9664  {
9665  edge1[bisect] = edge2[bisect];
9666  }
9667 
9668  middle[bisect] = v_new;
9669  }
9670  else
9671  {
9672  v_new = middle[bisect];
9673 
9674  // This edge will require no more refinement.
9675  edge1[bisect] = -1;
9676  }
9677 
9678  // 2. Set the node indices for the new elements in v[0] and v[1] so that
9679  // the edge marked for refinement is between the first two nodes.
9680  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
9681  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
9682 
9683  tri->SetVertices(v[0]); // changes vert[0..2] !!!
9684 
9685  Triangle* tri_new = new Triangle(v[1], tri->GetAttribute());
9686  elements.Append(tri_new);
9687 
9688  int tr = tri->GetTransform();
9689  tri_new->ResetTransform(tr);
9690 
9691  // record the sequence of refinements
9692  tri->PushTransform(4);
9693  tri_new->PushTransform(5);
9694 
9695  int coarse = FindCoarseElement(i);
9696  CoarseFineTr.embeddings[i].parent = coarse;
9698 
9699  // 3. edge1 and edge2 may have to be changed for the second triangle.
9700  if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
9701  {
9702  bisect = v_to_v(v[1][0], v[1][1]);
9703  MFEM_ASSERT(bisect >= 0, "");
9704 
9705  if (edge1[bisect] == i)
9706  {
9707  edge1[bisect] = NumOfElements;
9708  }
9709  else if (edge2[bisect] == i)
9710  {
9711  edge2[bisect] = NumOfElements;
9712  }
9713  }
9714  NumOfElements++;
9715  }
9716  else
9717  {
9718  MFEM_ABORT("Bisection for now works only for triangles.");
9719  }
9720 }
9721 
9723 {
9724  int *vert;
9725  int v[2][4], v_new, bisect, t;
9726  Element *el = elements[i];
9727  Vertex V;
9728 
9729  t = el->GetType();
9730  if (t == Element::TETRAHEDRON)
9731  {
9732  int j, type, new_type, old_redges[2], new_redges[2][2], flag;
9733  Tetrahedron *tet = (Tetrahedron *) el;
9734 
9735  MFEM_VERIFY(tet->GetRefinementFlag() != 0,
9736  "TETRAHEDRON element is not marked for refinement.");
9737 
9738  vert = tet->GetVertices();
9739 
9740  // 1. Get the index for the new vertex in v_new.
9741  bisect = v_to_v.FindId(vert[0], vert[1]);
9742  if (bisect == -1)
9743  {
9744  v_new = NumOfVertices + v_to_v.GetId(vert[0],vert[1]);
9745  for (j = 0; j < 3; j++)
9746  {
9747  V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j));
9748  }
9749  vertices.Append(V);
9750  }
9751  else
9752  {
9753  v_new = NumOfVertices + bisect;
9754  }
9755 
9756  // 2. Set the node indices for the new elements in v[2][4] so that
9757  // the edge marked for refinement is between the first two nodes.
9758  tet->ParseRefinementFlag(old_redges, type, flag);
9759 
9760  v[0][3] = v_new;
9761  v[1][3] = v_new;
9762  new_redges[0][0] = 2;
9763  new_redges[0][1] = 1;
9764  new_redges[1][0] = 2;
9765  new_redges[1][1] = 1;
9766  int tr1 = -1, tr2 = -1;
9767  switch (old_redges[0])
9768  {
9769  case 2:
9770  v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3];
9771  if (type == Tetrahedron::TYPE_PF) { new_redges[0][1] = 4; }
9772  tr1 = 0;
9773  break;
9774  case 3:
9775  v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2];
9776  tr1 = 2;
9777  break;
9778  case 5:
9779  v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0];
9780  tr1 = 4;
9781  }
9782  switch (old_redges[1])
9783  {
9784  case 1:
9785  v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3];
9786  if (type == Tetrahedron::TYPE_PF) { new_redges[1][0] = 3; }
9787  tr2 = 1;
9788  break;
9789  case 4:
9790  v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2];
9791  tr2 = 3;
9792  break;
9793  case 5:
9794  v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1];
9795  tr2 = 5;
9796  }
9797 
9798  int attr = tet->GetAttribute();
9799  tet->SetVertices(v[0]);
9800 
9801 #ifdef MFEM_USE_MEMALLOC
9802  Tetrahedron *tet2 = TetMemory.Alloc();
9803  tet2->SetVertices(v[1]);
9804  tet2->SetAttribute(attr);
9805 #else
9806  Tetrahedron *tet2 = new Tetrahedron(v[1], attr);
9807 #endif
9808  tet2->ResetTransform(tet->GetTransform());
9809  elements.Append(tet2);
9810 
9811  // record the sequence of refinements
9812  tet->PushTransform(tr1);
9813  tet2->PushTransform(tr2);
9814 
9815  int coarse = FindCoarseElement(i);
9816  CoarseFineTr.embeddings[i].parent = coarse;
9818 
9819  // 3. Set the bisection flag
9820  switch (type)
9821  {
9822  case Tetrahedron::TYPE_PU:
9823  new_type = Tetrahedron::TYPE_PF; break;
9824  case Tetrahedron::TYPE_PF:
9825  new_type = Tetrahedron::TYPE_A; break;
9826  default:
9827  new_type = Tetrahedron::TYPE_PU;
9828  }
9829 
9830  tet->CreateRefinementFlag(new_redges[0], new_type, flag+1);
9831  tet2->CreateRefinementFlag(new_redges[1], new_type, flag+1);
9832 
9833  NumOfElements++;
9834  }
9835  else
9836  {
9837  MFEM_ABORT("Bisection with HashTable for now works only for tetrahedra.");
9838  }
9839 }
9840 
9841 void Mesh::BdrBisection(int i, const HashTable<Hashed2> &v_to_v)
9842 {
9843  int *vert;
9844  int v[2][3], v_new, bisect, t;
9845  Element *bdr_el = boundary[i];
9846 
9847  t = bdr_el->GetType();
9848  if (t == Element::TRIANGLE)
9849  {
9850  Triangle *tri = (Triangle *) bdr_el;
9851 
9852  vert = tri->GetVertices();
9853 
9854  // 1. Get the index for the new vertex in v_new.
9855  bisect = v_to_v.FindId(vert[0], vert[1]);
9856  MFEM_ASSERT(bisect >= 0, "");
9857  v_new = NumOfVertices + bisect;
9858  MFEM_ASSERT(v_new != -1, "");
9859 
9860  // 2. Set the node indices for the new elements in v[0] and v[1] so that
9861  // the edge marked for refinement is between the first two nodes.
9862  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
9863  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
9864 
9865  tri->SetVertices(v[0]);
9866 
9867  boundary.Append(new Triangle(v[1], tri->GetAttribute()));
9868 
9869  NumOfBdrElements++;
9870  }
9871  else
9872  {
9873  MFEM_ABORT("Bisection of boundary elements with HashTable works only for"
9874  " triangles!");
9875  }
9876 }
9877 
9878 void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
9879  int *edge1, int *edge2, int *middle)
9880 {
9881  Array<int> v;
9882  int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3];
9883  Vertex V;
9884 
9885  if (elements[i]->GetType() == Element::TRIANGLE)
9886  {
9887  Triangle *tri0 = (Triangle*) elements[i];
9888  tri0->GetVertices(v);
9889 
9890  // 1. Get the indices for the new vertices in array v_new
9891  bisect[0] = v_to_v(v[0],v[1]);
9892  bisect[1] = v_to_v(v[1],v[2]);
9893  bisect[2] = v_to_v(v[0],v[2]);
9894  MFEM_ASSERT(bisect[0] >= 0 && bisect[1] >= 0 && bisect[2] >= 0, "");
9895 
9896  for (j = 0; j < 3; j++) // for the 3 edges fix v_new
9897  {
9898  if (middle[bisect[j]] == -1)
9899  {
9900  v_new[j] = NumOfVertices++;
9901  for (int d = 0; d < spaceDim; d++)
9902  {
9903  V(d) = (vertices[v[j]](d) + vertices[v[(j+1)%3]](d))/2.;
9904  }
9905  vertices.Append(V);
9906 
9907  // Put the element that may need refinement (because of this
9908  // bisection) in edge1, or -1 if no more refinement is needed.
9909  if (edge1[bisect[j]] == i)
9910  {
9911  edge1[bisect[j]] = edge2[bisect[j]];
9912  }
9913 
9914  middle[bisect[j]] = v_new[j];
9915  }
9916  else
9917  {
9918  v_new[j] = middle[bisect[j]];
9919 
9920  // This edge will require no more refinement.
9921  edge1[bisect[j]] = -1;
9922  }
9923  }
9924 
9925  // 2. Set the node indices for the new elements in v1, v2, v3 & v4 so that
9926  // the edges marked for refinement be between the first two nodes.
9927  v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2];
9928  v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1];
9929  v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2];
9930  v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0];
9931 
9932  Triangle* tri1 = new Triangle(v1, tri0->GetAttribute());
9933  Triangle* tri2 = new Triangle(v2, tri0->GetAttribute());
9934  Triangle* tri3 = new Triangle(v3, tri0->GetAttribute());
9935 
9936  elements.Append(tri1);
9937  elements.Append(tri2);
9938  elements.Append(tri3);
9939 
9940  tri0->SetVertices(v4);
9941 
9942  // record the sequence of refinements
9943  unsigned code = tri0->GetTransform();
9944  tri1->ResetTransform(code);
9945  tri2->ResetTransform(code);
9946  tri3->ResetTransform(code);
9947 
9948  tri0->PushTransform(3);
9949  tri1->PushTransform(0);
9950  tri2->PushTransform(1);
9951  tri3->PushTransform(2);
9952 
9953  // set parent indices
9954  int coarse = FindCoarseElement(i);
9959 
9960  NumOfElements += 3;
9961  }
9962  else
9963  {
9964  MFEM_ABORT("Uniform refinement for now works only for triangles.");
9965  }
9966 }
9967 
9969 {
9970  // initialize CoarseFineTr
9971  CoarseFineTr.Clear();
9973  for (int i = 0; i < NumOfElements; i++)
9974  {
9975  elements[i]->ResetTransform(0);
9977  }
9978 }
9979 
9981 {
9982  int coarse;
9983  while ((coarse = CoarseFineTr.embeddings[i].parent) != i)
9984  {
9985  i = coarse;
9986  }
9987  return coarse;
9988 }
9989 
9991 {
9992  MFEM_VERIFY(GetLastOperation() == Mesh::REFINE, "");
9993 
9994  if (ncmesh)
9995  {
9996  return ncmesh->GetRefinementTransforms();
9997  }
9998 
9999  Mesh::GeometryList elem_geoms(*this);
10000  for (int i = 0; i < elem_geoms.Size(); i++)
10001  {
10002  const Geometry::Type geom = elem_geoms[i];
10003  if (CoarseFineTr.point_matrices[geom].SizeK()) { continue; }
10004 
10005  if (geom == Geometry::TRIANGLE ||
10006  geom == Geometry::TETRAHEDRON)
10007  {
10008  std::map<unsigned, int> mat_no;
10009  mat_no[0] = 1; // identity
10010 
10011  // assign matrix indices to element transformations
10012  for (int j = 0; j < elements.Size(); j++)
10013  {
10014  int index = 0;
10015  unsigned code = elements[j]->GetTransform();
10016  if (code)
10017  {
10018  int &matrix = mat_no[code];
10019  if (!matrix) { matrix = mat_no.size(); }
10020  index = matrix-1;
10021  }
10022  CoarseFineTr.embeddings[j].matrix = index;
10023  }
10024 
10025  DenseTensor &pmats = CoarseFineTr.point_matrices[geom];
10026  pmats.SetSize(Dim, Dim+1, mat_no.size());
10027 
10028  // calculate the point matrices used
10029  std::map<unsigned, int>::iterator it;
10030  for (it = mat_no.begin(); it != mat_no.end(); ++it)
10031  {
10032  if (geom == Geometry::TRIANGLE)
10033  {
10034  Triangle::GetPointMatrix(it->first, pmats(it->second-1));
10035  }
10036  else
10037  {
10038  Tetrahedron::GetPointMatrix(it->first, pmats(it->second-1));
10039  }
10040  }
10041  }
10042  else
10043  {
10044  MFEM_ABORT("Don't know how to construct CoarseFineTransformations for"
10045  " geom = " << geom);
10046  }
10047  }
10048 
10049  // NOTE: quads and hexes already have trivial transformations ready
10050  return CoarseFineTr;
10051 }
10052 
10053 void Mesh::PrintXG(std::ostream &os) const
10054 {
10055  MFEM_ASSERT(Dim==spaceDim, "2D Manifold meshes not supported");
10056  int i, j;
10057  Array<int> v;
10058 
10059  if (Dim == 2)
10060  {
10061  // Print the type of the mesh.
10062  if (Nodes == NULL)
10063  {
10064  os << "areamesh2\n\n";
10065  }
10066  else
10067  {
10068  os << "curved_areamesh2\n\n";
10069  }
10070 
10071  // Print the boundary elements.
10072  os << NumOfBdrElements << '\n';
10073  for (i = 0; i < NumOfBdrElements; i++)
10074  {
10075  boundary[i]->GetVertices(v);
10076 
10077  os << boundary[i]->GetAttribute();
10078  for (j = 0; j < v.Size(); j++)
10079  {
10080  os << ' ' << v[j] + 1;
10081  }
10082  os << '\n';
10083  }
10084 
10085  // Print the elements.
10086  os << NumOfElements << '\n';
10087  for (i = 0; i < NumOfElements; i++)
10088  {
10089  elements[i]->GetVertices(v);
10090 
10091  os << elements[i]->GetAttribute() << ' ' << v.Size();
10092  for (j = 0; j < v.Size(); j++)
10093  {
10094  os << ' ' << v[j] + 1;
10095  }
10096  os << '\n';
10097  }
10098 
10099  if (Nodes == NULL)
10100  {
10101  // Print the vertices.
10102  os << NumOfVertices << '\n';
10103  for (i = 0; i < NumOfVertices; i++)
10104  {
10105  os << vertices[i](0);
10106  for (j = 1; j < Dim; j++)
10107  {
10108  os << ' ' << vertices[i](j);
10109  }
10110  os << '\n';
10111  }
10112  }
10113  else
10114  {
10115  os << NumOfVertices << '\n';
10116  Nodes->Save(os);
10117  }
10118  }
10119  else // ===== Dim != 2 =====
10120  {
10121  if (Nodes)
10122  {
10123  mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D");
10124  }
10125 
10126  if (meshgen == 1)
10127  {
10128  int nv;
10129  const int *ind;
10130 
10131  os << "NETGEN_Neutral_Format\n";
10132  // print the vertices
10133  os << NumOfVertices << '\n';
10134  for (i = 0; i < NumOfVertices; i++)
10135  {
10136  for (j = 0; j < Dim; j++)
10137  {
10138  os << ' ' << vertices[i](j);
10139  }
10140  os << '\n';
10141  }
10142 
10143  // print the elements
10144  os << NumOfElements << '\n';
10145  for (i = 0; i < NumOfElements; i++)
10146  {
10147  nv = elements[i]->GetNVertices();
10148  ind = elements[i]->GetVertices();
10149  os << elements[i]->GetAttribute();
10150  for (j = 0; j < nv; j++)
10151  {
10152  os << ' ' << ind[j]+1;
10153  }
10154  os << '\n';
10155  }
10156 
10157  // print the boundary information.
10158  os << NumOfBdrElements << '\n';
10159  for (i = 0; i < NumOfBdrElements; i++)
10160  {
10161  nv = boundary[i]->GetNVertices();
10162  ind = boundary[i]->GetVertices();
10163  os << boundary[i]->GetAttribute();
10164  for (j = 0; j < nv; j++)
10165  {
10166  os << ' ' << ind[j]+1;
10167  }
10168  os << '\n';
10169  }
10170  }
10171  else if (meshgen == 2) // TrueGrid
10172  {
10173  int nv;
10174  const int *ind;
10175 
10176  os << "TrueGrid\n"
10177  << "1 " << NumOfVertices << " " << NumOfElements
10178  << " 0 0 0 0 0 0 0\n"
10179  << "0 0 0 1 0 0 0 0 0 0 0\n"
10180  << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
10181  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
10182  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
10183 
10184  for (i = 0; i < NumOfVertices; i++)
10185  os << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1)
10186  << ' ' << vertices[i](2) << " 0.0\n";
10187 
10188  for (i = 0; i < NumOfElements; i++)
10189  {
10190  nv = elements[i]->GetNVertices();
10191  ind = elements[i]->GetVertices();
10192  os << i+1 << ' ' << elements[i]->GetAttribute();
10193  for (j = 0; j < nv; j++)
10194  {
10195  os << ' ' << ind[j]+1;
10196  }
10197  os << '\n';
10198  }
10199 
10200  for (i = 0; i < NumOfBdrElements; i++)
10201  {
10202  nv = boundary[i]->GetNVertices();
10203  ind = boundary[i]->GetVertices();
10204  os << boundary[i]->GetAttribute();
10205  for (j = 0; j < nv; j++)
10206  {
10207  os << ' ' << ind[j]+1;
10208  }
10209  os << " 1.0 1.0 1.0 1.0\n";
10210  }
10211  }
10212  }
10213 
10214  os << flush;
10215 }
10216 
10217 void Mesh::Printer(std::ostream &os, std::string section_delimiter) const
10218 {
10219  int i, j;
10220 
10221  if (NURBSext)
10222  {
10223  // general format
10224  NURBSext->Print(os);
10225  os << '\n';
10226  Nodes->Save(os);
10227 
10228  // patch-wise format
10229  // NURBSext->ConvertToPatches(*Nodes);
10230  // NURBSext->Print(os);
10231 
10232  return;
10233  }
10234 
10235  if (Nonconforming())
10236  {
10237  // nonconforming mesh format
10238  ncmesh->Print(os);
10239 
10240  if (Nodes)
10241  {
10242  os << "\n# mesh curvature GridFunction";
10243  os << "\nnodes\n";
10244  Nodes->Save(os);
10245  }
10246 
10247  os << "\nmfem_mesh_end" << endl;
10248  return;
10249  }
10250 
10251  // serial/parallel conforming mesh format
10252  os << (section_delimiter.empty()
10253  ? "MFEM mesh v1.0\n" : "MFEM mesh v1.2\n");
10254 
10255  // optional
10256  os <<
10257  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10258  "# POINT = 0\n"
10259  "# SEGMENT = 1\n"
10260  "# TRIANGLE = 2\n"
10261  "# SQUARE = 3\n"
10262  "# TETRAHEDRON = 4\n"
10263  "# CUBE = 5\n"
10264  "# PRISM = 6\n"
10265  "# PYRAMID = 7\n"
10266  "#\n";
10267 
10268  os << "\ndimension\n" << Dim;
10269 
10270  os << "\n\nelements\n" << NumOfElements << '\n';
10271  for (i = 0; i < NumOfElements; i++)
10272  {
10273  PrintElement(elements[i], os);
10274  }
10275 
10276  os << "\nboundary\n" << NumOfBdrElements << '\n';
10277  for (i = 0; i < NumOfBdrElements; i++)
10278  {
10279  PrintElement(boundary[i], os);
10280  }
10281 
10282  os << "\nvertices\n" << NumOfVertices << '\n';
10283  if (Nodes == NULL)
10284  {
10285  os << spaceDim << '\n';
10286  for (i = 0; i < NumOfVertices; i++)
10287  {
10288  os << vertices[i](0);
10289  for (j = 1; j < spaceDim; j++)
10290  {
10291  os << ' ' << vertices[i](j);
10292  }
10293  os << '\n';
10294  }
10295  os.flush();
10296  }
10297  else
10298  {
10299  os << "\nnodes\n";
10300  Nodes->Save(os);
10301  }
10302 
10303  if (!section_delimiter.empty())
10304  {
10305  os << section_delimiter << endl; // only with format v1.2
10306  }
10307 }
10308 
10309 void Mesh::PrintTopo(std::ostream &os,const Array<int> &e_to_k) const
10310 {
10311  int i;
10312  Array<int> vert;
10313 
10314  os << "MFEM NURBS mesh v1.0\n";
10315 
10316  // optional
10317  os <<
10318  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10319  "# SEGMENT = 1\n"
10320  "# SQUARE = 3\n"
10321  "# CUBE = 5\n"
10322  "#\n";
10323 
10324  os << "\ndimension\n" << Dim
10325  << "\n\nelements\n" << NumOfElements << '\n';
10326  for (i = 0; i < NumOfElements; i++)
10327  {
10328  PrintElement(elements[i], os);
10329  }
10330 
10331  os << "\nboundary\n" << NumOfBdrElements << '\n';
10332  for (i = 0; i < NumOfBdrElements; i++)
10333  {
10334  PrintElement(boundary[i], os);
10335  }
10336 
10337  os << "\nedges\n" << NumOfEdges << '\n';
10338  for (i = 0; i < NumOfEdges; i++)
10339  {
10340  edge_vertex->GetRow(i, vert);
10341  int ki = e_to_k[i];
10342  if (ki < 0)
10343  {
10344  ki = -1 - ki;
10345  }
10346  os << ki << ' ' << vert[0] << ' ' << vert[1] << '\n';
10347  }
10348  os << "\nvertices\n" << NumOfVertices << '\n';
10349 }
10350 
10351 void Mesh::Save(const char *fname, int precision) const
10352 {
10353  ofstream ofs(fname);
10354  ofs.precision(precision);
10355  Print(ofs);
10356 }
10357 
10358 #ifdef MFEM_USE_ADIOS2
10359 void Mesh::Print(adios2stream &os) const
10360 {
10361  os.Print(*this);
10362 }
10363 #endif
10364 
10365 void Mesh::PrintVTK(std::ostream &os)
10366 {
10367  os <<
10368  "# vtk DataFile Version 3.0\n"
10369  "Generated by MFEM\n"
10370  "ASCII\n"
10371  "DATASET UNSTRUCTURED_GRID\n";
10372 
10373  if (Nodes == NULL)
10374  {
10375  os << "POINTS " << NumOfVertices << " double\n";
10376  for (int i = 0; i < NumOfVertices; i++)
10377  {
10378  os << vertices[i](0);
10379  int j;
10380  for (j = 1; j < spaceDim; j++)
10381  {
10382  os << ' ' << vertices[i](j);
10383  }
10384  for ( ; j < 3; j++)
10385  {
10386  os << ' ' << 0.0;
10387  }
10388  os << '\n';
10389  }
10390  }
10391  else
10392  {
10393  Array<int> vdofs(3);
10394  os << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n";
10395  for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++)
10396  {
10397  vdofs.SetSize(1);
10398  vdofs[0] = i;
10399  Nodes->FESpace()->DofsToVDofs(vdofs);
10400  os << (*Nodes)(vdofs[0]);
10401  int j;
10402  for (j = 1; j < spaceDim; j++)
10403  {
10404  os << ' ' << (*Nodes)(vdofs[j]);
10405  }
10406  for ( ; j < 3; j++)
10407  {
10408  os << ' ' << 0.0;
10409  }
10410  os << '\n';
10411  }
10412  }
10413 
10414  int order = -1;
10415  if (Nodes == NULL)
10416  {
10417  int size = 0;
10418  for (int i = 0; i < NumOfElements; i++)
10419  {
10420  size += elements[i]->GetNVertices() + 1;
10421  }
10422  os << "CELLS " << NumOfElements << ' ' << size << '\n';
10423  for (int i = 0; i < NumOfElements; i++)
10424  {
10425  const int *v = elements[i]->GetVertices();
10426  const int nv = elements[i]->GetNVertices();
10427  os << nv;
10428  Geometry::Type geom = elements[i]->GetGeometryType();
10429  const int *perm = VTKGeometry::VertexPermutation[geom];
10430  for (int j = 0; j < nv; j++)
10431  {
10432  os << ' ' << v[perm ? perm[j] : j];
10433  }
10434  os << '\n';
10435  }
10436  order = 1;
10437  }
10438  else
10439  {
10440  Array<int> dofs;
10441  int size = 0;
10442  for (int i = 0; i < NumOfElements; i++)
10443  {
10444  Nodes->FESpace()->GetElementDofs(i, dofs);
10445  MFEM_ASSERT(Dim != 0 || dofs.Size() == 1,
10446  "Point meshes should have a single dof per element");
10447  size += dofs.Size() + 1;
10448  }
10449  os << "CELLS " << NumOfElements << ' ' << size << '\n';
10450  const char *fec_name = Nodes->FESpace()->FEColl()->Name();
10451 
10452  if (!strcmp(fec_name, "Linear") ||
10453  !strcmp(fec_name, "H1_0D_P1") ||
10454  !strcmp(fec_name, "H1_1D_P1") ||
10455  !strcmp(fec_name, "H1_2D_P1") ||
10456  !strcmp(fec_name, "H1_3D_P1"))
10457  {
10458  order = 1;
10459  }
10460  else if (!strcmp(fec_name, "Quadratic") ||
10461  !strcmp(fec_name, "H1_1D_P2") ||
10462  !strcmp(fec_name, "H1_2D_P2") ||
10463  !strcmp(fec_name, "H1_3D_P2"))
10464  {
10465  order = 2;
10466  }
10467  if (order == -1)
10468  {
10469  mfem::err << "Mesh::PrintVTK : can not save '"
10470  << fec_name << "' elements!" << endl;
10471  mfem_error();
10472  }
10473  for (int i = 0; i < NumOfElements; i++)
10474  {
10475  Nodes->FESpace()->GetElementDofs(i, dofs);
10476  os << dofs.Size();
10477  if (order == 1)
10478  {
10479  for (int j = 0; j < dofs.Size(); j++)
10480  {
10481  os << ' ' << dofs[j];
10482  }
10483  }
10484  else if (order == 2)
10485  {
10486  const int *vtk_mfem;
10487  switch (elements[i]->GetGeometryType())
10488  {
10489  case Geometry::SEGMENT:
10490  case Geometry::TRIANGLE:
10491  case Geometry::SQUARE:
10492  vtk_mfem = vtk_quadratic_hex; break; // identity map
10493  case Geometry::TETRAHEDRON:
10494  vtk_mfem = vtk_quadratic_tet; break;
10495  case Geometry::PRISM:
10496  vtk_mfem = vtk_quadratic_wedge; break;
10497  case Geometry::CUBE:
10498  default:
10499  vtk_mfem = vtk_quadratic_hex; break;
10500  }
10501  for (int j = 0; j < dofs.Size(); j++)
10502  {
10503  os << ' ' << dofs[vtk_mfem[j]];
10504  }
10505  }
10506  os << '\n';
10507  }
10508  }
10509 
10510  os << "CELL_TYPES " << NumOfElements << '\n';
10511  for (int i = 0; i < NumOfElements; i++)
10512  {
10513  int vtk_cell_type = 5;
10515  if (order == 1) { vtk_cell_type = VTKGeometry::Map[geom]; }
10516  else if (order == 2) { vtk_cell_type = VTKGeometry::QuadraticMap[geom]; }
10517  os << vtk_cell_type << '\n';
10518  }
10519 
10520  // write attributes
10521  os << "CELL_DATA " << NumOfElements << '\n'
10522  << "SCALARS material int\n"
10523  << "LOOKUP_TABLE default\n";
10524  for (int i = 0; i < NumOfElements; i++)
10525  {
10526  os << elements[i]->GetAttribute() << '\n';
10527  }
10528  os.flush();
10529 }
10530 
10531 void Mesh::PrintVTU(std::string fname,
10532  VTKFormat format,
10533  bool high_order_output,
10534  int compression_level,
10535  bool bdr)
10536 {
10537  int ref = (high_order_output && Nodes)
10538  ? Nodes->FESpace()->GetMaxElementOrder() : 1;
10539 
10540  fname = fname + ".vtu";
10541  std::fstream os(fname.c_str(),std::ios::out);
10542  os << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"";
10543  if (compression_level != 0)
10544  {
10545  os << " compressor=\"vtkZLibDataCompressor\"";
10546  }
10547  os << " byte_order=\"" << VTKByteOrder() << "\">\n";
10548  os << "<UnstructuredGrid>\n";
10549  PrintVTU(os, ref, format, high_order_output, compression_level, bdr);
10550  os << "</Piece>\n"; // need to close the piece open in the PrintVTU method
10551  os << "</UnstructuredGrid>\n";
10552  os << "</VTKFile>" << std::endl;
10553 
10554  os.close();
10555 }
10556 
10557 void Mesh::PrintBdrVTU(std::string fname,
10558  VTKFormat format,
10559  bool high_order_output,
10560  int compression_level)
10561 {
10562  PrintVTU(fname, format, high_order_output, compression_level, true);
10563 }
10564 
10565 void Mesh::PrintVTU(std::ostream &os, int ref, VTKFormat format,
10566  bool high_order_output, int compression_level,
10567  bool bdr_elements)
10568 {
10569  RefinedGeometry *RefG;
10570  DenseMatrix pmat;
10571 
10572  const char *fmt_str = (format == VTKFormat::ASCII) ? "ascii" : "binary";
10573  const char *type_str = (format != VTKFormat::BINARY32) ? "Float64" : "Float32";
10574  std::vector<char> buf;
10575 
10576  auto get_geom = [&](int i)
10577  {
10578  if (bdr_elements) { return GetBdrElementBaseGeometry(i); }
10579  else { return GetElementBaseGeometry(i); }
10580  };
10581 
10582  int ne = bdr_elements ? GetNBE() : GetNE();
10583  // count the number of points and cells
10584  int np = 0, nc_ref = 0;
10585  for (int i = 0; i < ne; i++)
10586  {
10587  Geometry::Type geom = get_geom(i);
10588  int nv = Geometries.GetVertices(geom)->GetNPoints();
10589  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10590  np += RefG->RefPts.GetNPoints();
10591  nc_ref += RefG->RefGeoms.Size() / nv;
10592  }
10593 
10594  os << "<Piece NumberOfPoints=\"" << np << "\" NumberOfCells=\""
10595  << (high_order_output ? ne : nc_ref) << "\">\n";
10596 
10597  // print out the points
10598  os << "<Points>\n";
10599  os << "<DataArray type=\"" << type_str
10600  << "\" NumberOfComponents=\"3\" format=\"" << fmt_str << "\">\n";
10601  for (int i = 0; i < ne; i++)
10602  {
10603  RefG = GlobGeometryRefiner.Refine(get_geom(i), ref, 1);
10604 
10605  if (bdr_elements)
10606  {
10607  GetBdrElementTransformation(i)->Transform(RefG->RefPts, pmat);
10608  }
10609  else
10610  {
10611  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
10612  }
10613 
10614  for (int j = 0; j < pmat.Width(); j++)
10615  {
10616  WriteBinaryOrASCII(os, buf, pmat(0,j), " ", format);
10617  if (pmat.Height() > 1)
10618  {
10619  WriteBinaryOrASCII(os, buf, pmat(1,j), " ", format);
10620  }
10621  else
10622  {
10623  WriteBinaryOrASCII(os, buf, 0.0, " ", format);
10624  }
10625  if (pmat.Height() > 2)
10626  {
10627  WriteBinaryOrASCII(os, buf, pmat(2,j), "", format);
10628  }
10629  else
10630  {
10631  WriteBinaryOrASCII(os, buf, 0.0, "", format);
10632  }
10633  if (format == VTKFormat::ASCII) { os << '\n'; }
10634  }
10635  }
10636  if (format != VTKFormat::ASCII)
10637  {
10638  WriteBase64WithSizeAndClear(os, buf, compression_level);
10639  }
10640  os << "</DataArray>" << std::endl;
10641  os << "</Points>" << std::endl;
10642 
10643  os << "<Cells>" << std::endl;
10644  os << "<DataArray type=\"Int32\" Name=\"connectivity\" format=\""
10645  << fmt_str << "\">" << std::endl;
10646  // connectivity
10647  std::vector<int> offset;
10648 
10649  np = 0;
10650  if (high_order_output)
10651  {
10652  Array<int> local_connectivity;
10653  for (int iel = 0; iel < ne; iel++)
10654  {
10655  Geometry::Type geom = get_geom(iel);
10656  CreateVTKElementConnectivity(local_connectivity, geom, ref);
10657  int nnodes = local_connectivity.Size();
10658  for (int i=0; i<nnodes; ++i)
10659  {
10660  WriteBinaryOrASCII(os, buf, np+local_connectivity[i], " ",
10661  format);
10662  }
10663  if (format == VTKFormat::ASCII) { os << '\n'; }
10664  np += nnodes;
10665  offset.push_back(np);
10666  }
10667  }
10668  else
10669  {
10670  int coff = 0;
10671  for (int i = 0; i < ne; i++)
10672  {
10673  Geometry::Type geom = get_geom(i);
10674  int nv = Geometries.GetVertices(geom)->GetNPoints();
10675  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10676  Array<int> &RG = RefG->RefGeoms;
10677  for (int j = 0; j < RG.Size(); )
10678  {
10679  coff = coff+nv;
10680  offset.push_back(coff);
10681  const int *p = VTKGeometry::VertexPermutation[geom];
10682  for (int k = 0; k < nv; k++, j++)
10683  {
10684  WriteBinaryOrASCII(os, buf, np + RG[p ? p[j] : j], " ",
10685  format);
10686  }
10687  if (format == VTKFormat::ASCII) { os << '\n'; }
10688  }
10689  np += RefG->RefPts.GetNPoints();
10690  }
10691  }
10692  if (format != VTKFormat::ASCII)
10693  {
10694  WriteBase64WithSizeAndClear(os, buf, compression_level);
10695  }
10696  os << "</DataArray>" << std::endl;
10697 
10698  os << "<DataArray type=\"Int32\" Name=\"offsets\" format=\""
10699  << fmt_str << "\">" << std::endl;
10700  // offsets
10701  for (size_t ii=0; ii<offset.size(); ii++)
10702  {
10703  WriteBinaryOrASCII(os, buf, offset[ii], "\n", format);
10704  }
10705  if (format != VTKFormat::ASCII)
10706  {
10707  WriteBase64WithSizeAndClear(os, buf, compression_level);
10708  }
10709  os << "</DataArray>" << std::endl;
10710  os << "<DataArray type=\"UInt8\" Name=\"types\" format=\""
10711  << fmt_str << "\">" << std::endl;
10712  // cell types
10713  const int *vtk_geom_map =
10714  high_order_output ? VTKGeometry::HighOrderMap : VTKGeometry::Map;
10715  for (int i = 0; i < ne; i++)
10716  {
10717  Geometry::Type geom = get_geom(i);
10718  uint8_t vtk_cell_type = 5;
10719 
10720  vtk_cell_type = vtk_geom_map[geom];
10721 
10722  if (high_order_output)
10723  {
10724  WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
10725  }
10726  else
10727  {
10728  int nv = Geometries.GetVertices(geom)->GetNPoints();
10729  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10730  Array<int> &RG = RefG->RefGeoms;
10731  for (int j = 0; j < RG.Size(); j += nv)
10732  {
10733  WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
10734  }
10735  }
10736  }
10737  if (format != VTKFormat::ASCII)
10738  {
10739  WriteBase64WithSizeAndClear(os, buf, compression_level);
10740  }
10741  os << "</DataArray>" << std::endl;
10742  os << "</Cells>" << std::endl;
10743 
10744  os << "<CellData Scalars=\"attribute\">" << std::endl;
10745  os << "<DataArray type=\"Int32\" Name=\"attribute\" format=\""
10746  << fmt_str << "\">" << std::endl;
10747  for (int i = 0; i < ne; i++)
10748  {
10749  int attr = bdr_elements ? GetBdrAttribute(i) : GetAttribute(i);
10750  if (high_order_output)
10751  {
10752  WriteBinaryOrASCII(os, buf, attr, "\n", format);
10753  }
10754  else
10755  {
10756  Geometry::Type geom = get_geom(i);
10757  int nv = Geometries.GetVertices(geom)->GetNPoints();
10758  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10759  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10760  {
10761  WriteBinaryOrASCII(os, buf, attr, "\n", format);
10762  }
10763  }
10764  }
10765  if (format != VTKFormat::ASCII)
10766  {
10767  WriteBase64WithSizeAndClear(os, buf, compression_level);
10768  }
10769  os << "</DataArray>" << std::endl;
10770  os << "</CellData>" << std::endl;
10771 }
10772 
10773 
10774 void Mesh::PrintVTK(std::ostream &os, int ref, int field_data)
10775 {
10776  int np, nc, size;
10777  RefinedGeometry *RefG;
10778  DenseMatrix pmat;
10779 
10780  os <<
10781  "# vtk DataFile Version 3.0\n"
10782  "Generated by MFEM\n"
10783  "ASCII\n"
10784  "DATASET UNSTRUCTURED_GRID\n";
10785 
10786  // additional dataset information
10787  if (field_data)
10788  {
10789  os << "FIELD FieldData 1\n"
10790  << "MaterialIds " << 1 << " " << attributes.Size() << " int\n";
10791  for (int i = 0; i < attributes.Size(); i++)
10792  {
10793  os << ' ' << attributes[i];
10794  }
10795  os << '\n';
10796  }
10797 
10798  // count the points, cells, size
10799  np = nc = size = 0;
10800  for (int i = 0; i < GetNE(); i++)
10801  {
10803  int nv = Geometries.GetVertices(geom)->GetNPoints();
10804  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10805  np += RefG->RefPts.GetNPoints();
10806  nc += RefG->RefGeoms.Size() / nv;
10807  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
10808  }
10809  os << "POINTS " << np << " double\n";
10810  // write the points
10811  for (int i = 0; i < GetNE(); i++)
10812  {
10813  RefG = GlobGeometryRefiner.Refine(
10814  GetElementBaseGeometry(i), ref, 1);
10815 
10816  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
10817 
10818  for (int j = 0; j < pmat.Width(); j++)
10819  {
10820  os << pmat(0, j) << ' ';
10821  if (pmat.Height() > 1)
10822  {
10823  os << pmat(1, j) << ' ';
10824  if (pmat.Height() > 2)
10825  {
10826  os << pmat(2, j);
10827  }
10828  else
10829  {
10830  os << 0.0;
10831  }
10832  }
10833  else
10834  {
10835  os << 0.0 << ' ' << 0.0;
10836  }
10837  os << '\n';
10838  }
10839  }
10840 
10841  // write the cells
10842  os << "CELLS " << nc << ' ' << size << '\n';
10843  np = 0;
10844  for (int i = 0; i < GetNE(); i++)
10845  {
10847  int nv = Geometries.GetVertices(geom)->GetNPoints();
10848  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10849  Array<int> &RG = RefG->RefGeoms;
10850 
10851  for (int j = 0; j < RG.Size(); )
10852  {
10853  os << nv;
10854  for (int k = 0; k < nv; k++, j++)
10855  {
10856  os << ' ' << np + RG[j];
10857  }
10858  os << '\n';
10859  }
10860  np += RefG->RefPts.GetNPoints();
10861  }
10862  os << "CELL_TYPES " << nc << '\n';
10863  for (int i = 0; i < GetNE(); i++)
10864  {
10866  int nv = Geometries.GetVertices(geom)->GetNPoints();
10867  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10868  Array<int> &RG = RefG->RefGeoms;
10869  int vtk_cell_type = VTKGeometry::Map[geom];
10870 
10871  for (int j = 0; j < RG.Size(); j += nv)
10872  {
10873  os << vtk_cell_type << '\n';
10874  }
10875  }
10876  // write attributes (materials)
10877  os << "CELL_DATA " << nc << '\n'
10878  << "SCALARS material int\n"
10879  << "LOOKUP_TABLE default\n";
10880  for (int i = 0; i < GetNE(); i++)
10881  {
10883  int nv = Geometries.GetVertices(geom)->GetNPoints();
10884  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10885  int attr = GetAttribute(i);
10886  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10887  {
10888  os << attr << '\n';
10889  }
10890  }
10891 
10892  if (Dim > 1)
10893  {
10894  Array<int> coloring;
10895  srand((unsigned)time(0));
10896  double a = double(rand()) / (double(RAND_MAX) + 1.);
10897  int el0 = (int)floor(a * GetNE());
10898  GetElementColoring(coloring, el0);
10899  os << "SCALARS element_coloring int\n"
10900  << "LOOKUP_TABLE default\n";
10901  for (int i = 0; i < GetNE(); i++)
10902  {
10904  int nv = Geometries.GetVertices(geom)->GetNPoints();
10905  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10906  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10907  {
10908  os << coloring[i] + 1 << '\n';
10909  }
10910  }
10911  }
10912 
10913  // prepare to write data
10914  os << "POINT_DATA " << np << '\n' << flush;
10915 }
10916 
10917 void Mesh::GetElementColoring(Array<int> &colors, int el0)
10918 {
10919  int delete_el_to_el = (el_to_el) ? (0) : (1);
10920  const Table &el_el = ElementToElementTable();
10921  int num_el = GetNE(), stack_p, stack_top_p, max_num_col;
10922  Array<int> el_stack(num_el);
10923 
10924  const int *i_el_el = el_el.GetI();
10925  const int *j_el_el = el_el.GetJ();
10926 
10927  colors.SetSize(num_el);
10928  colors = -2;
10929  max_num_col = 1;
10930  stack_p = stack_top_p = 0;
10931  for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el)
10932  {
10933  if (colors[el] != -2)
10934  {
10935  continue;
10936  }
10937 
10938  colors[el] = -1;
10939  el_stack[stack_top_p++] = el;
10940 
10941  for ( ; stack_p < stack_top_p; stack_p++)
10942  {
10943  int i = el_stack[stack_p];
10944  int num_nb = i_el_el[i+1] - i_el_el[i];
10945  if (max_num_col < num_nb + 1)
10946  {
10947  max_num_col = num_nb + 1;
10948  }
10949  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
10950  {
10951  int k = j_el_el[j];
10952  if (colors[k] == -2)
10953  {
10954  colors[k] = -1;
10955  el_stack[stack_top_p++] = k;
10956  }
10957  }
10958  }
10959  }
10960 
10961  Array<int> col_marker(max_num_col);
10962 
10963  for (stack_p = 0; stack_p < stack_top_p; stack_p++)
10964  {
10965  int i = el_stack[stack_p], col;
10966  col_marker = 0;
10967  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
10968  {
10969  col = colors[j_el_el[j]];
10970  if (col != -1)
10971  {
10972  col_marker[col] = 1;
10973  }
10974  }
10975 
10976  for (col = 0; col < max_num_col; col++)
10977  if (col_marker[col] == 0)
10978  {
10979  break;
10980  }
10981 
10982  colors[i] = col;
10983  }
10984 
10985  if (delete_el_to_el)
10986  {
10987  delete el_to_el;
10988  el_to_el = NULL;
10989  }
10990 }
10991 
10992 void Mesh::PrintWithPartitioning(int *partitioning, std::ostream &os,
10993  int elem_attr) const
10994 {
10995  if (Dim != 3 && Dim != 2) { return; }
10996 
10997  int i, j, k, l, nv, nbe, *v;
10998 
10999  os << "MFEM mesh v1.0\n";
11000 
11001  // optional
11002  os <<
11003  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
11004  "# POINT = 0\n"
11005  "# SEGMENT = 1\n"
11006  "# TRIANGLE = 2\n"
11007  "# SQUARE = 3\n"
11008  "# TETRAHEDRON = 4\n"
11009  "# CUBE = 5\n"
11010  "# PRISM = 6\n"
11011  "#\n";
11012 
11013  os << "\ndimension\n" << Dim
11014  << "\n\nelements\n" << NumOfElements << '\n';
11015  for (i = 0; i < NumOfElements; i++)
11016  {
11017  os << int((elem_attr) ? partitioning[i]+1 : elements[i]->GetAttribute())
11018  << ' ' << elements[i]->GetGeometryType();
11019  nv = elements[i]->GetNVertices();
11020  v = elements[i]->GetVertices();
11021  for (j = 0; j < nv; j++)
11022  {
11023  os << ' ' << v[j];
11024  }
11025  os << '\n';
11026  }
11027  nbe = 0;
11028  for (i = 0; i < faces_info.Size(); i++)
11029  {
11030  if ((l = faces_info[i].Elem2No) >= 0)
11031  {
11032  k = partitioning[faces_info[i].Elem1No];
11033  l = partitioning[l];
11034  if (k != l)
11035  {
11036  nbe++;
11037  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
11038  {
11039  nbe++;
11040  }
11041  }
11042  }
11043  else
11044  {
11045  nbe++;
11046  }
11047  }
11048  os << "\nboundary\n" << nbe << '\n';
11049  for (i = 0; i < faces_info.Size(); i++)
11050  {
11051  if ((l = faces_info[i].Elem2No) >= 0)
11052  {
11053  k = partitioning[faces_info[i].Elem1No];
11054  l = partitioning[l];
11055  if (k != l)
11056  {
11057  nv = faces[i]->GetNVertices();
11058  v = faces[i]->GetVertices();
11059  os << k+1 << ' ' << faces[i]->GetGeometryType();
11060  for (j = 0; j < nv; j++)
11061  {
11062  os << ' ' << v[j];
11063  }
11064  os << '\n';
11065  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
11066  {
11067  os << l+1 << ' ' << faces[i]->GetGeometryType();
11068  for (j = nv-1; j >= 0; j--)
11069  {
11070  os << ' ' << v[j];
11071  }
11072  os << '\n';
11073  }
11074  }
11075  }
11076  else
11077  {
11078  k = partitioning[faces_info[i].Elem1No];
11079  nv = faces[i]->GetNVertices();
11080  v = faces[i]->GetVertices();
11081  os << k+1 << ' ' << faces[i]->GetGeometryType();
11082  for (j = 0; j < nv; j++)
11083  {
11084  os << ' ' << v[j];
11085  }
11086  os << '\n';
11087  }
11088  }
11089  os << "\nvertices\n" << NumOfVertices << '\n';
11090  if (Nodes == NULL)
11091  {
11092  os << spaceDim << '\n';
11093  for (i = 0; i < NumOfVertices; i++)
11094  {
11095  os << vertices[i](0);
11096  for (j = 1; j < spaceDim; j++)
11097  {
11098  os << ' ' << vertices[i](j);
11099  }
11100  os << '\n';
11101  }
11102  os.flush();
11103  }
11104  else
11105  {
11106  os << "\nnodes\n";
11107  Nodes->Save(os);
11108  }
11109 }
11110 
11112  std::ostream &os,
11113  int interior_faces)
11114 {
11115  MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported\n");
11116  if (Dim != 3 && Dim != 2) { return; }
11117 
11118  int *vcount = new int[NumOfVertices];
11119  for (int i = 0; i < NumOfVertices; i++)
11120  {
11121  vcount[i] = 0;
11122  }
11123  for (int i = 0; i < NumOfElements; i++)
11124  {
11125  int nv = elements[i]->GetNVertices();
11126  const int *ind = elements[i]->GetVertices();
11127  for (int j = 0; j < nv; j++)
11128  {
11129  vcount[ind[j]]++;
11130  }
11131  }
11132 
11133  int *voff = new int[NumOfVertices+1];
11134  voff[0] = 0;
11135  for (int i = 1; i <= NumOfVertices; i++)
11136  {
11137  voff[i] = vcount[i-1] + voff[i-1];
11138  }
11139 
11140  int **vown = new int*[NumOfVertices];
11141  for (int i = 0; i < NumOfVertices; i++)
11142  {
11143  vown[i] = new int[vcount[i]];
11144  }
11145 
11146  // 2D
11147  if (Dim == 2)
11148  {
11149  Table edge_el;
11150  Transpose(ElementToEdgeTable(), edge_el);
11151 
11152  // Fake printing of the elements.
11153  for (int i = 0; i < NumOfElements; i++)
11154  {
11155  int nv = elements[i]->GetNVertices();
11156  const int *ind = elements[i]->GetVertices();
11157  for (int j = 0; j < nv; j++)
11158  {
11159  vcount[ind[j]]--;
11160  vown[ind[j]][vcount[ind[j]]] = i;
11161  }
11162  }
11163 
11164  for (int i = 0; i < NumOfVertices; i++)
11165  {
11166  vcount[i] = voff[i+1] - voff[i];
11167  }
11168 
11169  int nbe = 0;
11170  for (int i = 0; i < edge_el.Size(); i++)
11171  {
11172  const int *el = edge_el.GetRow(i);
11173  if (edge_el.RowSize(i) > 1)
11174  {
11175  int k = partitioning[el[0]];
11176  int l = partitioning[el[1]];
11177  if (interior_faces || k != l)
11178  {
11179  nbe += 2;
11180  }
11181  }
11182  else
11183  {
11184  nbe++;
11185  }
11186  }
11187 
11188  // Print the type of the mesh and the boundary elements.
11189  os << "areamesh2\n\n" << nbe << '\n';
11190 
11191  for (int i = 0; i < edge_el.Size(); i++)
11192  {
11193  const int *el = edge_el.GetRow(i);
11194  if (edge_el.RowSize(i) > 1)
11195  {
11196  int k = partitioning[el[0]];
11197  int l = partitioning[el[1]];
11198  if (interior_faces || k != l)
11199  {
11200  Array<int> ev;
11201  GetEdgeVertices(i,ev);
11202  os << k+1; // attribute
11203  for (int j = 0; j < 2; j++)
11204  for (int s = 0; s < vcount[ev[j]]; s++)
11205  if (vown[ev[j]][s] == el[0])
11206  {
11207  os << ' ' << voff[ev[j]]+s+1;
11208  }
11209  os << '\n';
11210  os << l+1; // attribute
11211  for (int j = 1; j >= 0; j--)
11212  for (int s = 0; s < vcount[ev[j]]; s++)
11213  if (vown[ev[j]][s] == el[1])
11214  {
11215  os << ' ' << voff[ev[j]]+s+1;
11216  }
11217  os << '\n';
11218  }
11219  }
11220  else
11221  {
11222  int k = partitioning[el[0]];
11223  Array<int> ev;
11224  GetEdgeVertices(i,ev);
11225  os << k+1; // attribute
11226  for (int j = 0; j < 2; j++)
11227  for (int s = 0; s < vcount[ev[j]]; s++)
11228  if (vown[ev[j]][s] == el[0])
11229  {
11230  os << ' ' << voff[ev[j]]+s+1;
11231  }
11232  os << '\n';
11233  }
11234  }
11235 
11236  // Print the elements.
11237  os << NumOfElements << '\n';
11238  for (int i = 0; i < NumOfElements; i++)
11239  {
11240  int nv = elements[i]->GetNVertices();
11241  const int *ind = elements[i]->GetVertices();
11242  os << partitioning[i]+1 << ' '; // use subdomain number as attribute
11243  os << nv << ' ';
11244  for (int j = 0; j < nv; j++)
11245  {
11246  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11247  vown[ind[j]][vcount[ind[j]]] = i;
11248  }
11249  os << '\n';
11250  }
11251 
11252  for (int i = 0; i < NumOfVertices; i++)
11253  {
11254  vcount[i] = voff[i+1] - voff[i];
11255  }
11256 
11257  // Print the vertices.
11258  os << voff[NumOfVertices] << '\n';
11259  for (int i = 0; i < NumOfVertices; i++)
11260  for (int k = 0; k < vcount[i]; k++)
11261  {
11262  for (int j = 0; j < Dim; j++)
11263  {
11264  os << vertices[i](j) << ' ';
11265  }
11266  os << '\n';
11267  }
11268  }
11269  // Dim is 3
11270  else if (meshgen == 1)
11271  {
11272  os << "NETGEN_Neutral_Format\n";
11273  // print the vertices
11274  os << voff[NumOfVertices] << '\n';
11275  for (int i = 0; i < NumOfVertices; i++)
11276  for (int k = 0; k < vcount[i]; k++)
11277  {
11278  for (int j = 0; j < Dim; j++)
11279  {
11280  os << ' ' << vertices[i](j);
11281  }
11282  os << '\n';
11283  }
11284 
11285  // print the elements
11286  os << NumOfElements << '\n';
11287  for (int i = 0; i < NumOfElements; i++)
11288  {
11289  int nv = elements[i]->GetNVertices();
11290  const int *ind = elements[i]->GetVertices();
11291  os << partitioning[i]+1; // use subdomain number as attribute
11292  for (int j = 0; j < nv; j++)
11293  {
11294  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11295  vown[ind[j]][vcount[ind[j]]] = i;
11296  }
11297  os << '\n';
11298  }
11299 
11300  for (int i = 0; i < NumOfVertices; i++)
11301  {
11302  vcount[i] = voff[i+1] - voff[i];
11303  }
11304 
11305  // print the boundary information.
11306  int nbe = 0;
11307  for (int i = 0; i < NumOfFaces; i++)
11308  {
11309  int l = faces_info[i].Elem2No;
11310  if (l >= 0)
11311  {
11312  int k = partitioning[faces_info[i].Elem1No];
11313  l = partitioning[l];
11314  if (interior_faces || k != l)
11315  {
11316  nbe += 2;
11317  }
11318  }
11319  else
11320  {
11321  nbe++;
11322  }
11323  }
11324 
11325  os << nbe << '\n';
11326  for (int i = 0; i < NumOfFaces; i++)
11327  {
11328  int l = faces_info[i].Elem2No;
11329  if (l >= 0)
11330  {
11331  int k = partitioning[faces_info[i].Elem1No];
11332  l = partitioning[l];
11333  if (interior_faces || k != l)
11334  {
11335  int nv = faces[i]->GetNVertices();
11336  const int *ind = faces[i]->GetVertices();
11337  os << k+1; // attribute
11338  for (int j = 0; j < nv; j++)
11339  for (int s = 0; s < vcount[ind[j]]; s++)
11340  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11341  {
11342  os << ' ' << voff[ind[j]]+s+1;
11343  }
11344  os << '\n';
11345  os << l+1; // attribute
11346  for (int j = nv-1; j >= 0; j--)
11347  for (int s = 0; s < vcount[ind[j]]; s++)
11348  if (vown[ind[j]][s] == faces_info[i].Elem2No)
11349  {
11350  os << ' ' << voff[ind[j]]+s+1;
11351  }
11352  os << '\n';
11353  }
11354  }
11355  else
11356  {
11357  int k = partitioning[faces_info[i].Elem1No];
11358  int nv = faces[i]->GetNVertices();
11359  const int *ind = faces[i]->GetVertices();
11360  os << k+1; // attribute
11361  for (int j = 0; j < nv; j++)
11362  for (int s = 0; s < vcount[ind[j]]; s++)
11363  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11364  {
11365  os << ' ' << voff[ind[j]]+s+1;
11366  }
11367  os << '\n';
11368  }
11369  }
11370  }
11371  // Dim is 3
11372  else if (meshgen == 2) // TrueGrid
11373  {
11374  // count the number of the boundary elements.
11375  int nbe = 0;
11376  for (int i = 0; i < NumOfFaces; i++)
11377  {
11378  int l = faces_info[i].Elem2No;
11379  if (l >= 0)
11380  {
11381  int k = partitioning[faces_info[i].Elem1No];
11382  l = partitioning[l];
11383  if (interior_faces || k != l)
11384  {
11385  nbe += 2;
11386  }
11387  }
11388  else
11389  {
11390  nbe++;
11391  }
11392  }
11393 
11394  os << "TrueGrid\n"
11395  << "1 " << voff[NumOfVertices] << " " << NumOfElements
11396  << " 0 0 0 0 0 0 0\n"
11397  << "0 0 0 1 0 0 0 0 0 0 0\n"
11398  << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
11399  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
11400  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
11401 
11402  for (int i = 0; i < NumOfVertices; i++)
11403  for (int k = 0; k < vcount[i]; k++)
11404  os << voff[i]+k << " 0.0 " << vertices[i](0) << ' '
11405  << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n";
11406 
11407  for (int i = 0; i < NumOfElements; i++)
11408  {
11409  int nv = elements[i]->GetNVertices();
11410  const int *ind = elements[i]->GetVertices();
11411  os << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute
11412  for (int j = 0; j < nv; j++)
11413  {
11414  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11415  vown[ind[j]][vcount[ind[j]]] = i;
11416  }
11417  os << '\n';
11418  }
11419 
11420  for (int i = 0; i < NumOfVertices; i++)
11421  {
11422  vcount[i] = voff[i+1] - voff[i];
11423  }
11424 
11425  // boundary elements
11426  for (int i = 0; i < NumOfFaces; i++)
11427  {
11428  int l = faces_info[i].Elem2No;
11429  if (l >= 0)
11430  {
11431  int k = partitioning[faces_info[i].Elem1No];
11432  l = partitioning[l];
11433  if (interior_faces || k != l)
11434  {
11435  int nv = faces[i]->GetNVertices();
11436  const int *ind = faces[i]->GetVertices();
11437  os << k+1; // attribute
11438  for (int j = 0; j < nv; j++)
11439  for (int s = 0; s < vcount[ind[j]]; s++)
11440  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11441  {
11442  os << ' ' << voff[ind[j]]+s+1;
11443  }
11444  os << " 1.0 1.0 1.0 1.0\n";
11445  os << l+1; // attribute
11446  for (int j = nv-1; j >= 0; j--)
11447  for (int s = 0; s < vcount[ind[j]]; s++)
11448  if (vown[ind[j]][s] == faces_info[i].Elem2No)
11449  {
11450  os << ' ' << voff[ind[j]]+s+1;
11451  }
11452  os << " 1.0 1.0 1.0 1.0\n";
11453  }
11454  }
11455  else
11456  {
11457  int k = partitioning[faces_info[i].Elem1No];
11458  int nv = faces[i]->GetNVertices();
11459  const int *ind = faces[i]->GetVertices();
11460  os << k+1; // attribute
11461  for (int j = 0; j < nv; j++)
11462  for (int s = 0; s < vcount[ind[j]]; s++)
11463  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11464  {
11465  os << ' ' << voff[ind[j]]+s+1;
11466  }
11467  os << " 1.0 1.0 1.0 1.0\n";
11468  }
11469  }
11470  }
11471 
11472  os << flush;
11473 
11474  for (int i = 0; i < NumOfVertices; i++)
11475  {
11476  delete [] vown[i];
11477  }
11478 
11479  delete [] vcount;
11480  delete [] voff;
11481  delete [] vown;
11482 }
11483 
11484 void Mesh::PrintSurfaces(const Table & Aface_face, std::ostream &os) const
11485 {
11486  int i, j;
11487 
11488  if (NURBSext)
11489  {
11490  mfem_error("Mesh::PrintSurfaces"
11491  " NURBS mesh is not supported!");
11492  return;
11493  }
11494 
11495  os << "MFEM mesh v1.0\n";
11496 
11497  // optional
11498  os <<
11499  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
11500  "# POINT = 0\n"
11501  "# SEGMENT = 1\n"
11502  "# TRIANGLE = 2\n"
11503  "# SQUARE = 3\n"
11504  "# TETRAHEDRON = 4\n"
11505  "# CUBE = 5\n"
11506  "# PRISM = 6\n"
11507  "#\n";
11508 
11509  os << "\ndimension\n" << Dim
11510  << "\n\nelements\n" << NumOfElements << '\n';
11511  for (i = 0; i < NumOfElements; i++)
11512  {
11513  PrintElement(elements[i], os);
11514  }
11515 
11516  os << "\nboundary\n" << Aface_face.Size_of_connections() << '\n';
11517  const int * const i_AF_f = Aface_face.GetI();
11518  const int * const j_AF_f = Aface_face.GetJ();
11519 
11520  for (int iAF=0; iAF < Aface_face.Size(); ++iAF)
11521  for (const int * iface = j_AF_f + i_AF_f[iAF];
11522  iface < j_AF_f + i_AF_f[iAF+1];
11523  ++iface)
11524  {
11525  os << iAF+1 << ' ';
11526  PrintElementWithoutAttr(faces[*iface],os);
11527  }
11528 
11529  os << "\nvertices\n" << NumOfVertices << '\n';
11530  if (Nodes == NULL)
11531  {
11532  os << spaceDim << '\n';
11533  for (i = 0; i < NumOfVertices; i++)
11534  {
11535  os << vertices[i](0);
11536  for (j = 1; j < spaceDim; j++)
11537  {
11538  os << ' ' << vertices[i](j);
11539  }
11540  os << '\n';
11541  }
11542  os.flush();
11543  }
11544  else
11545  {
11546  os << "\nnodes\n";
11547  Nodes->Save(os);
11548  }
11549 }
11550 
11551 void Mesh::ScaleSubdomains(double sf)
11552 {
11553  int i,j,k;
11554  Array<int> vert;
11555  DenseMatrix pointmat;
11556  int na = attributes.Size();
11557  double *cg = new double[na*spaceDim];
11558  int *nbea = new int[na];
11559 
11560  int *vn = new int[NumOfVertices];
11561  for (i = 0; i < NumOfVertices; i++)
11562  {
11563  vn[i] = 0;
11564  }
11565  for (i = 0; i < na; i++)
11566  {
11567  for (j = 0; j < spaceDim; j++)
11568  {
11569  cg[i*spaceDim+j] = 0.0;
11570  }
11571  nbea[i] = 0;
11572  }
11573 
11574  for (i = 0; i < NumOfElements; i++)
11575  {
11576  GetElementVertices(i, vert);
11577  for (k = 0; k < vert.Size(); k++)
11578  {
11579  vn[vert[k]] = 1;
11580  }
11581  }
11582 
11583  for (i = 0; i < NumOfElements; i++)
11584  {
11585  int bea = GetAttribute(i)-1;
11586  GetPointMatrix(i, pointmat);
11587  GetElementVertices(i, vert);
11588 
11589  for (k = 0; k < vert.Size(); k++)
11590  if (vn[vert[k]] == 1)
11591  {
11592  nbea[bea]++;
11593  for (j = 0; j < spaceDim; j++)
11594  {
11595  cg[bea*spaceDim+j] += pointmat(j,k);
11596  }
11597  vn[vert[k]] = 2;
11598  }
11599  }
11600 
11601  for (i = 0; i < NumOfElements; i++)
11602  {
11603  int bea = GetAttribute(i)-1;
11604  GetElementVertices (i, vert);
11605 
11606  for (k = 0; k < vert.Size(); k++)
11607  if (vn[vert[k]])
11608  {
11609  for (j = 0; j < spaceDim; j++)
11610  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
11611  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
11612  vn[vert[k]] = 0;
11613  }
11614  }
11615 
11616  delete [] cg;
11617  delete [] nbea;
11618  delete [] vn;
11619 }
11620 
11621 void Mesh::ScaleElements(double sf)
11622 {
11623  int i,j,k;
11624  Array<int> vert;
11625  DenseMatrix pointmat;
11626  int na = NumOfElements;
11627  double *cg = new double[na*spaceDim];
11628  int *nbea = new int[na];
11629 
11630  int *vn = new int[NumOfVertices];
11631  for (i = 0; i < NumOfVertices; i++)
11632  {
11633  vn[i] = 0;
11634  }
11635  for (i = 0; i < na; i++)
11636  {
11637  for (j = 0; j < spaceDim; j++)
11638  {
11639  cg[i*spaceDim+j] = 0.0;
11640  }
11641  nbea[i] = 0;
11642  }
11643 
11644  for (i = 0; i < NumOfElements; i++)
11645  {
11646  GetElementVertices(i, vert);
11647  for (k = 0; k < vert.Size(); k++)
11648  {
11649  vn[vert[k]] = 1;
11650  }
11651  }
11652 
11653  for (i = 0; i < NumOfElements; i++)
11654  {
11655  int bea = i;
11656  GetPointMatrix(i, pointmat);
11657  GetElementVertices(i, vert);
11658 
11659  for (k = 0; k < vert.Size(); k++)
11660  if (vn[vert[k]] == 1)
11661  {
11662  nbea[bea]++;
11663  for (j = 0; j < spaceDim; j++)
11664  {
11665  cg[bea*spaceDim+j] += pointmat(j,k);
11666  }
11667  vn[vert[k]] = 2;
11668  }
11669  }
11670 
11671  for (i = 0; i < NumOfElements; i++)
11672  {
11673  int bea = i;
11674  GetElementVertices(i, vert);
11675 
11676  for (k = 0; k < vert.Size(); k++)
11677  if (vn[vert[k]])
11678  {
11679  for (j = 0; j < spaceDim; j++)
11680  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
11681  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
11682  vn[vert[k]] = 0;
11683  }
11684  }
11685 
11686  delete [] cg;
11687  delete [] nbea;
11688  delete [] vn;
11689 }
11690 
11691 void Mesh::Transform(void (*f)(const Vector&, Vector&))
11692 {
11693  // TODO: support for different new spaceDim.
11694  if (Nodes == NULL)
11695  {
11696  Vector vold(spaceDim), vnew(NULL, spaceDim);
11697  for (int i = 0; i < vertices.Size(); i++)
11698  {
11699  for (int j = 0; j < spaceDim; j++)
11700  {
11701  vold(j) = vertices[i](j);
11702  }
11703  vnew.SetData(vertices[i]());
11704  (*f)(vold, vnew);
11705  }
11706  }
11707  else
11708  {
11709  GridFunction xnew(Nodes->FESpace());
11711  xnew.ProjectCoefficient(f_pert);
11712  *Nodes = xnew;
11713  }
11714  NodesUpdated();
11715 }
11716 
11718 {
11719  MFEM_VERIFY(spaceDim == deformation.GetVDim(),
11720  "incompatible vector dimensions");
11721  if (Nodes == NULL)
11722  {
11723  LinearFECollection fec;
11724  FiniteElementSpace fes(this, &fec, spaceDim, Ordering::byVDIM);
11725  GridFunction xnew(&fes);
11726  xnew.ProjectCoefficient(deformation);
11727  for (int i = 0; i < NumOfVertices; i++)
11728  for (int d = 0; d < spaceDim; d++)
11729  {
11730  vertices[i](d) = xnew(d + spaceDim*i);
11731  }
11732  }
11733  else
11734  {
11735  GridFunction xnew(Nodes->FESpace());
11736  xnew.ProjectCoefficient(deformation);
11737  *Nodes = xnew;
11738  }
11739  NodesUpdated();
11740 }
11741 
11743 {
11744  if (NURBSext || ncmesh) { return; }
11745 
11746  Array<int> v2v(GetNV());
11747  v2v = -1;
11748  for (int i = 0; i < GetNE(); i++)
11749  {
11750  Element *el = GetElement(i);
11751  int nv = el->GetNVertices();
11752  int *v = el->GetVertices();
11753  for (int j = 0; j < nv; j++)
11754  {
11755  v2v[v[j]] = 0;
11756  }
11757  }
11758  for (int i = 0; i < GetNBE(); i++)
11759  {
11760  Element *el = GetBdrElement(i);
11761  int *v = el->GetVertices();
11762  int nv = el->GetNVertices();
11763  for (int j = 0; j < nv; j++)
11764  {
11765  v2v[v[j]] = 0;
11766  }
11767  }
11768  int num_vert = 0;
11769  for (int i = 0; i < v2v.Size(); i++)
11770  {
11771  if (v2v[i] == 0)
11772  {
11773  vertices[num_vert] = vertices[i];
11774  v2v[i] = num_vert++;
11775  }
11776  }
11777 
11778  if (num_vert == v2v.Size()) { return; }
11779 
11780  Vector nodes_by_element;
11781  Array<int> vdofs;
11782  if (Nodes)
11783  {
11784  int s = 0;
11785  for (int i = 0; i < GetNE(); i++)
11786  {
11787  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11788  s += vdofs.Size();
11789  }
11790  nodes_by_element.SetSize(s);
11791  s = 0;
11792  for (int i = 0; i < GetNE(); i++)
11793  {
11794  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11795  Nodes->GetSubVector(vdofs, &nodes_by_element(s));
11796  s += vdofs.Size();
11797  }
11798  }
11799  vertices.SetSize(num_vert);
11800  NumOfVertices = num_vert;
11801  for (int i = 0; i < GetNE(); i++)
11802  {
11803  Element *el = GetElement(i);
11804  int *v = el->GetVertices();
11805  int nv = el->GetNVertices();
11806  for (int j = 0; j < nv; j++)
11807  {
11808  v[j] = v2v[v[j]];
11809  }
11810  }
11811  for (int i = 0; i < GetNBE(); i++)
11812  {
11813  Element *el = GetBdrElement(i);
11814  int *v = el->GetVertices();
11815  int nv = el->GetNVertices();
11816  for (int j = 0; j < nv; j++)
11817  {
11818  v[j] = v2v[v[j]];
11819  }
11820  }
11821  DeleteTables();
11822  if (Dim > 1)
11823  {
11824  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
11825  el_to_edge = new Table;
11827  }
11828  if (Dim > 2)
11829  {
11830  // generate el_to_face, be_to_face
11832  }
11833  // Update faces and faces_info
11834  GenerateFaces();
11835  if (Nodes)
11836  {
11837  Nodes->FESpace()->Update();
11838  Nodes->Update();
11839  int s = 0;
11840  for (int i = 0; i < GetNE(); i++)
11841  {
11842  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11843  Nodes->SetSubVector(vdofs, &nodes_by_element(s));
11844  s += vdofs.Size();
11845  }
11846  }
11847 }
11848 
11850 {
11851  if (NURBSext || ncmesh) { return; }
11852 
11853  int num_bdr_elem = 0;
11854  int new_bel_to_edge_nnz = 0;
11855  for (int i = 0; i < GetNBE(); i++)
11856  {
11858  {
11859  FreeElement(boundary[i]);
11860  }
11861  else
11862  {
11863  num_bdr_elem++;
11864  if (Dim == 3)
11865  {
11866  new_bel_to_edge_nnz += bel_to_edge->RowSize(i);
11867  }
11868  }
11869  }
11870 
11871  if (num_bdr_elem == GetNBE()) { return; }
11872 
11873  Array<Element *> new_boundary(num_bdr_elem);
11874  Array<int> new_be_to_edge, new_be_to_face;
11875  Table *new_bel_to_edge = NULL;
11876  new_boundary.SetSize(0);
11877  if (Dim == 2)
11878  {
11879  new_be_to_edge.Reserve(num_bdr_elem);
11880  }
11881  else if (Dim == 3)
11882  {
11883  new_be_to_face.Reserve(num_bdr_elem);
11884  new_bel_to_edge = new Table;
11885  new_bel_to_edge->SetDims(num_bdr_elem, new_bel_to_edge_nnz);
11886  }
11887  for (int i = 0; i < GetNBE(); i++)
11888  {
11890  {
11891  new_boundary.Append(boundary[i]);
11892  if (Dim == 2)
11893  {
11894  new_be_to_edge.Append(be_to_edge[i]);
11895  }
11896  else if (Dim == 3)
11897  {
11898  int row = new_be_to_face.Size();
11899  new_be_to_face.Append(be_to_face[i]);
11900  int *e = bel_to_edge->GetRow(i);
11901  int ne = bel_to_edge->RowSize(i);
11902  int *new_e = new_bel_to_edge->GetRow(row);
11903  for (int j = 0; j < ne; j++)
11904  {
11905  new_e[j] = e[j];
11906  }
11907  new_bel_to_edge->GetI()[row+1] = new_bel_to_edge->GetI()[row] + ne;
11908  }
11909  }
11910  }
11911 
11912  NumOfBdrElements = new_boundary.Size();
11913  mfem::Swap(boundary, new_boundary);
11914 
11915  if (Dim == 2)
11916  {
11917  mfem::Swap(be_to_edge, new_be_to_edge);
11918  }
11919  else if (Dim == 3)
11920  {
11921  mfem::Swap(be_to_face, new_be_to_face);
11922  delete bel_to_edge;
11923  bel_to_edge = new_bel_to_edge;
11924  }
11925 
11926  Array<int> attribs(num_bdr_elem);
11927  for (int i = 0; i < attribs.Size(); i++)
11928  {
11929  attribs[i] = GetBdrAttribute(i);
11930  }
11931  attribs.Sort();
11932  attribs.Unique();
11934  attribs.Copy(bdr_attributes);
11935 }
11936 
11938 {
11939 #ifdef MFEM_USE_MEMALLOC
11940  if (E)
11941  {
11942  if (E->GetType() == Element::TETRAHEDRON)
11943  {
11944  TetMemory.Free((Tetrahedron*) E);
11945  }
11946  else
11947  {
11948  delete E;
11949  }
11950  }
11951 #else
11952  delete E;
11953 #endif
11954 }
11955 
11956 std::ostream &operator<<(std::ostream &os, const Mesh &mesh)
11957 {
11958  mesh.Print(os);
11959  return os;
11960 }
11961 
11962 int Mesh::FindPoints(DenseMatrix &point_mat, Array<int>& elem_ids,
11963  Array<IntegrationPoint>& ips, bool warn,
11964  InverseElementTransformation *inv_trans)
11965 {
11966  const int npts = point_mat.Width();
11967  if (!npts) { return 0; }
11968  MFEM_VERIFY(point_mat.Height() == spaceDim,"Invalid points matrix");
11969  elem_ids.SetSize(npts);
11970  ips.SetSize(npts);
11971  elem_ids = -1;
11972  if (!GetNE()) { return 0; }
11973 
11974  double *data = point_mat.GetData();
11975  InverseElementTransformation *inv_tr = inv_trans;
11976  inv_tr = inv_tr ? inv_tr : new InverseElementTransformation;
11977 
11978  // For each point in 'point_mat', find the element whose center is closest.
11979  Vector min_dist(npts);
11980  Array<int> e_idx(npts);
11981  min_dist = std::numeric_limits<double>::max();
11982  e_idx = -1;
11983 
11984  Vector pt(spaceDim);
11985  for (int i = 0; i < GetNE(); i++)
11986  {
11987  GetElementTransformation(i)->Transform(
11989  for (int k = 0; k < npts; k++)
11990  {
11991  double dist = pt.DistanceTo(data+k*spaceDim);
11992  if (dist < min_dist(k))
11993  {
11994  min_dist(k) = dist;
11995  e_idx[k] = i;
11996  }
11997  }
11998  }
11999 
12000  // Checks if the points lie in the closest element
12001  int pts_found = 0;
12002  pt.NewDataAndSize(NULL, spaceDim);
12003  for (int k = 0; k < npts; k++)
12004  {
12005  pt.SetData(data+k*spaceDim);
12006  inv_tr->SetTransformation(*GetElementTransformation(e_idx[k]));
12007  int res = inv_tr->Transform(pt, ips[k]);
12009  {
12010  elem_ids[k] = e_idx[k];
12011  pts_found++;
12012  }
12013  }
12014  if (pts_found != npts)
12015  {
12016  Array<int> elvertices;
12017  Table *vtoel = GetVertexToElementTable();
12018  for (int k = 0; k < npts; k++)
12019  {
12020  if (elem_ids[k] != -1) { continue; }
12021  // Try all vertex-neighbors of element e_idx[k]
12022  pt.SetData(data+k*spaceDim);
12023  GetElementVertices(e_idx[k], elvertices);
12024  for (int v = 0; v < elvertices.Size(); v++)
12025  {
12026  int vv = elvertices[v];
12027  int ne = vtoel->RowSize(vv);
12028  const int* els = vtoel->GetRow(vv);
12029  for (int e = 0; e < ne; e++)
12030  {
12031  if (els[e] == e_idx[k]) { continue; }
12032  inv_tr->SetTransformation(*GetElementTransformation(els[e]));
12033  int res = inv_tr->Transform(pt, ips[k]);
12035  {
12036  elem_ids[k] = els[e];
12037  pts_found++;
12038  goto next_point;
12039  }
12040  }
12041  }
12042  // Try neighbors for non-conforming meshes
12043  if (ncmesh)
12044  {
12045  Array<int> neigh;
12046  int le = ncmesh->leaf_elements[e_idx[k]];
12047  ncmesh->FindNeighbors(le,neigh);
12048  for (int e = 0; e < neigh.Size(); e++)
12049  {
12050  int nn = neigh[e];
12051  if (ncmesh->IsGhost(ncmesh->elements[nn])) { continue; }
12052  int el = ncmesh->elements[nn].index;
12054  int res = inv_tr->Transform(pt, ips[k]);
12056  {
12057  elem_ids[k] = el;
12058  pts_found++;
12059  goto next_point;
12060  }
12061  }
12062  }
12063  next_point: ;
12064  }
12065  delete vtoel;
12066  }
12067  if (inv_trans == NULL) { delete inv_tr; }
12068 
12069  if (warn && pts_found != npts)
12070  {
12071  MFEM_WARNING((npts-pts_found) << " points were not found");
12072  }
12073  return pts_found;
12074 }
12075 
12076 
12078  int flags, MemoryType d_mt)
12079 {
12080  this->mesh = mesh;
12081  IntRule = &ir;
12082  computed_factors = flags;
12083 
12084  MFEM_ASSERT(mesh->GetNumGeometries(mesh->Dimension()) <= 1,
12085  "mixed meshes are not supported!");
12086  MFEM_ASSERT(mesh->GetNodes(), "meshes without nodes are not supported!");
12087 
12088  Compute(*mesh->GetNodes(), d_mt);
12089 }
12090 
12092  const IntegrationRule &ir,
12093  int flags, MemoryType d_mt)
12094 {
12095  this->mesh = nodes.FESpace()->GetMesh();
12096  IntRule = &ir;
12097  computed_factors = flags;
12098 
12099  Compute(nodes, d_mt);
12100 }
12101 
12102 void GeometricFactors::Compute(const GridFunction &nodes,
12103  MemoryType d_mt)
12104 {
12105 
12106  const FiniteElementSpace *fespace = nodes.FESpace();
12107  const FiniteElement *fe = fespace->GetFE(0);
12108  const int dim = fe->GetDim();
12109  const int vdim = fespace->GetVDim();
12110  const int NE = fespace->GetNE();
12111  const int ND = fe->GetDof();
12112  const int NQ = IntRule->GetNPoints();
12113 
12114  unsigned eval_flags = 0;
12115  MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
12118  {
12119  X.SetSize(vdim*NQ*NE, my_d_mt); // NQ x SDIM x NE
12120  eval_flags |= QuadratureInterpolator::VALUES;
12121  }
12123  {
12124  J.SetSize(dim*vdim*NQ*NE, my_d_mt); // NQ x SDIM x DIM x NE
12126  }
12128  {
12129  detJ.SetSize(NQ*NE, my_d_mt); // NQ x NE
12131  }
12132 
12133  const QuadratureInterpolator *qi = fespace->GetQuadratureInterpolator(*IntRule);
12134  // All X, J, and detJ use this layout:
12136 
12137  const bool use_tensor_products = UsesTensorBasis(*fespace);
12138 
12139  qi->DisableTensorProducts(!use_tensor_products);
12140  const ElementDofOrdering e_ordering = use_tensor_products ?
12143  const Operator *elem_restr = fespace->GetElementRestriction(e_ordering);
12144 
12145  if (elem_restr) // Always true as of 2021-04-27
12146  {
12147  Vector Enodes(vdim*ND*NE, my_d_mt);
12148  elem_restr->Mult(nodes, Enodes);
12149  qi->Mult(Enodes, eval_flags, X, J, detJ);
12150  }
12151  else
12152  {
12153  qi->Mult(nodes, eval_flags, X, J, detJ);
12154  }
12155 }
12156 
12158  const IntegrationRule &ir,
12159  int flags, FaceType type,
12160  MemoryType d_mt)
12161  : type(type)
12162 {
12163  this->mesh = mesh;
12164  IntRule = &ir;
12165  computed_factors = flags;
12166 
12167  const GridFunction *nodes = mesh->GetNodes();
12168  const FiniteElementSpace *fespace = nodes->FESpace();
12169  const int vdim = fespace->GetVDim();
12170  const int NF = fespace->GetNFbyType(type);
12171  const int NQ = ir.GetNPoints();
12172 
12173  const FaceRestriction *face_restr = fespace->GetFaceRestriction(
12175  type,
12177 
12178 
12179  MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
12181 
12182  Vector Fnodes(face_restr->Height(), my_d_mt);
12183  face_restr->Mult(*nodes, Fnodes);
12184 
12185  unsigned eval_flags = 0;
12186 
12188  {
12189  X.SetSize(vdim*NQ*NF, my_d_mt);
12190  eval_flags |= FaceQuadratureInterpolator::VALUES;
12191  }
12192  if (flags & FaceGeometricFactors::JACOBIANS)
12193  {
12194  J.SetSize(vdim*vdim*NQ*NF, my_d_mt);
12196  }
12198  {
12199  detJ.SetSize(NQ*NF, my_d_mt);
12201  }
12202  if (flags & FaceGeometricFactors::NORMALS)
12203  {
12204  normal.SetSize(vdim*NQ*NF, my_d_mt);
12206  }
12207 
12208  const FaceQuadratureInterpolator *qi =
12209  fespace->GetFaceQuadratureInterpolator(ir, type);
12210  // All face data vectors assume layout byNODES.
12212  const bool use_tensor_products = UsesTensorBasis(*fespace);
12213  qi->DisableTensorProducts(!use_tensor_products);
12214 
12215  qi->Mult(Fnodes, eval_flags, X, J, detJ, normal);
12216 }
12217 
12219  const double s_)
12220  : VectorCoefficient(dim), n(n_), s(s_), tip(p, dim-1)
12221 {
12222 }
12223 
12225  const IntegrationPoint &ip)
12226 {
12227  V.SetSize(vdim);
12228  T.Transform(ip, tip);
12229  V(0) = p[0];
12230  if (vdim == 2)
12231  {
12232  V(1) = s * ((ip.y + layer) / n);
12233  }
12234  else
12235  {
12236  V(1) = p[1];
12237  V(2) = s * ((ip.z + layer) / n);
12238  }
12239 }
12240 
12241 
12242 Mesh *Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
12243 {
12244  if (mesh->Dimension() != 1)
12245  {
12246  mfem::err << "Extrude1D : Not a 1D mesh!" << endl;
12247  mfem_error();
12248  }
12249 
12250  int nvy = (closed) ? (ny) : (ny + 1);
12251  int nvt = mesh->GetNV() * nvy;
12252 
12253  Mesh *mesh2d;
12254 
12255  if (closed)
12256  {
12257  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny, mesh->GetNBE()*ny);
12258  }
12259  else
12260  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny,
12261  mesh->GetNBE()*ny+2*mesh->GetNE());
12262 
12263  // vertices
12264  double vc[2];
12265  for (int i = 0; i < mesh->GetNV(); i++)
12266  {
12267  vc[0] = mesh->GetVertex(i)[0];
12268  for (int j = 0; j < nvy; j++)
12269  {
12270  vc[1] = sy * (double(j) / ny);
12271  mesh2d->AddVertex(vc);
12272  }
12273  }
12274  // elements
12275  Array<int> vert;
12276  for (int i = 0; i < mesh->GetNE(); i++)
12277  {
12278  const Element *elem = mesh->GetElement(i);
12279  elem->GetVertices(vert);
12280  const int attr = elem->GetAttribute();
12281  for (int j = 0; j < ny; j++)
12282  {
12283  int qv[4];
12284  qv[0] = vert[0] * nvy + j;
12285  qv[1] = vert[1] * nvy + j;
12286  qv[2] = vert[1] * nvy + (j + 1) % nvy;
12287  qv[3] = vert[0] * nvy + (j + 1) % nvy;
12288 
12289  mesh2d->AddQuad(qv, attr);
12290  }
12291  }
12292  // 2D boundary from the 1D boundary
12293  for (int i = 0; i < mesh->GetNBE(); i++)
12294  {
12295  const Element *elem = mesh->GetBdrElement(i);
12296  elem->GetVertices(vert);
12297  const int attr = elem->GetAttribute();
12298  for (int j = 0; j < ny; j++)
12299  {
12300  int sv[2];
12301  sv[0] = vert[0] * nvy + j;
12302  sv[1] = vert[0] * nvy + (j + 1) % nvy;
12303 
12304  if (attr%2)
12305  {
12306  Swap<int>(sv[0], sv[1]);
12307  }
12308 
12309  mesh2d->AddBdrSegment(sv, attr);
12310  }
12311  }
12312 
12313  if (!closed)
12314  {
12315  // 2D boundary from the 1D elements (bottom + top)
12316  int nba = (mesh->bdr_attributes.Size() > 0 ?
12317  mesh->bdr_attributes.Max() : 0);
12318  for (int i = 0; i < mesh->GetNE(); i++)
12319  {
12320  const Element *elem = mesh->GetElement(i);
12321  elem->GetVertices(vert);
12322  const int attr = nba + elem->GetAttribute();
12323  int sv[2];
12324  sv[0] = vert[0] * nvy;
12325  sv[1] = vert[1] * nvy;
12326 
12327  mesh2d->AddBdrSegment(sv, attr);
12328 
12329  sv[0] = vert[1] * nvy + ny;
12330  sv[1] = vert[0] * nvy + ny;
12331 
12332  mesh2d->AddBdrSegment(sv, attr);
12333  }
12334  }
12335 
12336  mesh2d->FinalizeQuadMesh(1, 0, false);
12337 
12338  GridFunction *nodes = mesh->GetNodes();
12339  if (nodes)
12340  {
12341  // duplicate the fec of the 1D mesh so that it can be deleted safely
12342  // along with its nodes, fes and fec
12343  FiniteElementCollection *fec2d = NULL;
12344  FiniteElementSpace *fes2d;
12345  const char *name = nodes->FESpace()->FEColl()->Name();
12346  string cname = name;
12347  if (cname == "Linear")
12348  {
12349  fec2d = new LinearFECollection;
12350  }
12351  else if (cname == "Quadratic")
12352  {
12353  fec2d = new QuadraticFECollection;
12354  }
12355  else if (cname == "Cubic")
12356  {
12357  fec2d = new CubicFECollection;
12358  }
12359  else if (!strncmp(name, "H1_", 3))
12360  {
12361  fec2d = new H1_FECollection(atoi(name + 7), 2);
12362  }
12363  else if (!strncmp(name, "L2_T", 4))
12364  {
12365  fec2d = new L2_FECollection(atoi(name + 10), 2, atoi(name + 4));
12366  }
12367  else if (!strncmp(name, "L2_", 3))
12368  {
12369  fec2d = new L2_FECollection(atoi(name + 7), 2);
12370  }
12371  else
12372  {
12373  delete mesh2d;
12374  mfem::err << "Extrude1D : The mesh uses unknown FE collection : "
12375  << cname << endl;
12376  mfem_error();
12377  }
12378  fes2d = new FiniteElementSpace(mesh2d, fec2d, 2);
12379  mesh2d->SetNodalFESpace(fes2d);
12380  GridFunction *nodes2d = mesh2d->GetNodes();
12381  nodes2d->MakeOwner(fec2d);
12382 
12383  NodeExtrudeCoefficient ecoeff(2, ny, sy);
12384  Vector lnodes;
12385  Array<int> vdofs2d;
12386  for (int i = 0; i < mesh->GetNE(); i++)
12387  {
12389  for (int j = ny-1; j >= 0; j--)
12390  {
12391  fes2d->GetElementVDofs(i*ny+j, vdofs2d);
12392  lnodes.SetSize(vdofs2d.Size());
12393  ecoeff.SetLayer(j);
12394  fes2d->GetFE(i*ny+j)->Project(ecoeff, T, lnodes);
12395  nodes2d->SetSubVector(vdofs2d, lnodes);
12396  }
12397  }
12398  }
12399  return mesh2d;
12400 }
12401 
12402 Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz)
12403 {
12404  if (mesh->Dimension() != 2)
12405  {
12406  mfem::err << "Extrude2D : Not a 2D mesh!" << endl;
12407  mfem_error();
12408  }
12409 
12410  int nvz = nz + 1;
12411  int nvt = mesh->GetNV() * nvz;
12412 
12413  Mesh *mesh3d = new Mesh(3, nvt, mesh->GetNE()*nz,
12414  mesh->GetNBE()*nz+2*mesh->GetNE());
12415 
12416  bool wdgMesh = false;
12417  bool hexMesh = false;
12418 
12419  // vertices
12420  double vc[3];
12421  for (int i = 0; i < mesh->GetNV(); i++)
12422  {
12423  vc[0] = mesh->GetVertex(i)[0];
12424  vc[1] = mesh->GetVertex(i)[1];
12425  for (int j = 0; j < nvz; j++)
12426  {
12427  vc[2] = sz * (double(j) / nz);
12428  mesh3d->AddVertex(vc);
12429  }
12430  }
12431  // elements
12432  Array<int> vert;
12433  for (int i = 0; i < mesh->GetNE(); i++)
12434  {
12435  const Element *elem = mesh->GetElement(i);
12436  elem->GetVertices(vert);
12437  const int attr = elem->GetAttribute();
12438  Geometry::Type geom = elem->GetGeometryType();
12439  switch (geom)
12440  {
12441  case Geometry::TRIANGLE:
12442  wdgMesh = true;
12443  for (int j = 0; j < nz; j++)
12444  {
12445  int pv[6];
12446  pv[0] = vert[0] * nvz + j;
12447  pv[1] = vert[1] * nvz + j;
12448  pv[2] = vert[2] * nvz + j;
12449  pv[3] = vert[0] * nvz + (j + 1) % nvz;
12450  pv[4] = vert[1] * nvz + (j + 1) % nvz;
12451  pv[5] = vert[2] * nvz + (j + 1) % nvz;
12452 
12453  mesh3d->AddWedge(pv, attr);
12454  }
12455  break;
12456  case Geometry::SQUARE:
12457  hexMesh = true;
12458  for (int j = 0; j < nz; j++)
12459  {
12460  int hv[8];
12461  hv[0] = vert[0] * nvz + j;
12462  hv[1] = vert[1] * nvz + j;
12463  hv[2] = vert[2] * nvz + j;
12464  hv[3] = vert[3] * nvz + j;
12465  hv[4] = vert[0] * nvz + (j + 1) % nvz;
12466  hv[5] = vert[1] * nvz + (j + 1) % nvz;
12467  hv[6] = vert[2] * nvz + (j + 1) % nvz;
12468  hv[7] = vert[3] * nvz + (j + 1) % nvz;
12469 
12470  mesh3d->AddHex(hv, attr);
12471  }
12472  break;
12473  default:
12474  mfem::err << "Extrude2D : Invalid 2D element type \'"
12475  << geom << "\'" << endl;
12476  mfem_error();
12477  break;
12478  }
12479  }
12480  // 3D boundary from the 2D boundary
12481  for (int i = 0; i < mesh->GetNBE(); i++)
12482  {
12483  const Element *elem = mesh->GetBdrElement(i);
12484  elem->GetVertices(vert);
12485  const int attr = elem->GetAttribute();
12486  for (int j = 0; j < nz; j++)
12487  {
12488  int qv[4];
12489  qv[0] = vert[0] * nvz + j;
12490  qv[1] = vert[1] * nvz + j;
12491  qv[2] = vert[1] * nvz + (j + 1) % nvz;
12492  qv[3] = vert[0] * nvz + (j + 1) % nvz;
12493 
12494  mesh3d->AddBdrQuad(qv, attr);
12495  }
12496  }
12497 
12498  // 3D boundary from the 2D elements (bottom + top)
12499  int nba = (mesh->bdr_attributes.Size() > 0 ?
12500  mesh->bdr_attributes.Max() : 0);
12501  for (int i = 0; i < mesh->GetNE(); i++)
12502  {
12503  const Element *elem = mesh->GetElement(i);
12504  elem->GetVertices(vert);
12505  const int attr = nba + elem->GetAttribute();
12506  Geometry::Type geom = elem->GetGeometryType();
12507  switch (geom)
12508  {
12509  case Geometry::TRIANGLE:
12510  {
12511  int tv[3];
12512  tv[0] = vert[0] * nvz;
12513  tv[1] = vert[2] * nvz;
12514  tv[2] = vert[1] * nvz;
12515 
12516  mesh3d->AddBdrTriangle(tv, attr);
12517 
12518  tv[0] = vert[0] * nvz + nz;
12519  tv[1] = vert[1] * nvz + nz;
12520  tv[2] = vert[2] * nvz + nz;
12521 
12522  mesh3d->AddBdrTriangle(tv, attr);
12523  }
12524  break;
12525  case Geometry::SQUARE:
12526  {
12527  int qv[4];
12528  qv[0] = vert[0] * nvz;
12529  qv[1] = vert[3] * nvz;
12530  qv[2] = vert[2] * nvz;
12531  qv[3] = vert[1] * nvz;
12532 
12533  mesh3d->AddBdrQuad(qv, attr);
12534 
12535  qv[0] = vert[0] * nvz + nz;
12536  qv[1] = vert[1] * nvz + nz;
12537  qv[2] = vert[2] * nvz + nz;
12538  qv[3] = vert[3] * nvz + nz;
12539 
12540  mesh3d->AddBdrQuad(qv, attr);
12541  }
12542  break;
12543  default:
12544  mfem::err << "Extrude2D : Invalid 2D element type \'"
12545  << geom << "\'" << endl;
12546  mfem_error();
12547  break;
12548  }
12549  }
12550 
12551  if ( hexMesh && wdgMesh )
12552  {
12553  mesh3d->FinalizeMesh(0, false);
12554  }
12555  else if ( hexMesh )
12556  {
12557  mesh3d->FinalizeHexMesh(1, 0, false);
12558  }
12559  else if ( wdgMesh )
12560  {
12561  mesh3d->FinalizeWedgeMesh(1, 0, false);
12562  }
12563 
12564  GridFunction *nodes = mesh->GetNodes();
12565  if (nodes)
12566  {
12567  // duplicate the fec of the 2D mesh so that it can be deleted safely
12568  // along with its nodes, fes and fec
12569  FiniteElementCollection *fec3d = NULL;
12570  FiniteElementSpace *fes3d;
12571  const char *name = nodes->FESpace()->FEColl()->Name();
12572  string cname = name;
12573  if (cname == "Linear")
12574  {
12575  fec3d = new LinearFECollection;
12576  }
12577  else if (cname == "Quadratic")
12578  {
12579  fec3d = new QuadraticFECollection;
12580  }
12581  else if (cname == "Cubic")
12582  {
12583  fec3d = new CubicFECollection;
12584  }
12585  else if (!strncmp(name, "H1_", 3))
12586  {
12587  fec3d = new H1_FECollection(atoi(name + 7), 3);
12588  }
12589  else if (!strncmp(name, "L2_T", 4))
12590  {
12591  fec3d = new L2_FECollection(atoi(name + 10), 3, atoi(name + 4));
12592  }
12593  else if (!strncmp(name, "L2_", 3))
12594  {
12595  fec3d = new L2_FECollection(atoi(name + 7), 3);
12596  }
12597  else
12598  {
12599  delete mesh3d;
12600  mfem::err << "Extrude3D : The mesh uses unknown FE collection : "
12601  << cname << endl;
12602  mfem_error();
12603  }
12604  fes3d = new FiniteElementSpace(mesh3d, fec3d, 3);
12605  mesh3d->SetNodalFESpace(fes3d);
12606  GridFunction *nodes3d = mesh3d->GetNodes();
12607  nodes3d->MakeOwner(fec3d);
12608 
12609  NodeExtrudeCoefficient ecoeff(3, nz, sz);
12610  Vector lnodes;
12611  Array<int> vdofs3d;
12612  for (int i = 0; i < mesh->GetNE(); i++)
12613  {
12615  for (int j = nz-1; j >= 0; j--)
12616  {
12617  fes3d->GetElementVDofs(i*nz+j, vdofs3d);
12618  lnodes.SetSize(vdofs3d.Size());
12619  ecoeff.SetLayer(j);
12620  fes3d->GetFE(i*nz+j)->Project(ecoeff, T, lnodes);
12621  nodes3d->SetSubVector(vdofs3d, lnodes);
12622  }
12623  }
12624  }
12625  return mesh3d;
12626 }
12627 
12628 #ifdef MFEM_DEBUG
12629 void Mesh::DebugDump(std::ostream &os) const
12630 {
12631  // dump vertices and edges (NCMesh "nodes")
12632  os << NumOfVertices + NumOfEdges << "\n";
12633  for (int i = 0; i < NumOfVertices; i++)
12634  {
12635  const double *v = GetVertex(i);
12636  os << i << " " << v[0] << " " << v[1] << " " << v[2]
12637  << " 0 0 " << i << " -1 0\n";
12638  }
12639 
12640  Array<int> ev;
12641  for (int i = 0; i < NumOfEdges; i++)
12642  {
12643  GetEdgeVertices(i, ev);
12644  double mid[3] = {0, 0, 0};
12645  for (int j = 0; j < 2; j++)
12646  {
12647  for (int k = 0; k < spaceDim; k++)
12648  {
12649  mid[k] += GetVertex(ev[j])[k];
12650  }
12651  }
12652  os << NumOfVertices+i << " "
12653  << mid[0]/2 << " " << mid[1]/2 << " " << mid[2]/2 << " "
12654  << ev[0] << " " << ev[1] << " -1 " << i << " 0\n";
12655  }
12656 
12657  // dump elements
12658  os << NumOfElements << "\n";
12659  for (int i = 0; i < NumOfElements; i++)
12660  {
12661  const Element* e = elements[i];
12662  os << e->GetNVertices() << " ";
12663  for (int j = 0; j < e->GetNVertices(); j++)
12664  {
12665  os << e->GetVertices()[j] << " ";
12666  }
12667  os << e->GetAttribute() << " 0 " << i << "\n";
12668  }
12669 
12670  // dump faces
12671  os << "0\n";
12672 }
12673 #endif
12674 
12675 }
static Mesh MakePeriodic(const Mesh &orig_mesh, const std::vector< int > &v2v)
Create a periodic mesh by identifying vertices of orig_mesh.
Definition: mesh.cpp:4904
Abstract class for all finite elements.
Definition: fe_base.hpp:232
const IntegrationRule * IntRule
Definition: mesh.hpp:1973
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
Definition: array.cpp:85
void Loader(std::istream &input, int generate_edges=0, std::string parse_tag="")
Definition: mesh.cpp:3979
Mesh * Make3D(int nsteps, double rstep, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:370
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3066
Table * GetEdgeVertexTable() const
Returns the edge-to-vertex Table (3D)
Definition: mesh.cpp:6066
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:574
void SetCoordsFromPatches(Vector &Nodes)
Definition: nurbs.cpp:2966
void Print(std::ostream &out) const
I/O: Print the mesh in "MFEM NC mesh v1.0" format.
Definition: ncmesh.cpp:5626
BiLinear2DFiniteElement QuadrilateralFE
static const int vtk_quadratic_hex[27]
Definition: mesh.hpp:251
int * CartesianPartitioning(int nxyz[])
Definition: mesh.cpp:7030
void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:247
int Push(int i, int j)
Definition: table.cpp:219
int * GetJ()
Definition: table.hpp:114
Arc::Index insert_arc(Node::Index i, Node::Index j, Float w=1, Float b=1)
Definition: gecko.cpp:679
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
const FiniteElementSpace * GetNodalFESpace() const
Definition: mesh.cpp:5351
void Init(int ind1, int ind2, int ind3, int ind4, int attr=1, int ref_flag=0)
Initialize the vertex indices and the attribute of a Tetrahedron.
Definition: tetrahedron.cpp:43
void NewDataAndSize(double *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition: vector.hpp:162
void ScaleElements(double sf)
Definition: mesh.cpp:11621
static const int HighOrderMap[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to arbitrary-order Lagrange VTK geometries.
Definition: vtk.hpp:80
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
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:5945
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T...
Definition: array.hpp:259
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition: array.hpp:295
void ReadVTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo)
void UseExternalData(double *ext_data, int i, int j, int k)
Definition: densemat.hpp:1039
void FreeElement(Element *E)
Definition: mesh.cpp:11937
void Mult(const Vector &x, Vector &y) const override=0
Extract the face degrees of freedom from x into y.
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition: fespace.cpp:3336
int AddQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1686
int CheckElementOrientation(bool fix_it=true)
Check (and optionally attempt to fix) the orientation of the elements.
Definition: mesh.cpp:5433
void SetVertices(const Vector &vert_coord)
Definition: mesh.cpp:7889
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:923
static const int vtk_quadratic_tet[10]
Definition: mesh.hpp:248
void Make2D(int nx, int ny, Element::Type type, double sx, double sy, bool generate_edges, bool sfc_ordering)
Definition: mesh.cpp:3351
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:2003
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:78
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:1947
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition: globals.hpp:71
virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip)
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
Definition: mesh.cpp:12224
static Mesh MakeSimplicial(const Mesh &orig_mesh)
Definition: mesh.cpp:4575
Base class for vector Coefficients that optionally depend on time and space.
void UniformRefinement3D_base(Array< int > *f2qf=NULL, DSTable *v_to_v_p=NULL, bool update_nodes=true)
Definition: mesh.cpp:8206
Linear1DFiniteElement SegmentFE
Definition: segment.cpp:49
int GetNV() const
Definition: nurbs.hpp:358
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:81
void METIS_PartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
class LinearPyramidFiniteElement PyramidFE
Definition: fe.cpp:44
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:1108
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:6235
static const int NumGeom
Definition: geom.hpp:42
const Table & ElementToFaceTable() const
Definition: mesh.cpp:6472
Array< Slave > slaves
Definition: ncmesh.hpp:231
Array< Element * > boundary
Definition: mesh.hpp:91
int Dimension() const
Definition: mesh.hpp:1047
int * GeneratePartitioning(int nparts, int part_method=1)
Definition: mesh.cpp:7074
CoarseFineTransformations CoarseFineTr
Definition: mesh.hpp:240
int own_nodes
Definition: mesh.hpp:246
virtual void LimitNCLevel(int max_nc_level)
Definition: ncmesh.cpp:5429
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:5389
void MoveVertices(const Vector &displacements)
Definition: mesh.cpp:7869
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:512
bool HasGeometry(Geometry::Type geom) const
Return true iff the given geom is encountered in the mesh. Geometries of dimensions lower than Dimens...
Definition: mesh.hpp:1116
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: tetrahedron.hpp:82
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:452
static FiniteElement * GetTransformationFEforElementType(Element::Type)
Definition: mesh.cpp:327
void SetElementOrder(int i, int p)
Sets the order of the i&#39;th finite element.
Definition: fespace.cpp:151
FaceGeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, FaceType type, MemoryType d_mt=MemoryType::DEFAULT)
Definition: mesh.cpp:12157
static Mesh MakeCartesian3D(int nx, int ny, int nz, Element::Type type, double sx=1.0, double sy=1.0, double sz=1.0, bool sfc_ordering=true)
Definition: mesh.cpp:3736
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
Definition: mesh.cpp:7976
int Dimension() const
Return the dimension of the NCMesh.
Definition: ncmesh.hpp:144
int NumOfEdges
Definition: mesh.hpp:70
virtual int Transform(const Vector &pt, IntegrationPoint &ip)
Given a point, pt, in physical space, find its reference coordinates, ip.
Definition: eltrans.cpp:336
void UniformRefinement()
Definition: nurbs.cpp:3105
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:227
virtual void UniformRefinement2D()
Refine a mixed 2D mesh uniformly.
Definition: mesh.hpp:404
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Swap the internal node GridFunction pointer and ownership flag members with the given ones...
Definition: mesh.cpp:7998
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:475
Element::Type GetBdrElementType(int i) const
Returns the type of boundary element i.
Definition: mesh.cpp:6296
void DisableTensorProducts(bool disable=true) const
Disable the use of tensor product evaluations, for tensor-product elements, e.g. quads and hexes...
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition: mesh.hpp:1341
void ReadNetgen2DMesh(std::istream &input, int &curved)
void ShiftRight(int &a, int &b, int &c)
Definition: mesh.hpp:2044
void SetDims(int rows, int nnz)
Definition: table.cpp:140
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:226
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:72
int Push(int a, int b)
Definition: table.hpp:267
virtual DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element &#39;bel&#39;.
Definition: fespace.cpp:2814
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:6372
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:93
int GetAttribute() const
Return element&#39;s attribute.
Definition: element.hpp:55
static Mesh MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
Create a refined (by any factor) version of orig_mesh.
Definition: mesh.cpp:3746
A specialized ElementTransformation class representing a face and its two neighboring elements...
Definition: eltrans.hpp:480
unsigned matrix
index into NCList::point_matrices[geom]
Definition: ncmesh.hpp:217
T * GetData()
Returns the data.
Definition: array.hpp:115
long GetSequence() const
Definition: mesh.hpp:1742
unsigned int uint
Definition: gecko.hpp:204
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:2009
double Det() const
Definition: densemat.cpp:488
bool Nonconforming() const
Definition: mesh.hpp:1729
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:274
int Size() const
Returns the size of the vector.
Definition: vector.hpp:199
static const int Edges[NumEdges][2]
Definition: geom.hpp:270
int Push(int r, int c, int f)
Check to see if this entry is in the table and add it to the table if it is not there. Returns the number assigned to the table entry.
Definition: stable3d.cpp:64
void DeleteTables()
Definition: mesh.hpp:295
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition: array.cpp:68
Piecewise-(bi/tri)linear continuous finite elements.
Definition: fe_coll.hpp:695
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
const NURBSExtension * GetNURBSext() const
Definition: fespace.hpp:443
GridFunction * Nodes
Definition: mesh.hpp:245
int NumOfElements
Definition: mesh.hpp:69
double * Data() const
Returns the matrix data array.
Definition: densemat.hpp:111
void GetBdrElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of boundary element i.
Definition: mesh.hpp:1152
int Dimension() const
Definition: nurbs.hpp:345
Mesh * Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
Extrude a 1D mesh.
Definition: mesh.cpp:12242
int idxtype
Definition: mesh.cpp:44
void Transform(void(*f)(const Vector &, Vector &))
Definition: mesh.cpp:11691
bool IsSlaveFace(const FaceInfo &fi) const
Definition: mesh.cpp:1051
int GetNDofs() const
Returns number of degrees of freedom.
Definition: fespace.hpp:584
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:524
void AverageVertices(const int *indexes, int n, int result)
Averages the vertices with given indexes and saves the result in vertices[result].
Definition: mesh.cpp:8011
int GetNE() const
Definition: nurbs.hpp:360
static int GetQuadrature1D(int b_type)
Get the corresponding Quadrature1D constant, when that makes sense; otherwise return Quadrature1D::In...
Definition: fe_base.hpp:60
void FinalizeWedgeMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a wedge Mesh.
Definition: mesh.cpp:2830
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: triangle.cpp:188
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
Definition: densemat.cpp:1268
virtual void SetVertices(const int *ind)
Set the indices the element according to the input.
Definition: element.cpp:17
void GetBdrElementTopo(Array< Element *> &boundary) const
Definition: nurbs.cpp:2540
void GetElementData(const Array< Element *> &elem_array, int geom, Array< int > &elem_vtx, Array< int > &attr) const
Definition: mesh.cpp:9403
void order(Functional *functional, uint iterations=1, uint window=2, uint period=2, uint seed=0, Progress *progress=0)
Definition: gecko.cpp:1232
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:942
const Element * GetElement(int i) const
Definition: mesh.hpp:1081
double kappa
Definition: ex24.cpp:54
TriLinear3DFiniteElement HexahedronFE
Definition: hexahedron.cpp:52
Evaluate the derivatives at quadrature points.
bool IsGhost(const Element &el) const
Return true if the Element el is a ghost element.
Definition: ncmesh.hpp:605
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition: mesh.hpp:1915
NodeExtrudeCoefficient(const int dim, const int n_, const double s_)
Definition: mesh.cpp:12218
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec and fes.
Definition: gridfunc.hpp:122
Data type for vertex.
Definition: vertex.hpp:22
void GetElementLocalToGlobal(Array< int > &lelem_elem)
Definition: nurbs.cpp:2903
void SetMeshGen()
Determine the mesh generator bitmask meshgen, see MeshGenerator().
Definition: mesh.cpp:3926
STL namespace.
void KnotInsert(Array< KnotVector *> &kv)
Definition: nurbs.cpp:3113
virtual void Transform(const IntegrationPoint &, Vector &)
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Definition: eltrans.cpp:492
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:548
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition: mesh.cpp:5629
Data type quadrilateral element.
void ReadNetgen3DMesh(std::istream &input)
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
Definition: fespace.hpp:957
double Weight() const
Definition: densemat.cpp:545
Data arrays will be written in ASCII format.
The inverse transformation of a given ElementTransformation.
Definition: eltrans.hpp:185
void Print(std::ostream &out) const
Definition: nurbs.cpp:1701
const IntegrationPoint & GetCenter(int GeomType)
Return the center of the given Geometry::Type, GeomType.
Definition: geom.hpp:71
void GetVertexLocalToGlobal(Array< int > &lvert_vert)
Definition: nurbs.cpp:2893
void ReadInlineMesh(std::istream &input, bool generate_edges=false)
virtual int OrderJ() const =0
Return the order of the elements of the Jacobian of the transformation.
void RemoveInternalBoundaries()
Definition: mesh.cpp:11849
void GetVertexDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3035
Mesh * Extrude2D(Mesh *mesh, const int nz, const double sz)
Extrude a 2D mesh.
Definition: mesh.cpp:12402
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: triangle.hpp:62
void Print(const Mesh &mesh, const adios2stream::mode print_mode=mode::sync)
int RowSize(int i) const
Definition: table.hpp:108
Data type Wedge element.
Definition: wedge.hpp:22
void SetEmpty()
Definition: mesh.cpp:1473
Array< Element * > faces
Definition: mesh.hpp:92
int spaceDim
dimensions of the elements and the vertex coordinates
Definition: ncmesh.hpp:418
const IntegrationRule * GetVertices(int GeomType)
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType...
Definition: geom.cpp:265
std::vector< int > CreatePeriodicVertexMapping(const std::vector< Vector > &translations, double tol=1e-8) const
Creates a mapping v2v from the vertex indices of the mesh such that coincident vertices under the giv...
Definition: mesh.cpp:4938
void FinalizeHexMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a hexahedral Mesh.
Definition: mesh.cpp:2865
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:6301
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:939
friend class NURBSExtension
Definition: mesh.hpp:59
Geometry Geometries
Definition: fe.cpp:49
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:359
void WriteBinaryOrASCII(std::ostream &os, std::vector< char > &buf, const T &val, const char *suffix, VTKFormat format)
Write either ASCII data to the stream or binary data to the buffer depending on the given format...
Definition: vtk.hpp:145
Operation last_operation
Definition: mesh.hpp:289
void ReadCubit(const char *filename, int &curved, int &read_gf)
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
Definition: text.hpp:31
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition: vector.cpp:314
void DeleteAll()
Delete the whole array.
Definition: array.hpp:851
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th element in t...
Definition: fespace.cpp:2783
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition: mesh.cpp:5921
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:104
int master
master number (in Mesh numbering)
Definition: ncmesh.hpp:216
void InitRefinementTransforms()
Definition: mesh.cpp:9968
const NCList & GetFaceList()
Return the current list of conforming and nonconforming faces.
Definition: ncmesh.hpp:253
void UniformRefinement2D_base(bool update_nodes=true)
Definition: mesh.cpp:8047
Array< NCFaceInfo > nc_faces_info
Definition: mesh.hpp:218
Element * ReadElement(std::istream &)
Definition: mesh.cpp:3908
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:379
void OnMeshUpdated(Mesh *mesh)
Definition: ncmesh.cpp:2532
Element * NewElement(int geom)
Definition: mesh.cpp:3854
Table * el_to_face
Definition: mesh.hpp:221
void SetTransformation(ElementTransformation &Trans)
Set a new forward ElementTransformation, Trans.
Definition: eltrans.hpp:292
void SetVerticesFromNodes(const GridFunction *nodes)
Helper to set vertex coordinates given a high-order curvature function.
Definition: mesh.cpp:5375
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition: fespace.cpp:1259
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition: fespace.hpp:631
Structure for storing face geometric factors: coordinates, Jacobians, determinants of the Jacobians...
Definition: mesh.hpp:1969
ElementTransformation * GetBdrElementTransformation(int i)
Definition: mesh.cpp:431
void GetElementTopo(Array< Element *> &elements) const
Definition: nurbs.cpp:2445
virtual void UpdateMeshPointer(Mesh *new_mesh)
Definition: fespace.cpp:3441
void DebugDump(std::ostream &out) const
Output an NCMesh-compatible debug dump.
Definition: mesh.cpp:12629
int AddBdrTriangle(int v1, int v2, int v3, int attr=1)
Definition: mesh.cpp:1849
Mesh * Make2D(int nsteps, double rstep, double phi, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:49
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Given a coefficient and a transformation, compute its projection (approximation) in the local finite ...
Definition: fe_base.cpp:125
void GetMeshComponents(Mesh &mesh) const
Fill Mesh::{vertices,elements,boundary} for the current finest level.
Definition: ncmesh.cpp:2435
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:933
void MakeRefined_(Mesh &orig_mesh, const Array< int > ref_factors, int ref_type)
Internal function used in Mesh::MakeRefined.
Definition: mesh.cpp:4346
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe_base.hpp:319
int GetAttribute(int i) const
Return the attribute of element i.
Definition: mesh.hpp:1544
friend class NCMesh
Definition: mesh.hpp:58
Piecewise-(bi)cubic continuous finite elements.
Definition: fe_coll.hpp:775
void GetElementJacobian(int i, DenseMatrix &J)
Definition: mesh.cpp:60
Data type hexahedron element.
Definition: hexahedron.hpp:22
static int GetTetOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition: mesh.cpp:5677
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:250
void GetBdrElementAdjacentElement2(int bdr_el, int &el, int &info) const
For the given boundary element, bdr_el, return its adjacent element and its info, i...
Definition: mesh.cpp:6269
int AddVertex(double x, double y=0.0, double z=0.0)
Definition: mesh.cpp:1618
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition: eltrans.hpp:401
void GetBdrElementFace(int i, int *f, int *o) const
Return the index and the orientation of the face of bdr element i. (3D)
Definition: mesh.cpp:6212
uint Index
Definition: gecko.hpp:595
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:1956
FaceType
Definition: mesh.hpp:45
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: segment.cpp:40
Data type Pyramid element.
Definition: pyramid.hpp:22
static const int Edges[NumEdges][2]
Definition: geom.hpp:168
void MoveNodes(const Vector &displacements)
Definition: mesh.cpp:7937
double DistanceTo(const double *p) const
Compute the Euclidean distance to another vector.
Definition: vector.hpp:664
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
Definition: mesh.cpp:6161
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:1773
The point is inside the element.
Definition: eltrans.hpp:224
double * GetData() const
Returns the matrix data array.
Definition: densemat.hpp:115
double f(const Vector &xvec)
Definition: lor_mms.hpp:32
void UpdateNURBS()
Definition: mesh.cpp:5137
int GetMaxElementOrder() const
Return the maximum polynomial order.
Definition: fespace.hpp:459
Geometry::Type GetGeometryType() const
Definition: element.hpp:52
Symmetric 3D Table stored as an array of rows each of which has a stack of column, floor, number nodes. The number of the node is assigned by counting the nodes from zero as they are pushed into the table. Diagonals of any kind are not allowed so the row, column and floor must all be different for each node. Only one node is stored for all 6 symmetric entries that are indexable by unique triplets of row, column, and floor.
Definition: stable3d.hpp:34
void GetVertices(Vector &vert_coord) const
Definition: mesh.cpp:7878
const Table & GetDerefinementTable()
Definition: ncmesh.cpp:1937
double UserTime()
Definition: tic_toc.cpp:431
void PrintVTK(std::ostream &os)
Definition: mesh.cpp:10365
DenseTensor point_matrices[Geometry::NumGeom]
Definition: ncmesh.hpp:77
Native ordering as defined by the FiniteElement.
void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
Definition: mesh.cpp:7531
void Make3D(int nx, int ny, int nz, Element::Type type, double sx, double sy, double sz, bool sfc_ordering)
Definition: mesh.cpp:3070
unsigned matrix
Definition: ncmesh.hpp:58
void AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
Definition: mesh.cpp:6522
virtual void SetAttributes()
Definition: mesh.cpp:1564
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:756
void SetType(const int t)
Set the Quadrature1D type of points to use for subdivision.
Definition: geom.hpp:338
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition: mesh.cpp:9535
void GetNode(int i, double *coord) const
Definition: mesh.cpp:7898
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: triangle.hpp:61
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:601
IntegrationPointTransformation Loc1
Definition: eltrans.hpp:524
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:1962
int FindCoarseElement(int i)
Definition: mesh.cpp:9980
int SpaceDimension() const
Return the space dimension of the NCMesh.
Definition: ncmesh.hpp:146
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:215
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:154
virtual void Derefine(const Array< int > &derefs)
Definition: ncmesh.cpp:1981
double b
Definition: lissajous.cpp:42
void CreateRefinementFlag(int refinement_edges[2], int type, int flag=0)
Definition: tetrahedron.cpp:71
void FindNeighbors(int elem, Array< int > &neighbors, const Array< int > *search_set=NULL)
Definition: ncmesh.cpp:3731
virtual void PrintXG(std::ostream &os=mfem::out) const
Print the mesh to the given stream using Netgen/Truegrid format.
Definition: mesh.cpp:10053
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:9878
static const int Map[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to linear VTK geometries.
Definition: vtk.hpp:76
void AddQuadFaceElement(int lf, int gf, int el, int v0, int v1, int v2, int v3)
Definition: mesh.cpp:6587
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Definition: device.hpp:273
const DenseMatrix & Jacobian()
Return the Jacobian matrix of the transformation at the currently set IntegrationPoint, using the method SetIntPoint().
Definition: eltrans.hpp:119
Type
Ordering methods:
Definition: fespace.hpp:33
static const int NumVerts[NumGeom]
Definition: geom.hpp:49
void CheckPartitioning(int *partitioning_)
Definition: mesh.cpp:7474
Timing object.
Definition: tic_toc.hpp:34
void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
void KnotInsert(Array< KnotVector *> &kv)
Definition: mesh.cpp:5063
void AddConnection(int r, int c)
Definition: table.hpp:80
void LoadPatchTopo(std::istream &input, Array< int > &edge_to_knot)
Read NURBS patch/macro-element mesh.
Definition: mesh.cpp:5202
void ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:6839
void Reset()
Force the reevaluation of the Jacobian in the next call.
Definition: eltrans.hpp:89
bool Conforming() const
Definition: mesh.hpp:1728
A pair of objects.
Definition: sort_pairs.hpp:23
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Definition: mesh.cpp:5356
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:6029
Type
Constants for the classes derived from Element.
Definition: element.hpp:41
void InitTables()
Definition: mesh.cpp:1466
void Get(double *p, const int dim) const
Definition: intrules.hpp:51
void CheckDisplacements(const Vector &displacements, double &tmax)
Definition: mesh.cpp:7792
This structure stores the low level information necessary to interpret the configuration of elements ...
Definition: mesh.hpp:153
NURBSExtension * StealNURBSext()
Definition: fespace.cpp:2231
Array< DenseMatrix * > point_matrices[Geometry::NumGeom]
List of unique point matrices for each slave geometry.
Definition: ncmesh.hpp:234
void Mult(const Vector &e_vec, unsigned eval_flags, Vector &q_val, Vector &q_der, Vector &q_det, Vector &q_nor) const
Interpolate the E-vector e_vec to quadrature points.
PointFiniteElement PointFE
Definition: point.cpp:30
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:1053
VTKFormat
Data array format for VTK and VTU files.
Definition: vtk.hpp:96
virtual const char * Name() const
Definition: fe_coll.hpp:73
int mesh_geoms
Definition: mesh.hpp:78
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:159
int AddBdrSegment(int v1, int v2, int attr=1)
Definition: mesh.cpp:1835
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition: mesh.hpp:1148
const FaceQuadratureInterpolator * GetFaceQuadratureInterpolator(const IntegrationRule &ir, FaceType type) const
Return a FaceQuadratureInterpolator that interpolates E-vectors to quadrature point values and/or der...
Definition: fespace.cpp:1356
int AddElement(Element *elem)
The parameter elem should be allocated using the NewElement() method.
Definition: mesh.cpp:1821
void ReadLineMesh(std::istream &input)
Array< Embedding > embeddings
Fine element positions in their parents.
Definition: ncmesh.hpp:73
virtual void Load(std::istream &input, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition: mesh.hpp:904
const CoarseFineTransformations & GetRefinementTransforms()
Definition: ncmesh.cpp:4564
void SetLayer(const int l)
Definition: mesh.hpp:2028
Table * GetFaceToElementTable() const
Definition: mesh.cpp:6127
Array< int > FindFaceNeighbors(const int elem) const
Returns the sorted, unique indices of elements sharing a face with element elem, including elem...
Definition: mesh.cpp:6184
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:6397
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition: array.hpp:292
void SetKnotsFromPatches()
Definition: nurbs.cpp:2974
double Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition: eltrans.hpp:131
int nbBoundaryFaces
Definition: mesh.hpp:75
void RandomRefinement(double prob, bool aniso=false, int nonconforming=-1, int nc_limit=0)
Refine each element with given probability. Uses GeneralRefinement.
Definition: mesh.cpp:9559
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:5967
Data type triangle element.
Definition: triangle.hpp:23
void MarkCoarseLevel()
Definition: ncmesh.cpp:4516
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Definition: triangle.cpp:45
void ResetLazyData()
Definition: mesh.cpp:1553
IntegrationRule RefPts
Definition: geom.hpp:314
signed char local
local number within &#39;element&#39;
Definition: ncmesh.hpp:191
void GetColumn(int c, Vector &col) const
Definition: densemat.cpp:1331
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
Definition: densemat.hpp:1030
double Float
Definition: gecko.hpp:208
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
Definition: array.hpp:251
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
Definition: geom.cpp:1099
int GetVDim()
Returns dimension of the vector.
void Init()
Definition: mesh.cpp:1448
virtual void SetNodalFESpace(FiniteElementSpace *nfes)
Definition: mesh.cpp:5298
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: tetrahedron.hpp:81
Vector normal
Normals at all quadrature points.
Definition: mesh.hpp:2016
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
Definition: ncmesh.hpp:121
static const int Edges[NumEdges][2]
Definition: geom.hpp:222
void SetData(double *d)
Definition: vector.hpp:149
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:683
bool IsOfFaceType(FaceType type) const
Return true if the face is of the same type as type.
Definition: mesh.hpp:1465
struct mfem::Mesh::FaceInformation::@13 element[2]
virtual MFEM_DEPRECATED void ReorientTetMesh()
Definition: mesh.cpp:6968
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:187
prob_type prob
Definition: ex25.cpp:153
int NumOfBdrElements
Definition: mesh.hpp:69
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:614
Table * el_to_edge
Definition: mesh.hpp:220
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:311
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3078
static const int QuadraticMap[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to legacy quadratic VTK geometries/.
Definition: vtk.hpp:78
A class that performs interpolation from a face E-vector to quadrature point values and/or derivative...
void GetNodalValues(int i, Array< double > &nval, int vdim=1) const
Returns the values in the vertices of i&#39;th element for dimension vdim.
Definition: gridfunc.cpp:396
void ReadMFEMMesh(std::istream &input, int version, int &curved)
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:8913
MPI_Comm GetComm() const
Definition: pmesh.hpp:351
void Start()
Start the stopwatch. The elapsed time is not cleared.
Definition: tic_toc.cpp:411
Table * GetFaceEdgeTable() const
Returns the face-to-edge Table (3D)
Definition: mesh.cpp:6038
void FindPartitioningComponents(Table &elem_elem, const Array< int > &partitioning, Array< int > &component, Array< int > &num_comp)
Definition: mesh.cpp:7403
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:208
void MakeTopologyOnly()
Definition: ncmesh.hpp:413
List of mesh geometries stored as Array<Geometry::Type>.
Definition: mesh.hpp:1131
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:581
A general vector function coefficient.
void PrintVTU(std::ostream &os, int ref=1, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0, bool bdr_elements=false)
Definition: mesh.cpp:10565
This structure is used as a human readable output format that decipheres the information contained in...
Definition: mesh.hpp:1417
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:281
int CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition: mesh.cpp:5810
Geometry::Type GetElementGeometry(int i) const
Definition: mesh.hpp:1094
int GetMyRank() const
Definition: pmesh.hpp:353
GeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, MemoryType d_mt=MemoryType::DEFAULT)
Definition: mesh.cpp:12077
void PrintElementsWithPartitioning(int *partitioning, std::ostream &out, int interior_faces=0)
Definition: mesh.cpp:11111
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition: mesh.hpp:1550
static const int Edges[NumEdges][2]
Definition: geom.hpp:198
void AddPointFaceElement(int lf, int gf, int el)
Used in GenerateFaces()
Definition: mesh.cpp:6490
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:3529
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:441
virtual const int * DofOrderForOrientation(Geometry::Type GeomType, int Or) const =0
Returns an array, say p, that maps a local permuted index i to a local base index: base_i = p[i]...
void Swap(Array< T > &, Array< T > &)
Definition: array.hpp:635
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:275
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:9155
virtual void PushTransform(int tr)
Add &#39;tr&#39; to the current chain of coarse-fine transformations.
Definition: tetrahedron.hpp:85
void FinalizeMesh(int refine=0, bool fix_orientation=true)
Finalize the construction of any type of Mesh.
Definition: mesh.cpp:2895
const Table & ElementToEdgeTable() const
Definition: mesh.cpp:6481
static int CheckClosed(int type)
If the Quadrature1D type is not closed return Invalid; otherwise return type.
Definition: intrules.cpp:854
Table * el_to_el
Definition: mesh.hpp:222
int GetDim() const
Returns the reference space dimension for the finite element.
Definition: fe_base.hpp:310
void Finalize()
Definition: table.cpp:242
Nonconforming edge/face within a bigger edge/face.
Definition: ncmesh.hpp:214
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:96
static Mesh LoadFromFile(const char *filename, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition: mesh.cpp:3708
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition: mesh.cpp:11742
static void PrintElement(const Element *, std::ostream &)
Definition: mesh.cpp:3920
virtual void NURBSUniformRefinement()
Refine NURBS mesh.
Definition: mesh.cpp:5107
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int attr=1)
Definition: mesh.cpp:1749
const IntegrationRule * IntRule
Definition: mesh.hpp:1924
MemoryType
Memory types supported by MFEM.
Definition: mem_manager.hpp:31
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:1994
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition: mesh.cpp:2902
void AddAColumnInRow(int r)
Definition: table.hpp:77
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition: mesh.hpp:1610
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:684
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
Definition: mesh.cpp:2493
int AddBdrQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1863
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
Definition: array.cpp:103
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition: table.cpp:413
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition: eltrans.cpp:546
int FindRoots(const Vector &z, Vector &x)
Definition: mesh.cpp:7611
Array< Vertex > vertices
Definition: mesh.hpp:90
void PrintTopo(std::ostream &out, const Array< int > &e_to_k) const
Definition: mesh.cpp:10309
int Push4(int r, int c, int f, int t)
Check to see if this entry is in the table and add it to the table if it is not there. The entry is addressed by the three smallest values of (r,c,f,t). Returns the number assigned to the table entry.
Definition: stable3d.cpp:140
void JacToPerfJac(int GeomType, const DenseMatrix &J, DenseMatrix &PJ) const
Definition: geom.cpp:867
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, double sx=1.0, double sy=1.0, bool sfc_ordering=true)
Definition: mesh.cpp:3726
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Definition: mesh.cpp:1595
void ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo, const std::string &xml_prefix="")
Helper struct for defining a connectivity table, see Table::MakeFromList.
Definition: table.hpp:27
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe_base.hpp:322
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:66
void RefineAtVertex(const Vertex &vert, double eps=0.0, int nonconforming=-1)
Refine elements sharing the specified vertex. Uses GeneralRefinement.
Definition: mesh.cpp:9578
MFEM_EXPORT class Linear3DFiniteElement TetrahedronFE
Definition: fe.cpp:36
A class to initialize the size of a Tensor.
Definition: dtensor.hpp:54
static Mesh MakeCartesian1D(int n, double sx=1.0)
Definition: mesh.cpp:3718
virtual DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element &#39;elem&#39;.
Definition: fespace.cpp:2680
Array< Element * > elements
Definition: mesh.hpp:85
const Table & ElementToElementTable()
Definition: mesh.cpp:6436
void SetRelaxedHpConformity(bool relaxed=true)
Definition: fespace.hpp:939
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition: gridfunc.cpp:165
void ShiftUpI()
Definition: table.cpp:115
MFEM_EXPORT Linear2DFiniteElement TriangleFE
Definition: fe.cpp:32
int SpaceDimension() const
Definition: mesh.hpp:1048
int meshgen
Definition: mesh.hpp:77
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:252
const CoarseFineTransformations & GetRefinementTransforms()
Definition: mesh.cpp:9990
bool RefineByError(const Array< double > &elem_error, double threshold, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:9604
Table * bel_to_edge
Definition: mesh.hpp:224
void GetGeometries(int dim, Array< Geometry::Type > &el_geoms) const
Return all element geometries of the given dimension present in the mesh.
Definition: mesh.cpp:5932
Evaluate the values at quadrature points.
Geometry::Type GetBdrElementGeometry(int i) const
Definition: mesh.hpp:1099
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:936
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
Definition: mesh.cpp:5999
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
double a
Definition: lissajous.cpp:41
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:277
int nbInteriorFaces
Definition: mesh.hpp:75
void PrintBdrVTU(std::string fname, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0)
Definition: mesh.cpp:10557
Array< int > be_to_edge
Definition: mesh.hpp:223
static const int Edges[NumEdges][2]
Definition: geom.hpp:292
Class for integration point with weight.
Definition: intrules.hpp:25
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition: mesh.cpp:6291
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition: fespace.cpp:1327
Element * ReadElementWithoutAttr(std::istream &)
Definition: mesh.cpp:3878
void Swap(Mesh &other, bool non_geometry)
Definition: mesh.cpp:9346
int VectorDim() const
Definition: gridfunc.cpp:324
int GetElementOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:178
A standard isoparametric element transformation.
Definition: eltrans.hpp:361
static const int vtk_quadratic_wedge[18]
Definition: mesh.hpp:250
virtual long long ReduceInt(int value) const
Utility function: sum integers from all processors (Allreduce).
Definition: mesh.hpp:965
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: mesh.cpp:348
static const int DimStart[MaxDim+2]
Definition: geom.hpp:48
virtual int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type, does not count master nonconforming face...
Definition: mesh.cpp:5405
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
MFEM_EXPORT class LinearWedgeFiniteElement WedgeFE
Definition: fe.cpp:40
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:599
Table * face_edge
Definition: mesh.hpp:231
void FinalizeQuadMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a quadrilateral Mesh.
Definition: mesh.cpp:1980
Array< int > leaf_elements
finest elements, in Mesh ordering (+ ghosts)
Definition: ncmesh.hpp:540
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
Definition: mesh.cpp:2995
int FindId(int p1, int p2) const
Find id of item whose parents are p1, p2... Return -1 if it doesn&#39;t exist.
Definition: hash.hpp:699
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:209
bool DerefineByError(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
Definition: mesh.cpp:9273
Array< Master > masters
Definition: ncmesh.hpp:230
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition: fespace.hpp:74
const char * VTKByteOrder()
Determine the byte order and return either "BigEndian" or "LittleEndian".
Definition: vtk.cpp:602
void MakeJ()
Definition: table.cpp:91
void DegreeElevate(int rel_degree, int degree=16)
Definition: mesh.cpp:5120
int dim
Definition: ex24.cpp:53
Table * edge_vertex
Definition: mesh.hpp:232
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition: eltrans.hpp:381
long sequence
Definition: mesh.hpp:83
signed char geom
Geometry::Type (faces only) (char to save RAM)
Definition: ncmesh.hpp:192
void FindTMax(Vector &c, Vector &x, double &tmax, const double factor, const int Dim)
Definition: mesh.cpp:7758
IsoparametricTransformation Transf
Definition: eltrans.hpp:464
int index(int i, int j, int nx, int ny)
Definition: life.cpp:235
int NumberOfEntries() const
Definition: table.hpp:266
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:861
ElementTransformation * Elem1
Definition: eltrans.hpp:522
constexpr int dimension
This example only works in 3D. Kernels for 2D are not implemented.
Definition: hooke.cpp:45
static const int Edges[NumEdges][2]
Definition: geom.hpp:248
const Mesh * mesh
Definition: mesh.hpp:1923
Float cost() const
Definition: gecko.cpp:857
void MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
Definition: mesh.cpp:4582
Lexicographic ordering for tensor-product FiniteElements.
Array< FaceInfo > faces_info
Definition: mesh.hpp:217
double infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition: vector.hpp:46
virtual int GetNVertices() const =0
int GetNKV() const
Definition: nurbs.hpp:355
int parent
Coarse Element index in the coarse mesh.
Definition: ncmesh.hpp:52
void SetAttribute(const int attr)
Set element&#39;s attribute.
Definition: element.hpp:58
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Definition: gridfunc.cpp:2396
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:235
double Norml2() const
Returns the l2 norm of the vector.
Definition: vector.cpp:804
STable3D * GetFacesTable()
Definition: mesh.cpp:6776
Piecewise-(bi)quadratic continuous finite elements.
Definition: fe_coll.hpp:723
int Size_of_connections() const
Definition: table.hpp:98
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
Definition: sparsemat.hpp:711
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition: mesh.hpp:278
virtual void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level)
Definition: ncmesh.cpp:1952
virtual void UniformRefinement3D()
Refine a mixed 3D mesh uniformly.
Definition: mesh.hpp:414
int AddBdrElement(Element *elem)
Definition: mesh.cpp:1828
int Size() const
Return the logical size of the array.
Definition: array.hpp:141
RefCoord t[3]
NQPT x VDIM x NE (values) / NQPT x VDIM x DIM x NE (grads)
static void PrintElementWithoutAttr(const Element *, std::ostream &)
Definition: mesh.cpp:3896
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr=1)
Definition: mesh.cpp:1721
BlockArray< Element > elements
Definition: ncmesh.hpp:511
FaceInformation GetFaceInformation(int f) const
Definition: mesh.cpp:1131
virtual bool NonconformingDerefinement(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
NC version of GeneralDerefinement.
Definition: mesh.cpp:9225
int Dim
Definition: mesh.hpp:66
void Clear()
Clear the contents of the Mesh.
Definition: mesh.hpp:912
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:45
const int * GetDofMap(Geometry::Type GeomType) const
Get the Cartesian to local H1 dof map.
Definition: fe_coll.cpp:2007
ElementConformity conformity
Definition: mesh.hpp:1424
double AggregateError(const Array< double > &elem_error, const int *fine, int nfine, int op)
Derefinement helper.
Definition: mesh.cpp:9205
virtual int FindPoints(DenseMatrix &point_mat, Array< int > &elem_ids, Array< IntegrationPoint > &ips, bool warn=true, InverseElementTransformation *inv_trans=NULL)
Find the ids of the elements that contain the given points, and their corresponding reference coordin...
Definition: mesh.cpp:11962
int DofToVDof(int dof, int vd, int ndofs=-1) const
Definition: fespace.cpp:251
Mesh & operator=(Mesh &&mesh)
Move assignment operstor.
Definition: mesh.cpp:3702
Evaluate the derivatives at quadrature points.
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:945
Vector data type.
Definition: vector.hpp:60
Data type point element.
Definition: point.hpp:22
void ReadTrueGridMesh(std::istream &input)
virtual void Print(std::ostream &os=mfem::out) const
Definition: mesh.hpp:1749
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition: fespace.hpp:925
static void GetElementArrayEdgeTable(const Array< Element *> &elem_array, const DSTable &v_to_v, Table &el_to_edge)
Definition: mesh.cpp:6350
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition: eltrans.hpp:404
bool IsNonconformingCoarse() const
Return true if the face is a nonconforming coarse face.
Definition: mesh.hpp:1496
virtual void Save(const char *fname, int precision=16) const
Definition: mesh.cpp:10351
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition: mesh.cpp:5581
void SetNode(int i, const double *coord)
Definition: mesh.cpp:7917
Table * face_to_elem
Definition: mesh.hpp:230
int SizeK() const
Definition: densemat.hpp:1026
virtual void PushTransform(int tr)
Add &#39;tr&#39; to the current chain of coarse-fine transformations.
Definition: triangle.hpp:65
void CreateVTKElementConnectivity(Array< int > &con, Geometry::Type geom, int ref)
Create the VTK element connectivity array for a given element geometry and refinement level...
Definition: vtk.cpp:497
int * GetI()
Definition: table.hpp:113
int GetId(int p1, int p2)
Get id of item whose parents are p1, p2... Create it if it doesn&#39;t exist.
Definition: hash.hpp:608
void PrintSurfaces(const Table &Aface_face, std::ostream &out) const
Print set of disjoint surfaces:
Definition: mesh.cpp:11484
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:252
void XYZ_VectorFunction(const Vector &p, Vector &v)
Definition: mesh.cpp:5261
void GenerateFaces()
Definition: mesh.cpp:6614
void GetElementColoring(Array< int > &colors, int el0=0)
Definition: mesh.cpp:10917
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:7949
void ChangeVertexDataOwnership(double *vertices, int len_vertices, bool zerocopy=false)
Set the internal Vertex array to point to the given vertices array without assuming ownership of the ...
Definition: mesh.cpp:3788
int GetNumFacesWithGhost() const
Return the number of faces (3D), edges (2D) or vertices (1D) including ghost faces.
Definition: mesh.cpp:5400
int spaceDim
Definition: mesh.hpp:67
Defines the coarse-fine transformations of all fine elements.
Definition: ncmesh.hpp:70
RefCoord s[3]
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
void Printer(std::ostream &out=mfem::out, std::string section_delimiter="") const
Definition: mesh.cpp:10217
const std::string filename
Definition: zstr.hpp:811
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Definition: ncmesh.hpp:260
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3045
MemAlloc< Tetrahedron, 1024 > TetMemory
Definition: mesh.hpp:255
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag)
Definition: tetrahedron.cpp:55
Node::Index insert_node(Float length=1)
Definition: gecko.cpp:657
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
Definition: mesh.cpp:2559
void SetNodes(const Vector &node_coord)
Updates the vertex/node locations. Invokes NodesUpdated().
Definition: mesh.cpp:7961
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:1085
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
friend class ParNCMesh
Definition: mesh.hpp:56
void SetNodalGridFunction(GridFunction *nodes, bool make_owner=false)
Definition: mesh.cpp:5345
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition: mesh.hpp:1736
virtual const FaceRestriction * GetFaceRestriction(ElementDofOrdering e_ordering, FaceType, L2FaceValues mul=L2FaceValues::DoubleValued) const
Return an Operator that converts L-vectors to E-vectors on each face.
Definition: fespace.cpp:1292
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition: densemat.hpp:105
void ReadNURBSMesh(std::istream &input, int &curved, int &read_gf)
int NumOfVertices
Definition: mesh.hpp:69
static const int * VertexPermutation[Geometry::NUM_GEOMETRIES]
Permutation from MFEM&#39;s vertex ordering to VTK&#39;s vertex ordering.
Definition: vtk.hpp:73
void ScaleSubdomains(double sf)
Definition: mesh.cpp:11551
std::ostream & operator<<(std::ostream &os, const Mesh &mesh)
Definition: mesh.cpp:11956
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:3673
Array< int > be_to_face
Definition: mesh.hpp:225
void DegreeElevate(int rel_degree, int degree=16)
Definition: nurbs.cpp:3089
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
Definition: mesh.cpp:9302
Base class for operators that extracts Face degrees of freedom.
void Bisection(int i, const DSTable &, int *, int *, int *)
Bisect a triangle: element with index i is bisected.
Definition: mesh.cpp:9633
int GetNBE() const
Definition: nurbs.hpp:362
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition: fe_base.hpp:388
virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const =0
Evaluate the gradients of all shape functions of a scalar finite element in reference space at the gi...
uint rank(Node::Index i) const
Definition: gecko.hpp:672
int index
Mesh number.
Definition: ncmesh.hpp:189
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:9467
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:978
ElementLocation location
Definition: mesh.hpp:1423
Class for parallel meshes.
Definition: pmesh.hpp:32
Geometry::Type GetBdrElementBaseGeometry(int i) const
Definition: mesh.hpp:1111
Abstract data type element.
Definition: element.hpp:28
void AddTriangleFaceElement(int lf, int gf, int el, int v0, int v1, int v2)
Definition: mesh.cpp:6559
void WriteBase64WithSizeAndClear(std::ostream &os, std::vector< char > &buf, int compression_level)
Encode in base 64 (and potentially compress) the given data, write it to the output stream (with a he...
Definition: vtk.cpp:654
Data type line segment element.
Definition: segment.hpp:22
Array< GeometricFactors * > geom_factors
Optional geometric factors.
Definition: mesh.hpp:279
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition: fespace.hpp:608
int NumberOfRows() const
Definition: table.hpp:265
void BdrBisection(int i, const HashTable< Hashed2 > &)
Bisect a boundary triangle: boundary element with index i is bisected.
Definition: mesh.cpp:9841
MPI_Comm GetGlobalMPI_Comm()
Get MFEM&#39;s "global" MPI communicator.
Definition: globals.cpp:62
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:215
int NumberOfElements()
Return the number of elements added to the table.
Definition: stable3d.hpp:70
void GenerateNCFaceInfo()
Definition: mesh.cpp:6715
Array< int > RefGeoms
Definition: geom.hpp:315
friend class Tetrahedron
Definition: mesh.hpp:254
virtual Type GetType() const =0
Returns element&#39;s type.
double GetLength(int i, int j) const
Return the length of the segment from node i to node j.
Definition: mesh.cpp:6335
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition: mesh.hpp:273
class Mesh * mesh
The Mesh object containing the element.
Definition: eltrans.hpp:84
Table * GetVertexToElementTable()
The returned Table must be destroyed by the caller.
Definition: mesh.cpp:6092
void EnsureNodes()
Make sure that the mesh has valid nodes, i.e. its geometry is described by a vector finite element gr...
Definition: mesh.cpp:5304
void ConvertToPatches(const Vector &Nodes)
Definition: nurbs.cpp:2955
void PrintWithPartitioning(int *partitioning, std::ostream &os, int elem_attr=0) const
Prints the mesh with boundary elements given by the boundary of the subdomains, so that the boundary ...
Definition: mesh.cpp:10992
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:184
const DenseMatrix * point_matrix
Definition: mesh.hpp:1432
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
Definition: triangle.cpp:126
void UpdateNodes()
Update the nodes of a curved mesh after the topological part of a Mesh::Operation, such as refinement, has been performed.
Definition: mesh.cpp:8032
Defines the position of a fine element within a coarse element.
Definition: ncmesh.hpp:49
void GetBdrPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:6319
void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
For the given boundary element, bdr_el, return its adjacent element and its info, i...
Definition: mesh.cpp:6247
int idx_t
Definition: mesh.cpp:43
virtual void Refine(const Array< Refinement > &refinements)
Definition: ncmesh.cpp:1620
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:365
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition: fe_coll.hpp:320
Evaluate the values at quadrature points.
double f(const Vector &p)
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:296
void NodesUpdated()
This function should be called after the mesh node coordinates have been updated externally, e.g. by modifying the internal nodal GridFunction returned by GetNodes().
Definition: mesh.hpp:1038
Class used to extrude the nodes of a mesh.
Definition: mesh.hpp:2020
int NumOfFaces
Definition: mesh.hpp:70