MFEM  v4.5.1
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
mesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, 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(GetFaceBaseGeometry(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[GetFaceBaseGeometry(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 = GetFaceGeometryType(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(GetFaceGeometryType(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::GetFaceGeometryType(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 }
1471 
1472 void Mesh::SetEmpty()
1473 {
1474  Init();
1475  InitTables();
1476 }
1477 
1478 void Mesh::DestroyTables()
1479 {
1480  delete el_to_edge;
1481  delete el_to_face;
1482  delete el_to_el;
1483  DeleteGeometricFactors();
1484 
1485  if (Dim == 3)
1486  {
1487  delete bel_to_edge;
1488  }
1489 
1490  delete face_edge;
1491  delete edge_vertex;
1492 }
1493 
1494 void Mesh::DestroyPointers()
1495 {
1496  if (own_nodes) { delete Nodes; }
1497 
1498  delete ncmesh;
1499 
1500  delete NURBSext;
1501 
1502  for (int i = 0; i < NumOfElements; i++)
1503  {
1504  FreeElement(elements[i]);
1505  }
1506 
1507  for (int i = 0; i < NumOfBdrElements; i++)
1508  {
1509  FreeElement(boundary[i]);
1510  }
1511 
1512  for (int i = 0; i < faces.Size(); i++)
1513  {
1514  FreeElement(faces[i]);
1515  }
1516 
1517  DestroyTables();
1518 }
1519 
1520 void Mesh::Destroy()
1521 {
1522  DestroyPointers();
1523 
1524  elements.DeleteAll();
1525  vertices.DeleteAll();
1526  boundary.DeleteAll();
1527  faces.DeleteAll();
1528  faces_info.DeleteAll();
1529  nc_faces_info.DeleteAll();
1530  be_to_edge.DeleteAll();
1531  be_to_face.DeleteAll();
1532 
1533  // TODO:
1534  // IsoparametricTransformations
1535  // Transformation, Transformation2, BdrTransformation, FaceTransformation,
1536  // EdgeTransformation;
1537  // FaceElementTransformations FaceElemTr;
1538 
1539  CoarseFineTr.Clear();
1540 
1541 #ifdef MFEM_USE_MEMALLOC
1542  TetMemory.Clear();
1543 #endif
1544 
1545  attributes.DeleteAll();
1546  bdr_attributes.DeleteAll();
1547 }
1548 
1549 void Mesh::ResetLazyData()
1550 {
1551  delete el_to_el; el_to_el = NULL;
1552  delete face_edge; face_edge = NULL;
1553  delete edge_vertex; edge_vertex = NULL;
1554  DeleteGeometricFactors();
1555  nbInteriorFaces = -1;
1556  nbBoundaryFaces = -1;
1557 }
1558 
1559 void Mesh::SetAttributes()
1560 {
1561  Array<int> attribs;
1562 
1563  attribs.SetSize(GetNBE());
1564  for (int i = 0; i < attribs.Size(); i++)
1565  {
1566  attribs[i] = GetBdrAttribute(i);
1567  }
1568  attribs.Sort();
1569  attribs.Unique();
1570  attribs.Copy(bdr_attributes);
1571  if (bdr_attributes.Size() > 0 && bdr_attributes[0] <= 0)
1572  {
1573  MFEM_WARNING("Non-positive attributes on the boundary!");
1574  }
1575 
1576  attribs.SetSize(GetNE());
1577  for (int i = 0; i < attribs.Size(); i++)
1578  {
1579  attribs[i] = GetAttribute(i);
1580  }
1581  attribs.Sort();
1582  attribs.Unique();
1583  attribs.Copy(attributes);
1584  if (attributes.Size() > 0 && attributes[0] <= 0)
1585  {
1586  MFEM_WARNING("Non-positive attributes in the domain!");
1587  }
1588 }
1589 
1590 void Mesh::InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
1591 {
1592  SetEmpty();
1593 
1594  Dim = Dim_;
1595  spaceDim = spaceDim_;
1596 
1597  NumOfVertices = 0;
1598  vertices.SetSize(NVert); // just allocate space for vertices
1599 
1600  NumOfElements = 0;
1601  elements.SetSize(NElem); // just allocate space for Element *
1602 
1603  NumOfBdrElements = 0;
1604  boundary.SetSize(NBdrElem); // just allocate space for Element *
1605 }
1606 
1607 template<typename T>
1608 static void CheckEnlarge(Array<T> &array, int size)
1609 {
1610  if (size >= array.Size()) { array.SetSize(size + 1); }
1611 }
1612 
1613 int Mesh::AddVertex(double x, double y, double z)
1614 {
1615  CheckEnlarge(vertices, NumOfVertices);
1616  double *v = vertices[NumOfVertices]();
1617  v[0] = x;
1618  v[1] = y;
1619  v[2] = z;
1620  return NumOfVertices++;
1621 }
1622 
1623 int Mesh::AddVertex(const double *coords)
1624 {
1625  CheckEnlarge(vertices, NumOfVertices);
1626  vertices[NumOfVertices].SetCoords(spaceDim, coords);
1627  return NumOfVertices++;
1628 }
1629 
1630 void Mesh::AddVertexParents(int i, int p1, int p2)
1631 {
1632  tmp_vertex_parents.Append(Triple<int, int, int>(i, p1, p2));
1633 
1634  // if vertex coordinates are defined, make sure the hanging vertex has the
1635  // correct position
1636  if (i < vertices.Size())
1637  {
1638  double *vi = vertices[i](), *vp1 = vertices[p1](), *vp2 = vertices[p2]();
1639  for (int j = 0; j < 3; j++)
1640  {
1641  vi[j] = (vp1[j] + vp2[j]) * 0.5;
1642  }
1643  }
1644 }
1645 
1646 int Mesh::AddSegment(int v1, int v2, int attr)
1647 {
1648  CheckEnlarge(elements, NumOfElements);
1649  elements[NumOfElements] = new Segment(v1, v2, attr);
1650  return NumOfElements++;
1651 }
1652 
1653 int Mesh::AddSegment(const int *vi, int attr)
1654 {
1655  CheckEnlarge(elements, NumOfElements);
1656  elements[NumOfElements] = new Segment(vi, attr);
1657  return NumOfElements++;
1658 }
1659 
1660 int Mesh::AddTriangle(int v1, int v2, int v3, int attr)
1661 {
1662  CheckEnlarge(elements, NumOfElements);
1663  elements[NumOfElements] = new Triangle(v1, v2, v3, attr);
1664  return NumOfElements++;
1665 }
1666 
1667 int Mesh::AddTriangle(const int *vi, int attr)
1668 {
1669  CheckEnlarge(elements, NumOfElements);
1670  elements[NumOfElements] = new Triangle(vi, attr);
1671  return NumOfElements++;
1672 }
1673 
1674 int Mesh::AddQuad(int v1, int v2, int v3, int v4, int attr)
1675 {
1676  CheckEnlarge(elements, NumOfElements);
1677  elements[NumOfElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1678  return NumOfElements++;
1679 }
1680 
1681 int Mesh::AddQuad(const int *vi, int attr)
1682 {
1683  CheckEnlarge(elements, NumOfElements);
1684  elements[NumOfElements] = new Quadrilateral(vi, attr);
1685  return NumOfElements++;
1686 }
1687 
1688 int Mesh::AddTet(int v1, int v2, int v3, int v4, int attr)
1689 {
1690  int vi[4] = {v1, v2, v3, v4};
1691  return AddTet(vi, attr);
1692 }
1693 
1694 int Mesh::AddTet(const int *vi, int attr)
1695 {
1696  CheckEnlarge(elements, NumOfElements);
1697 #ifdef MFEM_USE_MEMALLOC
1698  Tetrahedron *tet;
1699  tet = TetMemory.Alloc();
1700  tet->SetVertices(vi);
1701  tet->SetAttribute(attr);
1702  elements[NumOfElements] = tet;
1703 #else
1704  elements[NumOfElements] = new Tetrahedron(vi, attr);
1705 #endif
1706  return NumOfElements++;
1707 }
1708 
1709 int Mesh::AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr)
1710 {
1711  CheckEnlarge(elements, NumOfElements);
1712  elements[NumOfElements] = new Wedge(v1, v2, v3, v4, v5, v6, attr);
1713  return NumOfElements++;
1714 }
1715 
1716 int Mesh::AddWedge(const int *vi, int attr)
1717 {
1718  CheckEnlarge(elements, NumOfElements);
1719  elements[NumOfElements] = new Wedge(vi, attr);
1720  return NumOfElements++;
1721 }
1722 
1723 int Mesh::AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr)
1724 {
1725  CheckEnlarge(elements, NumOfElements);
1726  elements[NumOfElements] = new Pyramid(v1, v2, v3, v4, v5, attr);
1727  return NumOfElements++;
1728 }
1729 
1730 int Mesh::AddPyramid(const int *vi, int attr)
1731 {
1732  CheckEnlarge(elements, NumOfElements);
1733  elements[NumOfElements] = new Pyramid(vi, attr);
1734  return NumOfElements++;
1735 }
1736 
1737 int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
1738  int attr)
1739 {
1740  CheckEnlarge(elements, NumOfElements);
1741  elements[NumOfElements] =
1742  new Hexahedron(v1, v2, v3, v4, v5, v6, v7, v8, attr);
1743  return NumOfElements++;
1744 }
1745 
1746 int Mesh::AddHex(const int *vi, int attr)
1747 {
1748  CheckEnlarge(elements, NumOfElements);
1749  elements[NumOfElements] = new Hexahedron(vi, attr);
1750  return NumOfElements++;
1751 }
1752 
1753 void Mesh::AddHexAsTets(const int *vi, int attr)
1754 {
1755  static const int hex_to_tet[6][4] =
1756  {
1757  { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
1758  { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
1759  };
1760  int ti[4];
1761 
1762  for (int i = 0; i < 6; i++)
1763  {
1764  for (int j = 0; j < 4; j++)
1765  {
1766  ti[j] = vi[hex_to_tet[i][j]];
1767  }
1768  AddTet(ti, attr);
1769  }
1770 }
1771 
1772 void Mesh::AddHexAsWedges(const int *vi, int attr)
1773 {
1774  static const int hex_to_wdg[2][6] =
1775  {
1776  { 0, 1, 2, 4, 5, 6 }, { 0, 2, 3, 4, 6, 7 }
1777  };
1778  int ti[6];
1779 
1780  for (int i = 0; i < 2; i++)
1781  {
1782  for (int j = 0; j < 6; j++)
1783  {
1784  ti[j] = vi[hex_to_wdg[i][j]];
1785  }
1786  AddWedge(ti, attr);
1787  }
1788 }
1789 
1790 void Mesh::AddHexAsPyramids(const int *vi, int attr)
1791 {
1792  static const int hex_to_pyr[6][5] =
1793  {
1794  { 0, 1, 2, 3, 8 }, { 0, 4, 5, 1, 8 }, { 1, 5, 6, 2, 8 },
1795  { 2, 6, 7, 3, 8 }, { 3, 7, 4, 0, 8 }, { 7, 6, 5, 4, 8 }
1796  };
1797  int ti[5];
1798 
1799  for (int i = 0; i < 6; i++)
1800  {
1801  for (int j = 0; j < 5; j++)
1802  {
1803  ti[j] = vi[hex_to_pyr[i][j]];
1804  }
1805  AddPyramid(ti, attr);
1806  }
1807 }
1808 
1809 int Mesh::AddElement(Element *elem)
1810 {
1811  CheckEnlarge(elements, NumOfElements);
1812  elements[NumOfElements] = elem;
1813  return NumOfElements++;
1814 }
1815 
1816 int Mesh::AddBdrElement(Element *elem)
1817 {
1818  CheckEnlarge(boundary, NumOfBdrElements);
1819  boundary[NumOfBdrElements] = elem;
1820  return NumOfBdrElements++;
1821 }
1822 
1823 int Mesh::AddBdrSegment(int v1, int v2, int attr)
1824 {
1825  CheckEnlarge(boundary, NumOfBdrElements);
1826  boundary[NumOfBdrElements] = new Segment(v1, v2, attr);
1827  return NumOfBdrElements++;
1828 }
1829 
1830 int Mesh::AddBdrSegment(const int *vi, int attr)
1831 {
1832  CheckEnlarge(boundary, NumOfBdrElements);
1833  boundary[NumOfBdrElements] = new Segment(vi, attr);
1834  return NumOfBdrElements++;
1835 }
1836 
1837 int Mesh::AddBdrTriangle(int v1, int v2, int v3, int attr)
1838 {
1839  CheckEnlarge(boundary, NumOfBdrElements);
1840  boundary[NumOfBdrElements] = new Triangle(v1, v2, v3, attr);
1841  return NumOfBdrElements++;
1842 }
1843 
1844 int Mesh::AddBdrTriangle(const int *vi, int attr)
1845 {
1846  CheckEnlarge(boundary, NumOfBdrElements);
1847  boundary[NumOfBdrElements] = new Triangle(vi, attr);
1848  return NumOfBdrElements++;
1849 }
1850 
1851 int Mesh::AddBdrQuad(int v1, int v2, int v3, int v4, int attr)
1852 {
1853  CheckEnlarge(boundary, NumOfBdrElements);
1854  boundary[NumOfBdrElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1855  return NumOfBdrElements++;
1856 }
1857 
1858 int Mesh::AddBdrQuad(const int *vi, int attr)
1859 {
1860  CheckEnlarge(boundary, NumOfBdrElements);
1861  boundary[NumOfBdrElements] = new Quadrilateral(vi, attr);
1862  return NumOfBdrElements++;
1863 }
1864 
1865 void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
1866 {
1867  static const int quad_to_tri[2][3] = { { 0, 1, 2 }, { 0, 2, 3 } };
1868  int ti[3];
1869 
1870  for (int i = 0; i < 2; i++)
1871  {
1872  for (int j = 0; j < 3; j++)
1873  {
1874  ti[j] = vi[quad_to_tri[i][j]];
1875  }
1876  AddBdrTriangle(ti, attr);
1877  }
1878 }
1879 
1880 int Mesh::AddBdrPoint(int v, int attr)
1881 {
1882  CheckEnlarge(boundary, NumOfBdrElements);
1883  boundary[NumOfBdrElements] = new Point(&v, attr);
1884  return NumOfBdrElements++;
1885 }
1886 
1887 void Mesh::GenerateBoundaryElements()
1888 {
1889  int i, j;
1890  Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
1891 
1892  // GenerateFaces();
1893 
1894  for (i = 0; i < boundary.Size(); i++)
1895  {
1896  FreeElement(boundary[i]);
1897  }
1898 
1899  if (Dim == 3)
1900  {
1901  delete bel_to_edge;
1902  bel_to_edge = NULL;
1903  }
1904 
1905  // count the 'NumOfBdrElements'
1906  NumOfBdrElements = 0;
1907  for (i = 0; i < faces_info.Size(); i++)
1908  {
1909  if (faces_info[i].Elem2No < 0) { NumOfBdrElements++; }
1910  }
1911 
1912  boundary.SetSize(NumOfBdrElements);
1913  be2face.SetSize(NumOfBdrElements);
1914  for (j = i = 0; i < faces_info.Size(); i++)
1915  {
1916  if (faces_info[i].Elem2No < 0)
1917  {
1918  boundary[j] = faces[i]->Duplicate(this);
1919  be2face[j++] = i;
1920  }
1921  }
1922  // In 3D, 'bel_to_edge' is destroyed but it's not updated.
1923 }
1924 
1925 void Mesh::FinalizeCheck()
1926 {
1927  MFEM_VERIFY(vertices.Size() == NumOfVertices ||
1928  vertices.Size() == 0,
1929  "incorrect number of vertices: preallocated: " << vertices.Size()
1930  << ", actually added: " << NumOfVertices);
1931  MFEM_VERIFY(elements.Size() == NumOfElements,
1932  "incorrect number of elements: preallocated: " << elements.Size()
1933  << ", actually added: " << NumOfElements);
1934  MFEM_VERIFY(boundary.Size() == NumOfBdrElements,
1935  "incorrect number of boundary elements: preallocated: "
1936  << boundary.Size() << ", actually added: " << NumOfBdrElements);
1937 }
1938 
1939 void Mesh::FinalizeTriMesh(int generate_edges, int refine, bool fix_orientation)
1940 {
1941  FinalizeCheck();
1942  CheckElementOrientation(fix_orientation);
1943 
1944  if (refine)
1945  {
1946  MarkTriMeshForRefinement();
1947  }
1948 
1949  if (generate_edges)
1950  {
1951  el_to_edge = new Table;
1952  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1953  GenerateFaces();
1954  CheckBdrElementOrientation();
1955  }
1956  else
1957  {
1958  NumOfEdges = 0;
1959  }
1960 
1961  NumOfFaces = 0;
1962 
1963  SetAttributes();
1964 
1965  SetMeshGen();
1966 }
1967 
1968 void Mesh::FinalizeQuadMesh(int generate_edges, int refine,
1969  bool fix_orientation)
1970 {
1971  FinalizeCheck();
1972  if (fix_orientation)
1973  {
1974  CheckElementOrientation(fix_orientation);
1975  }
1976 
1977  if (generate_edges)
1978  {
1979  el_to_edge = new Table;
1980  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1981  GenerateFaces();
1982  CheckBdrElementOrientation();
1983  }
1984  else
1985  {
1986  NumOfEdges = 0;
1987  }
1988 
1989  NumOfFaces = 0;
1990 
1991  SetAttributes();
1992 
1993  SetMeshGen();
1994 }
1995 
1996 
1997 class GeckoProgress : public Gecko::Progress
1998 {
1999  double limit;
2000  mutable StopWatch sw;
2001 public:
2002  GeckoProgress(double limit) : limit(limit) { sw.Start(); }
2003  virtual bool quit() const { return limit > 0 && sw.UserTime() > limit; }
2004 };
2005 
2006 class GeckoVerboseProgress : public GeckoProgress
2007 {
2008  using Float = Gecko::Float;
2009  using Graph = Gecko::Graph;
2010  using uint = Gecko::uint;
2011 public:
2012  GeckoVerboseProgress(double limit) : GeckoProgress(limit) {}
2013 
2014  virtual void beginorder(const Graph* graph, Float cost) const
2015  { mfem::out << "Begin Gecko ordering, cost = " << cost << std::endl; }
2016  virtual void endorder(const Graph* graph, Float cost) const
2017  { mfem::out << "End ordering, cost = " << cost << std::endl; }
2018 
2019  virtual void beginiter(const Graph* graph,
2020  uint iter, uint maxiter, uint window) const
2021  {
2022  mfem::out << "Iteration " << iter << "/" << maxiter << ", window "
2023  << window << std::flush;
2024  }
2025  virtual void enditer(const Graph* graph, Float mincost, Float cost) const
2026  { mfem::out << ", cost = " << cost << endl; }
2027 };
2028 
2029 
2030 double Mesh::GetGeckoElementOrdering(Array<int> &ordering,
2031  int iterations, int window,
2032  int period, int seed, bool verbose,
2033  double time_limit)
2034 {
2035  Gecko::Graph graph;
2036  Gecko::FunctionalGeometric functional; // edge product cost
2037 
2038  GeckoProgress progress(time_limit);
2039  GeckoVerboseProgress vprogress(time_limit);
2040 
2041  // insert elements as nodes in the graph
2042  for (int elemid = 0; elemid < GetNE(); ++elemid)
2043  {
2044  graph.insert_node();
2045  }
2046 
2047  // insert graph edges for element neighbors
2048  // NOTE: indices in Gecko are 1 based hence the +1 on insertion
2049  const Table &my_el_to_el = ElementToElementTable();
2050  for (int elemid = 0; elemid < GetNE(); ++elemid)
2051  {
2052  const int *neighid = my_el_to_el.GetRow(elemid);
2053  for (int i = 0; i < my_el_to_el.RowSize(elemid); ++i)
2054  {
2055  graph.insert_arc(elemid + 1, neighid[i] + 1);
2056  }
2057  }
2058 
2059  // get the ordering from Gecko and copy it into the Array<int>
2060  graph.order(&functional, iterations, window, period, seed,
2061  verbose ? &vprogress : &progress);
2062 
2063  ordering.SetSize(GetNE());
2064  Gecko::Node::Index NE = GetNE();
2065  for (Gecko::Node::Index gnodeid = 1; gnodeid <= NE; ++gnodeid)
2066  {
2067  ordering[gnodeid - 1] = graph.rank(gnodeid);
2068  }
2069 
2070  return graph.cost();
2071 }
2072 
2073 
2074 struct HilbertCmp
2075 {
2076  int coord;
2077  bool dir;
2078  const Array<double> &points;
2079  double mid;
2080 
2081  HilbertCmp(int coord, bool dir, const Array<double> &points, double mid)
2082  : coord(coord), dir(dir), points(points), mid(mid) {}
2083 
2084  bool operator()(int i) const
2085  {
2086  return (points[3*i + coord] < mid) != dir;
2087  }
2088 };
2089 
2090 static void HilbertSort2D(int coord1, // major coordinate to sort points by
2091  bool dir1, // sort coord1 ascending/descending?
2092  bool dir2, // sort coord2 ascending/descending?
2093  const Array<double> &points, int *beg, int *end,
2094  double xmin, double ymin, double xmax, double ymax)
2095 {
2096  if (end - beg <= 1) { return; }
2097 
2098  double xmid = (xmin + xmax)*0.5;
2099  double ymid = (ymin + ymax)*0.5;
2100 
2101  int coord2 = (coord1 + 1) % 2; // the 'other' coordinate
2102 
2103  // sort (partition) points into four quadrants
2104  int *p0 = beg, *p4 = end;
2105  int *p2 = std::partition(p0, p4, HilbertCmp(coord1, dir1, points, xmid));
2106  int *p1 = std::partition(p0, p2, HilbertCmp(coord2, dir2, points, ymid));
2107  int *p3 = std::partition(p2, p4, HilbertCmp(coord2, !dir2, points, ymid));
2108 
2109  if (p1 != p4)
2110  {
2111  HilbertSort2D(coord2, dir2, dir1, points, p0, p1,
2112  ymin, xmin, ymid, xmid);
2113  }
2114  if (p1 != p0 || p2 != p4)
2115  {
2116  HilbertSort2D(coord1, dir1, dir2, points, p1, p2,
2117  xmin, ymid, xmid, ymax);
2118  }
2119  if (p2 != p0 || p3 != p4)
2120  {
2121  HilbertSort2D(coord1, dir1, dir2, points, p2, p3,
2122  xmid, ymid, xmax, ymax);
2123  }
2124  if (p3 != p0)
2125  {
2126  HilbertSort2D(coord2, !dir2, !dir1, points, p3, p4,
2127  ymid, xmax, ymin, xmid);
2128  }
2129 }
2130 
2131 static void HilbertSort3D(int coord1, bool dir1, bool dir2, bool dir3,
2132  const Array<double> &points, int *beg, int *end,
2133  double xmin, double ymin, double zmin,
2134  double xmax, double ymax, double zmax)
2135 {
2136  if (end - beg <= 1) { return; }
2137 
2138  double xmid = (xmin + xmax)*0.5;
2139  double ymid = (ymin + ymax)*0.5;
2140  double zmid = (zmin + zmax)*0.5;
2141 
2142  int coord2 = (coord1 + 1) % 3;
2143  int coord3 = (coord1 + 2) % 3;
2144 
2145  // sort (partition) points into eight octants
2146  int *p0 = beg, *p8 = end;
2147  int *p4 = std::partition(p0, p8, HilbertCmp(coord1, dir1, points, xmid));
2148  int *p2 = std::partition(p0, p4, HilbertCmp(coord2, dir2, points, ymid));
2149  int *p6 = std::partition(p4, p8, HilbertCmp(coord2, !dir2, points, ymid));
2150  int *p1 = std::partition(p0, p2, HilbertCmp(coord3, dir3, points, zmid));
2151  int *p3 = std::partition(p2, p4, HilbertCmp(coord3, !dir3, points, zmid));
2152  int *p5 = std::partition(p4, p6, HilbertCmp(coord3, dir3, points, zmid));
2153  int *p7 = std::partition(p6, p8, HilbertCmp(coord3, !dir3, points, zmid));
2154 
2155  if (p1 != p8)
2156  {
2157  HilbertSort3D(coord3, dir3, dir1, dir2, points, p0, p1,
2158  zmin, xmin, ymin, zmid, xmid, ymid);
2159  }
2160  if (p1 != p0 || p2 != p8)
2161  {
2162  HilbertSort3D(coord2, dir2, dir3, dir1, points, p1, p2,
2163  ymin, zmid, xmin, ymid, zmax, xmid);
2164  }
2165  if (p2 != p0 || p3 != p8)
2166  {
2167  HilbertSort3D(coord2, dir2, dir3, dir1, points, p2, p3,
2168  ymid, zmid, xmin, ymax, zmax, xmid);
2169  }
2170  if (p3 != p0 || p4 != p8)
2171  {
2172  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p3, p4,
2173  xmin, ymax, zmid, xmid, ymid, zmin);
2174  }
2175  if (p4 != p0 || p5 != p8)
2176  {
2177  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p4, p5,
2178  xmid, ymax, zmid, xmax, ymid, zmin);
2179  }
2180  if (p5 != p0 || p6 != p8)
2181  {
2182  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p5, p6,
2183  ymax, zmid, xmax, ymid, zmax, xmid);
2184  }
2185  if (p6 != p0 || p7 != p8)
2186  {
2187  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p6, p7,
2188  ymid, zmid, xmax, ymin, zmax, xmid);
2189  }
2190  if (p7 != p0)
2191  {
2192  HilbertSort3D(coord3, !dir3, !dir1, dir2, points, p7, p8,
2193  zmid, xmax, ymin, zmin, xmid, ymid);
2194  }
2195 }
2196 
2197 void Mesh::GetHilbertElementOrdering(Array<int> &ordering)
2198 {
2199  MFEM_VERIFY(spaceDim <= 3, "");
2200 
2201  Vector min, max, center;
2202  GetBoundingBox(min, max);
2203 
2204  Array<int> indices(GetNE());
2205  Array<double> points(3*GetNE());
2206 
2207  if (spaceDim < 3) { points = 0.0; }
2208 
2209  // calculate element centers
2210  for (int i = 0; i < GetNE(); i++)
2211  {
2212  GetElementCenter(i, center);
2213  for (int j = 0; j < spaceDim; j++)
2214  {
2215  points[3*i + j] = center(j);
2216  }
2217  indices[i] = i;
2218  }
2219 
2220  if (spaceDim == 1)
2221  {
2222  indices.Sort([&](int a, int b)
2223  { return points[3*a] < points[3*b]; });
2224  }
2225  else if (spaceDim == 2)
2226  {
2227  // recursively partition the points in 2D
2228  HilbertSort2D(0, false, false,
2229  points, indices.begin(), indices.end(),
2230  min(0), min(1), max(0), max(1));
2231  }
2232  else
2233  {
2234  // recursively partition the points in 3D
2235  HilbertSort3D(0, false, false, false,
2236  points, indices.begin(), indices.end(),
2237  min(0), min(1), min(2), max(0), max(1), max(2));
2238  }
2239 
2240  // return ordering in the format required by ReorderElements
2241  ordering.SetSize(GetNE());
2242  for (int i = 0; i < GetNE(); i++)
2243  {
2244  ordering[indices[i]] = i;
2245  }
2246 }
2247 
2248 
2249 void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
2250 {
2251  if (NURBSext)
2252  {
2253  MFEM_WARNING("element reordering of NURBS meshes is not supported.");
2254  return;
2255  }
2256  if (ncmesh)
2257  {
2258  MFEM_WARNING("element reordering of non-conforming meshes is not"
2259  " supported.");
2260  return;
2261  }
2262  MFEM_VERIFY(ordering.Size() == GetNE(), "invalid reordering array.")
2263 
2264  // Data members that need to be updated:
2265 
2266  // - elements - reorder of the pointers and the vertex ids if reordering
2267  // the vertices
2268  // - vertices - if reordering the vertices
2269  // - boundary - update the vertex ids, if reordering the vertices
2270  // - faces - regenerate
2271  // - faces_info - regenerate
2272 
2273  // Deleted by DeleteTables():
2274  // - el_to_edge - rebuild in 2D and 3D only
2275  // - el_to_face - rebuild in 3D only
2276  // - bel_to_edge - rebuild in 3D only
2277  // - el_to_el - no need to rebuild
2278  // - face_edge - no need to rebuild
2279  // - edge_vertex - no need to rebuild
2280  // - geom_factors - no need to rebuild
2281 
2282  // - be_to_edge - 2D only
2283  // - be_to_face - 3D only
2284 
2285  // - Nodes
2286 
2287  // Save the locations of the Nodes so we can rebuild them later
2288  Array<Vector*> old_elem_node_vals;
2289  FiniteElementSpace *nodes_fes = NULL;
2290  if (Nodes)
2291  {
2292  old_elem_node_vals.SetSize(GetNE());
2293  nodes_fes = Nodes->FESpace();
2294  Array<int> old_dofs;
2295  Vector vals;
2296  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2297  {
2298  nodes_fes->GetElementVDofs(old_elid, old_dofs);
2299  Nodes->GetSubVector(old_dofs, vals);
2300  old_elem_node_vals[old_elid] = new Vector(vals);
2301  }
2302  }
2303 
2304  // Get the newly ordered elements
2305  Array<Element *> new_elements(GetNE());
2306  for (int old_elid = 0; old_elid < ordering.Size(); ++old_elid)
2307  {
2308  int new_elid = ordering[old_elid];
2309  new_elements[new_elid] = elements[old_elid];
2310  }
2311  mfem::Swap(elements, new_elements);
2312  new_elements.DeleteAll();
2313 
2314  if (reorder_vertices)
2315  {
2316  // Get the new vertex ordering permutation vectors and fill the new
2317  // vertices
2318  Array<int> vertex_ordering(GetNV());
2319  vertex_ordering = -1;
2320  Array<Vertex> new_vertices(GetNV());
2321  int new_vertex_ind = 0;
2322  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2323  {
2324  int *elem_vert = elements[new_elid]->GetVertices();
2325  int nv = elements[new_elid]->GetNVertices();
2326  for (int vi = 0; vi < nv; ++vi)
2327  {
2328  int old_vertex_ind = elem_vert[vi];
2329  if (vertex_ordering[old_vertex_ind] == -1)
2330  {
2331  vertex_ordering[old_vertex_ind] = new_vertex_ind;
2332  new_vertices[new_vertex_ind] = vertices[old_vertex_ind];
2333  new_vertex_ind++;
2334  }
2335  }
2336  }
2337  mfem::Swap(vertices, new_vertices);
2338  new_vertices.DeleteAll();
2339 
2340  // Replace the vertex ids in the elements with the reordered vertex
2341  // numbers
2342  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2343  {
2344  int *elem_vert = elements[new_elid]->GetVertices();
2345  int nv = elements[new_elid]->GetNVertices();
2346  for (int vi = 0; vi < nv; ++vi)
2347  {
2348  elem_vert[vi] = vertex_ordering[elem_vert[vi]];
2349  }
2350  }
2351 
2352  // Replace the vertex ids in the boundary with reordered vertex numbers
2353  for (int belid = 0; belid < GetNBE(); ++belid)
2354  {
2355  int *be_vert = boundary[belid]->GetVertices();
2356  int nv = boundary[belid]->GetNVertices();
2357  for (int vi = 0; vi < nv; ++vi)
2358  {
2359  be_vert[vi] = vertex_ordering[be_vert[vi]];
2360  }
2361  }
2362  }
2363 
2364  // Destroy tables that need to be rebuild
2365  DeleteTables();
2366 
2367  if (Dim > 1)
2368  {
2369  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
2370  el_to_edge = new Table;
2371  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2372  }
2373  if (Dim > 2)
2374  {
2375  // generate el_to_face, be_to_face
2376  GetElementToFaceTable();
2377  }
2378  // Update faces and faces_info
2379  GenerateFaces();
2380 
2381  // Build the nodes from the saved locations if they were around before
2382  if (Nodes)
2383  {
2384  // To force FE space update, we need to increase 'sequence':
2385  sequence++;
2386  last_operation = Mesh::NONE;
2387  nodes_fes->Update(false); // want_transform = false
2388  Nodes->Update(); // just needed to update Nodes->sequence
2389  Array<int> new_dofs;
2390  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2391  {
2392  int new_elid = ordering[old_elid];
2393  nodes_fes->GetElementVDofs(new_elid, new_dofs);
2394  Nodes->SetSubVector(new_dofs, *(old_elem_node_vals[old_elid]));
2395  delete old_elem_node_vals[old_elid];
2396  }
2397  }
2398 }
2399 
2400 
2401 void Mesh::MarkForRefinement()
2402 {
2403  if (meshgen & 1)
2404  {
2405  if (Dim == 2)
2406  {
2407  MarkTriMeshForRefinement();
2408  }
2409  else if (Dim == 3)
2410  {
2411  DSTable v_to_v(NumOfVertices);
2412  GetVertexToVertexTable(v_to_v);
2413  MarkTetMeshForRefinement(v_to_v);
2414  }
2415  }
2416 }
2417 
2418 void Mesh::MarkTriMeshForRefinement()
2419 {
2420  // Mark the longest triangle edge by rotating the indices so that
2421  // vertex 0 - vertex 1 is the longest edge in the triangle.
2422  DenseMatrix pmat;
2423  for (int i = 0; i < NumOfElements; i++)
2424  {
2425  if (elements[i]->GetType() == Element::TRIANGLE)
2426  {
2427  GetPointMatrix(i, pmat);
2428  static_cast<Triangle*>(elements[i])->MarkEdge(pmat);
2429  }
2430  }
2431 }
2432 
2433 void Mesh::GetEdgeOrdering(DSTable &v_to_v, Array<int> &order)
2434 {
2435  NumOfEdges = v_to_v.NumberOfEntries();
2436  order.SetSize(NumOfEdges);
2437  Array<Pair<double, int> > length_idx(NumOfEdges);
2438 
2439  for (int i = 0; i < NumOfVertices; i++)
2440  {
2441  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
2442  {
2443  int j = it.Index();
2444  length_idx[j].one = GetLength(i, it.Column());
2445  length_idx[j].two = j;
2446  }
2447  }
2448 
2449  // Sort by increasing edge-length.
2450  length_idx.Sort();
2451 
2452  for (int i = 0; i < NumOfEdges; i++)
2453  {
2454  order[length_idx[i].two] = i;
2455  }
2456 }
2457 
2458 void Mesh::MarkTetMeshForRefinement(DSTable &v_to_v)
2459 {
2460  // Mark the longest tetrahedral edge by rotating the indices so that
2461  // vertex 0 - vertex 1 is the longest edge in the element.
2462  Array<int> order;
2463  GetEdgeOrdering(v_to_v, order);
2464 
2465  for (int i = 0; i < NumOfElements; i++)
2466  {
2467  if (elements[i]->GetType() == Element::TETRAHEDRON)
2468  {
2469  elements[i]->MarkEdge(v_to_v, order);
2470  }
2471  }
2472  for (int i = 0; i < NumOfBdrElements; i++)
2473  {
2474  if (boundary[i]->GetType() == Element::TRIANGLE)
2475  {
2476  boundary[i]->MarkEdge(v_to_v, order);
2477  }
2478  }
2479 }
2480 
2481 void Mesh::PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
2482 {
2483  if (*old_v_to_v && *old_elem_vert)
2484  {
2485  return;
2486  }
2487 
2488  FiniteElementSpace *fes = Nodes->FESpace();
2489 
2490  if (*old_v_to_v == NULL)
2491  {
2492  bool need_v_to_v = false;
2493  Array<int> dofs;
2494  for (int i = 0; i < GetNEdges(); i++)
2495  {
2496  // Since edge indices may change, we need to permute edge interior dofs
2497  // any time an edge index changes and there is at least one dof on that
2498  // edge.
2499  fes->GetEdgeInteriorDofs(i, dofs);
2500  if (dofs.Size() > 0)
2501  {
2502  need_v_to_v = true;
2503  break;
2504  }
2505  }
2506  if (need_v_to_v)
2507  {
2508  *old_v_to_v = new DSTable(NumOfVertices);
2509  GetVertexToVertexTable(*(*old_v_to_v));
2510  }
2511  }
2512  if (*old_elem_vert == NULL)
2513  {
2514  bool need_elem_vert = false;
2515  Array<int> dofs;
2516  for (int i = 0; i < GetNE(); i++)
2517  {
2518  // Since element indices do not change, we need to permute element
2519  // interior dofs only when there are at least 2 interior dofs in an
2520  // element (assuming the nodal dofs are non-directional).
2521  fes->GetElementInteriorDofs(i, dofs);
2522  if (dofs.Size() > 1)
2523  {
2524  need_elem_vert = true;
2525  break;
2526  }
2527  }
2528  if (need_elem_vert)
2529  {
2530  *old_elem_vert = new Table;
2531  (*old_elem_vert)->MakeI(GetNE());
2532  for (int i = 0; i < GetNE(); i++)
2533  {
2534  (*old_elem_vert)->AddColumnsInRow(i, elements[i]->GetNVertices());
2535  }
2536  (*old_elem_vert)->MakeJ();
2537  for (int i = 0; i < GetNE(); i++)
2538  {
2539  (*old_elem_vert)->AddConnections(i, elements[i]->GetVertices(),
2540  elements[i]->GetNVertices());
2541  }
2542  (*old_elem_vert)->ShiftUpI();
2543  }
2544  }
2545 }
2546 
2547 void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
2548 {
2549  FiniteElementSpace *fes = Nodes->FESpace();
2550  const FiniteElementCollection *fec = fes->FEColl();
2551  Array<int> old_dofs, new_dofs;
2552 
2553  // assuming that all edges have the same number of dofs
2554  if (NumOfEdges) { fes->GetEdgeInteriorDofs(0, old_dofs); }
2555  const int num_edge_dofs = old_dofs.Size();
2556 
2557  // Save the original nodes
2558  const Vector onodes = *Nodes;
2559 
2560  // vertex dofs do not need to be moved
2561  fes->GetVertexDofs(0, old_dofs);
2562  int offset = NumOfVertices * old_dofs.Size();
2563 
2564  // edge dofs:
2565  // edge enumeration may be different but edge orientation is the same
2566  if (num_edge_dofs > 0)
2567  {
2568  DSTable new_v_to_v(NumOfVertices);
2569  GetVertexToVertexTable(new_v_to_v);
2570 
2571  for (int i = 0; i < NumOfVertices; i++)
2572  {
2573  for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it)
2574  {
2575  const int old_i = (*old_v_to_v)(i, it.Column());
2576  const int new_i = it.Index();
2577  if (new_i == old_i) { continue; }
2578 
2579  old_dofs.SetSize(num_edge_dofs);
2580  new_dofs.SetSize(num_edge_dofs);
2581  for (int j = 0; j < num_edge_dofs; j++)
2582  {
2583  old_dofs[j] = offset + old_i * num_edge_dofs + j;
2584  new_dofs[j] = offset + new_i * num_edge_dofs + j;
2585  }
2586  fes->DofsToVDofs(old_dofs);
2587  fes->DofsToVDofs(new_dofs);
2588  for (int j = 0; j < old_dofs.Size(); j++)
2589  {
2590  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2591  }
2592  }
2593  }
2594  offset += NumOfEdges * num_edge_dofs;
2595  }
2596 
2597  // face dofs:
2598  // both enumeration and orientation of the faces may be different
2599  if (fes->GetNFDofs() > 0)
2600  {
2601  // generate the old face-vertex table using the unmodified 'faces'
2602  Table old_face_vertex;
2603  old_face_vertex.MakeI(NumOfFaces);
2604  for (int i = 0; i < NumOfFaces; i++)
2605  {
2606  old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices());
2607  }
2608  old_face_vertex.MakeJ();
2609  for (int i = 0; i < NumOfFaces; i++)
2610  old_face_vertex.AddConnections(i, faces[i]->GetVertices(),
2611  faces[i]->GetNVertices());
2612  old_face_vertex.ShiftUpI();
2613 
2614  // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info'
2615  STable3D *faces_tbl = GetElementToFaceTable(1);
2616  GenerateFaces();
2617 
2618  // compute the new face dof offsets
2619  Array<int> new_fdofs(NumOfFaces+1);
2620  new_fdofs[0] = 0;
2621  for (int i = 0; i < NumOfFaces; i++) // i = old face index
2622  {
2623  const int *old_v = old_face_vertex.GetRow(i);
2624  int new_i; // new face index
2625  switch (old_face_vertex.RowSize(i))
2626  {
2627  case 3:
2628  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2629  break;
2630  case 4:
2631  default:
2632  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2633  break;
2634  }
2635  fes->GetFaceInteriorDofs(i, old_dofs);
2636  new_fdofs[new_i+1] = old_dofs.Size();
2637  }
2638  new_fdofs.PartialSum();
2639 
2640  // loop over the old face numbers
2641  for (int i = 0; i < NumOfFaces; i++)
2642  {
2643  const int *old_v = old_face_vertex.GetRow(i), *new_v;
2644  const int *dof_ord;
2645  int new_i, new_or;
2646  switch (old_face_vertex.RowSize(i))
2647  {
2648  case 3:
2649  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2650  new_v = faces[new_i]->GetVertices();
2651  new_or = GetTriOrientation(old_v, new_v);
2652  dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, new_or);
2653  break;
2654  case 4:
2655  default:
2656  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2657  new_v = faces[new_i]->GetVertices();
2658  new_or = GetQuadOrientation(old_v, new_v);
2659  dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, new_or);
2660  break;
2661  }
2662 
2663  fes->GetFaceInteriorDofs(i, old_dofs);
2664  new_dofs.SetSize(old_dofs.Size());
2665  for (int j = 0; j < old_dofs.Size(); j++)
2666  {
2667  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2668  const int old_j = dof_ord[j];
2669  new_dofs[old_j] = offset + new_fdofs[new_i] + j;
2670  }
2671  fes->DofsToVDofs(old_dofs);
2672  fes->DofsToVDofs(new_dofs);
2673  for (int j = 0; j < old_dofs.Size(); j++)
2674  {
2675  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2676  }
2677  }
2678 
2679  offset += fes->GetNFDofs();
2680  delete faces_tbl;
2681  }
2682 
2683  // element dofs:
2684  // element orientation may be different
2685  if (old_elem_vert) // have elements with 2 or more dofs
2686  {
2687  // matters when the 'fec' is
2688  // (this code is executed only for triangles/tets)
2689  // - Pk on triangles, k >= 4
2690  // - Qk on quads, k >= 3
2691  // - Pk on tets, k >= 5
2692  // - Qk on hexes, k >= 3
2693  // - DG spaces
2694  // - ...
2695 
2696  // loop over all elements
2697  for (int i = 0; i < GetNE(); i++)
2698  {
2699  const int *old_v = old_elem_vert->GetRow(i);
2700  const int *new_v = elements[i]->GetVertices();
2701  const int *dof_ord;
2702  int new_or;
2703  const Geometry::Type geom = elements[i]->GetGeometryType();
2704  switch (geom)
2705  {
2706  case Geometry::SEGMENT:
2707  new_or = (old_v[0] == new_v[0]) ? +1 : -1;
2708  break;
2709  case Geometry::TRIANGLE:
2710  new_or = GetTriOrientation(old_v, new_v);
2711  break;
2712  case Geometry::SQUARE:
2713  new_or = GetQuadOrientation(old_v, new_v);
2714  break;
2715  case Geometry::TETRAHEDRON:
2716  new_or = GetTetOrientation(old_v, new_v);
2717  break;
2718  default:
2719  new_or = 0;
2720  MFEM_ABORT(Geometry::Name[geom] << " elements (" << fec->Name()
2721  << " FE collection) are not supported yet!");
2722  break;
2723  }
2724  dof_ord = fec->DofOrderForOrientation(geom, new_or);
2725  MFEM_VERIFY(dof_ord != NULL,
2726  "FE collection '" << fec->Name()
2727  << "' does not define reordering for "
2728  << Geometry::Name[geom] << " elements!");
2729  fes->GetElementInteriorDofs(i, old_dofs);
2730  new_dofs.SetSize(old_dofs.Size());
2731  for (int j = 0; j < new_dofs.Size(); j++)
2732  {
2733  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2734  const int old_j = dof_ord[j];
2735  new_dofs[old_j] = offset + j;
2736  }
2737  offset += new_dofs.Size();
2738  fes->DofsToVDofs(old_dofs);
2739  fes->DofsToVDofs(new_dofs);
2740  for (int j = 0; j < old_dofs.Size(); j++)
2741  {
2742  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2743  }
2744  }
2745  }
2746 
2747  // Update Tables, faces, etc
2748  if (Dim > 2)
2749  {
2750  if (fes->GetNFDofs() == 0)
2751  {
2752  // needed for FE spaces that have face dofs, even if
2753  // the 'Nodes' do not have face dofs.
2754  GetElementToFaceTable();
2755  GenerateFaces();
2756  }
2757  CheckBdrElementOrientation();
2758  }
2759  if (el_to_edge)
2760  {
2761  // update 'el_to_edge', 'be_to_edge' (2D), 'bel_to_edge' (3D)
2762  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2763  if (Dim == 2)
2764  {
2765  // update 'faces' and 'faces_info'
2766  GenerateFaces();
2767  CheckBdrElementOrientation();
2768  }
2769  }
2770  // To force FE space update, we need to increase 'sequence':
2771  sequence++;
2772  last_operation = Mesh::NONE;
2773  fes->Update(false); // want_transform = false
2774  Nodes->Update(); // just needed to update Nodes->sequence
2775 }
2776 
2777 void Mesh::FinalizeTetMesh(int generate_edges, int refine, bool fix_orientation)
2778 {
2779  FinalizeCheck();
2780  CheckElementOrientation(fix_orientation);
2781 
2782  if (NumOfBdrElements == 0)
2783  {
2784  GetElementToFaceTable();
2785  GenerateFaces();
2786  GenerateBoundaryElements();
2787  }
2788 
2789  if (refine)
2790  {
2791  DSTable v_to_v(NumOfVertices);
2792  GetVertexToVertexTable(v_to_v);
2793  MarkTetMeshForRefinement(v_to_v);
2794  }
2795 
2796  GetElementToFaceTable();
2797  GenerateFaces();
2798 
2799  CheckBdrElementOrientation();
2800 
2801  if (generate_edges == 1)
2802  {
2803  el_to_edge = new Table;
2804  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2805  }
2806  else
2807  {
2808  el_to_edge = NULL; // Not really necessary -- InitTables was called
2809  bel_to_edge = NULL;
2810  NumOfEdges = 0;
2811  }
2812 
2813  SetAttributes();
2814 
2815  SetMeshGen();
2816 }
2817 
2818 void Mesh::FinalizeWedgeMesh(int generate_edges, int refine,
2819  bool fix_orientation)
2820 {
2821  FinalizeCheck();
2822  CheckElementOrientation(fix_orientation);
2823 
2824  if (NumOfBdrElements == 0)
2825  {
2826  GetElementToFaceTable();
2827  GenerateFaces();
2828  GenerateBoundaryElements();
2829  }
2830 
2831  GetElementToFaceTable();
2832  GenerateFaces();
2833 
2834  CheckBdrElementOrientation();
2835 
2836  if (generate_edges == 1)
2837  {
2838  el_to_edge = new Table;
2839  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2840  }
2841  else
2842  {
2843  el_to_edge = NULL; // Not really necessary -- InitTables was called
2844  bel_to_edge = NULL;
2845  NumOfEdges = 0;
2846  }
2847 
2848  SetAttributes();
2849 
2850  SetMeshGen();
2851 }
2852 
2853 void Mesh::FinalizeHexMesh(int generate_edges, int refine, bool fix_orientation)
2854 {
2855  FinalizeCheck();
2856  CheckElementOrientation(fix_orientation);
2857 
2858  GetElementToFaceTable();
2859  GenerateFaces();
2860 
2861  if (NumOfBdrElements == 0)
2862  {
2863  GenerateBoundaryElements();
2864  }
2865 
2866  CheckBdrElementOrientation();
2867 
2868  if (generate_edges)
2869  {
2870  el_to_edge = new Table;
2871  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2872  }
2873  else
2874  {
2875  NumOfEdges = 0;
2876  }
2877 
2878  SetAttributes();
2879 
2880  SetMeshGen();
2881 }
2882 
2883 void Mesh::FinalizeMesh(int refine, bool fix_orientation)
2884 {
2885  FinalizeTopology();
2886 
2887  Finalize(refine, fix_orientation);
2888 }
2889 
2890 void Mesh::FinalizeTopology(bool generate_bdr)
2891 {
2892  // Requirements: the following should be defined:
2893  // 1) Dim
2894  // 2) NumOfElements, elements
2895  // 3) NumOfBdrElements, boundary
2896  // 4) NumOfVertices
2897  // Optional:
2898  // 2) ncmesh may be defined
2899  // 3) el_to_edge may be allocated (it will be re-computed)
2900 
2901  FinalizeCheck();
2902  bool generate_edges = true;
2903 
2904  if (spaceDim == 0) { spaceDim = Dim; }
2905  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
2906 
2907  // if the user defined any hanging nodes (see AddVertexParent),
2908  // we're initializing a non-conforming mesh
2909  if (tmp_vertex_parents.Size())
2910  {
2911  MFEM_VERIFY(ncmesh == NULL, "");
2912  ncmesh = new NCMesh(this);
2913 
2914  // we need to recreate the Mesh because NCMesh reorders the vertices
2915  // (see NCMesh::UpdateVertices())
2916  InitFromNCMesh(*ncmesh);
2917  ncmesh->OnMeshUpdated(this);
2918  GenerateNCFaceInfo();
2919 
2920  SetAttributes();
2921 
2922  tmp_vertex_parents.DeleteAll();
2923  return;
2924  }
2925 
2926  // set the mesh type: 'meshgen', ...
2927  SetMeshGen();
2928 
2929  // generate the faces
2930  if (Dim > 2)
2931  {
2932  GetElementToFaceTable();
2933  GenerateFaces();
2934  if (NumOfBdrElements == 0 && generate_bdr)
2935  {
2936  GenerateBoundaryElements();
2937  GetElementToFaceTable(); // update be_to_face
2938  }
2939  }
2940  else
2941  {
2942  NumOfFaces = 0;
2943  }
2944 
2945  // generate edges if requested
2946  if (Dim > 1 && generate_edges)
2947  {
2948  // el_to_edge may already be allocated (P2 VTK meshes)
2949  if (!el_to_edge) { el_to_edge = new Table; }
2950  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2951  if (Dim == 2)
2952  {
2953  GenerateFaces(); // 'Faces' in 2D refers to the edges
2954  if (NumOfBdrElements == 0 && generate_bdr)
2955  {
2956  GenerateBoundaryElements();
2957  }
2958  }
2959  }
2960  else
2961  {
2962  NumOfEdges = 0;
2963  }
2964 
2965  if (Dim == 1)
2966  {
2967  GenerateFaces();
2968  }
2969 
2970  if (ncmesh)
2971  {
2972  // tell NCMesh the numbering of edges/faces
2973  ncmesh->OnMeshUpdated(this);
2974 
2975  // update faces_info with NC relations
2976  GenerateNCFaceInfo();
2977  }
2978 
2979  // generate the arrays 'attributes' and 'bdr_attributes'
2980  SetAttributes();
2981 }
2982 
2983 void Mesh::Finalize(bool refine, bool fix_orientation)
2984 {
2985  if (NURBSext || ncmesh)
2986  {
2987  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
2988  MFEM_ASSERT(CheckBdrElementOrientation() == 0, "");
2989  return;
2990  }
2991 
2992  // Requirements:
2993  // 1) FinalizeTopology() or equivalent was called
2994  // 2) if (Nodes == NULL), vertices must be defined
2995  // 3) if (Nodes != NULL), Nodes must be defined
2996 
2997  const bool check_orientation = true; // for regular elements, not boundary
2998  const bool curved = (Nodes != NULL);
2999  const bool may_change_topology =
3000  ( refine && (Dim > 1 && (meshgen & 1)) ) ||
3001  ( check_orientation && fix_orientation &&
3002  (Dim == 2 || (Dim == 3 && (meshgen & 1))) );
3003 
3004  DSTable *old_v_to_v = NULL;
3005  Table *old_elem_vert = NULL;
3006 
3007  if (curved && may_change_topology)
3008  {
3009  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
3010  }
3011 
3012  if (check_orientation)
3013  {
3014  // check and optionally fix element orientation
3015  CheckElementOrientation(fix_orientation);
3016  }
3017  if (refine)
3018  {
3019  MarkForRefinement(); // may change topology!
3020  }
3021 
3022  if (may_change_topology)
3023  {
3024  if (curved)
3025  {
3026  DoNodeReorder(old_v_to_v, old_elem_vert); // updates the mesh topology
3027  delete old_elem_vert;
3028  delete old_v_to_v;
3029  }
3030  else
3031  {
3032  FinalizeTopology(); // Re-computes some data unnecessarily.
3033  }
3034 
3035  // TODO: maybe introduce Mesh::NODE_REORDER operation and FESpace::
3036  // NodeReorderMatrix and do Nodes->Update() instead of DoNodeReorder?
3037  }
3038 
3039  // check and fix boundary element orientation
3040  CheckBdrElementOrientation();
3041 
3042 #ifdef MFEM_DEBUG
3043  // For non-orientable surfaces/manifolds, the check below will fail, so we
3044  // only perform it when Dim == spaceDim.
3045  if (Dim >= 2 && Dim == spaceDim)
3046  {
3047  const int num_faces = GetNumFaces();
3048  for (int i = 0; i < num_faces; i++)
3049  {
3050  MFEM_VERIFY(faces_info[i].Elem2No < 0 ||
3051  faces_info[i].Elem2Inf%2 != 0, "Invalid mesh topology."
3052  " Interior face with incompatible orientations.");
3053  }
3054  }
3055 #endif
3056 }
3057 
3058 void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
3059  double sx, double sy, double sz, bool sfc_ordering)
3060 {
3061  int x, y, z;
3062 
3063  int NVert, NElem, NBdrElem;
3064 
3065  NVert = (nx+1) * (ny+1) * (nz+1);
3066  NElem = nx * ny * nz;
3067  NBdrElem = 2*(nx*ny+nx*nz+ny*nz);
3068  if (type == Element::TETRAHEDRON)
3069  {
3070  NElem *= 6;
3071  NBdrElem *= 2;
3072  }
3073  else if (type == Element::WEDGE)
3074  {
3075  NElem *= 2;
3076  NBdrElem += 2*nx*ny;
3077  }
3078  else if (type == Element::PYRAMID)
3079  {
3080  NElem *= 6;
3081  NVert += nx * ny * nz;
3082  }
3083 
3084  InitMesh(3, 3, NVert, NElem, NBdrElem);
3085 
3086  double coord[3];
3087  int ind[9];
3088 
3089  // Sets vertices and the corresponding coordinates
3090  for (z = 0; z <= nz; z++)
3091  {
3092  coord[2] = ((double) z / nz) * sz;
3093  for (y = 0; y <= ny; y++)
3094  {
3095  coord[1] = ((double) y / ny) * sy;
3096  for (x = 0; x <= nx; x++)
3097  {
3098  coord[0] = ((double) x / nx) * sx;
3099  AddVertex(coord);
3100  }
3101  }
3102  }
3103  if (type == Element::PYRAMID)
3104  {
3105  for (z = 0; z < nz; z++)
3106  {
3107  coord[2] = (((double) z + 0.5) / nz) * sz;
3108  for (y = 0; y < ny; y++)
3109  {
3110  coord[1] = (((double) y + 0.5 ) / ny) * sy;
3111  for (x = 0; x < nx; x++)
3112  {
3113  coord[0] = (((double) x + 0.5 ) / nx) * sx;
3114  AddVertex(coord);
3115  }
3116  }
3117  }
3118  }
3119 
3120 #define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
3121 #define VTXP(XC, YC, ZC) ((nx+1)*(ny+1)*(nz+1)+(XC)+((YC)+(ZC)*ny)*nx)
3122 
3123  // Sets elements and the corresponding indices of vertices
3124  if (sfc_ordering && type == Element::HEXAHEDRON)
3125  {
3126  Array<int> sfc;
3127  NCMesh::GridSfcOrdering3D(nx, ny, nz, sfc);
3128  MFEM_VERIFY(sfc.Size() == 3*nx*ny*nz, "");
3129 
3130  for (int k = 0; k < nx*ny*nz; k++)
3131  {
3132  x = sfc[3*k + 0];
3133  y = sfc[3*k + 1];
3134  z = sfc[3*k + 2];
3135 
3136  // *INDENT-OFF*
3137  ind[0] = VTX(x , y , z );
3138  ind[1] = VTX(x+1, y , z );
3139  ind[2] = VTX(x+1, y+1, z );
3140  ind[3] = VTX(x , y+1, z );
3141  ind[4] = VTX(x , y , z+1);
3142  ind[5] = VTX(x+1, y , z+1);
3143  ind[6] = VTX(x+1, y+1, z+1);
3144  ind[7] = VTX(x , y+1, z+1);
3145  // *INDENT-ON*
3146 
3147  AddHex(ind, 1);
3148  }
3149  }
3150  else
3151  {
3152  for (z = 0; z < nz; z++)
3153  {
3154  for (y = 0; y < ny; y++)
3155  {
3156  for (x = 0; x < nx; x++)
3157  {
3158  // *INDENT-OFF*
3159  ind[0] = VTX(x , y , z );
3160  ind[1] = VTX(x+1, y , z );
3161  ind[2] = VTX(x+1, y+1, z );
3162  ind[3] = VTX(x , y+1, z );
3163  ind[4] = VTX(x , y , z+1);
3164  ind[5] = VTX(x+1, y , z+1);
3165  ind[6] = VTX(x+1, y+1, z+1);
3166  ind[7] = VTX( x, y+1, z+1);
3167  // *INDENT-ON*
3168  if (type == Element::TETRAHEDRON)
3169  {
3170  AddHexAsTets(ind, 1);
3171  }
3172  else if (type == Element::WEDGE)
3173  {
3174  AddHexAsWedges(ind, 1);
3175  }
3176  else if (type == Element::PYRAMID)
3177  {
3178  ind[8] = VTXP(x, y, z);
3179  AddHexAsPyramids(ind, 1);
3180  }
3181  else
3182  {
3183  AddHex(ind, 1);
3184  }
3185  }
3186  }
3187  }
3188  }
3189 
3190  // Sets boundary elements and the corresponding indices of vertices
3191  // bottom, bdr. attribute 1
3192  for (y = 0; y < ny; y++)
3193  {
3194  for (x = 0; x < nx; x++)
3195  {
3196  // *INDENT-OFF*
3197  ind[0] = VTX(x , y , 0);
3198  ind[1] = VTX(x , y+1, 0);
3199  ind[2] = VTX(x+1, y+1, 0);
3200  ind[3] = VTX(x+1, y , 0);
3201  // *INDENT-ON*
3202  if (type == Element::TETRAHEDRON)
3203  {
3204  AddBdrQuadAsTriangles(ind, 1);
3205  }
3206  else if (type == Element::WEDGE)
3207  {
3208  AddBdrQuadAsTriangles(ind, 1);
3209  }
3210  else
3211  {
3212  AddBdrQuad(ind, 1);
3213  }
3214  }
3215  }
3216  // top, bdr. attribute 6
3217  for (y = 0; y < ny; y++)
3218  {
3219  for (x = 0; x < nx; x++)
3220  {
3221  // *INDENT-OFF*
3222  ind[0] = VTX(x , y , nz);
3223  ind[1] = VTX(x+1, y , nz);
3224  ind[2] = VTX(x+1, y+1, nz);
3225  ind[3] = VTX(x , y+1, nz);
3226  // *INDENT-ON*
3227  if (type == Element::TETRAHEDRON)
3228  {
3229  AddBdrQuadAsTriangles(ind, 6);
3230  }
3231  else if (type == Element::WEDGE)
3232  {
3233  AddBdrQuadAsTriangles(ind, 6);
3234  }
3235  else
3236  {
3237  AddBdrQuad(ind, 6);
3238  }
3239  }
3240  }
3241  // left, bdr. attribute 5
3242  for (z = 0; z < nz; z++)
3243  {
3244  for (y = 0; y < ny; y++)
3245  {
3246  // *INDENT-OFF*
3247  ind[0] = VTX(0 , y , z );
3248  ind[1] = VTX(0 , y , z+1);
3249  ind[2] = VTX(0 , y+1, z+1);
3250  ind[3] = VTX(0 , y+1, z );
3251  // *INDENT-ON*
3252  if (type == Element::TETRAHEDRON)
3253  {
3254  AddBdrQuadAsTriangles(ind, 5);
3255  }
3256  else
3257  {
3258  AddBdrQuad(ind, 5);
3259  }
3260  }
3261  }
3262  // right, bdr. attribute 3
3263  for (z = 0; z < nz; z++)
3264  {
3265  for (y = 0; y < ny; y++)
3266  {
3267  // *INDENT-OFF*
3268  ind[0] = VTX(nx, y , z );
3269  ind[1] = VTX(nx, y+1, z );
3270  ind[2] = VTX(nx, y+1, z+1);
3271  ind[3] = VTX(nx, y , z+1);
3272  // *INDENT-ON*
3273  if (type == Element::TETRAHEDRON)
3274  {
3275  AddBdrQuadAsTriangles(ind, 3);
3276  }
3277  else
3278  {
3279  AddBdrQuad(ind, 3);
3280  }
3281  }
3282  }
3283  // front, bdr. attribute 2
3284  for (x = 0; x < nx; x++)
3285  {
3286  for (z = 0; z < nz; z++)
3287  {
3288  // *INDENT-OFF*
3289  ind[0] = VTX(x , 0, z );
3290  ind[1] = VTX(x+1, 0, z );
3291  ind[2] = VTX(x+1, 0, z+1);
3292  ind[3] = VTX(x , 0, z+1);
3293  // *INDENT-ON*
3294  if (type == Element::TETRAHEDRON)
3295  {
3296  AddBdrQuadAsTriangles(ind, 2);
3297  }
3298  else
3299  {
3300  AddBdrQuad(ind, 2);
3301  }
3302  }
3303  }
3304  // back, bdr. attribute 4
3305  for (x = 0; x < nx; x++)
3306  {
3307  for (z = 0; z < nz; z++)
3308  {
3309  // *INDENT-OFF*
3310  ind[0] = VTX(x , ny, z );
3311  ind[1] = VTX(x , ny, z+1);
3312  ind[2] = VTX(x+1, ny, z+1);
3313  ind[3] = VTX(x+1, ny, z );
3314  // *INDENT-ON*
3315  if (type == Element::TETRAHEDRON)
3316  {
3317  AddBdrQuadAsTriangles(ind, 4);
3318  }
3319  else
3320  {
3321  AddBdrQuad(ind, 4);
3322  }
3323  }
3324  }
3325 
3326 #undef VTX
3327 
3328 #if 0
3329  ofstream test_stream("debug.mesh");
3330  Print(test_stream);
3331  test_stream.close();
3332 #endif
3333 
3334  FinalizeTopology();
3335 
3336  // Finalize(...) can be called after this method, if needed
3337 }
3338 
3339 void Mesh::Make2D(int nx, int ny, Element::Type type,
3340  double sx, double sy,
3341  bool generate_edges, bool sfc_ordering)
3342 {
3343  int i, j, k;
3344 
3345  SetEmpty();
3346 
3347  Dim = spaceDim = 2;
3348 
3349  // Creates quadrilateral mesh
3350  if (type == Element::QUADRILATERAL)
3351  {
3352  NumOfVertices = (nx+1) * (ny+1);
3353  NumOfElements = nx * ny;
3354  NumOfBdrElements = 2 * nx + 2 * ny;
3355 
3356  vertices.SetSize(NumOfVertices);
3357  elements.SetSize(NumOfElements);
3358  boundary.SetSize(NumOfBdrElements);
3359 
3360  double cx, cy;
3361  int ind[4];
3362 
3363  // Sets vertices and the corresponding coordinates
3364  k = 0;
3365  for (j = 0; j < ny+1; j++)
3366  {
3367  cy = ((double) j / ny) * sy;
3368  for (i = 0; i < nx+1; i++)
3369  {
3370  cx = ((double) i / nx) * sx;
3371  vertices[k](0) = cx;
3372  vertices[k](1) = cy;
3373  k++;
3374  }
3375  }
3376 
3377  // Sets elements and the corresponding indices of vertices
3378  if (sfc_ordering)
3379  {
3380  Array<int> sfc;
3381  NCMesh::GridSfcOrdering2D(nx, ny, sfc);
3382  MFEM_VERIFY(sfc.Size() == 2*nx*ny, "");
3383 
3384  for (k = 0; k < nx*ny; k++)
3385  {
3386  i = sfc[2*k + 0];
3387  j = sfc[2*k + 1];
3388  ind[0] = i + j*(nx+1);
3389  ind[1] = i + 1 +j*(nx+1);
3390  ind[2] = i + 1 + (j+1)*(nx+1);
3391  ind[3] = i + (j+1)*(nx+1);
3392  elements[k] = new Quadrilateral(ind);
3393  }
3394  }
3395  else
3396  {
3397  k = 0;
3398  for (j = 0; j < ny; j++)
3399  {
3400  for (i = 0; i < nx; i++)
3401  {
3402  ind[0] = i + j*(nx+1);
3403  ind[1] = i + 1 +j*(nx+1);
3404  ind[2] = i + 1 + (j+1)*(nx+1);
3405  ind[3] = i + (j+1)*(nx+1);
3406  elements[k] = new Quadrilateral(ind);
3407  k++;
3408  }
3409  }
3410  }
3411 
3412  // Sets boundary elements and the corresponding indices of vertices
3413  int m = (nx+1)*ny;
3414  for (i = 0; i < nx; i++)
3415  {
3416  boundary[i] = new Segment(i, i+1, 1);
3417  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3418  }
3419  m = nx+1;
3420  for (j = 0; j < ny; j++)
3421  {
3422  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3423  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3424  }
3425  }
3426  // Creates triangular mesh
3427  else if (type == Element::TRIANGLE)
3428  {
3429  NumOfVertices = (nx+1) * (ny+1);
3430  NumOfElements = 2 * nx * ny;
3431  NumOfBdrElements = 2 * nx + 2 * ny;
3432 
3433  vertices.SetSize(NumOfVertices);
3434  elements.SetSize(NumOfElements);
3435  boundary.SetSize(NumOfBdrElements);
3436 
3437  double cx, cy;
3438  int ind[3];
3439 
3440  // Sets vertices and the corresponding coordinates
3441  k = 0;
3442  for (j = 0; j < ny+1; j++)
3443  {
3444  cy = ((double) j / ny) * sy;
3445  for (i = 0; i < nx+1; i++)
3446  {
3447  cx = ((double) i / nx) * sx;
3448  vertices[k](0) = cx;
3449  vertices[k](1) = cy;
3450  k++;
3451  }
3452  }
3453 
3454  // Sets the elements and the corresponding indices of vertices
3455  k = 0;
3456  for (j = 0; j < ny; j++)
3457  {
3458  for (i = 0; i < nx; i++)
3459  {
3460  ind[0] = i + j*(nx+1);
3461  ind[1] = i + 1 + (j+1)*(nx+1);
3462  ind[2] = i + (j+1)*(nx+1);
3463  elements[k] = new Triangle(ind);
3464  k++;
3465  ind[1] = i + 1 + j*(nx+1);
3466  ind[2] = i + 1 + (j+1)*(nx+1);
3467  elements[k] = new Triangle(ind);
3468  k++;
3469  }
3470  }
3471 
3472  // Sets boundary elements and the corresponding indices of vertices
3473  int m = (nx+1)*ny;
3474  for (i = 0; i < nx; i++)
3475  {
3476  boundary[i] = new Segment(i, i+1, 1);
3477  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3478  }
3479  m = nx+1;
3480  for (j = 0; j < ny; j++)
3481  {
3482  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3483  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3484  }
3485 
3486  // MarkTriMeshForRefinement(); // done in Finalize(...)
3487  }
3488  else
3489  {
3490  MFEM_ABORT("Unsupported element type.");
3491  }
3492 
3493  SetMeshGen();
3494  CheckElementOrientation();
3495 
3496  if (generate_edges == 1)
3497  {
3498  el_to_edge = new Table;
3499  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3500  GenerateFaces();
3501  CheckBdrElementOrientation();
3502  }
3503  else
3504  {
3505  NumOfEdges = 0;
3506  }
3507 
3508  NumOfFaces = 0;
3509 
3510  attributes.Append(1);
3511  bdr_attributes.Append(1); bdr_attributes.Append(2);
3512  bdr_attributes.Append(3); bdr_attributes.Append(4);
3513 
3514  // Finalize(...) can be called after this method, if needed
3515 }
3516 
3517 void Mesh::Make1D(int n, double sx)
3518 {
3519  int j, ind[1];
3520 
3521  SetEmpty();
3522 
3523  Dim = 1;
3524  spaceDim = 1;
3525 
3526  NumOfVertices = n + 1;
3527  NumOfElements = n;
3528  NumOfBdrElements = 2;
3529  vertices.SetSize(NumOfVertices);
3530  elements.SetSize(NumOfElements);
3531  boundary.SetSize(NumOfBdrElements);
3532 
3533  // Sets vertices and the corresponding coordinates
3534  for (j = 0; j < n+1; j++)
3535  {
3536  vertices[j](0) = ((double) j / n) * sx;
3537  }
3538 
3539  // Sets elements and the corresponding indices of vertices
3540  for (j = 0; j < n; j++)
3541  {
3542  elements[j] = new Segment(j, j+1, 1);
3543  }
3544 
3545  // Sets the boundary elements
3546  ind[0] = 0;
3547  boundary[0] = new Point(ind, 1);
3548  ind[0] = n;
3549  boundary[1] = new Point(ind, 2);
3550 
3551  NumOfEdges = 0;
3552  NumOfFaces = 0;
3553 
3554  SetMeshGen();
3555  GenerateFaces();
3556 
3557  attributes.Append(1);
3558  bdr_attributes.Append(1); bdr_attributes.Append(2);
3559 }
3560 
3561 Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
3562 {
3563  Dim = mesh.Dim;
3564  spaceDim = mesh.spaceDim;
3565 
3566  NumOfVertices = mesh.NumOfVertices;
3567  NumOfElements = mesh.NumOfElements;
3568  NumOfBdrElements = mesh.NumOfBdrElements;
3569  NumOfEdges = mesh.NumOfEdges;
3570  NumOfFaces = mesh.NumOfFaces;
3571  nbInteriorFaces = mesh.nbInteriorFaces;
3572  nbBoundaryFaces = mesh.nbBoundaryFaces;
3573 
3574  meshgen = mesh.meshgen;
3575  mesh_geoms = mesh.mesh_geoms;
3576 
3577  // Create the new Mesh instance without a record of its refinement history
3578  sequence = 0;
3579  last_operation = Mesh::NONE;
3580 
3581  // Duplicate the elements
3582  elements.SetSize(NumOfElements);
3583  for (int i = 0; i < NumOfElements; i++)
3584  {
3585  elements[i] = mesh.elements[i]->Duplicate(this);
3586  }
3587 
3588  // Copy the vertices
3589  mesh.vertices.Copy(vertices);
3590 
3591  // Duplicate the boundary
3592  boundary.SetSize(NumOfBdrElements);
3593  for (int i = 0; i < NumOfBdrElements; i++)
3594  {
3595  boundary[i] = mesh.boundary[i]->Duplicate(this);
3596  }
3597 
3598  // Copy the element-to-face Table, el_to_face
3599  el_to_face = (mesh.el_to_face) ? new Table(*mesh.el_to_face) : NULL;
3600 
3601  // Copy the boundary-to-face Array, be_to_face.
3602  mesh.be_to_face.Copy(be_to_face);
3603 
3604  // Copy the element-to-edge Table, el_to_edge
3605  el_to_edge = (mesh.el_to_edge) ? new Table(*mesh.el_to_edge) : NULL;
3606 
3607  // Copy the boundary-to-edge Table, bel_to_edge (3D)
3608  bel_to_edge = (mesh.bel_to_edge) ? new Table(*mesh.bel_to_edge) : NULL;
3609 
3610  // Copy the boundary-to-edge Array, be_to_edge (2D)
3611  mesh.be_to_edge.Copy(be_to_edge);
3612 
3613  // Duplicate the faces and faces_info.
3614  faces.SetSize(mesh.faces.Size());
3615  for (int i = 0; i < faces.Size(); i++)
3616  {
3617  Element *face = mesh.faces[i]; // in 1D the faces are NULL
3618  faces[i] = (face) ? face->Duplicate(this) : NULL;
3619  }
3620  mesh.faces_info.Copy(faces_info);
3621  mesh.nc_faces_info.Copy(nc_faces_info);
3622 
3623  // Do NOT copy the element-to-element Table, el_to_el
3624  el_to_el = NULL;
3625 
3626  // Do NOT copy the face-to-edge Table, face_edge
3627  face_edge = NULL;
3628 
3629  // Copy the edge-to-vertex Table, edge_vertex
3630  edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
3631 
3632  // Copy the attributes and bdr_attributes
3633  mesh.attributes.Copy(attributes);
3634  mesh.bdr_attributes.Copy(bdr_attributes);
3635 
3636  // Deep copy the NURBSExtension.
3637 #ifdef MFEM_USE_MPI
3638  ParNURBSExtension *pNURBSext =
3639  dynamic_cast<ParNURBSExtension *>(mesh.NURBSext);
3640  if (pNURBSext)
3641  {
3642  NURBSext = new ParNURBSExtension(*pNURBSext);
3643  }
3644  else
3645 #endif
3646  {
3647  NURBSext = mesh.NURBSext ? new NURBSExtension(*mesh.NURBSext) : NULL;
3648  }
3649 
3650  // Deep copy the NCMesh.
3651 #ifdef MFEM_USE_MPI
3652  if (dynamic_cast<const ParMesh*>(&mesh))
3653  {
3654  ncmesh = NULL; // skip; will be done in ParMesh copy ctor
3655  }
3656  else
3657 #endif
3658  {
3659  ncmesh = mesh.ncmesh ? new NCMesh(*mesh.ncmesh) : NULL;
3660  }
3661 
3662  // Duplicate the Nodes, including the FiniteElementCollection and the
3663  // FiniteElementSpace
3664  if (mesh.Nodes && copy_nodes)
3665  {
3666  FiniteElementSpace *fes = mesh.Nodes->FESpace();
3667  const FiniteElementCollection *fec = fes->FEColl();
3668  FiniteElementCollection *fec_copy =
3669  FiniteElementCollection::New(fec->Name());
3670  FiniteElementSpace *fes_copy =
3671  new FiniteElementSpace(*fes, this, fec_copy);
3672  Nodes = new GridFunction(fes_copy);
3673  Nodes->MakeOwner(fec_copy);
3674  *Nodes = *mesh.Nodes;
3675  own_nodes = 1;
3676  }
3677  else
3678  {
3679  Nodes = mesh.Nodes;
3680  own_nodes = 0;
3681  }
3682 }
3683 
3684 Mesh::Mesh(Mesh &&mesh) : Mesh()
3685 {
3686  Swap(mesh, true);
3687 }
3688 
3690 {
3691  Swap(mesh, true);
3692  return *this;
3693 }
3694 
3695 Mesh Mesh::LoadFromFile(const char *filename, int generate_edges, int refine,
3696  bool fix_orientation)
3697 {
3698  Mesh mesh;
3699  named_ifgzstream imesh(filename);
3700  if (!imesh) { MFEM_ABORT("Mesh file not found: " << filename << '\n'); }
3701  else { mesh.Load(imesh, generate_edges, refine, fix_orientation); }
3702  return mesh;
3703 }
3704 
3705 Mesh Mesh::MakeCartesian1D(int n, double sx)
3706 {
3707  Mesh mesh;
3708  mesh.Make1D(n, sx);
3709  // mesh.Finalize(); not needed in this case
3710  return mesh;
3711 }
3712 
3714  int nx, int ny, Element::Type type, bool generate_edges,
3715  double sx, double sy, bool sfc_ordering)
3716 {
3717  Mesh mesh;
3718  mesh.Make2D(nx, ny, type, sx, sy, generate_edges, sfc_ordering);
3719  mesh.Finalize(true); // refine = true
3720  return mesh;
3721 }
3722 
3724  int nx, int ny, int nz, Element::Type type,
3725  double sx, double sy, double sz, bool sfc_ordering)
3726 {
3727  Mesh mesh;
3728  mesh.Make3D(nx, ny, nz, type, sx, sy, sz, sfc_ordering);
3729  mesh.Finalize(true); // refine = true
3730  return mesh;
3731 }
3732 
3733 Mesh Mesh::MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
3734 {
3735  Mesh mesh;
3736  Array<int> ref_factors(orig_mesh.GetNE());
3737  ref_factors = ref_factor;
3738  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3739  return mesh;
3740 }
3741 
3742 Mesh Mesh::MakeRefined(Mesh &orig_mesh, const Array<int> &ref_factors,
3743  int ref_type)
3744 {
3745  Mesh mesh;
3746  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3747  return mesh;
3748 }
3749 
3750 Mesh::Mesh(const char *filename, int generate_edges, int refine,
3751  bool fix_orientation)
3752 {
3753  // Initialization as in the default constructor
3754  SetEmpty();
3755 
3756  named_ifgzstream imesh(filename);
3757  if (!imesh)
3758  {
3759  // Abort with an error message.
3760  MFEM_ABORT("Mesh file not found: " << filename << '\n');
3761  }
3762  else
3763  {
3764  Load(imesh, generate_edges, refine, fix_orientation);
3765  }
3766 }
3767 
3768 Mesh::Mesh(std::istream &input, int generate_edges, int refine,
3769  bool fix_orientation)
3770 {
3771  SetEmpty();
3772  Load(input, generate_edges, refine, fix_orientation);
3773 }
3774 
3775 void Mesh::ChangeVertexDataOwnership(double *vertex_data, int len_vertex_data,
3776  bool zerocopy)
3777 {
3778  // A dimension of 3 is now required since we use mfem::Vertex objects as PODs
3779  // and these object have a hardcoded double[3] entry
3780  MFEM_VERIFY(len_vertex_data >= NumOfVertices * 3,
3781  "Not enough vertices in external array : "
3782  "len_vertex_data = "<< len_vertex_data << ", "
3783  "NumOfVertices * 3 = " << NumOfVertices * 3);
3784  // Allow multiple calls to this method with the same vertex_data
3785  if (vertex_data == (double *)(vertices.GetData()))
3786  {
3787  MFEM_ASSERT(!vertices.OwnsData(), "invalid ownership");
3788  return;
3789  }
3790  if (!zerocopy)
3791  {
3792  memcpy(vertex_data, vertices.GetData(),
3793  NumOfVertices * 3 * sizeof(double));
3794  }
3795  // Vertex is POD double[3]
3796  vertices.MakeRef(reinterpret_cast<Vertex*>(vertex_data), NumOfVertices);
3797 }
3798 
3799 Mesh::Mesh(double *vertices_, int num_vertices,
3800  int *element_indices, Geometry::Type element_type,
3801  int *element_attributes, int num_elements,
3802  int *boundary_indices, Geometry::Type boundary_type,
3803  int *boundary_attributes, int num_boundary_elements,
3804  int dimension, int space_dimension)
3805 {
3806  if (space_dimension == -1)
3807  {
3808  space_dimension = dimension;
3809  }
3810 
3811  InitMesh(dimension, space_dimension, /*num_vertices*/ 0, num_elements,
3812  num_boundary_elements);
3813 
3814  int element_index_stride = Geometry::NumVerts[element_type];
3815  int boundary_index_stride = num_boundary_elements > 0 ?
3816  Geometry::NumVerts[boundary_type] : 0;
3817 
3818  // assuming Vertex is POD
3819  vertices.MakeRef(reinterpret_cast<Vertex*>(vertices_), num_vertices);
3820  NumOfVertices = num_vertices;
3821 
3822  for (int i = 0; i < num_elements; i++)
3823  {
3824  elements[i] = NewElement(element_type);
3825  elements[i]->SetVertices(element_indices + i * element_index_stride);
3826  elements[i]->SetAttribute(element_attributes[i]);
3827  }
3828  NumOfElements = num_elements;
3829 
3830  for (int i = 0; i < num_boundary_elements; i++)
3831  {
3832  boundary[i] = NewElement(boundary_type);
3833  boundary[i]->SetVertices(boundary_indices + i * boundary_index_stride);
3834  boundary[i]->SetAttribute(boundary_attributes[i]);
3835  }
3836  NumOfBdrElements = num_boundary_elements;
3837 
3838  FinalizeTopology();
3839 }
3840 
3842 {
3843  switch (geom)
3844  {
3845  case Geometry::POINT: return (new Point);
3846  case Geometry::SEGMENT: return (new Segment);
3847  case Geometry::TRIANGLE: return (new Triangle);
3848  case Geometry::SQUARE: return (new Quadrilateral);
3849  case Geometry::TETRAHEDRON:
3850 #ifdef MFEM_USE_MEMALLOC
3851  return TetMemory.Alloc();
3852 #else
3853  return (new Tetrahedron);
3854 #endif
3855  case Geometry::CUBE: return (new Hexahedron);
3856  case Geometry::PRISM: return (new Wedge);
3857  case Geometry::PYRAMID: return (new Pyramid);
3858  default:
3859  MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
3860  }
3861 
3862  return NULL;
3863 }
3864 
3866 {
3867  int geom, nv, *v;
3868  Element *el;
3869 
3870  input >> geom;
3871  el = NewElement(geom);
3872  MFEM_VERIFY(el, "Unsupported element type: " << geom);
3873  nv = el->GetNVertices();
3874  v = el->GetVertices();
3875  for (int i = 0; i < nv; i++)
3876  {
3877  input >> v[i];
3878  }
3879 
3880  return el;
3881 }
3882 
3883 void Mesh::PrintElementWithoutAttr(const Element *el, std::ostream &os)
3884 {
3885  os << el->GetGeometryType();
3886  const int nv = el->GetNVertices();
3887  const int *v = el->GetVertices();
3888  for (int j = 0; j < nv; j++)
3889  {
3890  os << ' ' << v[j];
3891  }
3892  os << '\n';
3893 }
3894 
3895 Element *Mesh::ReadElement(std::istream &input)
3896 {
3897  int attr;
3898  Element *el;
3899 
3900  input >> attr;
3901  el = ReadElementWithoutAttr(input);
3902  el->SetAttribute(attr);
3903 
3904  return el;
3905 }
3906 
3907 void Mesh::PrintElement(const Element *el, std::ostream &os)
3908 {
3909  os << el->GetAttribute() << ' ';
3910  PrintElementWithoutAttr(el, os);
3911 }
3912 
3914 {
3915  meshgen = mesh_geoms = 0;
3916  for (int i = 0; i < NumOfElements; i++)
3917  {
3918  const Element::Type type = GetElement(i)->GetType();
3919  switch (type)
3920  {
3921  case Element::TETRAHEDRON:
3923  case Element::TRIANGLE:
3924  mesh_geoms |= (1 << Geometry::TRIANGLE);
3925  case Element::SEGMENT:
3926  mesh_geoms |= (1 << Geometry::SEGMENT);
3927  case Element::POINT:
3928  mesh_geoms |= (1 << Geometry::POINT);
3929  meshgen |= 1;
3930  break;
3931 
3932  case Element::HEXAHEDRON:
3933  mesh_geoms |= (1 << Geometry::CUBE);
3935  mesh_geoms |= (1 << Geometry::SQUARE);
3936  mesh_geoms |= (1 << Geometry::SEGMENT);
3937  mesh_geoms |= (1 << Geometry::POINT);
3938  meshgen |= 2;
3939  break;
3940 
3941  case Element::WEDGE:
3942  mesh_geoms |= (1 << Geometry::PRISM);
3943  mesh_geoms |= (1 << Geometry::SQUARE);
3944  mesh_geoms |= (1 << Geometry::TRIANGLE);
3945  mesh_geoms |= (1 << Geometry::SEGMENT);
3946  mesh_geoms |= (1 << Geometry::POINT);
3947  meshgen |= 4;
3948  break;
3949 
3950  case Element::PYRAMID:
3951  mesh_geoms |= (1 << Geometry::PYRAMID);
3952  mesh_geoms |= (1 << Geometry::SQUARE);
3953  mesh_geoms |= (1 << Geometry::TRIANGLE);
3954  mesh_geoms |= (1 << Geometry::SEGMENT);
3955  mesh_geoms |= (1 << Geometry::POINT);
3956  meshgen |= 8;
3957  break;
3958 
3959  default:
3960  MFEM_ABORT("invalid element type: " << type);
3961  break;
3962  }
3963  }
3964 }
3965 
3966 void Mesh::Loader(std::istream &input, int generate_edges,
3967  std::string parse_tag)
3968 {
3969  int curved = 0, read_gf = 1;
3970  bool finalize_topo = true;
3971 
3972  if (!input)
3973  {
3974  MFEM_ABORT("Input stream is not open");
3975  }
3976 
3977  Clear();
3978 
3979  string mesh_type;
3980  input >> ws;
3981  getline(input, mesh_type);
3982  filter_dos(mesh_type);
3983 
3984  // MFEM's conforming mesh formats
3985  int mfem_version = 0;
3986  if (mesh_type == "MFEM mesh v1.0") { mfem_version = 10; } // serial
3987  else if (mesh_type == "MFEM mesh v1.2") { mfem_version = 12; } // parallel
3988 
3989  // MFEM nonconforming mesh format
3990  // (NOTE: previous v1.1 is now under this branch for backward compatibility)
3991  int mfem_nc_version = 0;
3992  if (mesh_type == "MFEM NC mesh v1.0") { mfem_nc_version = 10; }
3993  else if (mesh_type == "MFEM mesh v1.1") { mfem_nc_version = 1 /*legacy*/; }
3994 
3995  if (mfem_version)
3996  {
3997  // Formats mfem_v12 and newer have a tag indicating the end of the mesh
3998  // section in the stream. A user provided parse tag can also be provided
3999  // via the arguments. For example, if this is called from parallel mesh
4000  // object, it can indicate to read until parallel mesh section begins.
4001  if (mfem_version == 12 && parse_tag.empty())
4002  {
4003  parse_tag = "mfem_mesh_end";
4004  }
4005  ReadMFEMMesh(input, mfem_version, curved);
4006  }
4007  else if (mfem_nc_version)
4008  {
4009  MFEM_ASSERT(ncmesh == NULL, "internal error");
4010  int is_nc = 1;
4011 
4012 #ifdef MFEM_USE_MPI
4013  ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
4014  if (pmesh)
4015  {
4016  MFEM_VERIFY(mfem_nc_version >= 10,
4017  "Legacy nonconforming format (MFEM mesh v1.1) cannot be "
4018  "used to load a parallel nonconforming mesh, sorry.");
4019 
4020  ncmesh = new ParNCMesh(pmesh->GetComm(),
4021  input, mfem_nc_version, curved, is_nc);
4022  }
4023  else
4024 #endif
4025  {
4026  ncmesh = new NCMesh(input, mfem_nc_version, curved, is_nc);
4027  }
4029 
4030  if (!is_nc)
4031  {
4032  // special case for backward compatibility with MFEM <=4.2:
4033  // if the "vertex_parents" section is missing in the v1.1 format,
4034  // the mesh is treated as conforming
4035  delete ncmesh;
4036  ncmesh = NULL;
4037  }
4038  }
4039  else if (mesh_type == "linemesh") // 1D mesh
4040  {
4041  ReadLineMesh(input);
4042  }
4043  else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2")
4044  {
4045  if (mesh_type == "curved_areamesh2")
4046  {
4047  curved = 1;
4048  }
4049  ReadNetgen2DMesh(input, curved);
4050  }
4051  else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format")
4052  {
4053  ReadNetgen3DMesh(input);
4054  }
4055  else if (mesh_type == "TrueGrid")
4056  {
4057  ReadTrueGridMesh(input);
4058  }
4059  else if (mesh_type.rfind("# vtk DataFile Version") == 0)
4060  {
4061  int major_vtk_version = mesh_type[mesh_type.length()-3] - '0';
4062  // int minor_vtk_version = mesh_type[mesh_type.length()-1] - '0';
4063  MFEM_VERIFY(major_vtk_version >= 2 && major_vtk_version <= 4,
4064  "Unsupported VTK format");
4065  ReadVTKMesh(input, curved, read_gf, finalize_topo);
4066  }
4067  else if (mesh_type.rfind("<VTKFile ") == 0 || mesh_type.rfind("<?xml") == 0)
4068  {
4069  ReadXML_VTKMesh(input, curved, read_gf, finalize_topo, mesh_type);
4070  }
4071  else if (mesh_type == "MFEM NURBS mesh v1.0")
4072  {
4073  ReadNURBSMesh(input, curved, read_gf);
4074  }
4075  else if (mesh_type == "MFEM INLINE mesh v1.0")
4076  {
4077  ReadInlineMesh(input, generate_edges);
4078  return; // done with inline mesh construction
4079  }
4080  else if (mesh_type == "$MeshFormat") // Gmsh
4081  {
4082  ReadGmshMesh(input, curved, read_gf);
4083  }
4084  else if
4085  ((mesh_type.size() > 2 &&
4086  mesh_type[0] == 'C' && mesh_type[1] == 'D' && mesh_type[2] == 'F') ||
4087  (mesh_type.size() > 3 &&
4088  mesh_type[1] == 'H' && mesh_type[2] == 'D' && mesh_type[3] == 'F'))
4089  {
4090  named_ifgzstream *mesh_input = dynamic_cast<named_ifgzstream *>(&input);
4091  if (mesh_input)
4092  {
4093 #ifdef MFEM_USE_NETCDF
4094  ReadCubit(mesh_input->filename.c_str(), curved, read_gf);
4095 #else
4096  MFEM_ABORT("NetCDF support requires configuration with"
4097  " MFEM_USE_NETCDF=YES");
4098  return;
4099 #endif
4100  }
4101  else
4102  {
4103  MFEM_ABORT("Can not determine Cubit mesh filename!"
4104  " Use mfem::named_ifgzstream for input.");
4105  return;
4106  }
4107  }
4108  else
4109  {
4110  MFEM_ABORT("Unknown input mesh format: " << mesh_type);
4111  return;
4112  }
4113 
4114  // at this point the following should be defined:
4115  // 1) Dim
4116  // 2) NumOfElements, elements
4117  // 3) NumOfBdrElements, boundary
4118  // 4) NumOfVertices, with allocated space in vertices
4119  // 5) curved
4120  // 5a) if curved == 0, vertices must be defined
4121  // 5b) if curved != 0 and read_gf != 0,
4122  // 'input' must point to a GridFunction
4123  // 5c) if curved != 0 and read_gf == 0,
4124  // vertices and Nodes must be defined
4125  // optional:
4126  // 1) el_to_edge may be allocated (as in the case of P2 VTK meshes)
4127  // 2) ncmesh may be allocated
4128 
4129  // FinalizeTopology() will:
4130  // - assume that generate_edges is true
4131  // - assume that refine is false
4132  // - does not check the orientation of regular and boundary elements
4133  if (finalize_topo)
4134  {
4135  // don't generate any boundary elements, especially in parallel
4136  bool generate_bdr = false;
4137 
4138  FinalizeTopology(generate_bdr);
4139  }
4140 
4141  if (curved && read_gf)
4142  {
4143  Nodes = new GridFunction(this, input);
4144 
4145  own_nodes = 1;
4146  spaceDim = Nodes->VectorDim();
4147  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
4148 
4149  // Set vertex coordinates from the 'Nodes'
4151  }
4152 
4153  // If a parse tag was supplied, keep reading the stream until the tag is
4154  // encountered.
4155  if (mfem_version == 12)
4156  {
4157  string line;
4158  do
4159  {
4160  skip_comment_lines(input, '#');
4161  MFEM_VERIFY(input.good(), "Required mesh-end tag not found");
4162  getline(input, line);
4163  filter_dos(line);
4164  // mfem v1.2 may not have parse_tag in it, e.g. if trying to read a
4165  // serial mfem v1.2 mesh as parallel with "mfem_serial_mesh_end" as
4166  // parse_tag. That's why, regardless of parse_tag, we stop reading if
4167  // we find "mfem_mesh_end" which is required by mfem v1.2 format.
4168  if (line == "mfem_mesh_end") { break; }
4169  }
4170  while (line != parse_tag);
4171  }
4172  else if (mfem_nc_version >= 10)
4173  {
4174  string ident;
4175  skip_comment_lines(input, '#');
4176  input >> ident;
4177  MFEM_VERIFY(ident == "mfem_mesh_end",
4178  "invalid mesh: end of file tag not found");
4179  }
4180 
4181  // Finalize(...) should be called after this, if needed.
4182 }
4183 
4184 Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
4185 {
4186  int i, j, ie, ib, iv, *v, nv;
4187  Element *el;
4188  Mesh *m;
4189 
4190  SetEmpty();
4191 
4192  Dim = mesh_array[0]->Dimension();
4193  spaceDim = mesh_array[0]->SpaceDimension();
4194 
4195  if (mesh_array[0]->NURBSext)
4196  {
4197  // assuming the pieces form a partition of a NURBS mesh
4198  NURBSext = new NURBSExtension(mesh_array, num_pieces);
4199 
4202 
4204 
4205  // NumOfBdrElements = NURBSext->GetNBE();
4206  // NURBSext->GetBdrElementTopo(boundary);
4207 
4208  Array<int> lvert_vert, lelem_elem;
4209 
4210  // Here, for visualization purposes, we copy the boundary elements from
4211  // the individual pieces which include the interior boundaries. This
4212  // creates 'boundary' array that is different from the one generated by
4213  // the NURBSExtension which, in particular, makes the boundary-dof table
4214  // invalid. This, in turn, causes GetBdrElementTransformation to not
4215  // function properly.
4216  NumOfBdrElements = 0;
4217  for (i = 0; i < num_pieces; i++)
4218  {
4219  NumOfBdrElements += mesh_array[i]->GetNBE();
4220  }
4221  boundary.SetSize(NumOfBdrElements);
4222  vertices.SetSize(NumOfVertices);
4223  ib = 0;
4224  for (i = 0; i < num_pieces; i++)
4225  {
4226  m = mesh_array[i];
4227  m->NURBSext->GetVertexLocalToGlobal(lvert_vert);
4228  m->NURBSext->GetElementLocalToGlobal(lelem_elem);
4229  // copy the element attributes
4230  for (j = 0; j < m->GetNE(); j++)
4231  {
4232  elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j));
4233  }
4234  // copy the boundary
4235  for (j = 0; j < m->GetNBE(); j++)
4236  {
4237  el = m->GetBdrElement(j)->Duplicate(this);
4238  v = el->GetVertices();
4239  nv = el->GetNVertices();
4240  for (int k = 0; k < nv; k++)
4241  {
4242  v[k] = lvert_vert[v[k]];
4243  }
4244  boundary[ib++] = el;
4245  }
4246  // copy the vertices
4247  for (j = 0; j < m->GetNV(); j++)
4248  {
4249  vertices[lvert_vert[j]].SetCoords(m->SpaceDimension(),
4250  m->GetVertex(j));
4251  }
4252  }
4253  }
4254  else // not a NURBS mesh
4255  {
4256  NumOfElements = 0;
4257  NumOfBdrElements = 0;
4258  NumOfVertices = 0;
4259  for (i = 0; i < num_pieces; i++)
4260  {
4261  m = mesh_array[i];
4262  NumOfElements += m->GetNE();
4263  NumOfBdrElements += m->GetNBE();
4264  NumOfVertices += m->GetNV();
4265  }
4266  elements.SetSize(NumOfElements);
4267  boundary.SetSize(NumOfBdrElements);
4268  vertices.SetSize(NumOfVertices);
4269  ie = ib = iv = 0;
4270  for (i = 0; i < num_pieces; i++)
4271  {
4272  m = mesh_array[i];
4273  // copy the elements
4274  for (j = 0; j < m->GetNE(); j++)
4275  {
4276  el = m->GetElement(j)->Duplicate(this);
4277  v = el->GetVertices();
4278  nv = el->GetNVertices();
4279  for (int k = 0; k < nv; k++)
4280  {
4281  v[k] += iv;
4282  }
4283  elements[ie++] = el;
4284  }
4285  // copy the boundary elements
4286  for (j = 0; j < m->GetNBE(); j++)
4287  {
4288  el = m->GetBdrElement(j)->Duplicate(this);
4289  v = el->GetVertices();
4290  nv = el->GetNVertices();
4291  for (int k = 0; k < nv; k++)
4292  {
4293  v[k] += iv;
4294  }
4295  boundary[ib++] = el;
4296  }
4297  // copy the vertices
4298  for (j = 0; j < m->GetNV(); j++)
4299  {
4300  vertices[iv++].SetCoords(m->SpaceDimension(), m->GetVertex(j));
4301  }
4302  }
4303  }
4304 
4305  FinalizeTopology();
4306 
4307  // copy the nodes (curvilinear meshes)
4308  GridFunction *g = mesh_array[0]->GetNodes();
4309  if (g)
4310  {
4311  Array<GridFunction *> gf_array(num_pieces);
4312  for (i = 0; i < num_pieces; i++)
4313  {
4314  gf_array[i] = mesh_array[i]->GetNodes();
4315  }
4316  Nodes = new GridFunction(this, gf_array, num_pieces);
4317  own_nodes = 1;
4318  }
4319 
4320 #ifdef MFEM_DEBUG
4321  CheckElementOrientation(false);
4323 #endif
4324 }
4325 
4326 Mesh::Mesh(Mesh *orig_mesh, int ref_factor, int ref_type)
4327 {
4328  Array<int> ref_factors(orig_mesh->GetNE());
4329  ref_factors = ref_factor;
4330  MakeRefined_(*orig_mesh, ref_factors, ref_type);
4331 }
4332 
4333 void Mesh::MakeRefined_(Mesh &orig_mesh, const Array<int> ref_factors,
4334  int ref_type)
4335 {
4336  SetEmpty();
4337  Dim = orig_mesh.Dimension();
4338  spaceDim = orig_mesh.SpaceDimension();
4339 
4340  int orig_ne = orig_mesh.GetNE();
4341  MFEM_VERIFY(ref_factors.Size() == orig_ne && orig_ne > 0,
4342  "Number of refinement factors must equal number of elements")
4343  MFEM_VERIFY(ref_factors.Min() >= 1, "Refinement factor must be >= 1");
4344  const int q_type = BasisType::GetQuadrature1D(ref_type);
4345  MFEM_VERIFY(Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid,
4346  "Invalid refinement type. Must use closed basis type.");
4347 
4348  int min_ref = ref_factors.Min();
4349  int max_ref = ref_factors.Max();
4350 
4351  bool var_order = (min_ref != max_ref);
4352 
4353  // variable order space can only be constructed over an NC mesh
4354  if (var_order) { orig_mesh.EnsureNCMesh(true); }
4355 
4356  // Construct a scalar H1 FE space of order ref_factor and use its dofs as
4357  // the indices of the new, refined vertices.
4358  H1_FECollection rfec(min_ref, Dim, ref_type);
4359  FiniteElementSpace rfes(&orig_mesh, &rfec);
4360 
4361  if (var_order)
4362  {
4363  rfes.SetRelaxedHpConformity(false);
4364  for (int i = 0; i < orig_ne; i++)
4365  {
4366  rfes.SetElementOrder(i, ref_factors[i]);
4367  }
4368  rfes.Update(false);
4369  }
4370 
4371  // Set the number of vertices, set the actual coordinates later
4372  NumOfVertices = rfes.GetNDofs();
4373  vertices.SetSize(NumOfVertices);
4374 
4375  Array<int> rdofs;
4376  DenseMatrix phys_pts;
4377 
4378  GeometryRefiner refiner;
4379  refiner.SetType(q_type);
4380 
4381  // Add refined elements and set vertex coordinates
4382  for (int el = 0; el < orig_ne; el++)
4383  {
4384  Geometry::Type geom = orig_mesh.GetElementGeometry(el);
4385  int attrib = orig_mesh.GetAttribute(el);
4386  int nvert = Geometry::NumVerts[geom];
4387  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el]);
4388 
4389  rfes.GetElementDofs(el, rdofs);
4390  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4391  const FiniteElement *rfe = rfes.GetFE(el);
4392  orig_mesh.GetElementTransformation(el)->Transform(rfe->GetNodes(),
4393  phys_pts);
4394  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[el]);
4395  for (int i = 0; i < phys_pts.Width(); i++)
4396  {
4397  vertices[rdofs[i]].SetCoords(spaceDim, phys_pts.GetColumn(i));
4398  }
4399  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4400  {
4401  Element *elem = NewElement(geom);
4402  elem->SetAttribute(attrib);
4403  int *v = elem->GetVertices();
4404  for (int k = 0; k < nvert; k++)
4405  {
4406  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4407  v[k] = rdofs[c2h_map[cid]];
4408  }
4409  AddElement(elem);
4410  }
4411  }
4412 
4413  if (Dim > 2)
4414  {
4415  GetElementToFaceTable(false);
4416  GenerateFaces();
4417  }
4418 
4419  // Add refined boundary elements
4420  for (int el = 0; el < orig_mesh.GetNBE(); el++)
4421  {
4422  int i, info;
4423  orig_mesh.GetBdrElementAdjacentElement(el, i, info);
4424  Geometry::Type geom = orig_mesh.GetBdrElementBaseGeometry(el);
4425  int attrib = orig_mesh.GetBdrAttribute(el);
4426  int nvert = Geometry::NumVerts[geom];
4427  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[i]);
4428 
4429  rfes.GetBdrElementDofs(el, rdofs);
4430  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4431  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[i]);
4432  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4433  {
4434  Element *elem = NewElement(geom);
4435  elem->SetAttribute(attrib);
4436  int *v = elem->GetVertices();
4437  for (int k = 0; k < nvert; k++)
4438  {
4439  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4440  v[k] = rdofs[c2h_map[cid]];
4441  }
4442  AddBdrElement(elem);
4443  }
4444  }
4445  FinalizeTopology(false);
4446  sequence = orig_mesh.GetSequence() + 1;
4448 
4449  // Set up the nodes of the new mesh (if the original mesh has nodes). The new
4450  // mesh is always straight-sided (i.e. degree 1 finite element space), but
4451  // the nodes are required for e.g. periodic meshes.
4452  if (orig_mesh.GetNodes())
4453  {
4454  bool discont = orig_mesh.GetNodalFESpace()->IsDGSpace();
4455  Ordering::Type dof_ordering = orig_mesh.GetNodalFESpace()->GetOrdering();
4456  Mesh::SetCurvature(1, discont, spaceDim, dof_ordering);
4457  FiniteElementSpace *nodal_fes = Nodes->FESpace();
4458  const FiniteElementCollection *nodal_fec = nodal_fes->FEColl();
4459  H1_FECollection vertex_fec(1, Dim);
4460  Array<int> dofs;
4461  int el_counter = 0;
4462  for (int iel = 0; iel < orig_ne; iel++)
4463  {
4464  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(iel);
4465  int nvert = Geometry::NumVerts[geom];
4466  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[iel]);
4467  rfes.GetElementDofs(iel, rdofs);
4468  const FiniteElement *rfe = rfes.GetFE(iel);
4469  orig_mesh.GetElementTransformation(iel)->Transform(rfe->GetNodes(),
4470  phys_pts);
4471  const int *node_map = NULL;
4472  const H1_FECollection *h1_fec =
4473  dynamic_cast<const H1_FECollection *>(nodal_fec);
4474  if (h1_fec != NULL) { node_map = h1_fec->GetDofMap(geom); }
4475  const int *vertex_map = vertex_fec.GetDofMap(geom);
4476  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[iel]);
4477  for (int jel = 0; jel < RG.RefGeoms.Size()/nvert; jel++)
4478  {
4479  nodal_fes->GetElementVDofs(el_counter++, dofs);
4480  for (int iv_lex=0; iv_lex<nvert; ++iv_lex)
4481  {
4482  // convert from lexicographic to vertex index
4483  int iv = vertex_map[iv_lex];
4484  // index of vertex of current element in phys_pts matrix
4485  int pt_idx = c2h_map[RG.RefGeoms[iv+nvert*jel]];
4486  // index of current vertex into DOF array
4487  int node_idx = node_map ? node_map[iv_lex] : iv_lex;
4488  for (int d=0; d<spaceDim; ++d)
4489  {
4490  (*Nodes)[dofs[node_idx + d*nvert]] = phys_pts(d,pt_idx);
4491  }
4492  }
4493  }
4494  }
4495  }
4496 
4497  // Setup the data for the coarse-fine refinement transformations
4498  CoarseFineTr.embeddings.SetSize(GetNE());
4499  // First, compute total number of point matrices that we need per geometry
4500  // and the offsets into that array
4501  using GeomRef = std::pair<Geometry::Type, int>;
4502  std::map<GeomRef, int> point_matrices_offsets;
4503  int n_point_matrices[Geometry::NumGeom] = {}; // initialize to zero
4504  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4505  {
4506  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4507  // Have we seen this pair of (goemetry, refinement level) before?
4508  GeomRef id(geom, ref_factors[el_coarse]);
4509  if (point_matrices_offsets.find(id) == point_matrices_offsets.end())
4510  {
4511  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el_coarse]);
4512  int nvert = Geometry::NumVerts[geom];
4513  int nref_el = RG.RefGeoms.Size()/nvert;
4514  // If not, then store the offset and add to the size required
4515  point_matrices_offsets[id] = n_point_matrices[geom];
4516  n_point_matrices[geom] += nref_el;
4517  }
4518  }
4519 
4520  // Set up the sizes
4521  for (int geom = 0; geom < Geometry::NumGeom; ++geom)
4522  {
4523  int nmatrices = n_point_matrices[geom];
4524  int nvert = Geometry::NumVerts[geom];
4525  CoarseFineTr.point_matrices[geom].SetSize(Dim, nvert, nmatrices);
4526  }
4527 
4528  // Compute the point matrices and embeddings
4529  int el_fine = 0;
4530  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4531  {
4532  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4533  int ref = ref_factors[el_coarse];
4534  int offset = point_matrices_offsets[GeomRef(geom, ref)];
4535  int nvert = Geometry::NumVerts[geom];
4536  RefinedGeometry &RG = *refiner.Refine(geom, ref);
4537  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4538  {
4539  DenseMatrix &Pj = CoarseFineTr.point_matrices[geom](offset + j);
4540  for (int k = 0; k < nvert; k++)
4541  {
4542  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4543  const IntegrationPoint &ip = RG.RefPts[cid];
4544  ip.Get(Pj.GetColumn(k), Dim);
4545  }
4546 
4547  Embedding &emb = CoarseFineTr.embeddings[el_fine];
4548  emb.parent = el_coarse;
4549  emb.matrix = offset + j;
4550  ++el_fine;
4551  }
4552  }
4553 
4554  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4555 
4556  // The check below is disabled because is fails for parallel meshes with
4557  // interior "boundary" element that, when such "boundary" element is between
4558  // two elements on different processors.
4559  // MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4560 }
4561 
4562 Mesh Mesh::MakeSimplicial(const Mesh &orig_mesh)
4563 {
4564  Mesh mesh;
4565  mesh.MakeSimplicial_(orig_mesh, NULL);
4566  return mesh;
4567 }
4568 
4569 void Mesh::MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
4570 {
4571  MFEM_VERIFY(const_cast<Mesh&>(orig_mesh).CheckElementOrientation(false) == 0,
4572  "Mesh::MakeSimplicial requires a properly oriented input mesh");
4573  MFEM_VERIFY(orig_mesh.Conforming(),
4574  "Mesh::MakeSimplicial does not support non-conforming meshes.")
4575 
4576  int dim = orig_mesh.Dimension();
4577  int sdim = orig_mesh.SpaceDimension();
4578 
4579  if (dim == 1)
4580  {
4581  Mesh copy(orig_mesh);
4582  Swap(copy, true);
4583  return;
4584  }
4585 
4586  int nv = orig_mesh.GetNV();
4587  int ne = orig_mesh.GetNE();
4588  int nbe = orig_mesh.GetNBE();
4589 
4590  static int num_subdivisions[Geometry::NUM_GEOMETRIES];
4591  num_subdivisions[Geometry::POINT] = 1;
4592  num_subdivisions[Geometry::SEGMENT] = 1;
4593  num_subdivisions[Geometry::TRIANGLE] = 1;
4594  num_subdivisions[Geometry::TETRAHEDRON] = 1;
4595  num_subdivisions[Geometry::SQUARE] = 2;
4596  num_subdivisions[Geometry::PRISM] = 3;
4597  num_subdivisions[Geometry::CUBE] = 6;
4598  // NOTE: some hexes may be subdivided into only 5 tets, so this is an
4599  // estimate only. The actual number of created tets may be less, so the
4600  // elements array will need to be shrunk after mesh creation.
4601  int new_ne = 0, new_nbe = 0;
4602  for (int i=0; i<ne; ++i)
4603  {
4604  new_ne += num_subdivisions[orig_mesh.GetElementBaseGeometry(i)];
4605  }
4606  for (int i=0; i<nbe; ++i)
4607  {
4608  new_nbe += num_subdivisions[orig_mesh.GetBdrElementBaseGeometry(i)];
4609  }
4610 
4611  InitMesh(dim, sdim, nv, new_ne, new_nbe);
4612 
4613  // Vertices of the new mesh are same as the original mesh
4614  NumOfVertices = nv;
4615  for (int i=0; i<nv; ++i)
4616  {
4617  vertices[i].SetCoords(dim, orig_mesh.vertices[i]());
4618  }
4619 
4620  // We need a global vertex numbering to identify which diagonals to split
4621  // (quad faces are split using the diagonal originating from the smallest
4622  // global vertex number). Use the supplied global numbering, if it is
4623  // non-NULL, otherwise use the local numbering.
4624  Array<int> vglobal_id;
4625  if (vglobal == NULL)
4626  {
4627  vglobal_id.SetSize(nv);
4628  for (int i=0; i<nv; ++i) { vglobal_id[i] = i; }
4629  vglobal = vglobal_id.GetData();
4630  }
4631 
4632  constexpr int nv_tri = 3, nv_quad = 4, nv_tet = 4, nv_prism = 6, nv_hex = 8;
4633  constexpr int quad_ntris = 2, prism_ntets = 3;
4634  static const int quad_trimap[2][nv_tri*quad_ntris] =
4635  {
4636  {
4637  0, 0,
4638  1, 2,
4639  2, 3
4640  },{
4641  0, 1,
4642  1, 2,
4643  3, 3
4644  }
4645  };
4646  static const int prism_rot[nv_prism*nv_prism] =
4647  {
4648  0, 1, 2, 3, 4, 5,
4649  1, 2, 0, 4, 5, 3,
4650  2, 0, 1, 5, 3, 4,
4651  3, 5, 4, 0, 2, 1,
4652  4, 3, 5, 1, 0, 2,
4653  5, 4, 3, 2, 1, 0
4654  };
4655  static const int prism_f[nv_quad] = {1, 2, 5, 4};
4656  static const int prism_tetmaps[2][nv_prism*prism_ntets] =
4657  {
4658  {
4659  0, 0, 0,
4660  1, 1, 4,
4661  2, 5, 5,
4662  5, 4, 3
4663  },{
4664  0, 0, 0,
4665  1, 4, 4,
4666  2, 2, 5,
4667  4, 5, 3
4668  }
4669  };
4670  static const int hex_rot[nv_hex*nv_hex] =
4671  {
4672  0, 1, 2, 3, 4, 5, 6, 7,
4673  1, 0, 4, 5, 2, 3, 7, 6,
4674  2, 1, 5, 6, 3, 0, 4, 7,
4675  3, 0, 1, 2, 7, 4, 5, 6,
4676  4, 0, 3, 7, 5, 1, 2, 6,
4677  5, 1, 0, 4, 6, 2, 3, 7,
4678  6, 2, 1, 5, 7, 3, 0, 4,
4679  7, 3, 2, 6, 4, 0, 1, 5
4680  };
4681  static const int hex_f0[nv_quad] = {1, 2, 6, 5};
4682  static const int hex_f1[nv_quad] = {2, 3, 7, 6};
4683  static const int hex_f2[nv_quad] = {4, 5, 6, 7};
4684  static const int num_rot[8] = {0, 1, 2, 0, 0, 2, 1, 0};
4685  static const int hex_tetmap0[nv_tet*5] =
4686  {
4687  0, 0, 0, 0, 2,
4688  1, 2, 2, 5, 7,
4689  2, 7, 3, 7, 5,
4690  5, 5, 7, 4, 6
4691  };
4692  static const int hex_tetmap1[nv_tet*6] =
4693  {
4694  0, 0, 1, 0, 0, 1,
4695  5, 1, 6, 7, 7, 7,
4696  7, 7, 7, 2, 1, 6,
4697  4, 5, 5, 3, 2, 2
4698  };
4699  static const int hex_tetmap2[nv_tet*6] =
4700  {
4701  0, 0, 0, 0, 0, 0,
4702  4, 3, 7, 1, 3, 6,
4703  5, 7, 4, 2, 6, 5,
4704  6, 6, 6, 5, 2, 2
4705  };
4706  static const int hex_tetmap3[nv_tet*6] =
4707  {
4708  0, 0, 0, 0, 1, 1,
4709  2, 3, 7, 5, 5, 6,
4710  3, 7, 4, 6, 6, 2,
4711  6, 6, 6, 4, 0, 0
4712  };
4713  static const int *hex_tetmaps[4] =
4714  {
4715  hex_tetmap0, hex_tetmap1, hex_tetmap2, hex_tetmap3
4716  };
4717 
4718  auto find_min = [](const int*a, int n) { return std::min_element(a,a+n)-a; };
4719 
4720  for (int i=0; i<ne; ++i)
4721  {
4722  const int *v = orig_mesh.elements[i]->GetVertices();
4723  const int attrib = orig_mesh.GetAttribute(i);
4724  const Geometry::Type orig_geom = orig_mesh.GetElementBaseGeometry(i);
4725 
4726  if (num_subdivisions[orig_geom] == 1)
4727  {
4728  // (num_subdivisions[orig_geom] == 1) implies that the element does
4729  // not need to be further split (it is either a segment, triangle,
4730  // or tetrahedron), and so it is left unchanged.
4731  Element *e = NewElement(orig_geom);
4732  e->SetAttribute(attrib);
4733  e->SetVertices(v);
4734  AddElement(e);
4735  }
4736  else if (orig_geom == Geometry::SQUARE)
4737  {
4738  for (int itri=0; itri<quad_ntris; ++itri)
4739  {
4741  e->SetAttribute(attrib);
4742  int *v2 = e->GetVertices();
4743  for (int iv=0; iv<nv_tri; ++iv)
4744  {
4745  v2[iv] = v[quad_trimap[0][itri + iv*quad_ntris]];
4746  }
4747  AddElement(e);
4748  }
4749  }
4750  else if (orig_geom == Geometry::PRISM)
4751  {
4752  int vg[nv_prism];
4753  for (int iv=0; iv<nv_prism; ++iv) { vg[iv] = vglobal[v[iv]]; }
4754  // Rotate the vertices of the prism so that the smallest vertex index
4755  // is in the first place
4756  int irot = find_min(vg, nv_prism);
4757  for (int iv=0; iv<nv_prism; ++iv)
4758  {
4759  int jv = prism_rot[iv + irot*nv_prism];
4760  vg[iv] = v[jv];
4761  }
4762  // Two cases according to which diagonal splits third quad face
4763  int q[nv_quad];
4764  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[prism_f[iv]]]; }
4765  int j = find_min(q, nv_quad);
4766  const int *tetmap = (j == 0 || j == 2) ? prism_tetmaps[0] : prism_tetmaps[1];
4767  for (int itet=0; itet<prism_ntets; ++itet)
4768  {
4770  e->SetAttribute(attrib);
4771  int *v2 = e->GetVertices();
4772  for (int iv=0; iv<nv_tet; ++iv)
4773  {
4774  v2[iv] = vg[tetmap[itet + iv*prism_ntets]];
4775  }
4776  AddElement(e);
4777  }
4778  }
4779  else if (orig_geom == Geometry::CUBE)
4780  {
4781  int vg[nv_hex];
4782  for (int iv=0; iv<nv_hex; ++iv) { vg[iv] = vglobal[v[iv]]; }
4783 
4784  // Rotate the vertices of the hex so that the smallest vertex index is
4785  // in the first place
4786  int irot = find_min(vg, nv_hex);
4787  for (int iv=0; iv<nv_hex; ++iv)
4788  {
4789  int jv = hex_rot[iv + irot*nv_hex];
4790  vg[iv] = v[jv];
4791  }
4792 
4793  int q[nv_quad];
4794  // Bitmask is three binary digits, each digit is 1 if the diagonal of
4795  // the corresponding face goes through the 7th vertex, and 0 if not.
4796  int bitmask = 0;
4797  int j;
4798  // First quad face
4799  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f0[iv]]]; }
4800  j = find_min(q, nv_quad);
4801  if (j == 0 || j == 2) { bitmask += 4; }
4802  // Second quad face
4803  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f1[iv]]]; }
4804  j = find_min(q, nv_quad);
4805  if (j == 1 || j == 3) { bitmask += 2; }
4806  // Third quad face
4807  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f2[iv]]]; }
4808  j = find_min(q, nv_quad);
4809  if (j == 0 || j == 2) { bitmask += 1; }
4810 
4811  // Apply rotations
4812  int nrot = num_rot[bitmask];
4813  for (int k=0; k<nrot; ++k)
4814  {
4815  int vtemp;
4816  vtemp = vg[1];
4817  vg[1] = vg[4];
4818  vg[4] = vg[3];
4819  vg[3] = vtemp;
4820  vtemp = vg[5];
4821  vg[5] = vg[7];
4822  vg[7] = vg[2];
4823  vg[2] = vtemp;
4824  }
4825 
4826  // Sum up nonzero bits in bitmask
4827  int ndiags = ((bitmask&4) >> 2) + ((bitmask&2) >> 1) + (bitmask&1);
4828  int ntets = (ndiags == 0) ? 5 : 6;
4829  const int *tetmap = hex_tetmaps[ndiags];
4830  for (int itet=0; itet<ntets; ++itet)
4831  {
4833  e->SetAttribute(attrib);
4834  int *v2 = e->GetVertices();
4835  for (int iv=0; iv<nv_tet; ++iv)
4836  {
4837  v2[iv] = vg[tetmap[itet + iv*ntets]];
4838  }
4839  AddElement(e);
4840  }
4841  }
4842  }
4843  // In 3D, shrink the element array because some hexes have only 5 tets
4844  if (dim == 3) { elements.SetSize(NumOfElements); }
4845 
4846  for (int i=0; i<nbe; ++i)
4847  {
4848  const int *v = orig_mesh.boundary[i]->GetVertices();
4849  const int attrib = orig_mesh.GetBdrAttribute(i);
4850  const Geometry::Type orig_geom = orig_mesh.GetBdrElementBaseGeometry(i);
4851  if (num_subdivisions[orig_geom] == 1)
4852  {
4853  Element *be = NewElement(orig_geom);
4854  be->SetAttribute(attrib);
4855  be->SetVertices(v);
4856  AddBdrElement(be);
4857  }
4858  else if (orig_geom == Geometry::SQUARE)
4859  {
4860  int vg[nv_quad];
4861  for (int iv=0; iv<nv_quad; ++iv) { vg[iv] = vglobal[v[iv]]; }
4862  // Split quad according the smallest (global) vertex
4863  int iv_min = find_min(vg, nv_quad);
4864  int isplit = (iv_min == 0 || iv_min == 2) ? 0 : 1;
4865  for (int itri=0; itri<quad_ntris; ++itri)
4866  {
4868  be->SetAttribute(attrib);
4869  int *v2 = be->GetVertices();
4870  for (int iv=0; iv<nv_tri; ++iv)
4871  {
4872  v2[iv] = v[quad_trimap[isplit][itri + iv*quad_ntris]];
4873  }
4874  AddBdrElement(be);
4875  }
4876  }
4877  else
4878  {
4879  MFEM_ABORT("Unreachable");
4880  }
4881  }
4882 
4883  FinalizeTopology(false);
4884  sequence = orig_mesh.GetSequence();
4885  last_operation = orig_mesh.last_operation;
4886 
4887  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4888  MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4889 }
4890 
4891 Mesh Mesh::MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v)
4892 {
4893  Mesh periodic_mesh(orig_mesh, true); // Make a copy of the original mesh
4894  const FiniteElementSpace *nodal_fes = orig_mesh.GetNodalFESpace();
4895  int nodal_order = nodal_fes ? nodal_fes->GetMaxElementOrder() : 1;
4896  periodic_mesh.SetCurvature(nodal_order, true);
4897 
4898  // renumber element vertices
4899  for (int i = 0; i < periodic_mesh.GetNE(); i++)
4900  {
4901  Element *el = periodic_mesh.GetElement(i);
4902  int *v = el->GetVertices();
4903  int nv = el->GetNVertices();
4904  for (int j = 0; j < nv; j++)
4905  {
4906  v[j] = v2v[v[j]];
4907  }
4908  }
4909  // renumber boundary element vertices
4910  for (int i = 0; i < periodic_mesh.GetNBE(); i++)
4911  {
4912  Element *el = periodic_mesh.GetBdrElement(i);
4913  int *v = el->GetVertices();
4914  int nv = el->GetNVertices();
4915  for (int j = 0; j < nv; j++)
4916  {
4917  v[j] = v2v[v[j]];
4918  }
4919  }
4920 
4921  periodic_mesh.RemoveUnusedVertices();
4922  return periodic_mesh;
4923 }
4924 
4926  const std::vector<Vector> &translations, double tol) const
4927 {
4928  int sdim = SpaceDimension();
4929 
4930  Vector coord(sdim), at(sdim), dx(sdim);
4931  Vector xMax(sdim), xMin(sdim), xDiff(sdim);
4932  xMax = xMin = xDiff = 0.0;
4933 
4934  // Get a list of all vertices on the boundary
4935  set<int> bdr_v;
4936  for (int be = 0; be < GetNBE(); be++)
4937  {
4938  Array<int> dofs;
4939  GetBdrElementVertices(be,dofs);
4940 
4941  for (int i = 0; i < dofs.Size(); i++)
4942  {
4943  bdr_v.insert(dofs[i]);
4944 
4945  coord = GetVertex(dofs[i]);
4946  for (int j = 0; j < sdim; j++)
4947  {
4948  xMax[j] = max(xMax[j], coord[j]);
4949  xMin[j] = min(xMin[j], coord[j]);
4950  }
4951  }
4952  }
4953  add(xMax, -1.0, xMin, xDiff);
4954  double dia = xDiff.Norml2(); // compute mesh diameter
4955 
4956  // We now identify coincident vertices. Several originally distinct vertices
4957  // may become coincident under the periodic mapping. One of these vertices
4958  // will be identified as the "primary" vertex, and all other coincident
4959  // vertices will be considered as "replicas".
4960 
4961  // replica2primary[v] is the index of the primary vertex of replica `v`
4962  map<int, int> replica2primary;
4963  // primary2replicas[v] is a set of indices of replicas of primary vertex `v`
4964  map<int, set<int>> primary2replicas;
4965 
4966  // We begin with the assumption that all vertices are primary, and that there
4967  // are no replicas.
4968  for (int v : bdr_v) { primary2replicas[v]; }
4969 
4970  // Make `r` and all of `r`'s replicas be replicas of `p`. Delete `r` from the
4971  // list of primary vertices.
4972  auto make_replica = [&replica2primary, &primary2replicas](int r, int p)
4973  {
4974  if (r == p) { return; }
4975  primary2replicas[p].insert(r);
4976  replica2primary[r] = p;
4977  for (int s : primary2replicas[r])
4978  {
4979  primary2replicas[p].insert(s);
4980  replica2primary[s] = p;
4981  }
4982  primary2replicas.erase(r);
4983  };
4984 
4985  for (unsigned int i = 0; i < translations.size(); i++)
4986  {
4987  for (int vi : bdr_v)
4988  {
4989  coord = GetVertex(vi);
4990  add(coord, translations[i], at);
4991 
4992  for (int vj : bdr_v)
4993  {
4994  coord = GetVertex(vj);
4995  add(at, -1.0, coord, dx);
4996  if (dx.Norml2() > dia*tol) { continue; }
4997 
4998  // The two vertices vi and vj are coincident.
4999 
5000  // Are vertices `vi` and `vj` already primary?
5001  bool pi = primary2replicas.find(vi) != primary2replicas.end();
5002  bool pj = primary2replicas.find(vj) != primary2replicas.end();
5003 
5004  if (pi && pj)
5005  {
5006  // Both vertices are currently primary
5007  // Demote `vj` to be a replica of `vi`
5008  make_replica(vj, vi);
5009  }
5010  else if (pi && !pj)
5011  {
5012  // `vi` is primary and `vj` is a replica
5013  int owner_of_vj = replica2primary[vj];
5014  // Make `vi` and its replicas be replicas of `vj`'s owner
5015  make_replica(vi, owner_of_vj);
5016  }
5017  else if (!pi && pj)
5018  {
5019  // `vi` is currently a replica and `vj` is currently primary
5020  // Make `vj` and its replicas be replicas of `vi`'s owner
5021  int owner_of_vi = replica2primary[vi];
5022  make_replica(vj, owner_of_vi);
5023  }
5024  else
5025  {
5026  // Both vertices are currently replicas
5027  // Make `vj`'s owner and all of its owner's replicas be replicas
5028  // of `vi`'s owner
5029  int owner_of_vi = replica2primary[vi];
5030  int owner_of_vj = replica2primary[vj];
5031  make_replica(owner_of_vj, owner_of_vi);
5032  }
5033  break;
5034  }
5035  }
5036  }
5037 
5038  std::vector<int> v2v(GetNV());
5039  for (size_t i = 0; i < v2v.size(); i++)
5040  {
5041  v2v[i] = i;
5042  }
5043  for (auto &&r2p : replica2primary)
5044  {
5045  v2v[r2p.first] = r2p.second;
5046  }
5047  return v2v;
5048 }
5049 
5051 {
5052  if (NURBSext == NULL)
5053  {
5054  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5055  }
5056 
5057  if (kv.Size() != NURBSext->GetNKV())
5058  {
5059  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5060  }
5061 
5063 
5064  NURBSext->KnotInsert(kv);
5065 
5066  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5067  sequence++;
5068 
5069  UpdateNURBS();
5070 }
5071 
5073 {
5074  if (NURBSext == NULL)
5075  {
5076  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5077  }
5078 
5079  if (kv.Size() != NURBSext->GetNKV())
5080  {
5081  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5082  }
5083 
5085 
5086  NURBSext->KnotInsert(kv);
5087 
5088  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5089  sequence++;
5090 
5091  UpdateNURBS();
5092 }
5093 
5095 {
5096  // do not check for NURBSext since this method is protected
5098 
5100 
5101  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5102  sequence++;
5103 
5104  UpdateNURBS();
5105 }
5106 
5107 void Mesh::DegreeElevate(int rel_degree, int degree)
5108 {
5109  if (NURBSext == NULL)
5110  {
5111  mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!");
5112  }
5113 
5115 
5116  NURBSext->DegreeElevate(rel_degree, degree);
5117 
5118  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5119  sequence++;
5120 
5121  UpdateNURBS();
5122 }
5123 
5125 {
5126  ResetLazyData();
5127 
5129 
5130  Dim = NURBSext->Dimension();
5131  spaceDim = Dim;
5132 
5133  if (NumOfElements != NURBSext->GetNE())
5134  {
5135  for (int i = 0; i < elements.Size(); i++)
5136  {
5137  FreeElement(elements[i]);
5138  }
5141  }
5142 
5143  if (NumOfBdrElements != NURBSext->GetNBE())
5144  {
5145  for (int i = 0; i < boundary.Size(); i++)
5146  {
5147  FreeElement(boundary[i]);
5148  }
5151  }
5152 
5153  Nodes->FESpace()->Update();
5154  Nodes->Update();
5156 
5157  if (NumOfVertices != NURBSext->GetNV())
5158  {
5160  vertices.SetSize(NumOfVertices);
5161  int vd = Nodes->VectorDim();
5162  for (int i = 0; i < vd; i++)
5163  {
5164  Vector vert_val;
5165  Nodes->GetNodalValues(vert_val, i+1);
5166  for (int j = 0; j < NumOfVertices; j++)
5167  {
5168  vertices[j](i) = vert_val(j);
5169  }
5170  }
5171  }
5172 
5173  if (el_to_edge)
5174  {
5176  if (Dim == 2)
5177  {
5178  GenerateFaces();
5179  }
5180  }
5181 
5182  if (el_to_face)
5183  {
5185  GenerateFaces();
5186  }
5187 }
5188 
5189 void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot)
5190 {
5191  SetEmpty();
5192 
5193  // Read MFEM NURBS mesh v1.0 format
5194  string ident;
5195 
5196  skip_comment_lines(input, '#');
5197 
5198  input >> ident; // 'dimension'
5199  input >> Dim;
5200  spaceDim = Dim;
5201 
5202  skip_comment_lines(input, '#');
5203 
5204  input >> ident; // 'elements'
5205  input >> NumOfElements;
5206  elements.SetSize(NumOfElements);
5207  for (int j = 0; j < NumOfElements; j++)
5208  {
5209  elements[j] = ReadElement(input);
5210  }
5211 
5212  skip_comment_lines(input, '#');
5213 
5214  input >> ident; // 'boundary'
5215  input >> NumOfBdrElements;
5216  boundary.SetSize(NumOfBdrElements);
5217  for (int j = 0; j < NumOfBdrElements; j++)
5218  {
5219  boundary[j] = ReadElement(input);
5220  }
5221 
5222  skip_comment_lines(input, '#');
5223 
5224  input >> ident; // 'edges'
5225  input >> NumOfEdges;
5226  edge_vertex = new Table(NumOfEdges, 2);
5227  edge_to_knot.SetSize(NumOfEdges);
5228  for (int j = 0; j < NumOfEdges; j++)
5229  {
5230  int *v = edge_vertex->GetRow(j);
5231  input >> edge_to_knot[j] >> v[0] >> v[1];
5232  if (v[0] > v[1])
5233  {
5234  edge_to_knot[j] = -1 - edge_to_knot[j];
5235  }
5236  }
5237 
5238  skip_comment_lines(input, '#');
5239 
5240  input >> ident; // 'vertices'
5241  input >> NumOfVertices;
5242  vertices.SetSize(0);
5243 
5244  FinalizeTopology();
5245  CheckBdrElementOrientation(); // check and fix boundary element orientation
5246 }
5247 
5249 {
5250  if (p.Size() >= v.Size())
5251  {
5252  for (int d = 0; d < v.Size(); d++)
5253  {
5254  v(d) = p(d);
5255  }
5256  }
5257  else
5258  {
5259  int d;
5260  for (d = 0; d < p.Size(); d++)
5261  {
5262  v(d) = p(d);
5263  }
5264  for ( ; d < v.Size(); d++)
5265  {
5266  v(d) = 0.0;
5267  }
5268  }
5269 }
5270 
5271 void Mesh::GetNodes(GridFunction &nodes) const
5272 {
5273  if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
5274  {
5275  const int newSpaceDim = nodes.FESpace()->GetVDim();
5277  nodes.ProjectCoefficient(xyz);
5278  }
5279  else
5280  {
5281  nodes = *Nodes;
5282  }
5283 }
5284 
5286 {
5287  GridFunction *nodes = new GridFunction(nfes);
5288  SetNodalGridFunction(nodes, true);
5289 }
5290 
5292 {
5293  if (Nodes)
5294  {
5296  if (dynamic_cast<const H1_FECollection*>(fec)
5297  || dynamic_cast<const L2_FECollection*>(fec))
5298  {
5299  return;
5300  }
5301  else // Mesh using a legacy FE_Collection
5302  {
5303  const int order = GetNodalFESpace()->GetElementOrder(0);
5304  if (NURBSext)
5305  {
5306 #ifndef MFEM_USE_MPI
5307  const bool warn = true;
5308 #else
5309  ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
5310  const bool warn = !pmesh || pmesh->GetMyRank() == 0;
5311 #endif
5312  if (warn)
5313  {
5314  MFEM_WARNING("converting NURBS mesh to order " << order <<
5315  " H1-continuous mesh!\n "
5316  "If this is the desired behavior, you can silence"
5317  " this warning by converting\n "
5318  "the NURBS mesh to high-order mesh in advance by"
5319  " calling the method\n "
5320  "Mesh::SetCurvature().");
5321  }
5322  }
5323  SetCurvature(order, false, -1, Ordering::byVDIM);
5324  }
5325  }
5326  else // First order H1 mesh
5327  {
5328  SetCurvature(1, false, -1, Ordering::byVDIM);
5329  }
5330 }
5331 
5332 void Mesh::SetNodalGridFunction(GridFunction *nodes, bool make_owner)
5333 {
5334  GetNodes(*nodes);
5335  NewNodes(*nodes, make_owner);
5336 }
5337 
5339 {
5340  return ((Nodes) ? Nodes->FESpace() : NULL);
5341 }
5342 
5343 void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
5344 {
5345  space_dim = (space_dim == -1) ? spaceDim : space_dim;
5347  if (discont)
5348  {
5349  const int type = 1; // Gauss-Lobatto points
5350  nfec = new L2_FECollection(order, Dim, type);
5351  }
5352  else
5353  {
5354  nfec = new H1_FECollection(order, Dim);
5355  }
5356  FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
5357  ordering);
5358  SetNodalFESpace(nfes);
5359  Nodes->MakeOwner(nfec);
5360 }
5361 
5363 {
5364  MFEM_ASSERT(nodes != NULL, "");
5365  for (int i = 0; i < spaceDim; i++)
5366  {
5367  Vector vert_val;
5368  nodes->GetNodalValues(vert_val, i+1);
5369  for (int j = 0; j < NumOfVertices; j++)
5370  {
5371  vertices[j](i) = vert_val(j);
5372  }
5373  }
5374 }
5375 
5377 {
5378  switch (Dim)
5379  {
5380  case 1: return GetNV();
5381  case 2: return GetNEdges();
5382  case 3: return GetNFaces();
5383  }
5384  return 0;
5385 }
5386 
5388 {
5389  return faces_info.Size();
5390 }
5391 
5393 {
5394  const bool isInt = type==FaceType::Interior;
5395  int &nf = isInt ? nbInteriorFaces : nbBoundaryFaces;
5396  if (nf<0)
5397  {
5398  nf = 0;
5399  for (int f = 0; f < GetNumFacesWithGhost(); ++f)
5400  {
5402  if ( face.IsOfFaceType(type) )
5403  {
5404  if (face.IsNonconformingCoarse())
5405  {
5406  // We don't count nonconforming coarse faces.
5407  continue;
5408  }
5409  nf++;
5410  }
5411  }
5412  }
5413  return nf;
5414 }
5415 
5416 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5417 static const char *fixed_or_not[] = { "fixed", "NOT FIXED" };
5418 #endif
5419 
5421 {
5422  int i, j, k, wo = 0, fo = 0;
5423  double *v[4];
5424 
5425  if (Dim == 2 && spaceDim == 2)
5426  {
5427  DenseMatrix J(2, 2);
5428 
5429  for (i = 0; i < NumOfElements; i++)
5430  {
5431  int *vi = elements[i]->GetVertices();
5432  if (Nodes == NULL)
5433  {
5434  for (j = 0; j < 3; j++)
5435  {
5436  v[j] = vertices[vi[j]]();
5437  }
5438  for (j = 0; j < 2; j++)
5439  for (k = 0; k < 2; k++)
5440  {
5441  J(j, k) = v[j+1][k] - v[0][k];
5442  }
5443  }
5444  else
5445  {
5446  // only check the Jacobian at the center of the element
5447  GetElementJacobian(i, J);
5448  }
5449  if (J.Det() < 0.0)
5450  {
5451  if (fix_it)
5452  {
5453  switch (GetElementType(i))
5454  {
5455  case Element::TRIANGLE:
5456  mfem::Swap(vi[0], vi[1]);
5457  break;
5459  mfem::Swap(vi[1], vi[3]);
5460  break;
5461  default:
5462  MFEM_ABORT("Invalid 2D element type \""
5463  << GetElementType(i) << "\"");
5464  break;
5465  }
5466  fo++;
5467  }
5468  wo++;
5469  }
5470  }
5471  }
5472 
5473  if (Dim == 3)
5474  {
5475  DenseMatrix J(3, 3);
5476 
5477  for (i = 0; i < NumOfElements; i++)
5478  {
5479  int *vi = elements[i]->GetVertices();
5480  switch (GetElementType(i))
5481  {
5482  case Element::TETRAHEDRON:
5483  if (Nodes == NULL)
5484  {
5485  for (j = 0; j < 4; j++)
5486  {
5487  v[j] = vertices[vi[j]]();
5488  }
5489  for (j = 0; j < 3; j++)
5490  for (k = 0; k < 3; k++)
5491  {
5492  J(j, k) = v[j+1][k] - v[0][k];
5493  }
5494  }
5495  else
5496  {
5497  // only check the Jacobian at the center of the element
5498  GetElementJacobian(i, J);
5499  }
5500  if (J.Det() < 0.0)
5501  {
5502  wo++;
5503  if (fix_it)
5504  {
5505  mfem::Swap(vi[0], vi[1]);
5506  fo++;
5507  }
5508  }
5509  break;
5510 
5511  case Element::WEDGE:
5512  // only check the Jacobian at the center of the element
5513  GetElementJacobian(i, J);
5514  if (J.Det() < 0.0)
5515  {
5516  wo++;
5517  if (fix_it)
5518  {
5519  // how?
5520  }
5521  }
5522  break;
5523 
5524  case Element::PYRAMID:
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::HEXAHEDRON:
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  default:
5551  MFEM_ABORT("Invalid 3D element type \""
5552  << GetElementType(i) << "\"");
5553  break;
5554  }
5555  }
5556  }
5557 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5558  if (wo > 0)
5559  {
5560  mfem::out << "Elements with wrong orientation: " << wo << " / "
5561  << NumOfElements << " (" << fixed_or_not[(wo == fo) ? 0 : 1]
5562  << ")" << endl;
5563  }
5564 #endif
5565  return wo;
5566 }
5567 
5568 int Mesh::GetTriOrientation(const int *base, const int *test)
5569 {
5570  // Static method.
5571  // This function computes the index 'j' of the permutation that transforms
5572  // test into base: test[tri_orientation[j][i]]=base[i].
5573  // tri_orientation = Geometry::Constants<Geometry::TRIANGLE>::Orient
5574  int orient;
5575 
5576  if (test[0] == base[0])
5577  if (test[1] == base[1])
5578  {
5579  orient = 0; // (0, 1, 2)
5580  }
5581  else
5582  {
5583  orient = 5; // (0, 2, 1)
5584  }
5585  else if (test[0] == base[1])
5586  if (test[1] == base[0])
5587  {
5588  orient = 1; // (1, 0, 2)
5589  }
5590  else
5591  {
5592  orient = 2; // (1, 2, 0)
5593  }
5594  else // test[0] == base[2]
5595  if (test[1] == base[0])
5596  {
5597  orient = 4; // (2, 0, 1)
5598  }
5599  else
5600  {
5601  orient = 3; // (2, 1, 0)
5602  }
5603 
5604 #ifdef MFEM_DEBUG
5605  const int *aor = tri_t::Orient[orient];
5606  for (int j = 0; j < 3; j++)
5607  if (test[aor[j]] != base[j])
5608  {
5609  mfem_error("Mesh::GetTriOrientation(...)");
5610  }
5611 #endif
5612 
5613  return orient;
5614 }
5615 
5616 int Mesh::GetQuadOrientation(const int *base, const int *test)
5617 {
5618  int i;
5619 
5620  for (i = 0; i < 4; i++)
5621  if (test[i] == base[0])
5622  {
5623  break;
5624  }
5625 
5626 #ifdef MFEM_DEBUG
5627  int orient;
5628  if (test[(i+1)%4] == base[1])
5629  {
5630  orient = 2*i;
5631  }
5632  else
5633  {
5634  orient = 2*i+1;
5635  }
5636  const int *aor = quad_t::Orient[orient];
5637  for (int j = 0; j < 4; j++)
5638  if (test[aor[j]] != base[j])
5639  {
5640  mfem::err << "Mesh::GetQuadOrientation(...)" << endl;
5641  mfem::err << " base = [";
5642  for (int k = 0; k < 4; k++)
5643  {
5644  mfem::err << " " << base[k];
5645  }
5646  mfem::err << " ]\n test = [";
5647  for (int k = 0; k < 4; k++)
5648  {
5649  mfem::err << " " << test[k];
5650  }
5651  mfem::err << " ]" << endl;
5652  mfem_error();
5653  }
5654 #endif
5655 
5656  if (test[(i+1)%4] == base[1])
5657  {
5658  return 2*i;
5659  }
5660 
5661  return 2*i+1;
5662 }
5663 
5664 int Mesh::GetTetOrientation(const int *base, const int *test)
5665 {
5666  // Static method.
5667  // This function computes the index 'j' of the permutation that transforms
5668  // test into base: test[tet_orientation[j][i]]=base[i].
5669  // tet_orientation = Geometry::Constants<Geometry::TETRAHEDRON>::Orient
5670  int orient;
5671 
5672  if (test[0] == base[0])
5673  if (test[1] == base[1])
5674  if (test[2] == base[2])
5675  {
5676  orient = 0; // (0, 1, 2, 3)
5677  }
5678  else
5679  {
5680  orient = 1; // (0, 1, 3, 2)
5681  }
5682  else if (test[2] == base[1])
5683  if (test[3] == base[2])
5684  {
5685  orient = 2; // (0, 2, 3, 1)
5686  }
5687  else
5688  {
5689  orient = 3; // (0, 2, 1, 3)
5690  }
5691  else // test[3] == base[1]
5692  if (test[1] == base[2])
5693  {
5694  orient = 4; // (0, 3, 1, 2)
5695  }
5696  else
5697  {
5698  orient = 5; // (0, 3, 2, 1)
5699  }
5700  else if (test[1] == base[0])
5701  if (test[2] == base[1])
5702  if (test[0] == base[2])
5703  {
5704  orient = 6; // (1, 2, 0, 3)
5705  }
5706  else
5707  {
5708  orient = 7; // (1, 2, 3, 0)
5709  }
5710  else if (test[3] == base[1])
5711  if (test[2] == base[2])
5712  {
5713  orient = 8; // (1, 3, 2, 0)
5714  }
5715  else
5716  {
5717  orient = 9; // (1, 3, 0, 2)
5718  }
5719  else // test[0] == base[1]
5720  if (test[3] == base[2])
5721  {
5722  orient = 10; // (1, 0, 3, 2)
5723  }
5724  else
5725  {
5726  orient = 11; // (1, 0, 2, 3)
5727  }
5728  else if (test[2] == base[0])
5729  if (test[3] == base[1])
5730  if (test[0] == base[2])
5731  {
5732  orient = 12; // (2, 3, 0, 1)
5733  }
5734  else
5735  {
5736  orient = 13; // (2, 3, 1, 0)
5737  }
5738  else if (test[0] == base[1])
5739  if (test[1] == base[2])
5740  {
5741  orient = 14; // (2, 0, 1, 3)
5742  }
5743  else
5744  {
5745  orient = 15; // (2, 0, 3, 1)
5746  }
5747  else // test[1] == base[1]
5748  if (test[3] == base[2])
5749  {
5750  orient = 16; // (2, 1, 3, 0)
5751  }
5752  else
5753  {
5754  orient = 17; // (2, 1, 0, 3)
5755  }
5756  else // (test[3] == base[0])
5757  if (test[0] == base[1])
5758  if (test[2] == base[2])
5759  {
5760  orient = 18; // (3, 0, 2, 1)
5761  }
5762  else
5763  {
5764  orient = 19; // (3, 0, 1, 2)
5765  }
5766  else if (test[1] == base[1])
5767  if (test[0] == base[2])
5768  {
5769  orient = 20; // (3, 1, 0, 2)
5770  }
5771  else
5772  {
5773  orient = 21; // (3, 1, 2, 0)
5774  }
5775  else // test[2] == base[1]
5776  if (test[1] == base[2])
5777  {
5778  orient = 22; // (3, 2, 1, 0)
5779  }
5780  else
5781  {
5782  orient = 23; // (3, 2, 0, 1)
5783  }
5784 
5785 #ifdef MFEM_DEBUG
5786  const int *aor = tet_t::Orient[orient];
5787  for (int j = 0; j < 4; j++)
5788  if (test[aor[j]] != base[j])
5789  {
5790  mfem_error("Mesh::GetTetOrientation(...)");
5791  }
5792 #endif
5793 
5794  return orient;
5795 }
5796 
5798 {
5799  int wo = 0; // count wrong orientations
5800 
5801  if (Dim == 2)
5802  {
5803  if (el_to_edge == NULL) // edges were not generated
5804  {
5805  el_to_edge = new Table;
5807  GenerateFaces(); // 'Faces' in 2D refers to the edges
5808  }
5809  for (int i = 0; i < NumOfBdrElements; i++)
5810  {
5811  if (faces_info[be_to_edge[i]].Elem2No < 0) // boundary face
5812  {
5813  int *bv = boundary[i]->GetVertices();
5814  int *fv = faces[be_to_edge[i]]->GetVertices();
5815  if (bv[0] != fv[0])
5816  {
5817  if (fix_it)
5818  {
5819  mfem::Swap<int>(bv[0], bv[1]);
5820  }
5821  wo++;
5822  }
5823  }
5824  }
5825  }
5826 
5827  if (Dim == 3)
5828  {
5829  for (int i = 0; i < NumOfBdrElements; i++)
5830  {
5831  const int fi = be_to_face[i];
5832 
5833  if (faces_info[fi].Elem2No >= 0) { continue; }
5834 
5835  // boundary face
5836  int *bv = boundary[i]->GetVertices();
5837  // Make sure the 'faces' are generated:
5838  MFEM_ASSERT(fi < faces.Size(), "internal error");
5839  const int *fv = faces[fi]->GetVertices();
5840  int orientation; // orientation of the bdr. elem. w.r.t. the
5841  // corresponding face element (that's the base)
5842  const Element::Type bdr_type = GetBdrElementType(i);
5843  switch (bdr_type)
5844  {
5845  case Element::TRIANGLE:
5846  {
5847  orientation = GetTriOrientation(fv, bv);
5848  break;
5849  }
5851  {
5852  orientation = GetQuadOrientation(fv, bv);
5853  break;
5854  }
5855  default:
5856  MFEM_ABORT("Invalid 2D boundary element type \""
5857  << bdr_type << "\"");
5858  orientation = 0; // suppress a warning
5859  break;
5860  }
5861 
5862  if (orientation % 2 == 0) { continue; }
5863  wo++;
5864  if (!fix_it) { continue; }
5865 
5866  switch (bdr_type)
5867  {
5868  case Element::TRIANGLE:
5869  {
5870  // swap vertices 0 and 1 so that we don't change the marked edge:
5871  // (0,1,2) -> (1,0,2)
5872  mfem::Swap<int>(bv[0], bv[1]);
5873  if (bel_to_edge)
5874  {
5875  int *be = bel_to_edge->GetRow(i);
5876  mfem::Swap<int>(be[1], be[2]);
5877  }
5878  break;
5879  }
5881  {
5882  mfem::Swap<int>(bv[0], bv[2]);
5883  if (bel_to_edge)
5884  {
5885  int *be = bel_to_edge->GetRow(i);
5886  mfem::Swap<int>(be[0], be[1]);
5887  mfem::Swap<int>(be[2], be[3]);
5888  }
5889  break;
5890  }
5891  default: // unreachable
5892  break;
5893  }
5894  }
5895  }
5896  // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5897 #ifdef MFEM_DEBUG
5898  if (wo > 0)
5899  {
5900  mfem::out << "Boundary elements with wrong orientation: " << wo << " / "
5901  << NumOfBdrElements << " (" << fixed_or_not[fix_it ? 0 : 1]
5902  << ")" << endl;
5903  }
5904 #endif
5905  return wo;
5906 }
5907 
5909 {
5910  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
5911  int num_geoms = 0;
5912  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
5913  {
5914  if (HasGeometry(Geometry::Type(g))) { num_geoms++; }
5915  }
5916  return num_geoms;
5917 }
5918 
5920 {
5921  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
5922  el_geoms.SetSize(0);
5923  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
5924  {
5925  if (HasGeometry(Geometry::Type(g)))
5926  {
5927  el_geoms.Append(Geometry::Type(g));
5928  }
5929  }
5930 }
5931 
5932 void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const
5933 {
5934  if (el_to_edge)
5935  {
5936  el_to_edge->GetRow(i, edges);
5937  }
5938  else
5939  {
5940  mfem_error("Mesh::GetElementEdges(...) element to edge table "
5941  "is not generated.");
5942  }
5943 
5944  const int *v = elements[i]->GetVertices();
5945  const int ne = elements[i]->GetNEdges();
5946  cor.SetSize(ne);
5947  for (int j = 0; j < ne; j++)
5948  {
5949  const int *e = elements[i]->GetEdgeVertices(j);
5950  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5951  }
5952 }
5953 
5954 void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const
5955 {
5956  if (Dim == 2)
5957  {
5958  edges.SetSize(1);
5959  cor.SetSize(1);
5960  edges[0] = be_to_edge[i];
5961  const int *v = boundary[i]->GetVertices();
5962  cor[0] = (v[0] < v[1]) ? (1) : (-1);
5963  }
5964  else if (Dim == 3)
5965  {
5966  if (bel_to_edge)
5967  {
5968  bel_to_edge->GetRow(i, edges);
5969  }
5970  else
5971  {
5972  mfem_error("Mesh::GetBdrElementEdges(...)");
5973  }
5974 
5975  const int *v = boundary[i]->GetVertices();
5976  const int ne = boundary[i]->GetNEdges();
5977  cor.SetSize(ne);
5978  for (int j = 0; j < ne; j++)
5979  {
5980  const int *e = boundary[i]->GetEdgeVertices(j);
5981  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5982  }
5983  }
5984 }
5985 
5986 void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const
5987 {
5988  if (Dim == 2)
5989  {
5990  edges.SetSize(1);
5991  edges[0] = i;
5992  o.SetSize(1);
5993  const int *v = faces[i]->GetVertices();
5994  o[0] = (v[0] < v[1]) ? (1) : (-1);
5995  }
5996 
5997  if (Dim != 3)
5998  {
5999  return;
6000  }
6001 
6002  GetFaceEdgeTable(); // generate face_edge Table (if not generated)
6003 
6004  face_edge->GetRow(i, edges);
6005 
6006  const int *v = faces[i]->GetVertices();
6007  const int ne = faces[i]->GetNEdges();
6008  o.SetSize(ne);
6009  for (int j = 0; j < ne; j++)
6010  {
6011  const int *e = faces[i]->GetEdgeVertices(j);
6012  o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
6013  }
6014 }
6015 
6016 void Mesh::GetEdgeVertices(int i, Array<int> &vert) const
6017 {
6018  // the two vertices are sorted: vert[0] < vert[1]
6019  // this is consistent with the global edge orientation
6020  // generate edge_vertex Table (if not generated)
6021  if (!edge_vertex) { GetEdgeVertexTable(); }
6022  edge_vertex->GetRow(i, vert);
6023 }
6024 
6026 {
6027  if (face_edge)
6028  {
6029  return face_edge;
6030  }
6031 
6032  if (Dim != 3)
6033  {
6034  return NULL;
6035  }
6036 
6037 #ifdef MFEM_DEBUG
6038  if (faces.Size() != NumOfFaces)
6039  {
6040  mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!");
6041  }
6042 #endif
6043 
6044  DSTable v_to_v(NumOfVertices);
6045  GetVertexToVertexTable(v_to_v);
6046 
6047  face_edge = new Table;
6049 
6050  return (face_edge);
6051 }
6052 
6054 {
6055  if (edge_vertex)
6056  {
6057  return edge_vertex;
6058  }
6059 
6060  DSTable v_to_v(NumOfVertices);
6061  GetVertexToVertexTable(v_to_v);
6062 
6063  int nedges = v_to_v.NumberOfEntries();
6064  edge_vertex = new Table(nedges, 2);
6065  for (int i = 0; i < NumOfVertices; i++)
6066  {
6067  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
6068  {
6069  int j = it.Index();
6070  edge_vertex->Push(j, i);
6071  edge_vertex->Push(j, it.Column());
6072  }
6073  }
6074  edge_vertex->Finalize();
6075 
6076  return edge_vertex;
6077 }
6078 
6080 {
6081  int i, j, nv, *v;
6082 
6083  Table *vert_elem = new Table;
6084 
6085  vert_elem->MakeI(NumOfVertices);
6086 
6087  for (i = 0; i < NumOfElements; i++)
6088  {
6089  nv = elements[i]->GetNVertices();
6090  v = elements[i]->GetVertices();
6091  for (j = 0; j < nv; j++)
6092  {
6093  vert_elem->AddAColumnInRow(v[j]);
6094  }
6095  }
6096 
6097  vert_elem->MakeJ();
6098 
6099  for (i = 0; i < NumOfElements; i++)
6100  {
6101  nv = elements[i]->GetNVertices();
6102  v = elements[i]->GetVertices();
6103  for (j = 0; j < nv; j++)
6104  {
6105  vert_elem->AddConnection(v[j], i);
6106  }
6107  }
6108 
6109  vert_elem->ShiftUpI();
6110 
6111  return vert_elem;
6112 }
6113 
6115 {
6116  Table *face_elem = new Table;
6117 
6118  face_elem->MakeI(faces_info.Size());
6119 
6120  for (int i = 0; i < faces_info.Size(); i++)
6121  {
6122  if (faces_info[i].Elem2No >= 0)
6123  {
6124  face_elem->AddColumnsInRow(i, 2);
6125  }
6126  else
6127  {
6128  face_elem->AddAColumnInRow(i);
6129  }
6130  }
6131 
6132  face_elem->MakeJ();
6133 
6134  for (int i = 0; i < faces_info.Size(); i++)
6135  {
6136  face_elem->AddConnection(i, faces_info[i].Elem1No);
6137  if (faces_info[i].Elem2No >= 0)
6138  {
6139  face_elem->AddConnection(i, faces_info[i].Elem2No);
6140  }
6141  }
6142 
6143  face_elem->ShiftUpI();
6144 
6145  return face_elem;
6146 }
6147 
6148 void Mesh::GetElementFaces(int i, Array<int> &el_faces, Array<int> &ori) const
6149 {
6150  MFEM_VERIFY(el_to_face != NULL, "el_to_face not generated");
6151 
6152  el_to_face->GetRow(i, el_faces);
6153 
6154  int n = el_faces.Size();
6155  ori.SetSize(n);
6156 
6157  for (int j = 0; j < n; j++)
6158  {
6159  if (faces_info[el_faces[j]].Elem1No == i)
6160  {
6161  ori[j] = faces_info[el_faces[j]].Elem1Inf % 64;
6162  }
6163  else
6164  {
6165  MFEM_ASSERT(faces_info[el_faces[j]].Elem2No == i, "internal error");
6166  ori[j] = faces_info[el_faces[j]].Elem2Inf % 64;
6167  }
6168  }
6169 }
6170 
6171 void Mesh::GetBdrElementFace(int i, int *f, int *o) const
6172 {
6173  const int *bv, *fv;
6174 
6175  *f = be_to_face[i];
6176  bv = boundary[i]->GetVertices();
6177  fv = faces[be_to_face[i]]->GetVertices();
6178 
6179  // find the orientation of the bdr. elem. w.r.t.
6180  // the corresponding face element (that's the base)
6181  switch (GetBdrElementType(i))
6182  {
6183  case Element::TRIANGLE:
6184  *o = GetTriOrientation(fv, bv);
6185  break;
6187  *o = GetQuadOrientation(fv, bv);
6188  break;
6189  default:
6190  MFEM_ABORT("invalid geometry");
6191  }
6192 }
6193 
6195 {
6196  switch (Dim)
6197  {
6198  case 1: return boundary[i]->GetVertices()[0];
6199  case 2: return be_to_edge[i];
6200  case 3: return be_to_face[i];
6201  default: MFEM_ABORT("invalid dimension!");
6202  }
6203  return -1;
6204 }
6205 
6206 void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
6207 {
6208  int fid = GetBdrElementEdgeIndex(bdr_el);
6209 
6210  const FaceInfo &fi = faces_info[fid];
6211  MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
6212 
6213  const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
6214  const int *bv = boundary[bdr_el]->GetVertices();
6215  int ori;
6216  switch (GetBdrElementGeometry(bdr_el))
6217  {
6218  case Geometry::POINT: ori = 0; break;
6219  case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
6220  case Geometry::TRIANGLE: ori = GetTriOrientation(fv, bv); break;
6221  case Geometry::SQUARE: ori = GetQuadOrientation(fv, bv); break;
6222  default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
6223  }
6224  el = fi.Elem1No;
6225  info = fi.Elem1Inf + ori;
6226 }
6227 
6228 void Mesh::GetBdrElementAdjacentElement2(int bdr_el, int &el, int &info) const
6229 {
6230  int fid = GetBdrElementEdgeIndex(bdr_el);
6231 
6232  const FaceInfo &fi = faces_info[fid];
6233  MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
6234 
6235  const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
6236  const int *bv = boundary[bdr_el]->GetVertices();
6237  int ori;
6238  switch (GetBdrElementGeometry(bdr_el))
6239  {
6240  case Geometry::POINT: ori = 0; break;
6241  case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
6242  case Geometry::TRIANGLE: ori = GetTriOrientation(bv, fv); break;
6243  case Geometry::SQUARE: ori = GetQuadOrientation(bv, fv); break;
6244  default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
6245  }
6246  el = fi.Elem1No;
6247  info = fi.Elem1Inf + ori;
6248 }
6249 
6251 {
6252  return elements[i]->GetType();
6253 }
6254 
6256 {
6257  return boundary[i]->GetType();
6258 }
6259 
6260 void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const
6261 {
6262  int k, j, nv;
6263  const int *v;
6264 
6265  v = elements[i]->GetVertices();
6266  nv = elements[i]->GetNVertices();
6267 
6268  pointmat.SetSize(spaceDim, nv);
6269  for (k = 0; k < spaceDim; k++)
6270  {
6271  for (j = 0; j < nv; j++)
6272  {
6273  pointmat(k, j) = vertices[v[j]](k);
6274  }
6275  }
6276 }
6277 
6278 void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const
6279 {
6280  int k, j, nv;
6281  const int *v;
6282 
6283  v = boundary[i]->GetVertices();
6284  nv = boundary[i]->GetNVertices();
6285 
6286  pointmat.SetSize(spaceDim, nv);
6287  for (k = 0; k < spaceDim; k++)
6288  for (j = 0; j < nv; j++)
6289  {
6290  pointmat(k, j) = vertices[v[j]](k);
6291  }
6292 }
6293 
6294 double Mesh::GetLength(int i, int j) const
6295 {
6296  const double *vi = vertices[i]();
6297  const double *vj = vertices[j]();
6298  double length = 0.;
6299 
6300  for (int k = 0; k < spaceDim; k++)
6301  {
6302  length += (vi[k]-vj[k])*(vi[k]-vj[k]);
6303  }
6304 
6305  return sqrt(length);
6306 }
6307 
6308 // static method
6310  const DSTable &v_to_v, Table &el_to_edge)
6311 {
6312  el_to_edge.MakeI(elem_array.Size());
6313  for (int i = 0; i < elem_array.Size(); i++)
6314  {
6315  el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges());
6316  }
6317  el_to_edge.MakeJ();
6318  for (int i = 0; i < elem_array.Size(); i++)
6319  {
6320  const int *v = elem_array[i]->GetVertices();
6321  const int ne = elem_array[i]->GetNEdges();
6322  for (int j = 0; j < ne; j++)
6323  {
6324  const int *e = elem_array[i]->GetEdgeVertices(j);
6325  el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]]));
6326  }
6327  }
6328  el_to_edge.ShiftUpI();
6329 }
6330 
6332 {
6333  if (edge_vertex)
6334  {
6335  for (int i = 0; i < edge_vertex->Size(); i++)
6336  {
6337  const int *v = edge_vertex->GetRow(i);
6338  v_to_v.Push(v[0], v[1]);
6339  }
6340  }
6341  else
6342  {
6343  for (int i = 0; i < NumOfElements; i++)
6344  {
6345  const int *v = elements[i]->GetVertices();
6346  const int ne = elements[i]->GetNEdges();
6347  for (int j = 0; j < ne; j++)
6348  {
6349  const int *e = elements[i]->GetEdgeVertices(j);
6350  v_to_v.Push(v[e[0]], v[e[1]]);
6351  }
6352  }
6353  }
6354 }
6355 
6357 {
6358  int i, NumberOfEdges;
6359 
6360  DSTable v_to_v(NumOfVertices);
6361  GetVertexToVertexTable(v_to_v);
6362 
6363  NumberOfEdges = v_to_v.NumberOfEntries();
6364 
6365  // Fill the element to edge table
6366  GetElementArrayEdgeTable(elements, v_to_v, e_to_f);
6367 
6368  if (Dim == 2)
6369  {
6370  // Initialize the indices for the boundary elements.
6371  be_to_f.SetSize(NumOfBdrElements);
6372  for (i = 0; i < NumOfBdrElements; i++)
6373  {
6374  const int *v = boundary[i]->GetVertices();
6375  be_to_f[i] = v_to_v(v[0], v[1]);
6376  }
6377  }
6378  else if (Dim == 3)
6379  {
6380  if (bel_to_edge == NULL)
6381  {
6382  bel_to_edge = new Table;
6383  }
6385  }
6386  else
6387  {
6388  mfem_error("1D GetElementToEdgeTable is not yet implemented.");
6389  }
6390 
6391  // Return the number of edges
6392  return NumberOfEdges;
6393 }
6394 
6396 {
6397  if (el_to_el)
6398  {
6399  return *el_to_el;
6400  }
6401 
6402  // Note that, for ParNCMeshes, faces_info will contain also the ghost faces
6403  MFEM_ASSERT(faces_info.Size() >= GetNumFaces(), "faces were not generated!");
6404 
6405  Array<Connection> conn;
6406  conn.Reserve(2*faces_info.Size());
6407 
6408  for (int i = 0; i < faces_info.Size(); i++)
6409  {
6410  const FaceInfo &fi = faces_info[i];
6411  if (fi.Elem2No >= 0)
6412  {
6413  conn.Append(Connection(fi.Elem1No, fi.Elem2No));
6414  conn.Append(Connection(fi.Elem2No, fi.Elem1No));
6415  }
6416  else if (fi.Elem2Inf >= 0)
6417  {
6418  int nbr_elem_idx = NumOfElements - 1 - fi.Elem2No;
6419  conn.Append(Connection(fi.Elem1No, nbr_elem_idx));
6420  conn.Append(Connection(nbr_elem_idx, fi.Elem1No));
6421  }
6422  }
6423 
6424  conn.Sort();
6425  conn.Unique();
6426  el_to_el = new Table(NumOfElements, conn);
6427 
6428  return *el_to_el;
6429 }
6430 
6432 {
6433  if (el_to_face == NULL)
6434  {
6435  mfem_error("Mesh::ElementToFaceTable()");
6436  }
6437  return *el_to_face;
6438 }
6439 
6441 {
6442  if (el_to_edge == NULL)
6443  {
6444  mfem_error("Mesh::ElementToEdgeTable()");
6445  }
6446  return *el_to_edge;
6447 }
6448 
6449 void Mesh::AddPointFaceElement(int lf, int gf, int el)
6450 {
6451  if (faces_info[gf].Elem1No == -1) // this will be elem1
6452  {
6453  // faces[gf] = new Point(&gf);
6454  faces_info[gf].Elem1No = el;
6455  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6456  faces_info[gf].Elem2No = -1; // in case there's no other side
6457  faces_info[gf].Elem2Inf = -1; // face is not shared
6458  }
6459  else // this will be elem2
6460  {
6461  /* WARNING: Without the following check the mesh faces_info data structure
6462  may contain unreliable data. Normally, the order in which elements are
6463  processed could swap which elements appear as Elem1No and Elem2No. In
6464  branched meshes, where more than two elements can meet at a given node,
6465  the indices stored in Elem1No and Elem2No will be the first and last,
6466  respectively, elements found which touch a given node. This can lead to
6467  inconsistencies in any algorithms which rely on this data structure. To
6468  properly support branched meshes this data structure should be extended
6469  to support multiple elements per face. */
6470  /*
6471  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6472  "Interior point found connecting 1D elements "
6473  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6474  << " and " << el << ".");
6475  */
6476  faces_info[gf].Elem2No = el;
6477  faces_info[gf].Elem2Inf = 64 * lf + 1;
6478  }
6479 }
6480 
6481 void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
6482 {
6483  if (faces[gf] == NULL) // this will be elem1
6484  {
6485  faces[gf] = new Segment(v0, v1);
6486  faces_info[gf].Elem1No = el;
6487  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6488  faces_info[gf].Elem2No = -1; // in case there's no other side
6489  faces_info[gf].Elem2Inf = -1; // face is not shared
6490  }
6491  else // this will be elem2
6492  {
6493  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6494  "Interior edge found between 2D elements "
6495  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6496  << " and " << el << ".");
6497  int *v = faces[gf]->GetVertices();
6498  faces_info[gf].Elem2No = el;
6499  if ( v[1] == v0 && v[0] == v1 )
6500  {
6501  faces_info[gf].Elem2Inf = 64 * lf + 1;
6502  }
6503  else if ( v[0] == v0 && v[1] == v1 )
6504  {
6505  // Temporarily allow even edge orientations: see the remark in
6506  // AddTriangleFaceElement().
6507  // Also, in a non-orientable surface mesh, the orientation will be even
6508  // for edges that connect elements with opposite orientations.
6509  faces_info[gf].Elem2Inf = 64 * lf;
6510  }
6511  else
6512  {
6513  MFEM_ABORT("internal error");
6514  }
6515  }
6516 }
6517 
6518 void Mesh::AddTriangleFaceElement(int lf, int gf, int el,
6519  int v0, int v1, int v2)
6520 {
6521  if (faces[gf] == NULL) // this will be elem1
6522  {
6523  faces[gf] = new Triangle(v0, v1, v2);
6524  faces_info[gf].Elem1No = el;
6525  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6526  faces_info[gf].Elem2No = -1; // in case there's no other side
6527  faces_info[gf].Elem2Inf = -1; // face is not shared
6528  }
6529  else // this will be elem2
6530  {
6531  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6532  "Interior triangular face found connecting elements "
6533  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6534  << " and " << el << ".");
6535  int orientation, vv[3] = { v0, v1, v2 };
6536  orientation = GetTriOrientation(faces[gf]->GetVertices(), vv);
6537  // In a valid mesh, we should have (orientation % 2 != 0), however, if
6538  // one of the adjacent elements has wrong orientation, both face
6539  // orientations can be even, until the element orientations are fixed.
6540  // MFEM_ASSERT(orientation % 2 != 0, "");
6541  faces_info[gf].Elem2No = el;
6542  faces_info[gf].Elem2Inf = 64 * lf + orientation;
6543  }
6544 }
6545 
6546 void Mesh::AddQuadFaceElement(int lf, int gf, int el,
6547  int v0, int v1, int v2, int v3)
6548 {
6549  if (faces_info[gf].Elem1No < 0) // this will be elem1
6550  {
6551  faces[gf] = new Quadrilateral(v0, v1, v2, v3);
6552  faces_info[gf].Elem1No = el;
6553  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6554  faces_info[gf].Elem2No = -1; // in case there's no other side
6555  faces_info[gf].Elem2Inf = -1; // face is not shared
6556  }
6557  else // this will be elem2
6558  {
6559  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6560  "Interior quadrilateral face found connecting elements "
6561  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6562  << " and " << el << ".");
6563  int vv[4] = { v0, v1, v2, v3 };
6564  int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv);
6565  // Temporarily allow even face orientations: see the remark in
6566  // AddTriangleFaceElement().
6567  // MFEM_ASSERT(oo % 2 != 0, "");
6568  faces_info[gf].Elem2No = el;
6569  faces_info[gf].Elem2Inf = 64 * lf + oo;
6570  }
6571 }
6572 
6574 {
6575  int i, nfaces = GetNumFaces();
6576 
6577  for (i = 0; i < faces.Size(); i++)
6578  {
6579  FreeElement(faces[i]);
6580  }
6581 
6582  // (re)generate the interior faces and the info for them
6583  faces.SetSize(nfaces);
6584  faces_info.SetSize(nfaces);
6585  for (i = 0; i < nfaces; i++)
6586  {
6587  faces[i] = NULL;
6588  faces_info[i].Elem1No = -1;
6589  faces_info[i].NCFace = -1;
6590  }
6591  for (i = 0; i < NumOfElements; i++)
6592  {
6593  const int *v = elements[i]->GetVertices();
6594  const int *ef;
6595  if (Dim == 1)
6596  {
6597  AddPointFaceElement(0, v[0], i);
6598  AddPointFaceElement(1, v[1], i);
6599  }
6600  else if (Dim == 2)
6601  {
6602  ef = el_to_edge->GetRow(i);
6603  const int ne = elements[i]->GetNEdges();
6604  for (int j = 0; j < ne; j++)
6605  {
6606  const int *e = elements[i]->GetEdgeVertices(j);
6607  AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]);
6608  }
6609  }
6610  else
6611  {
6612  ef = el_to_face->GetRow(i);
6613  switch (GetElementType(i))
6614  {
6615  case Element::TETRAHEDRON:
6616  {
6617  for (int j = 0; j < 4; j++)
6618  {
6619  const int *fv = tet_t::FaceVert[j];
6620  AddTriangleFaceElement(j, ef[j], i,
6621  v[fv[0]], v[fv[1]], v[fv[2]]);
6622  }
6623  break;
6624  }
6625  case Element::WEDGE:
6626  {
6627  for (int j = 0; j < 2; j++)
6628  {
6629  const int *fv = pri_t::FaceVert[j];
6630  AddTriangleFaceElement(j, ef[j], i,
6631  v[fv[0]], v[fv[1]], v[fv[2]]);
6632  }
6633  for (int j = 2; j < 5; j++)
6634  {
6635  const int *fv = pri_t::FaceVert[j];
6636  AddQuadFaceElement(j, ef[j], i,
6637  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6638  }
6639  break;
6640  }
6641  case Element::PYRAMID:
6642  {
6643  for (int j = 0; j < 1; j++)
6644  {
6645  const int *fv = pyr_t::FaceVert[j];
6646  AddQuadFaceElement(j, ef[j], i,
6647  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6648  }
6649  for (int j = 1; j < 5; j++)
6650  {
6651  const int *fv = pyr_t::FaceVert[j];
6652  AddTriangleFaceElement(j, ef[j], i,
6653  v[fv[0]], v[fv[1]], v[fv[2]]);
6654  }
6655  break;
6656  }
6657  case Element::HEXAHEDRON:
6658  {
6659  for (int j = 0; j < 6; j++)
6660  {
6661  const int *fv = hex_t::FaceVert[j];
6662  AddQuadFaceElement(j, ef[j], i,
6663  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6664  }
6665  break;
6666  }
6667  default:
6668  MFEM_ABORT("Unexpected type of Element.");
6669  }
6670  }
6671  }
6672 }
6673 
6675 {
6676  MFEM_VERIFY(ncmesh, "missing NCMesh.");
6677 
6678  for (int i = 0; i < faces_info.Size(); i++)
6679  {
6680  faces_info[i].NCFace = -1;
6681  }
6682 
6683  const NCMesh::NCList &list =
6684  (Dim == 2) ? ncmesh->GetEdgeList() : ncmesh->GetFaceList();
6685 
6686  nc_faces_info.SetSize(0);
6687  nc_faces_info.Reserve(list.masters.Size() + list.slaves.Size());
6688 
6689  int nfaces = GetNumFaces();
6690 
6691  // add records for master faces
6692  for (int i = 0; i < list.masters.Size(); i++)
6693  {
6694  const NCMesh::Master &master = list.masters[i];
6695  if (master.index >= nfaces) { continue; }
6696 
6697  FaceInfo &master_fi = faces_info[master.index];
6698  master_fi.NCFace = nc_faces_info.Size();
6699  nc_faces_info.Append(NCFaceInfo(false, master.local, NULL));
6700  // NOTE: one of the unused members stores local face no. to be used below
6701  MFEM_ASSERT(master_fi.Elem2No == -1, "internal error");
6702  MFEM_ASSERT(master_fi.Elem2Inf == -1, "internal error");
6703  }
6704 
6705  // add records for slave faces
6706  for (int i = 0; i < list.slaves.Size(); i++)
6707  {
6708  const NCMesh::Slave &slave = list.slaves[i];
6709 
6710  if (slave.index < 0 || // degenerate slave face
6711  slave.index >= nfaces || // ghost slave
6712  slave.master >= nfaces) // has ghost master
6713  {
6714  continue;
6715  }
6716 
6717  FaceInfo &slave_fi = faces_info[slave.index];
6718  FaceInfo &master_fi = faces_info[slave.master];
6719  NCFaceInfo &master_nc = nc_faces_info[master_fi.NCFace];
6720 
6721  slave_fi.NCFace = nc_faces_info.Size();
6722  slave_fi.Elem2No = master_fi.Elem1No;
6723  slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
6724  // NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
6725  // matrix. In 2D, the point matrix has the orientation of the parent
6726  // edge, so its columns need to be flipped when applying it, see
6727  // ApplyLocalSlaveTransformation.
6728 
6729  nc_faces_info.Append(
6730  NCFaceInfo(true, slave.master,
6731  list.point_matrices[slave.geom][slave.matrix]));
6732  }
6733 }
6734 
6736 {
6737  STable3D *faces_tbl = new STable3D(NumOfVertices);
6738  for (int i = 0; i < NumOfElements; i++)
6739  {
6740  const int *v = elements[i]->GetVertices();
6741  switch (GetElementType(i))
6742  {
6743  case Element::TETRAHEDRON:
6744  {
6745  for (int j = 0; j < 4; j++)
6746  {
6747  const int *fv = tet_t::FaceVert[j];
6748  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6749  }
6750  break;
6751  }
6752  case Element::PYRAMID:
6753  {
6754  for (int j = 0; j < 1; j++)
6755  {
6756  const int *fv = pyr_t::FaceVert[j];
6757  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6758  }
6759  for (int j = 1; j < 5; j++)
6760  {
6761  const int *fv = pyr_t::FaceVert[j];
6762  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6763  }
6764  break;
6765  }
6766  case Element::WEDGE:
6767  {
6768  for (int j = 0; j < 2; j++)
6769  {
6770  const int *fv = pri_t::FaceVert[j];
6771  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6772  }
6773  for (int j = 2; j < 5; j++)
6774  {
6775  const int *fv = pri_t::FaceVert[j];
6776  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6777  }
6778  break;
6779  }
6780  case Element::HEXAHEDRON:
6781  {
6782  // find the face by the vertices with the smallest 3 numbers
6783  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
6784  for (int j = 0; j < 6; j++)
6785  {
6786  const int *fv = hex_t::FaceVert[j];
6787  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6788  }
6789  break;
6790  }
6791  default:
6792  MFEM_ABORT("Unexpected type of Element.");
6793  }
6794  }
6795  return faces_tbl;
6796 }
6797 
6799 {
6800  int i, *v;
6801  STable3D *faces_tbl;
6802 
6803  if (el_to_face != NULL)
6804  {
6805  delete el_to_face;
6806  }
6807  el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra
6808  faces_tbl = new STable3D(NumOfVertices);
6809  for (i = 0; i < NumOfElements; i++)
6810  {
6811  v = elements[i]->GetVertices();
6812  switch (GetElementType(i))
6813  {
6814  case Element::TETRAHEDRON:
6815  {
6816  for (int j = 0; j < 4; j++)
6817  {
6818  const int *fv = tet_t::FaceVert[j];
6819  el_to_face->Push(
6820  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6821  }
6822  break;
6823  }
6824  case Element::WEDGE:
6825  {
6826  for (int j = 0; j < 2; j++)
6827  {
6828  const int *fv = pri_t::FaceVert[j];
6829  el_to_face->Push(
6830  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6831  }
6832  for (int j = 2; j < 5; j++)
6833  {
6834  const int *fv = pri_t::FaceVert[j];
6835  el_to_face->Push(
6836  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6837  }
6838  break;
6839  }
6840  case Element::PYRAMID:
6841  {
6842  for (int j = 0; j < 1; j++)
6843  {
6844  const int *fv = pyr_t::FaceVert[j];
6845  el_to_face->Push(
6846  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6847  }
6848  for (int j = 1; j < 5; j++)
6849  {
6850  const int *fv = pyr_t::FaceVert[j];
6851  el_to_face->Push(
6852  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6853  }
6854  break;
6855  }
6856  case Element::HEXAHEDRON:
6857  {
6858  // find the face by the vertices with the smallest 3 numbers
6859  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
6860  for (int j = 0; j < 6; j++)
6861  {
6862  const int *fv = hex_t::FaceVert[j];
6863  el_to_face->Push(
6864  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6865  }
6866  break;
6867  }
6868  default:
6869  MFEM_ABORT("Unexpected type of Element.");
6870  }
6871  }
6872  el_to_face->Finalize();
6873  NumOfFaces = faces_tbl->NumberOfElements();
6875  for (i = 0; i < NumOfBdrElements; i++)
6876  {
6877  v = boundary[i]->GetVertices();
6878  switch (GetBdrElementType(i))
6879  {
6880  case Element::TRIANGLE:
6881  {
6882  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]);
6883  break;
6884  }
6886  {
6887  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
6888  break;
6889  }
6890  default:
6891  MFEM_ABORT("Unexpected type of boundary Element.");
6892  }
6893  }
6894 
6895  if (ret_ftbl)
6896  {
6897  return faces_tbl;
6898  }
6899  delete faces_tbl;
6900  return NULL;
6901 }
6902 
6903 // shift cyclically 3 integers so that the smallest is first
6904 static inline
6905 void Rotate3(int &a, int &b, int &c)
6906 {
6907  if (a < b)
6908  {
6909  if (a > c)
6910  {
6911  ShiftRight(a, b, c);
6912  }
6913  }
6914  else
6915  {
6916  if (b < c)
6917  {
6918  ShiftRight(c, b, a);
6919  }
6920  else
6921  {
6922  ShiftRight(a, b, c);
6923  }
6924  }
6925 }
6926 
6928 {
6929  if (Dim != 3 || !(meshgen & 1))
6930  {
6931  return;
6932  }
6933 
6934  ResetLazyData();
6935 
6936  DSTable *old_v_to_v = NULL;
6937  Table *old_elem_vert = NULL;
6938 
6939  if (Nodes)
6940  {
6941  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
6942  }
6943 
6944  for (int i = 0; i < NumOfElements; i++)
6945  {
6947  {
6948  int *v = elements[i]->GetVertices();
6949 
6950  Rotate3(v[0], v[1], v[2]);
6951  if (v[0] < v[3])
6952  {
6953  Rotate3(v[1], v[2], v[3]);
6954  }
6955  else
6956  {
6957  ShiftRight(v[0], v[1], v[3]);
6958  }
6959  }
6960  }
6961 
6962  for (int i = 0; i < NumOfBdrElements; i++)
6963  {
6965  {
6966  int *v = boundary[i]->GetVertices();
6967 
6968  Rotate3(v[0], v[1], v[2]);
6969  }
6970  }
6971 
6972  if (!Nodes)
6973  {
6975  GenerateFaces();
6976  if (el_to_edge)
6977  {
6979  }
6980  }
6981  else
6982  {
6983  DoNodeReorder(old_v_to_v, old_elem_vert);
6984  delete old_elem_vert;
6985  delete old_v_to_v;
6986  }
6987 }
6988 
6990 {
6991  int *partitioning;
6992  double pmin[3] = { infinity(), infinity(), infinity() };
6993  double pmax[3] = { -infinity(), -infinity(), -infinity() };
6994  // find a bounding box using the vertices
6995  for (int vi = 0; vi < NumOfVertices; vi++)
6996  {
6997  const double *p = vertices[vi]();
6998  for (int i = 0; i < spaceDim; i++)
6999  {
7000  if (p[i] < pmin[i]) { pmin[i] = p[i]; }
7001  if (p[i] > pmax[i]) { pmax[i] = p[i]; }
7002  }
7003  }
7004 
7005  partitioning = new int[NumOfElements];
7006 
7007  // determine the partitioning using the centers of the elements
7008  double ppt[3];
7009  Vector pt(ppt, spaceDim);
7010  for (int el = 0; el < NumOfElements; el++)
7011  {
7012  GetElementTransformation(el)->Transform(
7014  int part = 0;
7015  for (int i = spaceDim-1; i >= 0; i--)
7016  {
7017  int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i])));
7018  if (idx < 0) { idx = 0; }
7019  if (idx >= nxyz[i]) { idx = nxyz[i]-1; }
7020  part = part * nxyz[i] + idx;
7021  }
7022  partitioning[el] = part;
7023  }
7024 
7025  return partitioning;
7026 }
7027 
7028 void FindPartitioningComponents(Table &elem_elem,
7029  const Array<int> &partitioning,
7030  Array<int> &component,
7031  Array<int> &num_comp);
7032 
7033 int *Mesh::GeneratePartitioning(int nparts, int part_method)
7034 {
7035 #ifdef MFEM_USE_METIS
7036 
7037  int print_messages = 1;
7038  // If running in parallel, print messages only from rank 0.
7039 #ifdef MFEM_USE_MPI
7040  int init_flag, fin_flag;
7041  MPI_Initialized(&init_flag);
7042  MPI_Finalized(&fin_flag);
7043  if (init_flag && !fin_flag)
7044  {
7045  int rank;
7046  MPI_Comm_rank(GetGlobalMPI_Comm(), &rank);
7047  if (rank != 0) { print_messages = 0; }
7048  }
7049 #endif
7050 
7051  int i, *partitioning;
7052 
7054 
7055  partitioning = new int[NumOfElements];
7056 
7057  if (nparts == 1)
7058  {
7059  for (i = 0; i < NumOfElements; i++)
7060  {
7061  partitioning[i] = 0;
7062  }
7063  }
7064  else if (NumOfElements <= nparts)
7065  {
7066  for (i = 0; i < NumOfElements; i++)
7067  {
7068  partitioning[i] = i;
7069  }
7070  }
7071  else
7072  {
7073  idx_t *I, *J, n;
7074 #ifndef MFEM_USE_METIS_5
7075  idx_t wgtflag = 0;
7076  idx_t numflag = 0;
7077  idx_t options[5];
7078 #else
7079  idx_t ncon = 1;
7080  idx_t errflag;
7081  idx_t options[40];
7082 #endif
7083  idx_t edgecut;
7084 
7085  // In case METIS have been compiled with 64bit indices
7086  bool freedata = false;
7087  idx_t mparts = (idx_t) nparts;
7088  idx_t *mpartitioning;
7089 
7090  n = NumOfElements;
7091  if (sizeof(idx_t) == sizeof(int))
7092  {
7093  I = (idx_t*) el_to_el->GetI();
7094  J = (idx_t*) el_to_el->GetJ();
7095  mpartitioning = (idx_t*) partitioning;
7096  }
7097  else
7098  {
7099  int *iI = el_to_el->GetI();
7100  int *iJ = el_to_el->GetJ();
7101  int m = iI[n];
7102  I = new idx_t[n+1];
7103  J = new idx_t[m];
7104  for (int k = 0; k < n+1; k++) { I[k] = iI[k]; }
7105  for (int k = 0; k < m; k++) { J[k] = iJ[k]; }
7106  mpartitioning = new idx_t[n];
7107  freedata = true;
7108  }
7109 #ifndef MFEM_USE_METIS_5
7110  options[0] = 0;
7111 #else
7112  METIS_SetDefaultOptions(options);
7113  options[METIS_OPTION_CONTIG] = 1; // set METIS_OPTION_CONTIG
7114  // If the mesh is disconnected, disable METIS_OPTION_CONTIG.
7115  {
7116  Array<int> part(partitioning, NumOfElements);
7117  part = 0; // single part for the whole mesh
7118  Array<int> component; // size will be set to num. elem.
7119  Array<int> num_comp; // size will be set to num. parts (1)
7120  FindPartitioningComponents(*el_to_el, part, component, num_comp);
7121  if (num_comp[0] > 1) { options[METIS_OPTION_CONTIG] = 0; }
7122  }
7123 #endif
7124 
7125  // Sort the neighbor lists
7126  if (part_method >= 0 && part_method <= 2)
7127  {
7128  for (i = 0; i < n; i++)
7129  {
7130  // Sort in increasing order.
7131  // std::sort(J+I[i], J+I[i+1]);
7132 
7133  // Sort in decreasing order, as in previous versions of MFEM.
7134  std::sort(J+I[i], J+I[i+1], std::greater<idx_t>());
7135  }
7136  }
7137 
7138  // This function should be used to partition a graph into a small
7139  // number of partitions (less than 8).
7140  if (part_method == 0 || part_method == 3)
7141  {
7142 #ifndef MFEM_USE_METIS_5
7144  I,
7145  J,
7146  NULL,
7147  NULL,
7148  &wgtflag,
7149  &numflag,
7150  &mparts,
7151  options,
7152  &edgecut,
7153  mpartitioning);
7154 #else
7155  errflag = METIS_PartGraphRecursive(&n,
7156  &ncon,
7157  I,
7158  J,
7159  NULL,
7160  NULL,
7161  NULL,
7162  &mparts,
7163  NULL,
7164  NULL,
7165  options,
7166  &edgecut,
7167  mpartitioning);
7168  if (errflag != 1)
7169  {
7170  mfem_error("Mesh::GeneratePartitioning: "
7171  " error in METIS_PartGraphRecursive!");
7172  }
7173 #endif
7174  }
7175 
7176  // This function should be used to partition a graph into a large
7177  // number of partitions (greater than 8).
7178  if (part_method == 1 || part_method == 4)
7179  {
7180 #ifndef MFEM_USE_METIS_5
7182  I,
7183  J,
7184  NULL,
7185  NULL,
7186  &wgtflag,
7187  &numflag,
7188  &mparts,
7189  options,
7190  &edgecut,
7191  mpartitioning);
7192 #else
7193  errflag = METIS_PartGraphKway(&n,
7194  &ncon,
7195  I,
7196  J,
7197  NULL,
7198  NULL,
7199  NULL,
7200  &mparts,
7201  NULL,
7202  NULL,
7203  options,
7204  &edgecut,
7205  mpartitioning);
7206  if (errflag != 1)
7207  {
7208  mfem_error("Mesh::GeneratePartitioning: "
7209  " error in METIS_PartGraphKway!");
7210  }
7211 #endif
7212  }
7213 
7214  // The objective of this partitioning is to minimize the total
7215  // communication volume
7216  if (part_method == 2 || part_method == 5)
7217  {
7218 #ifndef MFEM_USE_METIS_5
7220  I,
7221  J,
7222  NULL,
7223  NULL,
7224  &wgtflag,
7225  &numflag,
7226  &mparts,
7227  options,
7228  &edgecut,
7229  mpartitioning);
7230 #else
7231  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
7232  errflag = METIS_PartGraphKway(&n,
7233  &ncon,
7234  I,
7235  J,
7236  NULL,
7237  NULL,
7238  NULL,
7239  &mparts,
7240  NULL,
7241  NULL,
7242  options,
7243  &edgecut,
7244  mpartitioning);
7245  if (errflag != 1)
7246  {
7247  mfem_error("Mesh::GeneratePartitioning: "
7248  " error in METIS_PartGraphKway!");
7249  }
7250 #endif
7251  }
7252 
7253 #ifdef MFEM_DEBUG
7254  if (print_messages)
7255  {
7256  mfem::out << "Mesh::GeneratePartitioning(...): edgecut = "
7257  << edgecut << endl;
7258  }
7259 #endif
7260  nparts = (int) mparts;
7261  if (mpartitioning != (idx_t*)partitioning)
7262  {
7263  for (int k = 0; k<NumOfElements; k++)
7264  {
7265  partitioning[k] = mpartitioning[k];
7266  }
7267  }
7268  if (freedata)
7269  {
7270  delete[] I;
7271  delete[] J;
7272  delete[] mpartitioning;
7273  }
7274  }
7275 
7276  delete el_to_el;
7277  el_to_el = NULL;
7278 
7279  // Check for empty partitionings (a "feature" in METIS)
7280  if (nparts > 1 && NumOfElements > nparts)
7281  {
7282  Array< Pair<int,int> > psize(nparts);
7283  int empty_parts;
7284 
7285  // Count how many elements are in each partition, and store the result in
7286  // psize, where psize[i].one is the number of elements, and psize[i].two
7287  // is partition index. Keep track of the number of empty parts.
7288  auto count_partition_elements = [&]()
7289  {
7290  for (i = 0; i < nparts; i++)
7291  {
7292  psize[i].one = 0;
7293  psize[i].two = i;
7294  }
7295 
7296  for (i = 0; i < NumOfElements; i++)
7297  {
7298  psize[partitioning[i]].one++;
7299  }
7300 
7301  empty_parts = 0;
7302  for (i = 0; i < nparts; i++)
7303  {
7304  if (psize[i].one == 0) { empty_parts++; }
7305  }
7306  };
7307 
7308  count_partition_elements();
7309 
7310  // This code just split the largest partitionings in two.
7311  // Do we need to replace it with something better?
7312  while (empty_parts)
7313  {
7314  if (print_messages)
7315  {
7316  mfem::err << "Mesh::GeneratePartitioning(...): METIS returned "
7317  << empty_parts << " empty parts!"
7318  << " Applying a simple fix ..." << endl;
7319  }
7320 
7321  SortPairs<int,int>(psize, nparts);
7322 
7323  for (i = nparts-1; i > nparts-1-empty_parts; i--)
7324  {
7325  psize[i].one /= 2;
7326  }
7327 
7328  for (int j = 0; j < NumOfElements; j++)
7329  {
7330  for (i = nparts-1; i > nparts-1-empty_parts; i--)
7331  {
7332  if (psize[i].one == 0 || partitioning[j] != psize[i].two)
7333  {
7334  continue;
7335  }
7336  else
7337  {
7338  partitioning[j] = psize[nparts-1-i].two;
7339  psize[i].one--;
7340  }
7341  }
7342  }
7343 
7344  // Check for empty partitionings again
7345  count_partition_elements();
7346  }
7347  }
7348 
7349  return partitioning;
7350 
7351 #else
7352 
7353  mfem_error("Mesh::GeneratePartitioning(...): "
7354  "MFEM was compiled without Metis.");
7355 
7356  return NULL;
7357 
7358 #endif
7359 }
7360 
7361 /* required: 0 <= partitioning[i] < num_part */
7363  const Array<int> &partitioning,
7364  Array<int> &component,
7365  Array<int> &num_comp)
7366 {
7367  int i, j, k;
7368  int num_elem, *i_elem_elem, *j_elem_elem;
7369 
7370  num_elem = elem_elem.Size();
7371  i_elem_elem = elem_elem.GetI();
7372  j_elem_elem = elem_elem.GetJ();
7373 
7374  component.SetSize(num_elem);
7375 
7376  Array<int> elem_stack(num_elem);
7377  int stack_p, stack_top_p, elem;
7378  int num_part;
7379 
7380  num_part = -1;
7381  for (i = 0; i < num_elem; i++)
7382  {
7383  if (partitioning[i] > num_part)
7384  {
7385  num_part = partitioning[i];
7386  }
7387  component[i] = -1;
7388  }
7389  num_part++;
7390 
7391  num_comp.SetSize(num_part);
7392  for (i = 0; i < num_part; i++)
7393  {
7394  num_comp[i] = 0;
7395  }
7396 
7397  stack_p = 0;
7398  stack_top_p = 0; // points to the first unused element in the stack
7399  for (elem = 0; elem < num_elem; elem++)
7400  {
7401  if (component[elem] >= 0)
7402  {
7403  continue;
7404  }
7405 
7406  component[elem] = num_comp[partitioning[elem]]++;
7407 
7408  elem_stack[stack_top_p++] = elem;
7409 
7410  for ( ; stack_p < stack_top_p; stack_p++)
7411  {
7412  i = elem_stack[stack_p];
7413  for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++)
7414  {
7415  k = j_elem_elem[j];
7416  if (partitioning[k] == partitioning[i])
7417  {
7418  if (component[k] < 0)
7419  {
7420  component[k] = component[i];
7421  elem_stack[stack_top_p++] = k;
7422  }
7423  else if (component[k] != component[i])
7424  {
7425  mfem_error("FindPartitioningComponents");
7426  }
7427  }
7428  }
7429  }
7430  }
7431 }
7432 
7433 void Mesh::CheckPartitioning(int *partitioning_)
7434 {
7435  int i, n_empty, n_mcomp;
7436  Array<int> component, num_comp;
7437  const Array<int> partitioning(partitioning_, GetNE());
7438 
7440 
7441  FindPartitioningComponents(*el_to_el, partitioning, component, num_comp);
7442 
7443  n_empty = n_mcomp = 0;
7444  for (i = 0; i < num_comp.Size(); i++)
7445  if (num_comp[i] == 0)
7446  {
7447  n_empty++;
7448  }
7449  else if (num_comp[i] > 1)
7450  {
7451  n_mcomp++;
7452  }
7453 
7454  if (n_empty > 0)
7455  {
7456  mfem::out << "Mesh::CheckPartitioning(...) :\n"
7457  << "The following subdomains are empty :\n";
7458  for (i = 0; i < num_comp.Size(); i++)
7459  if (num_comp[i] == 0)
7460  {
7461  mfem::out << ' ' << i;
7462  }
7463  mfem::out << endl;
7464  }
7465  if (n_mcomp > 0)
7466  {
7467  mfem::out << "Mesh::CheckPartitioning(...) :\n"
7468  << "The following subdomains are NOT connected :\n";
7469  for (i = 0; i < num_comp.Size(); i++)
7470  if (num_comp[i] > 1)
7471  {
7472  mfem::out << ' ' << i;
7473  }
7474  mfem::out << endl;
7475  }
7476  if (n_empty == 0 && n_mcomp == 0)
7477  mfem::out << "Mesh::CheckPartitioning(...) : "
7478  "All subdomains are connected." << endl;
7479 
7480  if (el_to_el)
7481  {
7482  delete el_to_el;
7483  }
7484  el_to_el = NULL;
7485 }
7486 
7487 // compute the coefficients of the polynomial in t:
7488 // c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B)
7489 // where A, B are (d x d), d=2,3
7490 void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
7491 {
7492  const double *a = A.Data();
7493  const double *b = B.Data();
7494 
7495  c.SetSize(A.Width()+1);
7496  switch (A.Width())
7497  {
7498  case 2:
7499  {
7500  // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ |b0 b2|
7501  // |a1 a3| + \ |a1 b3| |b1 a3| / * t + |b1 b3| * t^2
7502  c(0) = a[0]*a[3]-a[1]*a[2];
7503  c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2];
7504  c(2) = b[0]*b[3]-b[1]*b[2];
7505  }
7506  break;
7507 
7508  case 3:
7509  {
7510  /* |a0 a3 a6|
7511  * det(A+t*B) = |a1 a4 a7| +
7512  * |a2 a5 a8|
7513 
7514  * / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \
7515  * + | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t +
7516  * \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| /
7517 
7518  * / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \
7519  * + | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 +
7520  * \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| /
7521 
7522  * |b0 b3 b6|
7523  * + |b1 b4 b7| * t^3
7524  * |b2 b5 b8| */
7525  c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) +
7526  a[1] * (a[5] * a[6] - a[3] * a[8]) +
7527  a[2] * (a[3] * a[7] - a[4] * a[6]));
7528 
7529  c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) +
7530  b[1] * (a[5] * a[6] - a[3] * a[8]) +
7531  b[2] * (a[3] * a[7] - a[4] * a[6]) +
7532 
7533  a[0] * (b[4] * a[8] - b[5] * a[7]) +
7534  a[1] * (b[5] * a[6] - b[3] * a[8]) +
7535  a[2] * (b[3] * a[7] - b[4] * a[6]) +
7536 
7537  a[0] * (a[4] * b[8] - a[5] * b[7]) +
7538  a[1] * (a[5] * b[6] - a[3] * b[8]) +
7539  a[2] * (a[3] * b[7] - a[4] * b[6]));
7540 
7541  c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) +
7542  a[1] * (b[5] * b[6] - b[3] * b[8]) +
7543  a[2] * (b[3] * b[7] - b[4] * b[6]) +
7544 
7545  b[0] * (a[4] * b[8] - a[5] * b[7]) +
7546  b[1] * (a[5] * b[6] - a[3] * b[8]) +
7547  b[2] * (a[3] * b[7] - a[4] * b[6]) +
7548 
7549  b[0] * (b[4] * a[8] - b[5] * a[7]) +
7550  b[1] * (b[5] * a[6] - b[3] * a[8]) +
7551  b[2] * (b[3] * a[7] - b[4] * a[6]));
7552 
7553  c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) +
7554  b[1] * (b[5] * b[6] - b[3] * b[8]) +
7555  b[2] * (b[3] * b[7] - b[4] * b[6]));
7556  }
7557  break;
7558 
7559  default:
7560  mfem_error("DetOfLinComb(...)");
7561  }
7562 }
7563 
7564 // compute the real roots of
7565 // z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3;
7566 // the roots are returned in x, sorted in increasing order;
7567 // it is assumed that x is at least of size d;
7568 // return the number of roots counting multiplicity;
7569 // return -1 if all z(i) are 0.
7570 int FindRoots(const Vector &z, Vector &x)
7571 {
7572  int d = z.Size()-1;
7573  if (d > 3 || d < 0)
7574  {
7575  mfem_error("FindRoots(...)");
7576  }
7577 
7578  while (z(d) == 0.0)
7579  {
7580  if (d == 0)
7581  {
7582  return (-1);
7583  }
7584  d--;
7585  }
7586  switch (d)
7587  {
7588  case 0:
7589  {
7590  return 0;
7591  }
7592 
7593  case 1:
7594  {
7595  x(0) = -z(0)/z(1);
7596  return 1;
7597  }
7598 
7599  case 2:
7600  {
7601  double a = z(2), b = z(1), c = z(0);
7602  double D = b*b-4*a*c;
7603  if (D < 0.0)
7604  {
7605  return 0;
7606  }
7607  if (D == 0.0)
7608  {
7609  x(0) = x(1) = -0.5 * b / a;
7610  return 2; // root with multiplicity 2
7611  }
7612  if (b == 0.0)
7613  {
7614  x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a));
7615  return 2;
7616  }
7617  else
7618  {
7619  double t;
7620  if (b > 0.0)
7621  {
7622  t = -0.5 * (b + sqrt(D));
7623  }
7624  else
7625  {
7626  t = -0.5 * (b - sqrt(D));
7627  }
7628  x(0) = t / a;
7629  x(1) = c / t;
7630  if (x(0) > x(1))
7631  {
7632  Swap<double>(x(0), x(1));
7633  }
7634  return 2;
7635  }
7636  }
7637 
7638  case 3:
7639  {
7640  double a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3);
7641 
7642  // find the real roots of x^3 + a x^2 + b x + c = 0
7643  double Q = (a * a - 3 * b) / 9;
7644  double R = (2 * a * a * a - 9 * a * b + 27 * c) / 54;
7645  double Q3 = Q * Q * Q;
7646  double R2 = R * R;
7647 
7648  if (R2 == Q3)
7649  {
7650  if (Q == 0)
7651  {
7652  x(0) = x(1) = x(2) = - a / 3;
7653  }
7654  else
7655  {
7656  double sqrtQ = sqrt(Q);
7657 
7658  if (R > 0)
7659  {
7660  x(0) = -2 * sqrtQ - a / 3;
7661  x(1) = x(2) = sqrtQ - a / 3;
7662  }
7663  else
7664  {
7665  x(0) = x(1) = - sqrtQ - a / 3;
7666  x(2) = 2 * sqrtQ - a / 3;
7667  }
7668  }
7669  return 3;
7670  }
7671  else if (R2 < Q3)
7672  {
7673  double theta = acos(R / sqrt(Q3));
7674  double A = -2 * sqrt(Q);
7675  double x0, x1, x2;
7676  x0 = A * cos(theta / 3) - a / 3;
7677  x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3;
7678  x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3;
7679 
7680  /* Sort x0, x1, x2 */
7681  if (x0 > x1)
7682  {
7683  Swap<double>(x0, x1);
7684  }
7685  if (x1 > x2)
7686  {
7687  Swap<double>(x1, x2);
7688  if (x0 > x1)
7689  {
7690  Swap<double>(x0, x1);
7691  }
7692  }
7693  x(0) = x0;
7694  x(1) = x1;
7695  x(2) = x2;
7696  return 3;
7697  }
7698  else
7699  {
7700  double A;
7701  if (R >= 0.0)
7702  {
7703  A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0);
7704  }
7705  else
7706  {
7707  A = pow(sqrt(R2 - Q3) - R, 1.0/3.0);
7708  }
7709  x(0) = A + Q / A - a / 3;
7710  return 1;
7711  }
7712  }
7713  }
7714  return 0;
7715 }
7716 
7717 void FindTMax(Vector &c, Vector &x, double &tmax,
7718  const double factor, const int Dim)
7719 {
7720  const double c0 = c(0);
7721  c(0) = c0 * (1.0 - pow(factor, -Dim));
7722  int nr = FindRoots(c, x);
7723  for (int j = 0; j < nr; j++)
7724  {
7725  if (x(j) > tmax)
7726  {
7727  break;
7728  }
7729  if (x(j) >= 0.0)
7730  {
7731  tmax = x(j);
7732  break;
7733  }
7734  }
7735  c(0) = c0 * (1.0 - pow(factor, Dim));
7736  nr = FindRoots(c, x);
7737  for (int j = 0; j < nr; j++)
7738  {
7739  if (x(j) > tmax)
7740  {
7741  break;
7742  }
7743  if (x(j) >= 0.0)
7744  {
7745  tmax = x(j);
7746  break;
7747  }
7748  }
7749 }
7750 
7751 void Mesh::CheckDisplacements(const Vector &displacements, double &tmax)
7752 {
7753  int nvs = vertices.Size();
7754  DenseMatrix P, V, DS, PDS(spaceDim), VDS(spaceDim);
7755  Vector c(spaceDim+1), x(spaceDim);
7756  const double factor = 2.0;
7757 
7758  // check for tangling assuming constant speed
7759  if (tmax < 1.0)
7760  {
7761  tmax = 1.0;
7762  }
7763  for (int i = 0; i < NumOfElements; i++)
7764  {
7765  Element *el = elements[i];
7766  int nv = el->GetNVertices();
7767  int *v = el->GetVertices();
7768  P.SetSize(spaceDim, nv);
7769  V.SetSize(spaceDim, nv);
7770  for (int j = 0; j < spaceDim; j++)
7771  for (int k = 0; k < nv; k++)
7772  {
7773  P(j, k) = vertices[v[k]](j);
7774  V(j, k) = displacements(v[k]+j*nvs);
7775  }
7776  DS.SetSize(nv, spaceDim);
7777  const FiniteElement *fe =
7779  // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1
7780  switch (el->GetType())
7781  {
7782  case Element::TRIANGLE:
7783  case Element::TETRAHEDRON:
7784  {
7785  // DS is constant
7786  fe->CalcDShape(Geometries.GetCenter(fe->GetGeomType()), DS);
7787  Mult(P, DS, PDS);
7788  Mult(V, DS, VDS);
7789  DetOfLinComb(PDS, VDS, c);
7790  if (c(0) <= 0.0)
7791  {
7792  tmax = 0.0;
7793  }
7794  else
7795  {
7796  FindTMax(c, x, tmax, factor, Dim);
7797  }
7798  }
7799  break;
7800 
7802  {
7803  const IntegrationRule &ir = fe->GetNodes();
7804  for (int j = 0; j < nv; j++)
7805  {
7806  fe->CalcDShape(ir.IntPoint(j), DS);
7807  Mult(P, DS, PDS);
7808  Mult(V, DS, VDS);
7809  DetOfLinComb(PDS, VDS, c);
7810  if (c(0) <= 0.0)
7811  {
7812  tmax = 0.0;
7813  }
7814  else
7815  {
7816  FindTMax(c, x, tmax, factor, Dim);
7817  }
7818  }
7819  }
7820  break;
7821 
7822  default:
7823  mfem_error("Mesh::CheckDisplacements(...)");
7824  }
7825  }
7826 }
7827 
7828 void Mesh::MoveVertices(const Vector &displacements)
7829 {
7830  for (int i = 0, nv = vertices.Size(); i < nv; i++)
7831  for (int j = 0; j < spaceDim; j++)
7832  {
7833  vertices[i](j) += displacements(j*nv+i);
7834  }
7835 }
7836 
7837 void Mesh::GetVertices(Vector &vert_coord) const
7838 {
7839  int nv = vertices.Size();
7840  vert_coord.SetSize(nv*spaceDim);
7841  for (int i = 0; i < nv; i++)
7842  for (int j = 0; j < spaceDim; j++)
7843  {
7844  vert_coord(j*nv+i) = vertices[i](j);
7845  }
7846 }
7847 
7848 void Mesh::SetVertices(const Vector &vert_coord)
7849 {
7850  for (int i = 0, nv = vertices.Size(); i < nv; i++)
7851  for (int j = 0; j < spaceDim; j++)
7852  {
7853  vertices[i](j) = vert_coord(j*nv+i);
7854  }
7855 }
7856 
7857 void Mesh::GetNode(int i, double *coord) const
7858 {
7859  if (Nodes)
7860  {
7861  FiniteElementSpace *fes = Nodes->FESpace();
7862  for (int j = 0; j < spaceDim; j++)
7863  {
7864  coord[j] = (*Nodes)(fes->DofToVDof(i, j));
7865  }
7866  }
7867  else
7868  {
7869  for (int j = 0; j < spaceDim; j++)
7870  {
7871  coord[j] = vertices[i](j);
7872  }
7873  }
7874 }
7875 
7876 void Mesh::SetNode(int i, const double *coord)
7877 {
7878  if (Nodes)
7879  {
7880  FiniteElementSpace *fes = Nodes->FESpace();
7881  for (int j = 0; j < spaceDim; j++)
7882  {
7883  (*Nodes)(fes->DofToVDof(i, j)) = coord[j];
7884  }
7885  }
7886  else
7887  {
7888  for (int j = 0; j < spaceDim; j++)
7889  {
7890  vertices[i](j) = coord[j];
7891  }
7892 
7893  }
7894 }
7895 
7896 void Mesh::MoveNodes(const Vector &displacements)
7897 {
7898  if (Nodes)
7899  {
7900  (*Nodes) += displacements;
7901  }
7902  else
7903  {
7904  MoveVertices(displacements);
7905  }
7906 }
7907 
7908 void Mesh::GetNodes(Vector &node_coord) const
7909 {
7910  if (Nodes)
7911  {
7912  node_coord = (*Nodes);
7913  }
7914  else
7915  {
7916  GetVertices(node_coord);
7917  }
7918 }
7919 
7920 void Mesh::SetNodes(const Vector &node_coord)
7921 {
7922  if (Nodes)
7923  {
7924  (*Nodes) = node_coord;
7925  }
7926  else
7927  {
7928  SetVertices(node_coord);
7929  }
7930 
7931  // Invalidate the old geometric factors
7932  NodesUpdated();
7933 }
7934 
7935 void Mesh::NewNodes(GridFunction &nodes, bool make_owner)
7936 {
7937  if (own_nodes) { delete Nodes; }
7938  Nodes = &nodes;
7939  spaceDim = Nodes->FESpace()->GetVDim();
7940  own_nodes = (int)make_owner;
7941 
7942  if (NURBSext != nodes.FESpace()->GetNURBSext())
7943  {
7944  delete NURBSext;
7945  NURBSext = nodes.FESpace()->StealNURBSext();
7946  }
7947 
7948  if (ncmesh)
7949  {
7951  }
7952 
7953  // Invalidate the old geometric factors
7954  NodesUpdated();
7955 }
7956 
7957 void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_)
7958 {
7959  mfem::Swap<GridFunction*>(Nodes, nodes);
7960  mfem::Swap<int>(own_nodes, own_nodes_);
7961  // TODO:
7962  // if (nodes)
7963  // nodes->FESpace()->MakeNURBSextOwner();
7964  // NURBSext = (Nodes) ? Nodes->FESpace()->StealNURBSext() : NULL;
7965 
7966  // Invalidate the old geometric factors
7967  NodesUpdated();
7968 }
7969 
7970 void Mesh::AverageVertices(const int *indexes, int n, int result)
7971 {
7972  int j, k;
7973 
7974  for (k = 0; k < spaceDim; k++)
7975  {
7976  vertices[result](k) = vertices[indexes[0]](k);
7977  }
7978 
7979  for (j = 1; j < n; j++)
7980  for (k = 0; k < spaceDim; k++)
7981  {
7982  vertices[result](k) += vertices[indexes[j]](k);
7983  }
7984 
7985  for (k = 0; k < spaceDim; k++)
7986  {
7987  vertices[result](k) *= (1.0 / n);
7988  }
7989 }
7990 
7992 {
7993  if (Nodes)
7994  {
7995  Nodes->FESpace()->Update();
7996  Nodes->Update();
7997 
7998  // update vertex coordinates for compatibility (e.g., GetVertex())
8000 
8001  // Invalidate the old geometric factors
8002  NodesUpdated();
8003  }
8004 }
8005 
8006 void Mesh::UniformRefinement2D_base(bool update_nodes)
8007 {
8008  ResetLazyData();
8009 
8010  if (el_to_edge == NULL)
8011  {
8012  el_to_edge = new Table;
8014  }
8015 
8016  int quad_counter = 0;
8017  for (int i = 0; i < NumOfElements; i++)
8018  {
8019  if (elements[i]->GetType() == Element::QUADRILATERAL)
8020  {
8021  quad_counter++;
8022  }
8023  }
8024 
8025  const int oedge = NumOfVertices;
8026  const int oelem = oedge + NumOfEdges;
8027 
8028  Array<Element*> new_elements;
8029  Array<Element*> new_boundary;
8030 
8031  vertices.SetSize(oelem + quad_counter);
8032  new_elements.SetSize(4 * NumOfElements);
8033  quad_counter = 0;
8034 
8035  for (int i = 0, j = 0; i < NumOfElements; i++)
8036  {
8037  const Element::Type el_type = elements[i]->GetType();
8038  const int attr = elements[i]->GetAttribute();
8039  int *v = elements[i]->GetVertices();
8040  const int *e = el_to_edge->GetRow(i);
8041  int vv[2];
8042 
8043  if (el_type == Element::TRIANGLE)
8044  {
8045  for (int ei = 0; ei < 3; ei++)
8046  {
8047  for (int k = 0; k < 2; k++)
8048  {
8049  vv[k] = v[tri_t::Edges[ei][k]];
8050  }
8051  AverageVertices(vv, 2, oedge+e[ei]);
8052  }
8053 
8054  new_elements[j++] =
8055  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
8056  new_elements[j++] =
8057  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
8058  new_elements[j++] =
8059  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
8060  new_elements[j++] =
8061  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
8062  }
8063  else if (el_type == Element::QUADRILATERAL)
8064  {
8065  const int qe = quad_counter;
8066  quad_counter++;
8067  AverageVertices(v, 4, oelem+qe);
8068 
8069  for (int ei = 0; ei < 4; ei++)
8070  {
8071  for (int k = 0; k < 2; k++)
8072  {
8073  vv[k] = v[quad_t::Edges[ei][k]];
8074  }
8075  AverageVertices(vv, 2, oedge+e[ei]);
8076  }
8077 
8078  new_elements[j++] =
8079  new Quadrilateral(v[0], oedge+e[0], oelem+qe, oedge+e[3], attr);
8080  new_elements[j++] =
8081  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oelem+qe, attr);
8082  new_elements[j++] =
8083  new Quadrilateral(oelem+qe, oedge+e[1], v[2], oedge+e[2], attr);
8084  new_elements[j++] =
8085  new Quadrilateral(oedge+e[3], oelem+qe, oedge+e[2], v[3], attr);
8086  }
8087  else
8088  {
8089  MFEM_ABORT("unknown element type: " << el_type);
8090  }
8091  FreeElement(elements[i]);
8092  }
8093  mfem::Swap(elements, new_elements);
8094 
8095  // refine boundary elements
8096  new_boundary.SetSize(2 * NumOfBdrElements);
8097  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
8098  {
8099  const int attr = boundary[i]->GetAttribute();
8100  int *v = boundary[i]->GetVertices();
8101 
8102  new_boundary[j++] = new Segment(v[0], oedge+be_to_edge[i], attr);
8103  new_boundary[j++] = new Segment(oedge+be_to_edge[i], v[1], attr);
8104 
8105  FreeElement(boundary[i]);
8106  }
8107  mfem::Swap(boundary, new_boundary);
8108 
8109  static const double A = 0.0, B = 0.5, C = 1.0;
8110  static double tri_children[2*3*4] =
8111  {
8112  A,A, B,A, A,B,
8113  B,B, A,B, B,A,
8114  B,A, C,A, B,B,
8115  A,B, B,B, A,C
8116  };
8117  static double quad_children[2*4*4] =
8118  {
8119  A,A, B,A, B,B, A,B, // lower-left
8120  B,A, C,A, C,B, B,B, // lower-right
8121  B,B, C,B, C,C, B,C, // upper-right
8122  A,B, B,B, B,C, A,C // upper-left
8123  };
8124 
8126  .UseExternalData(tri_children, 2, 3, 4);
8128  .UseExternalData(quad_children, 2, 4, 4);
8129  CoarseFineTr.embeddings.SetSize(elements.Size());
8130 
8131  for (int i = 0; i < elements.Size(); i++)
8132  {
8133  Embedding &emb = CoarseFineTr.embeddings[i];
8134  emb.parent = i / 4;
8135  emb.matrix = i % 4;
8136  }
8137 
8138  NumOfVertices = vertices.Size();
8139  NumOfElements = 4 * NumOfElements;
8140  NumOfBdrElements = 2 * NumOfBdrElements;
8141  NumOfFaces = 0;
8142 
8144  GenerateFaces();
8145 
8147  sequence++;
8148 
8149  if (update_nodes) { UpdateNodes(); }
8150 
8151 #ifdef MFEM_DEBUG
8152  if (!Nodes || update_nodes)
8153  {
8154  CheckElementOrientation(false);
8155  }
8157 #endif
8158 }
8159 
8160 static inline double sqr(const double &x)
8161 {
8162  return x*x;
8163 }
8164 
8166  bool update_nodes)
8167 {
8168  ResetLazyData();
8169 
8170  if (el_to_edge == NULL)
8171  {
8172  el_to_edge = new Table;
8174  }
8175 
8176  if (el_to_face == NULL)
8177  {
8179  }
8180 
8181  Array<int> f2qf_loc;
8182  Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
8183  f2qf.SetSize(0);
8184 
8185  int NumOfQuadFaces = 0;
8187  {
8189  {
8190  f2qf.SetSize(faces.Size());
8191  for (int i = 0; i < faces.Size(); i++)
8192  {
8193  if (faces[i]->GetType() == Element::QUADRILATERAL)
8194  {
8195  f2qf[i] = NumOfQuadFaces;
8196  NumOfQuadFaces++;
8197  }
8198  }
8199  }
8200  else
8201  {
8202  NumOfQuadFaces = faces.Size();
8203  }
8204  }
8205 
8206  int hex_counter = 0;
8208  {
8209  for (int i = 0; i < elements.Size(); i++)
8210  {
8211  if (elements[i]->GetType() == Element::HEXAHEDRON)
8212  {
8213  hex_counter++;
8214  }
8215  }
8216  }
8217 
8218  int pyr_counter = 0;
8220  {
8221  for (int i = 0; i < elements.Size(); i++)
8222  {
8223  if (elements[i]->GetType() == Element::PYRAMID)
8224  {
8225  pyr_counter++;
8226  }
8227  }
8228  }
8229 
8230  // Map from edge-index to vertex-index, needed for ReorientTetMesh() for
8231  // parallel meshes.
8232  // Note: with the removal of ReorientTetMesh() this may no longer
8233  // be needed. Unfortunately, it's hard to be sure.
8234  Array<int> e2v;
8236  {
8237  e2v.SetSize(NumOfEdges);
8238 
8239  DSTable *v_to_v_ptr = v_to_v_p;
8240  if (!v_to_v_p)
8241  {
8242  v_to_v_ptr = new DSTable(NumOfVertices);
8243  GetVertexToVertexTable(*v_to_v_ptr);
8244  }
8245 
8246  Array<Pair<int,int> > J_v2v(NumOfEdges); // (second vertex id, edge id)
8247  J_v2v.SetSize(0);
8248  for (int i = 0; i < NumOfVertices; i++)
8249  {
8250  Pair<int,int> *row_start = J_v2v.end();
8251  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
8252  {
8253  J_v2v.Append(Pair<int,int>(it.Column(), it.Index()));
8254  }
8255  std::sort(row_start, J_v2v.end());
8256  }
8257 
8258  for (int i = 0; i < J_v2v.Size(); i++)
8259  {
8260  e2v[J_v2v[i].two] = i;
8261  }
8262 
8263  if (!v_to_v_p)
8264  {
8265  delete v_to_v_ptr;
8266  }
8267  else
8268  {
8269  for (int i = 0; i < NumOfVertices; i++)
8270  {
8271  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
8272  {
8273  it.SetIndex(e2v[it.Index()]);
8274  }
8275  }
8276  }
8277  }
8278 
8279  // Offsets for new vertices from edges, faces (quads only), and elements
8280  // (hexes only); each of these entities generates one new vertex.
8281  const int oedge = NumOfVertices;
8282  const int oface = oedge + NumOfEdges;
8283  const int oelem = oface + NumOfQuadFaces;
8284 
8285  Array<Element*> new_elements;
8286  Array<Element*> new_boundary;
8287 
8288  vertices.SetSize(oelem + hex_counter);
8289  new_elements.SetSize(8 * NumOfElements + 2 * pyr_counter);
8290  CoarseFineTr.embeddings.SetSize(new_elements.Size());
8291 
8292  hex_counter = 0;
8293  for (int i = 0, j = 0; i < NumOfElements; i++)
8294  {
8295  const Element::Type el_type = elements[i]->GetType();
8296  const int attr = elements[i]->GetAttribute();
8297  int *v = elements[i]->GetVertices();
8298  const int *e = el_to_edge->GetRow(i);
8299  int vv[4], ev[12];
8300 
8301  if (e2v.Size())
8302  {
8303  const int ne = el_to_edge->RowSize(i);
8304  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
8305  e = ev;
8306  }
8307 
8308  switch (el_type)
8309  {
8310  case Element::TETRAHEDRON:
8311  {
8312  for (int ei = 0; ei < 6; ei++)
8313  {
8314  for (int k = 0; k < 2; k++)
8315  {
8316  vv[k] = v[tet_t::Edges[ei][k]];
8317  }
8318  AverageVertices(vv, 2, oedge+e[ei]);
8319  }
8320 
8321  // Algorithm for choosing refinement type:
8322  // 0: smallest octahedron diagonal
8323  // 1: best aspect ratio
8324  const int rt_algo = 1;
8325  // Refinement type:
8326  // 0: (v0,v1)-(v2,v3), 1: (v0,v2)-(v1,v3), 2: (v0,v3)-(v1,v2)
8327  // 0: e0-e5, 1: e1-e4, 2: e2-e3
8328  int rt;
8331  const DenseMatrix &J = T->Jacobian();
8332  if (rt_algo == 0)
8333  {
8334  // smallest octahedron diagonal
8335  double len_sqr, min_len;
8336 
8337  min_len = sqr(J(0,0)-J(0,1)-J(0,2)) +
8338  sqr(J(1,0)-J(1,1)-J(1,2)) +
8339  sqr(J(2,0)-J(2,1)-J(2,2));
8340  rt = 0;
8341 
8342  len_sqr = sqr(J(0,1)-J(0,0)-J(0,2)) +
8343  sqr(J(1,1)-J(1,0)-J(1,2)) +
8344  sqr(J(2,1)-J(2,0)-J(2,2));
8345  if (len_sqr < min_len) { min_len = len_sqr; rt = 1; }
8346 
8347  len_sqr = sqr(J(0,2)-J(0,0)-J(0,1)) +
8348  sqr(J(1,2)-J(1,0)-J(1,1)) +
8349  sqr(J(2,2)-J(2,0)-J(2,1));
8350  if (len_sqr < min_len) { rt = 2; }
8351  }
8352  else
8353  {
8354  // best aspect ratio
8355  double Em_data[18], Js_data[9], Jp_data[9];
8356  DenseMatrix Em(Em_data, 3, 6);
8357  DenseMatrix Js(Js_data, 3, 3), Jp(Jp_data, 3, 3);
8358  double ar1, ar2, kappa, kappa_min;
8359 
8360  for (int s = 0; s < 3; s++)
8361  {
8362  for (int t = 0; t < 3; t++)
8363  {
8364  Em(t,s) = 0.5*J(t,s);
8365  }
8366  }
8367  for (int t = 0; t < 3; t++)
8368  {
8369  Em(t,3) = 0.5*(J(t,0)+J(t,1));
8370  Em(t,4) = 0.5*(J(t,0)+J(t,2));
8371  Em(t,5) = 0.5*(J(t,1)+J(t,2));
8372  }
8373 
8374  // rt = 0; Em: {0,5,1,2}, {0,5,2,4}
8375  for (int t = 0; t < 3; t++)
8376  {
8377  Js(t,0) = Em(t,5)-Em(t,0);
8378  Js(t,1) = Em(t,1)-Em(t,0);
8379  Js(t,2) = Em(t,2)-Em(t,0);
8380  }
8382  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8383  for (int t = 0; t < 3; t++)
8384  {
8385  Js(t,0) = Em(t,5)-Em(t,0);
8386  Js(t,1) = Em(t,2)-Em(t,0);
8387  Js(t,2) = Em(t,4)-Em(t,0);
8388  }
8390  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8391  kappa_min = std::max(ar1, ar2);
8392  rt = 0;
8393 
8394  // rt = 1; Em: {1,0,4,2}, {1,2,4,5}
8395  for (int t = 0; t < 3; t++)
8396  {
8397  Js(t,0) = Em(t,0)-Em(t,1);
8398  Js(t,1) = Em(t,4)-Em(t,1);
8399  Js(t,2) = Em(t,2)-Em(t,1);
8400  }
8402  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8403  for (int t = 0; t < 3; t++)
8404  {
8405  Js(t,0) = Em(t,2)-Em(t,1);
8406  Js(t,1) = Em(t,4)-Em(t,1);
8407  Js(t,2) = Em(t,5)-Em(t,1);
8408  }
8410  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8411  kappa = std::max(ar1, ar2);
8412  if (kappa < kappa_min) { kappa_min = kappa; rt = 1; }
8413 
8414  // rt = 2; Em: {2,0,1,3}, {2,1,5,3}
8415  for (int t = 0; t < 3; t++)
8416  {
8417  Js(t,0) = Em(t,0)-Em(t,2);
8418  Js(t,1) = Em(t,1)-Em(t,2);
8419  Js(t,2) = Em(t,3)-Em(t,2);
8420  }
8422  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8423  for (int t = 0; t < 3; t++)
8424  {
8425  Js(t,0) = Em(t,1)-Em(t,2);
8426  Js(t,1) = Em(t,5)-Em(t,2);
8427  Js(t,2) = Em(t,3)-Em(t,2);
8428  }
8430  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8431  kappa = std::max(ar1, ar2);
8432  if (kappa < kappa_min) { rt = 2; }
8433  }
8434 
8435  static const int mv_all[3][4][4] =
8436  {
8437  { {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1} }, // rt = 0
8438  { {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0} }, // rt = 1
8439  { {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3} } // rt = 2
8440  };
8441  const int (&mv)[4][4] = mv_all[rt];
8442 
8443 #ifndef MFEM_USE_MEMALLOC
8444  new_elements[j+0] =
8445  new Tetrahedron(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
8446  new_elements[j+1] =
8447  new Tetrahedron(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
8448  new_elements[j+2] =
8449  new Tetrahedron(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
8450  new_elements[j+3] =
8451  new Tetrahedron(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
8452 
8453  for (int k = 0; k < 4; k++)
8454  {
8455  new_elements[j+4+k] =
8456  new Tetrahedron(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
8457  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
8458  }
8459 #else
8460  Tetrahedron *tet;
8461  new_elements[j+0] = tet = TetMemory.Alloc();
8462  tet->Init(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
8463 
8464  new_elements[j+1] = tet = TetMemory.Alloc();
8465  tet->Init(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
8466 
8467  new_elements[j+2] = tet = TetMemory.Alloc();
8468  tet->Init(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
8469 
8470  new_elements[j+3] = tet = TetMemory.Alloc();
8471  tet->Init(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
8472 
8473  for (int k = 0; k < 4; k++)
8474  {
8475  new_elements[j+4+k] = tet = TetMemory.Alloc();
8476  tet->Init(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
8477  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
8478  }
8479 #endif
8480  for (int k = 0; k < 4; k++)
8481  {
8482  CoarseFineTr.embeddings[j+k].parent = i;
8483  CoarseFineTr.embeddings[j+k].matrix = k;
8484  }
8485  for (int k = 0; k < 4; k++)
8486  {
8487  CoarseFineTr.embeddings[j+4+k].parent = i;
8488  CoarseFineTr.embeddings[j+4+k].matrix = 4*(rt+1)+k;
8489  }
8490 
8491  j += 8;
8492  }
8493  break;
8494 
8495  case Element::WEDGE:
8496  {
8497  const int *f = el_to_face->GetRow(i);
8498 
8499  for (int fi = 2; fi < 5; fi++)
8500  {
8501  for (int k = 0; k < 4; k++)
8502  {
8503  vv[k] = v[pri_t::FaceVert[fi][k]];
8504  }
8505  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
8506  }
8507 
8508  for (int ei = 0; ei < 9; ei++)
8509  {
8510  for (int k = 0; k < 2; k++)
8511  {
8512  vv[k] = v[pri_t::Edges[ei][k]];
8513  }
8514  AverageVertices(vv, 2, oedge+e[ei]);
8515  }
8516 
8517  const int qf2 = f2qf[f[2]];
8518  const int qf3 = f2qf[f[3]];
8519  const int qf4 = f2qf[f[4]];
8520 
8521  new_elements[j++] =
8522  new Wedge(v[0], oedge+e[0], oedge+e[2],
8523  oedge+e[6], oface+qf2, oface+qf4, attr);
8524 
8525  new_elements[j++] =
8526  new Wedge(oedge+e[1], oedge+e[2], oedge+e[0],
8527  oface+qf3, oface+qf4, oface+qf2, attr);
8528 
8529  new_elements[j++] =
8530  new Wedge(oedge+e[0], v[1], oedge+e[1],
8531  oface+qf2, oedge+e[7], oface+qf3, attr);
8532 
8533  new_elements[j++] =
8534  new Wedge(oedge+e[2], oedge+e[1], v[2],
8535  oface+qf4, oface+qf3, oedge+e[8], attr);
8536 
8537  new_elements[j++] =
8538  new Wedge(oedge+e[6], oface+qf2, oface+qf4,
8539  v[3], oedge+e[3], oedge+e[5], attr);
8540 
8541  new_elements[j++] =
8542  new Wedge(oface+qf3, oface+qf4, oface+qf2,
8543  oedge+e[4], oedge+e[5], oedge+e[3], attr);
8544 
8545  new_elements[j++] =
8546  new Wedge(oface+qf2, oedge+e[7], oface+qf3,
8547  oedge+e[3], v[4], oedge+e[4], attr);
8548 
8549  new_elements[j++] =
8550  new Wedge(oface+qf4, oface+qf3, oedge+e[8],
8551  oedge+e[5], oedge+e[4], v[5], attr);
8552  }
8553  break;
8554 
8555  case Element::PYRAMID:
8556  {
8557  const int *f = el_to_face->GetRow(i);
8558  // pyr_counter++;
8559 
8560  for (int fi = 0; fi < 1; fi++)
8561  {
8562  for (int k = 0; k < 4; k++)
8563  {
8564  vv[k] = v[pyr_t::FaceVert[fi][k]];
8565  }
8566  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
8567  }
8568 
8569  for (int ei = 0; ei < 8; ei++)
8570  {
8571  for (int k = 0; k < 2; k++)
8572  {
8573  vv[k] = v[pyr_t::Edges[ei][k]];
8574  }
8575  AverageVertices(vv, 2, oedge+e[ei]);
8576  }
8577 
8578  const int qf0 = f2qf[f[0]];
8579 
8580  new_elements[j++] =
8581  new Pyramid(v[0], oedge+e[0], oface+qf0,
8582  oedge+e[3], oedge+e[4], attr);
8583 
8584  new_elements[j++] =
8585  new Pyramid(oedge+e[0], v[1], oedge+e[1],
8586  oface+qf0, oedge+e[5], attr);
8587 
8588  new_elements[j++] =
8589  new Pyramid(oface+qf0, oedge+e[1], v[2],
8590  oedge+e[2], oedge+e[6], attr);
8591 
8592  new_elements[j++] =
8593  new Pyramid(oedge+e[3], oface+qf0, oedge+e[2],
8594  v[3], oedge+e[7], attr);
8595 
8596  new_elements[j++] =
8597  new Pyramid(oedge+e[4], oedge+e[5], oedge+e[6],
8598  oedge+e[7], v[4], attr);
8599 
8600  new_elements[j++] =
8601  new Pyramid(oedge+e[7], oedge+e[6], oedge+e[5],
8602  oedge+e[4], oface+qf0, attr);
8603 
8604  new_elements[j++] =
8605  new Tetrahedron(oedge+e[0], oedge+e[4], oedge+e[5],
8606  oface+qf0, attr);
8607 
8608  new_elements[j++] =
8609  new Tetrahedron(oedge+e[1], oedge+e[5], oedge+e[6],
8610  oface+qf0, attr);
8611 
8612  new_elements[j++] =
8613  new Tetrahedron(oedge+e[2], oedge+e[6], oedge+e[7],
8614  oface+qf0, attr);
8615 
8616  new_elements[j++] =
8617  new Tetrahedron(oedge+e[3], oedge+e[7], oedge+e[4],
8618  oface+qf0, attr);
8619  }
8620  break;
8621 
8622  case Element::HEXAHEDRON:
8623  {
8624  const int *f = el_to_face->GetRow(i);
8625  const int he = hex_counter;
8626  hex_counter++;
8627 
8628  const int *qf;
8629  int qf_data[6];
8630  if (f2qf.Size() == 0)
8631  {
8632  qf = f;
8633  }
8634  else
8635  {
8636  for (int k = 0; k < 6; k++) { qf_data[k] = f2qf[f[k]]; }
8637  qf = qf_data;
8638  }
8639 
8640  AverageVertices(v, 8, oelem+he);
8641 
8642  for (int fi = 0; fi < 6; fi++)
8643  {
8644  for (int k = 0; k < 4; k++)
8645  {
8646  vv[k] = v[hex_t::FaceVert[fi][k]];
8647  }
8648  AverageVertices(vv, 4, oface + qf[fi]);
8649  }
8650 
8651  for (int ei = 0; ei < 12; ei++)
8652  {
8653  for (int k = 0; k < 2; k++)
8654  {
8655  vv[k] = v[hex_t::Edges[ei][k]];
8656  }
8657  AverageVertices(vv, 2, oedge+e[ei]);
8658  }
8659 
8660  new_elements[j++] =
8661  new Hexahedron(v[0], oedge+e[0], oface+qf[0],
8662  oedge+e[3], oedge+e[8], oface+qf[1],
8663  oelem+he, oface+qf[4], attr);
8664  new_elements[j++] =
8665  new Hexahedron(oedge+e[0], v[1], oedge+e[1],
8666  oface+qf[0], oface+qf[1], oedge+e[9],
8667  oface+qf[2], oelem+he, attr);
8668  new_elements[j++] =
8669  new Hexahedron(oface+qf[0], oedge+e[1], v[2],
8670  oedge+e[2], oelem+he, oface+qf[2],
8671  oedge+e[10], oface+qf[3], attr);
8672  new_elements[j++] =
8673  new Hexahedron(oedge+e[3], oface+qf[0], oedge+e[2],
8674  v[3], oface+qf[4], oelem+he,
8675  oface+qf[3], oedge+e[11], attr);
8676  new_elements[j++] =
8677  new Hexahedron(oedge+e[8], oface+qf[1], oelem+he,
8678  oface+qf[4], v[4], oedge+e[4],
8679  oface+qf[5], oedge+e[7], attr);
8680  new_elements[j++] =
8681  new Hexahedron(oface+qf[1], oedge+e[9], oface+qf[2],
8682  oelem+he, oedge+e[4], v[5],
8683  oedge+e[5], oface+qf[5], attr);
8684  new_elements[j++] =
8685  new Hexahedron(oelem+he, oface+qf[2], oedge+e[10],
8686  oface+qf[3], oface+qf[5], oedge+e[5],
8687  v[6], oedge+e[6], attr);
8688  new_elements[j++] =
8689  new Hexahedron(oface+qf[4], oelem+he, oface+qf[3],
8690  oedge+e[11], oedge+e[7], oface+qf[5],
8691  oedge+e[6], v[7], attr);
8692  }
8693  break;
8694 
8695  default:
8696  MFEM_ABORT("Unknown 3D element type \"" << el_type << "\"");
8697  break;
8698  }
8699  FreeElement(elements[i]);
8700  }
8701  mfem::Swap(elements, new_elements);
8702 
8703  // refine boundary elements
8704  new_boundary.SetSize(4 * NumOfBdrElements);
8705  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
8706  {
8707  const Element::Type bdr_el_type = boundary[i]->GetType();
8708  const int attr = boundary[i]->GetAttribute();
8709  int *v = boundary[i]->GetVertices();
8710  const int *e = bel_to_edge->GetRow(i);
8711  int ev[4];
8712 
8713  if (e2v.Size())
8714  {
8715  const int ne = bel_to_edge->RowSize(i);
8716  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
8717  e = ev;
8718  }
8719 
8720  if (bdr_el_type == Element::TRIANGLE)
8721  {
8722  new_boundary[j++] =
8723  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
8724  new_boundary[j++] =
8725  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
8726  new_boundary[j++] =
8727  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
8728  new_boundary[j++] =
8729  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
8730  }
8731  else if (bdr_el_type == Element::QUADRILATERAL)
8732  {
8733  const int qf =
8734  (f2qf.Size() == 0) ? be_to_face[i] : f2qf[be_to_face[i]];
8735 
8736  new_boundary[j++] =
8737  new Quadrilateral(v[0], oedge+e[0], oface+qf, oedge+e[3], attr);
8738  new_boundary[j++] =
8739  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oface+qf, attr);
8740  new_boundary[j++] =
8741  new Quadrilateral(oface+qf, oedge+e[1], v[2], oedge+e[2], attr);
8742  new_boundary[j++] =
8743  new Quadrilateral(oedge+e[3], oface+qf, oedge+e[2], v[3], attr);
8744  }
8745  else
8746  {
8747  MFEM_ABORT("boundary Element is not a triangle or a quad!");
8748  }
8749  FreeElement(boundary[i]);
8750  }
8751  mfem::Swap(boundary, new_boundary);
8752 
8753  static const double A = 0.0, B = 0.5, C = 1.0, D = -1.0;
8754  static double tet_children[3*4*16] =
8755  {
8756  A,A,A, B,A,A, A,B,A, A,A,B,
8757  B,A,A, C,A,A, B,B,A, B,A,B,
8758  A,B,A, B,B,A, A,C,A, A,B,B,
8759  A,A,B, B,A,B, A,B,B, A,A,C,
8760  // edge coordinates:
8761  // 0 -> B,A,A 1 -> A,B,A 2 -> A,A,B
8762  // 3 -> B,B,A 4 -> B,A,B 5 -> A,B,B
8763  // rt = 0: {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1}
8764  B,A,A, A,B,B, A,B,A, A,A,B,
8765  B,A,A, A,B,B, A,A,B, B,A,B,
8766  B,A,A, A,B,B, B,A,B, B,B,A,
8767  B,A,A, A,B,B, B,B,A, A,B,A,
8768  // rt = 1: {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0}
8769  A,B,A, B,A,A, B,A,B, A,A,B,
8770  A,B,A, A,A,B, B,A,B, A,B,B,
8771  A,B,A, A,B,B, B,A,B, B,B,A,
8772  A,B,A, B,B,A, B,A,B, B,A,A,
8773  // rt = 2: {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3}
8774  A,A,B, B,A,A, A,B,A, B,B,A,
8775  A,A,B, A,B,A, A,B,B, B,B,A,
8776  A,A,B, A,B,B, B,A,B, B,B,A,
8777  A,A,B, B,A,B, B,A,A, B,B,A
8778  };
8779  static double pyr_children[3*5*10] =
8780  {
8781  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B,
8782  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B,
8783  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B,
8784  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B,
8785  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C,
8786  A,B,B, B,B,B, B,A,B, A,A,B, B,B,A,
8787  B,A,A, A,A,B, B,A,B, B,B,A, D,D,D,
8788  C,B,A, B,A,B, B,B,B, B,B,A, D,D,D,
8789  B,C,A, B,B,B, A,B,B, B,B,A, D,D,D,
8790  A,B,A, A,B,B, A,A,B, B,B,A, D,D,D
8791  };
8792  static double pri_children[3*6*8] =
8793  {
8794  A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
8795  B,B,A, A,B,A, B,A,A, B,B,B, A,B,B, B,A,B,
8796  B,A,A, C,A,A, B,B,A, B,A,B, C,A,B, B,B,B,
8797  A,B,A, B,B,A, A,C,A, A,B,B, B,B,B, A,C,B,
8798  A,A,B, B,A,B, A,B,B, A,A,C, B,A,C, A,B,C,
8799  B,B,B, A,B,B, B,A,B, B,B,C, A,B,C, B,A,C,
8800  B,A,B, C,A,B, B,B,B, B,A,C, C,A,C, B,B,C,
8801  A,B,B, B,B,B, A,C,B, A,B,C, B,B,C, A,C,C
8802  };
8803  static double hex_children[3*8*8] =
8804  {
8805  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B, B,A,B, B,B,B, A,B,B,
8806  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B, C,A,B, C,B,B, B,B,B,
8807  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B, C,B,B, C,C,B, B,C,B,
8808  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B, B,B,B, B,C,B, A,C,B,
8809  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C, B,A,C, B,B,C, A,B,C,
8810  B,A,B, C,A,B, C,B,B, B,B,B, B,A,C, C,A,C, C,B,C, B,B,C,
8811  B,B,B, C,B,B, C,C,B, B,C,B, B,B,C, C,B,C, C,C,C, B,C,C,
8812  A,B,B, B,B,B, B,C,B, A,C,B, A,B,C, B,B,C, B,C,C, A,C,C
8813  };
8814 
8816  .UseExternalData(tet_children, 3, 4, 16);
8818  .UseExternalData(pyr_children, 3, 5, 10);
8820  .UseExternalData(pri_children, 3, 6, 8);
8822  .UseExternalData(hex_children, 3, 8, 8);
8823 
8824  for (int i = 0; i < elements.Size(); i++)
8825  {
8826  // tetrahedron elements are handled above:
8827  if (elements[i]->GetType() == Element::TETRAHEDRON) { continue; }
8828 
8829  Embedding &emb = CoarseFineTr.embeddings[i];
8830  emb.parent = i / 8;
8831  emb.matrix = i % 8;
8832  }
8833 
8834  NumOfVertices = vertices.Size();
8835  NumOfElements = 8 * NumOfElements + 2 * pyr_counter;
8836  NumOfBdrElements = 4 * NumOfBdrElements;
8837 
8839  GenerateFaces();
8840 
8841 #ifdef MFEM_DEBUG
8843 #endif
8844 
8846 
8848  sequence++;
8849 
8850  if (update_nodes) { UpdateNodes(); }
8851 }
8852 
8853 void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
8854 {
8855  int i, j, ind, nedges;
8856  Array<int> v;
8857 
8858  ResetLazyData();
8859 
8860  if (ncmesh)
8861  {
8862  MFEM_ABORT("Local and nonconforming refinements cannot be mixed.");
8863  }
8864 
8866 
8867  if (Dim == 1) // --------------------------------------------------------
8868  {
8869  int cne = NumOfElements, cnv = NumOfVertices;
8870  NumOfVertices += marked_el.Size();
8871  NumOfElements += marked_el.Size();
8872  vertices.SetSize(NumOfVertices);
8873  elements.SetSize(NumOfElements);
8875 
8876  for (j = 0; j < marked_el.Size(); j++)
8877  {
8878  i = marked_el[j];
8879  Segment *c_seg = (Segment *)elements[i];
8880  int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
8881  int new_v = cnv + j, new_e = cne + j;
8882  AverageVertices(vert, 2, new_v);
8883  elements[new_e] = new Segment(new_v, vert[1], attr);
8884  vert[1] = new_v;
8885 
8888  }
8889 
8890  static double seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
8892  UseExternalData(seg_children, 1, 2, 3);
8893 
8894  GenerateFaces();
8895 
8896  } // end of 'if (Dim == 1)'
8897  else if (Dim == 2) // ---------------------------------------------------
8898  {
8899  // 1. Get table of vertex to vertex connections.
8900  DSTable v_to_v(NumOfVertices);
8901  GetVertexToVertexTable(v_to_v);
8902 
8903  // 2. Get edge to element connections in arrays edge1 and edge2
8904  nedges = v_to_v.NumberOfEntries();
8905  int *edge1 = new int[nedges];
8906  int *edge2 = new int[nedges];
8907  int *middle = new int[nedges];
8908 
8909  for (i = 0; i < nedges; i++)
8910  {
8911  edge1[i] = edge2[i] = middle[i] = -1;
8912  }
8913 
8914  for (i = 0; i < NumOfElements; i++)
8915  {
8916  elements[i]->GetVertices(v);
8917  for (j = 1; j < v.Size(); j++)
8918  {
8919  ind = v_to_v(v[j-1], v[j]);
8920  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
8921  }
8922  ind = v_to_v(v[0], v[v.Size()-1]);
8923  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
8924  }
8925 
8926  // 3. Do the red refinement.
8927  for (i = 0; i < marked_el.Size(); i++)
8928  {
8929  RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
8930  }
8931 
8932  // 4. Do the green refinement (to get conforming mesh).
8933  int need_refinement;
8934  do
8935  {
8936  need_refinement = 0;
8937  for (i = 0; i < nedges; i++)
8938  {
8939  if (middle[i] != -1 && edge1[i] != -1)
8940  {
8941  need_refinement = 1;
8942  GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
8943  }
8944  }
8945  }
8946  while (need_refinement == 1);
8947 
8948  // 5. Update the boundary elements.
8949  int v1[2], v2[2], bisect, temp;
8950  temp = NumOfBdrElements;
8951  for (i = 0; i < temp; i++)
8952  {
8953  boundary[i]->GetVertices(v);
8954  bisect = v_to_v(v[0], v[1]);
8955  if (middle[bisect] != -1) // the element was refined (needs updating)
8956  {
8957  if (boundary[i]->GetType() == Element::SEGMENT)
8958  {
8959  v1[0] = v[0]; v1[1] = middle[bisect];
8960  v2[0] = middle[bisect]; v2[1] = v[1];
8961 
8962  boundary[i]->SetVertices(v1);
8963  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
8964  }
8965  else
8966  mfem_error("Only bisection of segment is implemented"
8967  " for bdr elem.");
8968  }
8969  }
8970  NumOfBdrElements = boundary.Size();
8971 
8972  // 6. Free the allocated memory.
8973  delete [] edge1;
8974  delete [] edge2;
8975  delete [] middle;
8976 
8977  if (el_to_edge != NULL)
8978  {
8980  GenerateFaces();
8981  }
8982 
8983  }
8984  else if (Dim == 3) // ---------------------------------------------------
8985  {
8986  // 1. Hash table of vertex to vertex connections corresponding to refined
8987  // edges.
8988  HashTable<Hashed2> v_to_v;
8989 
8990  MFEM_VERIFY(GetNE() == 0 ||
8991  ((Tetrahedron*)elements[0])->GetRefinementFlag() != 0,
8992  "tetrahedral mesh is not marked for refinement:"
8993  " call Finalize(true)");
8994 
8995  // 2. Do the red refinement.
8996  int ii;
8997  switch (type)
8998  {
8999  case 1:
9000  for (i = 0; i < marked_el.Size(); i++)
9001  {
9002  Bisection(marked_el[i], v_to_v);
9003  }
9004  break;
9005  case 2:
9006  for (i = 0; i < marked_el.Size(); i++)
9007  {
9008  Bisection(marked_el[i], v_to_v);
9009 
9010  Bisection(NumOfElements - 1, v_to_v);
9011  Bisection(marked_el[i], v_to_v);
9012  }
9013  break;
9014  case 3:
9015  for (i = 0; i < marked_el.Size(); i++)
9016  {
9017  Bisection(marked_el[i], v_to_v);
9018 
9019  ii = NumOfElements - 1;
9020  Bisection(ii, v_to_v);
9021  Bisection(NumOfElements - 1, v_to_v);
9022  Bisection(ii, v_to_v);
9023 
9024  Bisection(marked_el[i], v_to_v);
9025  Bisection(NumOfElements-1, v_to_v);
9026  Bisection(marked_el[i], v_to_v);
9027  }
9028  break;
9029  }
9030 
9031  // 3. Do the green refinement (to get conforming mesh).
9032  int need_refinement;
9033  // int need_refinement, onoe, max_gen = 0;
9034  do
9035  {
9036  // int redges[2], type, flag;
9037  need_refinement = 0;
9038  // onoe = NumOfElements;
9039  // for (i = 0; i < onoe; i++)
9040  for (i = 0; i < NumOfElements; i++)
9041  {
9042  // ((Tetrahedron *)elements[i])->
9043  // ParseRefinementFlag(redges, type, flag);
9044  // if (flag > max_gen) max_gen = flag;
9045  if (elements[i]->NeedRefinement(v_to_v))
9046  {
9047  need_refinement = 1;
9048  Bisection(i, v_to_v);
9049  }
9050  }
9051  }
9052  while (need_refinement == 1);
9053 
9054  // mfem::out << "Maximum generation: " << max_gen << endl;
9055 
9056  // 4. Update the boundary elements.
9057  do
9058  {
9059  need_refinement = 0;
9060  for (i = 0; i < NumOfBdrElements; i++)
9061  if (boundary[i]->NeedRefinement(v_to_v))
9062  {
9063  need_refinement = 1;
9064  BdrBisection(i, v_to_v);
9065  }
9066  }
9067  while (need_refinement == 1);
9068 
9069  NumOfVertices = vertices.Size();
9070  NumOfBdrElements = boundary.Size();
9071 
9072  // 5. Update element-to-edge and element-to-face relations.
9073  if (el_to_edge != NULL)
9074  {
9076  }
9077  if (el_to_face != NULL)
9078  {
9080  GenerateFaces();
9081  }
9082 
9083  } // end 'if (Dim == 3)'
9084 
9086  sequence++;
9087 
9088  UpdateNodes();
9089 
9090 #ifdef MFEM_DEBUG
9091  CheckElementOrientation(false);
9092 #endif
9093 }
9094 
9096  int nc_limit)
9097 {
9098  MFEM_VERIFY(!NURBSext, "Nonconforming refinement of NURBS meshes is "
9099  "not supported. Project the NURBS to Nodes first.");
9100 
9101  ResetLazyData();
9102 
9103  if (!ncmesh)
9104  {
9105  // start tracking refinement hierarchy
9106  ncmesh = new NCMesh(this);
9107  }
9108 
9109  if (!refinements.Size())
9110  {
9112  return;
9113  }
9114 
9115  // do the refinements
9117  ncmesh->Refine(refinements);
9118 
9119  if (nc_limit > 0)
9120  {
9121  ncmesh->LimitNCLevel(nc_limit);
9122  }
9123 
9124  // create a second mesh containing the finest elements from 'ncmesh'
9125  Mesh* mesh2 = new Mesh(*ncmesh);
9126  ncmesh->OnMeshUpdated(mesh2);
9127 
9128  // now swap the meshes, the second mesh will become the old coarse mesh
9129  // and this mesh will be the new fine mesh
9130  Swap(*mesh2, false);
9131  delete mesh2;
9132 
9134 
9136  sequence++;
9137 
9138  if (Nodes) // update/interpolate curved mesh
9139  {
9140  Nodes->FESpace()->Update();
9141  Nodes->Update();
9142  }
9143 }
9144 
9145 double Mesh::AggregateError(const Array<double> &elem_error,
9146  const int *fine, int nfine, int op)
9147 {
9148  double error = 0.0;
9149  for (int i = 0; i < nfine; i++)
9150  {
9151  MFEM_VERIFY(fine[i] < elem_error.Size(), "");
9152 
9153  double err_fine = elem_error[fine[i]];
9154  switch (op)
9155  {
9156  case 0: error = std::min(error, err_fine); break;
9157  case 1: error += err_fine; break;
9158  case 2: error = std::max(error, err_fine); break;
9159  }
9160  }
9161  return error;
9162 }
9163 
9165  double threshold, int nc_limit, int op)
9166 {
9167  MFEM_VERIFY(ncmesh, "Only supported for non-conforming meshes.");
9168  MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. "
9169  "Project the NURBS to Nodes first.");
9170 
9171  ResetLazyData();
9172 
9173  const Table &dt = ncmesh->GetDerefinementTable();
9174 
9175  Array<int> level_ok;
9176  if (nc_limit > 0)
9177  {
9178  ncmesh->CheckDerefinementNCLevel(dt, level_ok, nc_limit);
9179  }
9180 
9181  Array<int> derefs;
9182  for (int i = 0; i < dt.Size(); i++)
9183  {
9184  if (nc_limit > 0 && !level_ok[i]) { continue; }
9185 
9186  double error =
9187  AggregateError(elem_error, dt.GetRow(i), dt.RowSize(i), op);
9188 
9189  if (error < threshold) { derefs.Append(i); }
9190  }
9191 
9192  if (!derefs.Size()) { return false; }
9193 
9194  ncmesh->Derefine(derefs);
9195 
9196  Mesh* mesh2 = new Mesh(*ncmesh);
9197  ncmesh->OnMeshUpdated(mesh2);
9198 
9199  Swap(*mesh2, false);
9200  delete mesh2;
9201 
9203 
9205  sequence++;
9206 
9207  UpdateNodes();
9208 
9209  return true;
9210 }
9211 
9212 bool Mesh::DerefineByError(Array<double> &elem_error, double threshold,
9213  int nc_limit, int op)
9214 {
9215  // NOTE: the error array is not const because it will be expanded in parallel
9216  // by ghost element errors
9217  if (Nonconforming())
9218  {
9219  return NonconformingDerefinement(elem_error, threshold, nc_limit, op);
9220  }
9221  else
9222  {
9223  MFEM_ABORT("Derefinement is currently supported for non-conforming "
9224  "meshes only.");
9225  return false;
9226  }
9227 }
9228 
9229 bool Mesh::DerefineByError(const Vector &elem_error, double threshold,
9230  int nc_limit, int op)
9231 {
9232  Array<double> tmp(elem_error.Size());
9233  for (int i = 0; i < tmp.Size(); i++)
9234  {
9235  tmp[i] = elem_error(i);
9236  }
9237  return DerefineByError(tmp, threshold, nc_limit, op);
9238 }
9239 
9240 
9241 void Mesh::InitFromNCMesh(const NCMesh &ncmesh_)
9242 {
9243  Dim = ncmesh_.Dimension();
9244  spaceDim = ncmesh_.SpaceDimension();
9245 
9246  DeleteTables();
9247 
9248  ncmesh_.GetMeshComponents(*this);
9249 
9250  NumOfVertices = vertices.Size();
9251  NumOfElements = elements.Size();
9252  NumOfBdrElements = boundary.Size();
9253 
9254  SetMeshGen(); // set the mesh type: 'meshgen', ...
9255 
9256  NumOfEdges = NumOfFaces = 0;
9258 
9259  if (Dim > 1)
9260  {
9261  el_to_edge = new Table;
9263  }
9264  if (Dim > 2)
9265  {
9267  }
9268  GenerateFaces();
9269 #ifdef MFEM_DEBUG
9271 #endif
9272 
9273  // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
9274  // outside after this method.
9275 }
9276 
9277 Mesh::Mesh(const NCMesh &ncmesh_)
9278 {
9279  Init();
9280  InitTables();
9281  InitFromNCMesh(ncmesh_);
9282  SetAttributes();
9283 }
9284 
9285 void Mesh::Swap(Mesh& other, bool non_geometry)
9286 {
9287  mfem::Swap(Dim, other.Dim);
9288  mfem::Swap(spaceDim, other.spaceDim);
9289 
9295 
9296  mfem::Swap(meshgen, other.meshgen);
9298 
9299  mfem::Swap(elements, other.elements);
9300  mfem::Swap(vertices, other.vertices);
9301  mfem::Swap(boundary, other.boundary);
9302  mfem::Swap(faces, other.faces);
9305 
9308  mfem::Swap(el_to_el, other.el_to_el);
9312  mfem::Swap(face_edge, other.face_edge);
9314 
9317 
9319 
9320 #ifdef MFEM_USE_MEMALLOC
9321  TetMemory.Swap(other.TetMemory);
9322 #endif
9323 
9324  if (non_geometry)
9325  {
9326  mfem::Swap(NURBSext, other.NURBSext);
9327  mfem::Swap(ncmesh, other.ncmesh);
9328 
9329  mfem::Swap(Nodes, other.Nodes);
9330  if (Nodes) { Nodes->FESpace()->UpdateMeshPointer(this); }
9331  if (other.Nodes) { other.Nodes->FESpace()->UpdateMeshPointer(&other); }
9332  mfem::Swap(own_nodes, other.own_nodes);
9333 
9335 
9336  mfem::Swap(sequence, other.sequence);
9338  }
9339 }
9340 
9341 void Mesh::GetElementData(const Array<Element*> &elem_array, int geom,
9342  Array<int> &elem_vtx, Array<int> &attr) const
9343 {
9344  // protected method
9345  const int nv = Geometry::NumVerts[geom];
9346  int num_elems = 0;
9347  for (int i = 0; i < elem_array.Size(); i++)
9348  {
9349  if (elem_array[i]->GetGeometryType() == geom)
9350  {
9351  num_elems++;
9352  }
9353  }
9354  elem_vtx.SetSize(nv*num_elems);
9355  attr.SetSize(num_elems);
9356  elem_vtx.SetSize(0);
9357  attr.SetSize(0);
9358  for (int i = 0; i < elem_array.Size(); i++)
9359  {
9360  Element *el = elem_array[i];
9361  if (el->GetGeometryType() != geom) { continue; }
9362 
9363  Array<int> loc_vtx(el->GetVertices(), nv);
9364  elem_vtx.Append(loc_vtx);
9365  attr.Append(el->GetAttribute());
9366  }
9367 }
9368 
9369 static Array<int>& AllElements(Array<int> &list, int nelem)
9370 {
9371  list.SetSize(nelem);
9372  for (int i = 0; i < nelem; i++) { list[i] = i; }
9373  return list;
9374 }
9375 
9376 void Mesh::UniformRefinement(int ref_algo)
9377 {
9378  Array<int> list;
9379 
9380  if (NURBSext)
9381  {
9383  }
9384  else if (ncmesh)
9385  {
9386  GeneralRefinement(AllElements(list, GetNE()));
9387  }
9388  else if (ref_algo == 1 && meshgen == 1 && Dim == 3)
9389  {
9390  // algorithm "B" for an all-tet mesh
9391  LocalRefinement(AllElements(list, GetNE()));
9392  }
9393  else
9394  {
9395  switch (Dim)
9396  {
9397  case 1: LocalRefinement(AllElements(list, GetNE())); break;
9398  case 2: UniformRefinement2D(); break;
9399  case 3: UniformRefinement3D(); break;
9400  default: MFEM_ABORT("internal error");
9401  }
9402  }
9403 }
9404 
9406  int nonconforming, int nc_limit)
9407 {
9408  if (ncmesh)
9409  {
9410  nonconforming = 1;
9411  }
9412  else if (Dim == 1 || (Dim == 3 && (meshgen & 1)))
9413  {
9414  nonconforming = 0;
9415  }
9416  else if (nonconforming < 0)
9417  {
9418  // determine if nonconforming refinement is suitable
9419  if ((meshgen & 2) || (meshgen & 4) || (meshgen & 8))
9420  {
9421  nonconforming = 1; // tensor product elements and wedges
9422  }
9423  else
9424  {
9425  nonconforming = 0; // simplices
9426  }
9427  }
9428 
9429  if (nonconforming)
9430  {
9431  // non-conforming refinement (hanging nodes)
9432  NonconformingRefinement(refinements, nc_limit);
9433  }
9434  else
9435  {
9436  Array<int> el_to_refine(refinements.Size());
9437  for (int i = 0; i < refinements.Size(); i++)
9438  {
9439  el_to_refine[i] = refinements[i].index;
9440  }
9441 
9442  // infer 'type' of local refinement from first element's 'ref_type'
9443  int type, rt = (refinements.Size() ? refinements[0].ref_type : 7);
9444  if (rt == 1 || rt == 2 || rt == 4)
9445  {
9446  type = 1; // bisection
9447  }
9448  else if (rt == 3 || rt == 5 || rt == 6)
9449  {
9450  type = 2; // quadrisection
9451  }
9452  else
9453  {
9454  type = 3; // octasection
9455  }
9456 
9457  // red-green refinement and bisection, no hanging nodes
9458  LocalRefinement(el_to_refine, type);
9459  }
9460 }
9461 
9462 void Mesh::GeneralRefinement(const Array<int> &el_to_refine, int nonconforming,
9463  int nc_limit)
9464 {
9465  Array<Refinement> refinements(el_to_refine.Size());
9466  for (int i = 0; i < el_to_refine.Size(); i++)
9467  {
9468  refinements[i] = Refinement(el_to_refine[i]);
9469  }
9470  GeneralRefinement(refinements, nonconforming, nc_limit);
9471 }
9472 
9473 void Mesh::EnsureNCMesh(bool simplices_nonconforming)
9474 {
9475  MFEM_VERIFY(!NURBSext, "Cannot convert a NURBS mesh to an NC mesh. "
9476  "Please project the NURBS to Nodes first, with SetCurvature().");
9477 
9478 #ifdef MFEM_USE_MPI
9479  MFEM_VERIFY(ncmesh != NULL || dynamic_cast<const ParMesh*>(this) == NULL,
9480  "Sorry, converting a conforming ParMesh to an NC mesh is "
9481  "not possible.");
9482 #endif
9483 
9484  if (!ncmesh)
9485  {
9486  if ((meshgen & 0x2) /* quads/hexes */ ||
9487  (meshgen & 0x4) /* wedges */ ||
9488  (simplices_nonconforming && (meshgen & 0x1)) /* simplices */)
9489  {
9490  ncmesh = new NCMesh(this);
9491  ncmesh->OnMeshUpdated(this);
9493  }
9494  }
9495 }
9496 
9497 void Mesh::RandomRefinement(double prob, bool aniso, int nonconforming,
9498  int nc_limit)
9499 {
9500  Array<Refinement> refs;
9501  for (int i = 0; i < GetNE(); i++)
9502  {
9503  if ((double) rand() / RAND_MAX < prob)
9504  {
9505  int type = 7;
9506  if (aniso)
9507  {
9508  type = (Dim == 3) ? (rand() % 7 + 1) : (rand() % 3 + 1);
9509  }
9510  refs.Append(Refinement(i, type));
9511  }
9512  }
9513  GeneralRefinement(refs, nonconforming, nc_limit);
9514 }
9515 
9516 void Mesh::RefineAtVertex(const Vertex& vert, double eps, int nonconforming)
9517 {
9518  Array<int> v;
9519  Array<Refinement> refs;
9520  for (int i = 0; i < GetNE(); i++)
9521  {
9522  GetElementVertices(i, v);
9523  bool refine = false;
9524  for (int j = 0; j < v.Size(); j++)
9525  {
9526  double dist = 0.0;
9527  for (int l = 0; l < spaceDim; l++)
9528  {
9529  double d = vert(l) - vertices[v[j]](l);
9530  dist += d*d;
9531  }
9532  if (dist <= eps*eps) { refine = true; break; }
9533  }
9534  if (refine)
9535  {
9536  refs.Append(Refinement(i));
9537  }
9538  }
9539  GeneralRefinement(refs, nonconforming);
9540 }
9541 
9542 bool Mesh::RefineByError(const Array<double> &elem_error, double threshold,
9543  int nonconforming, int nc_limit)
9544 {
9545  MFEM_VERIFY(elem_error.Size() == GetNE(), "");
9546  Array<Refinement> refs;
9547  for (int i = 0; i < GetNE(); i++)
9548  {
9549  if (elem_error[i] > threshold)
9550  {
9551  refs.Append(Refinement(i));
9552  }
9553  }
9554  if (ReduceInt(refs.Size()))
9555  {
9556  GeneralRefinement(refs, nonconforming, nc_limit);
9557  return true;
9558  }
9559  return false;
9560 }
9561 
9562 bool Mesh::RefineByError(const Vector &elem_error, double threshold,
9563  int nonconforming, int nc_limit)
9564 {
9565  Array<double> tmp(const_cast<double*>(elem_error.GetData()),
9566  elem_error.Size());
9567  return RefineByError(tmp, threshold, nonconforming, nc_limit);
9568 }
9569 
9570 
9571 void Mesh::Bisection(int i, const DSTable &v_to_v,
9572  int *edge1, int *edge2, int *middle)
9573 {
9574  int *vert;
9575  int v[2][4], v_new, bisect, t;
9576  Element *el = elements[i];
9577  Vertex V;
9578 
9579  t = el->GetType();
9580  if (t == Element::TRIANGLE)
9581  {
9582  Triangle *tri = (Triangle *) el;
9583 
9584  vert = tri->GetVertices();
9585 
9586  // 1. Get the index for the new vertex in v_new.
9587  bisect = v_to_v(vert[0], vert[1]);
9588  MFEM_ASSERT(bisect >= 0, "");
9589 
9590  if (middle[bisect] == -1)
9591  {
9592  v_new = NumOfVertices++;
9593  for (int d = 0; d < spaceDim; d++)
9594  {
9595  V(d) = 0.5 * (vertices[vert[0]](d) + vertices[vert[1]](d));
9596  }
9597  vertices.Append(V);
9598 
9599  // Put the element that may need refinement (because of this
9600  // bisection) in edge1, or -1 if no more refinement is needed.
9601  if (edge1[bisect] == i)
9602  {
9603  edge1[bisect] = edge2[bisect];
9604  }
9605 
9606  middle[bisect] = v_new;
9607  }
9608  else
9609  {
9610  v_new = middle[bisect];
9611 
9612  // This edge will require no more refinement.
9613  edge1[bisect] = -1;
9614  }
9615 
9616  // 2. Set the node indices for the new elements in v[0] and v[1] so that
9617  // the edge marked for refinement is between the first two nodes.
9618  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
9619  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
9620 
9621  tri->SetVertices(v[0]); // changes vert[0..2] !!!
9622 
9623  Triangle* tri_new = new Triangle(v[1], tri->GetAttribute());
9624  elements.Append(tri_new);
9625 
9626  int tr = tri->GetTransform();
9627  tri_new->ResetTransform(tr);
9628 
9629  // record the sequence of refinements
9630  tri->PushTransform(4);
9631  tri_new->PushTransform(5);
9632 
9633  int coarse = FindCoarseElement(i);
9634  CoarseFineTr.embeddings[i].parent = coarse;
9636 
9637  // 3. edge1 and edge2 may have to be changed for the second triangle.
9638  if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
9639  {
9640  bisect = v_to_v(v[1][0], v[1][1]);
9641  MFEM_ASSERT(bisect >= 0, "");
9642 
9643  if (edge1[bisect] == i)
9644  {
9645  edge1[bisect] = NumOfElements;
9646  }
9647  else if (edge2[bisect] == i)
9648  {
9649  edge2[bisect] = NumOfElements;
9650  }
9651  }
9652  NumOfElements++;
9653  }
9654  else
9655  {
9656  MFEM_ABORT("Bisection for now works only for triangles.");
9657  }
9658 }
9659 
9661 {
9662  int *vert;
9663  int v[2][4], v_new, bisect, t;
9664  Element *el = elements[i];
9665  Vertex V;
9666 
9667  t = el->GetType();
9668  if (t == Element::TETRAHEDRON)
9669  {
9670  int j, type, new_type, old_redges[2], new_redges[2][2], flag;
9671  Tetrahedron *tet = (Tetrahedron *) el;
9672 
9673  MFEM_VERIFY(tet->GetRefinementFlag() != 0,
9674  "TETRAHEDRON element is not marked for refinement.");
9675 
9676  vert = tet->GetVertices();
9677 
9678  // 1. Get the index for the new vertex in v_new.
9679  bisect = v_to_v.FindId(vert[0], vert[1]);
9680  if (bisect == -1)
9681  {
9682  v_new = NumOfVertices + v_to_v.GetId(vert[0],vert[1]);
9683  for (j = 0; j < 3; j++)
9684  {
9685  V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j));
9686  }
9687  vertices.Append(V);
9688  }
9689  else
9690  {
9691  v_new = NumOfVertices + bisect;
9692  }
9693 
9694  // 2. Set the node indices for the new elements in v[2][4] so that
9695  // the edge marked for refinement is between the first two nodes.
9696  tet->ParseRefinementFlag(old_redges, type, flag);
9697 
9698  v[0][3] = v_new;
9699  v[1][3] = v_new;
9700  new_redges[0][0] = 2;
9701  new_redges[0][1] = 1;
9702  new_redges[1][0] = 2;
9703  new_redges[1][1] = 1;
9704  int tr1 = -1, tr2 = -1;
9705  switch (old_redges[0])
9706  {
9707  case 2:
9708  v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3];
9709  if (type == Tetrahedron::TYPE_PF) { new_redges[0][1] = 4; }
9710  tr1 = 0;
9711  break;
9712  case 3:
9713  v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2];
9714  tr1 = 2;
9715  break;
9716  case 5:
9717  v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0];
9718  tr1 = 4;
9719  }
9720  switch (old_redges[1])
9721  {
9722  case 1:
9723  v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3];
9724  if (type == Tetrahedron::TYPE_PF) { new_redges[1][0] = 3; }
9725  tr2 = 1;
9726  break;
9727  case 4:
9728  v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2];
9729  tr2 = 3;
9730  break;
9731  case 5:
9732  v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1];
9733  tr2 = 5;
9734  }
9735 
9736  int attr = tet->GetAttribute();
9737  tet->SetVertices(v[0]);
9738 
9739 #ifdef MFEM_USE_MEMALLOC
9740  Tetrahedron *tet2 = TetMemory.Alloc();
9741  tet2->SetVertices(v[1]);
9742  tet2->SetAttribute(attr);
9743 #else
9744  Tetrahedron *tet2 = new Tetrahedron(v[1], attr);
9745 #endif
9746  tet2->ResetTransform(tet->GetTransform());
9747  elements.Append(tet2);
9748 
9749  // record the sequence of refinements
9750  tet->PushTransform(tr1);
9751  tet2->PushTransform(tr2);
9752 
9753  int coarse = FindCoarseElement(i);
9754  CoarseFineTr.embeddings[i].parent = coarse;
9756 
9757  // 3. Set the bisection flag
9758  switch (type)
9759  {
9760  case Tetrahedron::TYPE_PU:
9761  new_type = Tetrahedron::TYPE_PF; break;
9762  case Tetrahedron::TYPE_PF:
9763  new_type = Tetrahedron::TYPE_A; break;
9764  default:
9765  new_type = Tetrahedron::TYPE_PU;
9766  }
9767 
9768  tet->CreateRefinementFlag(new_redges[0], new_type, flag+1);
9769  tet2->CreateRefinementFlag(new_redges[1], new_type, flag+1);
9770 
9771  NumOfElements++;
9772  }
9773  else
9774  {
9775  MFEM_ABORT("Bisection with HashTable for now works only for tetrahedra.");
9776  }
9777 }
9778 
9779 void Mesh::BdrBisection(int i, const HashTable<Hashed2> &v_to_v)
9780 {
9781  int *vert;
9782  int v[2][3], v_new, bisect, t;
9783  Element *bdr_el = boundary[i];
9784 
9785  t = bdr_el->GetType();
9786  if (t == Element::TRIANGLE)
9787  {
9788  Triangle *tri = (Triangle *) bdr_el;
9789 
9790  vert = tri->GetVertices();
9791 
9792  // 1. Get the index for the new vertex in v_new.
9793  bisect = v_to_v.FindId(vert[0], vert[1]);
9794  MFEM_ASSERT(bisect >= 0, "");
9795  v_new = NumOfVertices + bisect;
9796  MFEM_ASSERT(v_new != -1, "");
9797 
9798  // 2. Set the node indices for the new elements in v[0] and v[1] so that
9799  // the edge marked for refinement is between the first two nodes.
9800  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
9801  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
9802 
9803  tri->SetVertices(v[0]);
9804 
9805  boundary.Append(new Triangle(v[1], tri->GetAttribute()));
9806 
9807  NumOfBdrElements++;
9808  }
9809  else
9810  {
9811  MFEM_ABORT("Bisection of boundary elements with HashTable works only for"
9812  " triangles!");
9813  }
9814 }
9815 
9816 void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
9817  int *edge1, int *edge2, int *middle)
9818 {
9819  Array<int> v;
9820  int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3];
9821  Vertex V;
9822 
9823  if (elements[i]->GetType() == Element::TRIANGLE)
9824  {
9825  Triangle *tri0 = (Triangle*) elements[i];
9826  tri0->GetVertices(v);
9827 
9828  // 1. Get the indices for the new vertices in array v_new
9829  bisect[0] = v_to_v(v[0],v[1]);
9830  bisect[1] = v_to_v(v[1],v[2]);
9831  bisect[2] = v_to_v(v[0],v[2]);
9832  MFEM_ASSERT(bisect[0] >= 0 && bisect[1] >= 0 && bisect[2] >= 0, "");
9833 
9834  for (j = 0; j < 3; j++) // for the 3 edges fix v_new
9835  {
9836  if (middle[bisect[j]] == -1)
9837  {
9838  v_new[j] = NumOfVertices++;
9839  for (int d = 0; d < spaceDim; d++)
9840  {
9841  V(d) = (vertices[v[j]](d) + vertices[v[(j+1)%3]](d))/2.;
9842  }
9843  vertices.Append(V);
9844 
9845  // Put the element that may need refinement (because of this
9846  // bisection) in edge1, or -1 if no more refinement is needed.
9847  if (edge1[bisect[j]] == i)
9848  {
9849  edge1[bisect[j]] = edge2[bisect[j]];
9850  }
9851 
9852  middle[bisect[j]] = v_new[j];
9853  }
9854  else
9855  {
9856  v_new[j] = middle[bisect[j]];
9857 
9858  // This edge will require no more refinement.
9859  edge1[bisect[j]] = -1;
9860  }
9861  }
9862 
9863  // 2. Set the node indices for the new elements in v1, v2, v3 & v4 so that
9864  // the edges marked for refinement be between the first two nodes.
9865  v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2];
9866  v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1];
9867  v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2];
9868  v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0];
9869 
9870  Triangle* tri1 = new Triangle(v1, tri0->GetAttribute());
9871  Triangle* tri2 = new Triangle(v2, tri0->GetAttribute());
9872  Triangle* tri3 = new Triangle(v3, tri0->GetAttribute());
9873 
9874  elements.Append(tri1);
9875  elements.Append(tri2);
9876  elements.Append(tri3);
9877 
9878  tri0->SetVertices(v4);
9879 
9880  // record the sequence of refinements
9881  unsigned code = tri0->GetTransform();
9882  tri1->ResetTransform(code);
9883  tri2->ResetTransform(code);
9884  tri3->ResetTransform(code);
9885 
9886  tri0->PushTransform(3);
9887  tri1->PushTransform(0);
9888  tri2->PushTransform(1);
9889  tri3->PushTransform(2);
9890 
9891  // set parent indices
9892  int coarse = FindCoarseElement(i);
9897 
9898  NumOfElements += 3;
9899  }
9900  else
9901  {
9902  MFEM_ABORT("Uniform refinement for now works only for triangles.");
9903  }
9904 }
9905 
9907 {
9908  // initialize CoarseFineTr
9909  CoarseFineTr.Clear();
9911  for (int i = 0; i < NumOfElements; i++)
9912  {
9913  elements[i]->ResetTransform(0);
9915  }
9916 }
9917 
9919 {
9920  int coarse;
9921  while ((coarse = CoarseFineTr.embeddings[i].parent) != i)
9922  {
9923  i = coarse;
9924  }
9925  return coarse;
9926 }
9927 
9929 {
9930  MFEM_VERIFY(GetLastOperation() == Mesh::REFINE, "");
9931 
9932  if (ncmesh)
9933  {
9934  return ncmesh->GetRefinementTransforms();
9935  }
9936 
9937  Mesh::GeometryList elem_geoms(*this);
9938  for (int i = 0; i < elem_geoms.Size(); i++)
9939  {
9940  const Geometry::Type geom = elem_geoms[i];
9941  if (CoarseFineTr.point_matrices[geom].SizeK()) { continue; }
9942 
9943  if (geom == Geometry::TRIANGLE ||
9944  geom == Geometry::TETRAHEDRON)
9945  {
9946  std::map<unsigned, int> mat_no;
9947  mat_no[0] = 1; // identity
9948 
9949  // assign matrix indices to element transformations
9950  for (int j = 0; j < elements.Size(); j++)
9951  {
9952  int index = 0;
9953  unsigned code = elements[j]->GetTransform();
9954  if (code)
9955  {
9956  int &matrix = mat_no[code];
9957  if (!matrix) { matrix = mat_no.size(); }
9958  index = matrix-1;
9959  }
9960  CoarseFineTr.embeddings[j].matrix = index;
9961  }
9962 
9963  DenseTensor &pmats = CoarseFineTr.point_matrices[geom];
9964  pmats.SetSize(Dim, Dim+1, mat_no.size());
9965 
9966  // calculate the point matrices used
9967  std::map<unsigned, int>::iterator it;
9968  for (it = mat_no.begin(); it != mat_no.end(); ++it)
9969  {
9970  if (geom == Geometry::TRIANGLE)
9971  {
9972  Triangle::GetPointMatrix(it->first, pmats(it->second-1));
9973  }
9974  else
9975  {
9976  Tetrahedron::GetPointMatrix(it->first, pmats(it->second-1));
9977  }
9978  }
9979  }
9980  else
9981  {
9982  MFEM_ABORT("Don't know how to construct CoarseFineTransformations for"
9983  " geom = " << geom);
9984  }
9985  }
9986 
9987  // NOTE: quads and hexes already have trivial transformations ready
9988  return CoarseFineTr;
9989 }
9990 
9991 void Mesh::PrintXG(std::ostream &os) const
9992 {
9993  MFEM_ASSERT(Dim==spaceDim, "2D Manifold meshes not supported");
9994  int i, j;
9995  Array<int> v;
9996 
9997  if (Dim == 2)
9998  {
9999  // Print the type of the mesh.
10000  if (Nodes == NULL)
10001  {
10002  os << "areamesh2\n\n";
10003  }
10004  else
10005  {
10006  os << "curved_areamesh2\n\n";
10007  }
10008 
10009  // Print the boundary elements.
10010  os << NumOfBdrElements << '\n';
10011  for (i = 0; i < NumOfBdrElements; i++)
10012  {
10013  boundary[i]->GetVertices(v);
10014 
10015  os << boundary[i]->GetAttribute();
10016  for (j = 0; j < v.Size(); j++)
10017  {
10018  os << ' ' << v[j] + 1;
10019  }
10020  os << '\n';
10021  }
10022 
10023  // Print the elements.
10024  os << NumOfElements << '\n';
10025  for (i = 0; i < NumOfElements; i++)
10026  {
10027  elements[i]->GetVertices(v);
10028 
10029  os << elements[i]->GetAttribute() << ' ' << v.Size();
10030  for (j = 0; j < v.Size(); j++)
10031  {
10032  os << ' ' << v[j] + 1;
10033  }
10034  os << '\n';
10035  }
10036 
10037  if (Nodes == NULL)
10038  {
10039  // Print the vertices.
10040  os << NumOfVertices << '\n';
10041  for (i = 0; i < NumOfVertices; i++)
10042  {
10043  os << vertices[i](0);
10044  for (j = 1; j < Dim; j++)
10045  {
10046  os << ' ' << vertices[i](j);
10047  }
10048  os << '\n';
10049  }
10050  }
10051  else
10052  {
10053  os << NumOfVertices << '\n';
10054  Nodes->Save(os);
10055  }
10056  }
10057  else // ===== Dim != 2 =====
10058  {
10059  if (Nodes)
10060  {
10061  mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D");
10062  }
10063 
10064  if (meshgen == 1)
10065  {
10066  int nv;
10067  const int *ind;
10068 
10069  os << "NETGEN_Neutral_Format\n";
10070  // print the vertices
10071  os << NumOfVertices << '\n';
10072  for (i = 0; i < NumOfVertices; i++)
10073  {
10074  for (j = 0; j < Dim; j++)
10075  {
10076  os << ' ' << vertices[i](j);
10077  }
10078  os << '\n';
10079  }
10080 
10081  // print the elements
10082  os << NumOfElements << '\n';
10083  for (i = 0; i < NumOfElements; i++)
10084  {
10085  nv = elements[i]->GetNVertices();
10086  ind = elements[i]->GetVertices();
10087  os << elements[i]->GetAttribute();
10088  for (j = 0; j < nv; j++)
10089  {
10090  os << ' ' << ind[j]+1;
10091  }
10092  os << '\n';
10093  }
10094 
10095  // print the boundary information.
10096  os << NumOfBdrElements << '\n';
10097  for (i = 0; i < NumOfBdrElements; i++)
10098  {
10099  nv = boundary[i]->GetNVertices();
10100  ind = boundary[i]->GetVertices();
10101  os << boundary[i]->GetAttribute();
10102  for (j = 0; j < nv; j++)
10103  {
10104  os << ' ' << ind[j]+1;
10105  }
10106  os << '\n';
10107  }
10108  }
10109  else if (meshgen == 2) // TrueGrid
10110  {
10111  int nv;
10112  const int *ind;
10113 
10114  os << "TrueGrid\n"
10115  << "1 " << NumOfVertices << " " << NumOfElements
10116  << " 0 0 0 0 0 0 0\n"
10117  << "0 0 0 1 0 0 0 0 0 0 0\n"
10118  << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
10119  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
10120  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
10121 
10122  for (i = 0; i < NumOfVertices; i++)
10123  os << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1)
10124  << ' ' << vertices[i](2) << " 0.0\n";
10125 
10126  for (i = 0; i < NumOfElements; i++)
10127  {
10128  nv = elements[i]->GetNVertices();
10129  ind = elements[i]->GetVertices();
10130  os << i+1 << ' ' << elements[i]->GetAttribute();
10131  for (j = 0; j < nv; j++)
10132  {
10133  os << ' ' << ind[j]+1;
10134  }
10135  os << '\n';
10136  }
10137 
10138  for (i = 0; i < NumOfBdrElements; i++)
10139  {
10140  nv = boundary[i]->GetNVertices();
10141  ind = boundary[i]->GetVertices();
10142  os << boundary[i]->GetAttribute();
10143  for (j = 0; j < nv; j++)
10144  {
10145  os << ' ' << ind[j]+1;
10146  }
10147  os << " 1.0 1.0 1.0 1.0\n";
10148  }
10149  }
10150  }
10151 
10152  os << flush;
10153 }
10154 
10155 void Mesh::Printer(std::ostream &os, std::string section_delimiter) const
10156 {
10157  int i, j;
10158 
10159  if (NURBSext)
10160  {
10161  // general format
10162  NURBSext->Print(os);
10163  os << '\n';
10164  Nodes->Save(os);
10165 
10166  // patch-wise format
10167  // NURBSext->ConvertToPatches(*Nodes);
10168  // NURBSext->Print(os);
10169 
10170  return;
10171  }
10172 
10173  if (Nonconforming())
10174  {
10175  // nonconforming mesh format
10176  ncmesh->Print(os);
10177 
10178  if (Nodes)
10179  {
10180  os << "\n# mesh curvature GridFunction";
10181  os << "\nnodes\n";
10182  Nodes->Save(os);
10183  }
10184 
10185  os << "\nmfem_mesh_end" << endl;
10186  return;
10187  }
10188 
10189  // serial/parallel conforming mesh format
10190  os << (section_delimiter.empty()
10191  ? "MFEM mesh v1.0\n" : "MFEM mesh v1.2\n");
10192 
10193  // optional
10194  os <<
10195  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10196  "# POINT = 0\n"
10197  "# SEGMENT = 1\n"
10198  "# TRIANGLE = 2\n"
10199  "# SQUARE = 3\n"
10200  "# TETRAHEDRON = 4\n"
10201  "# CUBE = 5\n"
10202  "# PRISM = 6\n"
10203  "# PYRAMID = 7\n"
10204  "#\n";
10205 
10206  os << "\ndimension\n" << Dim;
10207 
10208  os << "\n\nelements\n" << NumOfElements << '\n';
10209  for (i = 0; i < NumOfElements; i++)
10210  {
10211  PrintElement(elements[i], os);
10212  }
10213 
10214  os << "\nboundary\n" << NumOfBdrElements << '\n';
10215  for (i = 0; i < NumOfBdrElements; i++)
10216  {
10217  PrintElement(boundary[i], os);
10218  }
10219 
10220  os << "\nvertices\n" << NumOfVertices << '\n';
10221  if (Nodes == NULL)
10222  {
10223  os << spaceDim << '\n';
10224  for (i = 0; i < NumOfVertices; i++)
10225  {
10226  os << vertices[i](0);
10227  for (j = 1; j < spaceDim; j++)
10228  {
10229  os << ' ' << vertices[i](j);
10230  }
10231  os << '\n';
10232  }
10233  os.flush();
10234  }
10235  else
10236  {
10237  os << "\nnodes\n";
10238  Nodes->Save(os);
10239  }
10240 
10241  if (!section_delimiter.empty())
10242  {
10243  os << section_delimiter << endl; // only with format v1.2
10244  }
10245 }
10246 
10247 void Mesh::PrintTopo(std::ostream &os,const Array<int> &e_to_k) const
10248 {
10249  int i;
10250  Array<int> vert;
10251 
10252  os << "MFEM NURBS mesh v1.0\n";
10253 
10254  // optional
10255  os <<
10256  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10257  "# SEGMENT = 1\n"
10258  "# SQUARE = 3\n"
10259  "# CUBE = 5\n"
10260  "#\n";
10261 
10262  os << "\ndimension\n" << Dim
10263  << "\n\nelements\n" << NumOfElements << '\n';
10264  for (i = 0; i < NumOfElements; i++)
10265  {
10266  PrintElement(elements[i], os);
10267  }
10268 
10269  os << "\nboundary\n" << NumOfBdrElements << '\n';
10270  for (i = 0; i < NumOfBdrElements; i++)
10271  {
10272  PrintElement(boundary[i], os);
10273  }
10274 
10275  os << "\nedges\n" << NumOfEdges << '\n';
10276  for (i = 0; i < NumOfEdges; i++)
10277  {
10278  edge_vertex->GetRow(i, vert);
10279  int ki = e_to_k[i];
10280  if (ki < 0)
10281  {
10282  ki = -1 - ki;
10283  }
10284  os << ki << ' ' << vert[0] << ' ' << vert[1] << '\n';
10285  }
10286  os << "\nvertices\n" << NumOfVertices << '\n';
10287 }
10288 
10289 void Mesh::Save(const char *fname, int precision) const
10290 {
10291  ofstream ofs(fname);
10292  ofs.precision(precision);
10293  Print(ofs);
10294 }
10295 
10296 #ifdef MFEM_USE_ADIOS2
10297 void Mesh::Print(adios2stream &os) const
10298 {
10299  os.Print(*this);
10300 }
10301 #endif
10302 
10303 void Mesh::PrintVTK(std::ostream &os)
10304 {
10305  os <<
10306  "# vtk DataFile Version 3.0\n"
10307  "Generated by MFEM\n"
10308  "ASCII\n"
10309  "DATASET UNSTRUCTURED_GRID\n";
10310 
10311  if (Nodes == NULL)
10312  {
10313  os << "POINTS " << NumOfVertices << " double\n";
10314  for (int i = 0; i < NumOfVertices; i++)
10315  {
10316  os << vertices[i](0);
10317  int j;
10318  for (j = 1; j < spaceDim; j++)
10319  {
10320  os << ' ' << vertices[i](j);
10321  }
10322  for ( ; j < 3; j++)
10323  {
10324  os << ' ' << 0.0;
10325  }
10326  os << '\n';
10327  }
10328  }
10329  else
10330  {
10331  Array<int> vdofs(3);
10332  os << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n";
10333  for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++)
10334  {
10335  vdofs.SetSize(1);
10336  vdofs[0] = i;
10337  Nodes->FESpace()->DofsToVDofs(vdofs);
10338  os << (*Nodes)(vdofs[0]);
10339  int j;
10340  for (j = 1; j < spaceDim; j++)
10341  {
10342  os << ' ' << (*Nodes)(vdofs[j]);
10343  }
10344  for ( ; j < 3; j++)
10345  {
10346  os << ' ' << 0.0;
10347  }
10348  os << '\n';
10349  }
10350  }
10351 
10352  int order = -1;
10353  if (Nodes == NULL)
10354  {
10355  int size = 0;
10356  for (int i = 0; i < NumOfElements; i++)
10357  {
10358  size += elements[i]->GetNVertices() + 1;
10359  }
10360  os << "CELLS " << NumOfElements << ' ' << size << '\n';
10361  for (int i = 0; i < NumOfElements; i++)
10362  {
10363  const int *v = elements[i]->GetVertices();
10364  const int nv = elements[i]->GetNVertices();
10365  os << nv;
10366  Geometry::Type geom = elements[i]->GetGeometryType();
10367  const int *perm = VTKGeometry::VertexPermutation[geom];
10368  for (int j = 0; j < nv; j++)
10369  {
10370  os << ' ' << v[perm ? perm[j] : j];
10371  }
10372  os << '\n';
10373  }
10374  order = 1;
10375  }
10376  else
10377  {
10378  Array<int> dofs;
10379  int size = 0;
10380  for (int i = 0; i < NumOfElements; i++)
10381  {
10382  Nodes->FESpace()->GetElementDofs(i, dofs);
10383  MFEM_ASSERT(Dim != 0 || dofs.Size() == 1,
10384  "Point meshes should have a single dof per element");
10385  size += dofs.Size() + 1;
10386  }
10387  os << "CELLS " << NumOfElements << ' ' << size << '\n';
10388  const char *fec_name = Nodes->FESpace()->FEColl()->Name();
10389 
10390  if (!strcmp(fec_name, "Linear") ||
10391  !strcmp(fec_name, "H1_0D_P1") ||
10392  !strcmp(fec_name, "H1_1D_P1") ||
10393  !strcmp(fec_name, "H1_2D_P1") ||
10394  !strcmp(fec_name, "H1_3D_P1"))
10395  {
10396  order = 1;
10397  }
10398  else if (!strcmp(fec_name, "Quadratic") ||
10399  !strcmp(fec_name, "H1_1D_P2") ||
10400  !strcmp(fec_name, "H1_2D_P2") ||
10401  !strcmp(fec_name, "H1_3D_P2"))
10402  {
10403  order = 2;
10404  }
10405  if (order == -1)
10406  {
10407  mfem::err << "Mesh::PrintVTK : can not save '"
10408  << fec_name << "' elements!" << endl;
10409  mfem_error();
10410  }
10411  for (int i = 0; i < NumOfElements; i++)
10412  {
10413  Nodes->FESpace()->GetElementDofs(i, dofs);
10414  os << dofs.Size();
10415  if (order == 1)
10416  {
10417  for (int j = 0; j < dofs.Size(); j++)
10418  {
10419  os << ' ' << dofs[j];
10420  }
10421  }
10422  else if (order == 2)
10423  {
10424  const int *vtk_mfem;
10425  switch (elements[i]->GetGeometryType())
10426  {
10427  case Geometry::SEGMENT:
10428  case Geometry::TRIANGLE:
10429  case Geometry::SQUARE:
10430  vtk_mfem = vtk_quadratic_hex; break; // identity map
10431  case Geometry::TETRAHEDRON:
10432  vtk_mfem = vtk_quadratic_tet; break;
10433  case Geometry::PRISM:
10434  vtk_mfem = vtk_quadratic_wedge; break;
10435  case Geometry::CUBE:
10436  default:
10437  vtk_mfem = vtk_quadratic_hex; break;
10438  }
10439  for (int j = 0; j < dofs.Size(); j++)
10440  {
10441  os << ' ' << dofs[vtk_mfem[j]];
10442  }
10443  }
10444  os << '\n';
10445  }
10446  }
10447 
10448  os << "CELL_TYPES " << NumOfElements << '\n';
10449  for (int i = 0; i < NumOfElements; i++)
10450  {
10451  int vtk_cell_type = 5;
10453  if (order == 1) { vtk_cell_type = VTKGeometry::Map[geom]; }
10454  else if (order == 2) { vtk_cell_type = VTKGeometry::QuadraticMap[geom]; }
10455  os << vtk_cell_type << '\n';
10456  }
10457 
10458  // write attributes
10459  os << "CELL_DATA " << NumOfElements << '\n'
10460  << "SCALARS material int\n"
10461  << "LOOKUP_TABLE default\n";
10462  for (int i = 0; i < NumOfElements; i++)
10463  {
10464  os << elements[i]->GetAttribute() << '\n';
10465  }
10466  os.flush();
10467 }
10468 
10469 void Mesh::PrintVTU(std::string fname,
10470  VTKFormat format,
10471  bool high_order_output,
10472  int compression_level,
10473  bool bdr)
10474 {
10475  int ref = (high_order_output && Nodes)
10476  ? Nodes->FESpace()->GetElementOrder(0) : 1;
10477 
10478  fname = fname + ".vtu";
10479  std::fstream os(fname.c_str(),std::ios::out);
10480  os << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"";
10481  if (compression_level != 0)
10482  {
10483  os << " compressor=\"vtkZLibDataCompressor\"";
10484  }
10485  os << " byte_order=\"" << VTKByteOrder() << "\">\n";
10486  os << "<UnstructuredGrid>\n";
10487  PrintVTU(os, ref, format, high_order_output, compression_level, bdr);
10488  os << "</Piece>\n"; // need to close the piece open in the PrintVTU method
10489  os << "</UnstructuredGrid>\n";
10490  os << "</VTKFile>" << std::endl;
10491 
10492  os.close();
10493 }
10494 
10495 void Mesh::PrintBdrVTU(std::string fname,
10496  VTKFormat format,
10497  bool high_order_output,
10498  int compression_level)
10499 {
10500  PrintVTU(fname, format, high_order_output, compression_level, true);
10501 }
10502 
10503 void Mesh::PrintVTU(std::ostream &os, int ref, VTKFormat format,
10504  bool high_order_output, int compression_level,
10505  bool bdr_elements)
10506 {
10507  RefinedGeometry *RefG;
10508  DenseMatrix pmat;
10509 
10510  const char *fmt_str = (format == VTKFormat::ASCII) ? "ascii" : "binary";
10511  const char *type_str = (format != VTKFormat::BINARY32) ? "Float64" : "Float32";
10512  std::vector<char> buf;
10513 
10514  auto get_geom = [&](int i)
10515  {
10516  if (bdr_elements) { return GetBdrElementBaseGeometry(i); }
10517  else { return GetElementBaseGeometry(i); }
10518  };
10519 
10520  int ne = bdr_elements ? GetNBE() : GetNE();
10521  // count the number of points and cells
10522  int np = 0, nc_ref = 0;
10523  for (int i = 0; i < ne; i++)
10524  {
10525  Geometry::Type geom = get_geom(i);
10526  int nv = Geometries.GetVertices(geom)->GetNPoints();
10527  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10528  np += RefG->RefPts.GetNPoints();
10529  nc_ref += RefG->RefGeoms.Size() / nv;
10530  }
10531 
10532  os << "<Piece NumberOfPoints=\"" << np << "\" NumberOfCells=\""
10533  << (high_order_output ? ne : nc_ref) << "\">\n";
10534 
10535  // print out the points
10536  os << "<Points>\n";
10537  os << "<DataArray type=\"" << type_str
10538  << "\" NumberOfComponents=\"3\" format=\"" << fmt_str << "\">\n";
10539  for (int i = 0; i < ne; i++)
10540  {
10541  RefG = GlobGeometryRefiner.Refine(get_geom(i), ref, 1);
10542 
10543  if (bdr_elements)
10544  {
10545  GetBdrElementTransformation(i)->Transform(RefG->RefPts, pmat);
10546  }
10547  else
10548  {
10549  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
10550  }
10551 
10552  for (int j = 0; j < pmat.Width(); j++)
10553  {
10554  WriteBinaryOrASCII(os, buf, pmat(0,j), " ", format);
10555  if (pmat.Height() > 1)
10556  {
10557  WriteBinaryOrASCII(os, buf, pmat(1,j), " ", format);
10558  }
10559  else
10560  {
10561  WriteBinaryOrASCII(os, buf, 0.0, " ", format);
10562  }
10563  if (pmat.Height() > 2)
10564  {
10565  WriteBinaryOrASCII(os, buf, pmat(2,j), "", format);
10566  }
10567  else
10568  {
10569  WriteBinaryOrASCII(os, buf, 0.0, "", format);
10570  }
10571  if (format == VTKFormat::ASCII) { os << '\n'; }
10572  }
10573  }
10574  if (format != VTKFormat::ASCII)
10575  {
10576  WriteBase64WithSizeAndClear(os, buf, compression_level);
10577  }
10578  os << "</DataArray>" << std::endl;
10579  os << "</Points>" << std::endl;
10580 
10581  os << "<Cells>" << std::endl;
10582  os << "<DataArray type=\"Int32\" Name=\"connectivity\" format=\""
10583  << fmt_str << "\">" << std::endl;
10584  // connectivity
10585  std::vector<int> offset;
10586 
10587  np = 0;
10588  if (high_order_output)
10589  {
10590  Array<int> local_connectivity;
10591  for (int iel = 0; iel < ne; iel++)
10592  {
10593  Geometry::Type geom = get_geom(iel);
10594  CreateVTKElementConnectivity(local_connectivity, geom, ref);
10595  int nnodes = local_connectivity.Size();
10596  for (int i=0; i<nnodes; ++i)
10597  {
10598  WriteBinaryOrASCII(os, buf, np+local_connectivity[i], " ",
10599  format);
10600  }
10601  if (format == VTKFormat::ASCII) { os << '\n'; }
10602  np += nnodes;
10603  offset.push_back(np);
10604  }
10605  }
10606  else
10607  {
10608  int coff = 0;
10609  for (int i = 0; i < ne; i++)
10610  {
10611  Geometry::Type geom = get_geom(i);
10612  int nv = Geometries.GetVertices(geom)->GetNPoints();
10613  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10614  Array<int> &RG = RefG->RefGeoms;
10615  for (int j = 0; j < RG.Size(); )
10616  {
10617  coff = coff+nv;
10618  offset.push_back(coff);
10619  const int *p = VTKGeometry::VertexPermutation[geom];
10620  for (int k = 0; k < nv; k++, j++)
10621  {
10622  WriteBinaryOrASCII(os, buf, np + RG[p ? p[j] : j], " ",
10623  format);
10624  }
10625  if (format == VTKFormat::ASCII) { os << '\n'; }
10626  }
10627  np += RefG->RefPts.GetNPoints();
10628  }
10629  }
10630  if (format != VTKFormat::ASCII)
10631  {
10632  WriteBase64WithSizeAndClear(os, buf, compression_level);
10633  }
10634  os << "</DataArray>" << std::endl;
10635 
10636  os << "<DataArray type=\"Int32\" Name=\"offsets\" format=\""
10637  << fmt_str << "\">" << std::endl;
10638  // offsets
10639  for (size_t ii=0; ii<offset.size(); ii++)
10640  {
10641  WriteBinaryOrASCII(os, buf, offset[ii], "\n", format);
10642  }
10643  if (format != VTKFormat::ASCII)
10644  {
10645  WriteBase64WithSizeAndClear(os, buf, compression_level);
10646  }
10647  os << "</DataArray>" << std::endl;
10648  os << "<DataArray type=\"UInt8\" Name=\"types\" format=\""
10649  << fmt_str << "\">" << std::endl;
10650  // cell types
10651  const int *vtk_geom_map =
10652  high_order_output ? VTKGeometry::HighOrderMap : VTKGeometry::Map;
10653  for (int i = 0; i < ne; i++)
10654  {
10655  Geometry::Type geom = get_geom(i);
10656  uint8_t vtk_cell_type = 5;
10657 
10658  vtk_cell_type = vtk_geom_map[geom];
10659 
10660  if (high_order_output)
10661  {
10662  WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
10663  }
10664  else
10665  {
10666  int nv = Geometries.GetVertices(geom)->GetNPoints();
10667  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10668  Array<int> &RG = RefG->RefGeoms;
10669  for (int j = 0; j < RG.Size(); j += nv)
10670  {
10671  WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
10672  }
10673  }
10674  }
10675  if (format != VTKFormat::ASCII)
10676  {
10677  WriteBase64WithSizeAndClear(os, buf, compression_level);
10678  }
10679  os << "</DataArray>" << std::endl;
10680  os << "</Cells>" << std::endl;
10681 
10682  os << "<CellData Scalars=\"attribute\">" << std::endl;
10683  os << "<DataArray type=\"Int32\" Name=\"attribute\" format=\""
10684  << fmt_str << "\">" << std::endl;
10685  for (int i = 0; i < ne; i++)
10686  {
10687  int attr = bdr_elements ? GetBdrAttribute(i) : GetAttribute(i);
10688  if (high_order_output)
10689  {
10690  WriteBinaryOrASCII(os, buf, attr, "\n", format);
10691  }
10692  else
10693  {
10694  Geometry::Type geom = get_geom(i);
10695  int nv = Geometries.GetVertices(geom)->GetNPoints();
10696  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10697  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10698  {
10699  WriteBinaryOrASCII(os, buf, attr, "\n", format);
10700  }
10701  }
10702  }
10703  if (format != VTKFormat::ASCII)
10704  {
10705  WriteBase64WithSizeAndClear(os, buf, compression_level);
10706  }
10707  os << "</DataArray>" << std::endl;
10708  os << "</CellData>" << std::endl;
10709 }
10710 
10711 
10712 void Mesh::PrintVTK(std::ostream &os, int ref, int field_data)
10713 {
10714  int np, nc, size;
10715  RefinedGeometry *RefG;
10716  DenseMatrix pmat;
10717 
10718  os <<
10719  "# vtk DataFile Version 3.0\n"
10720  "Generated by MFEM\n"
10721  "ASCII\n"
10722  "DATASET UNSTRUCTURED_GRID\n";
10723 
10724  // additional dataset information
10725  if (field_data)
10726  {
10727  os << "FIELD FieldData 1\n"
10728  << "MaterialIds " << 1 << " " << attributes.Size() << " int\n";
10729  for (int i = 0; i < attributes.Size(); i++)
10730  {
10731  os << ' ' << attributes[i];
10732  }
10733  os << '\n';
10734  }
10735 
10736  // count the points, cells, size
10737  np = nc = size = 0;
10738  for (int i = 0; i < GetNE(); i++)
10739  {
10741  int nv = Geometries.GetVertices(geom)->GetNPoints();
10742  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10743  np += RefG->RefPts.GetNPoints();
10744  nc += RefG->RefGeoms.Size() / nv;
10745  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
10746  }
10747  os << "POINTS " << np << " double\n";
10748  // write the points
10749  for (int i = 0; i < GetNE(); i++)
10750  {
10751  RefG = GlobGeometryRefiner.Refine(
10752  GetElementBaseGeometry(i), ref, 1);
10753 
10754  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
10755 
10756  for (int j = 0; j < pmat.Width(); j++)
10757  {
10758  os << pmat(0, j) << ' ';
10759  if (pmat.Height() > 1)
10760  {
10761  os << pmat(1, j) << ' ';
10762  if (pmat.Height() > 2)
10763  {
10764  os << pmat(2, j);
10765  }
10766  else
10767  {
10768  os << 0.0;
10769  }
10770  }
10771  else
10772  {
10773  os << 0.0 << ' ' << 0.0;
10774  }
10775  os << '\n';
10776  }
10777  }
10778 
10779  // write the cells
10780  os << "CELLS " << nc << ' ' << size << '\n';
10781  np = 0;
10782  for (int i = 0; i < GetNE(); i++)
10783  {
10785  int nv = Geometries.GetVertices(geom)->GetNPoints();
10786  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10787  Array<int> &RG = RefG->RefGeoms;
10788 
10789  for (int j = 0; j < RG.Size(); )
10790  {
10791  os << nv;
10792  for (int k = 0; k < nv; k++, j++)
10793  {
10794  os << ' ' << np + RG[j];
10795  }
10796  os << '\n';
10797  }
10798  np += RefG->RefPts.GetNPoints();
10799  }
10800  os << "CELL_TYPES " << nc << '\n';
10801  for (int i = 0; i < GetNE(); i++)
10802  {
10804  int nv = Geometries.GetVertices(geom)->GetNPoints();
10805  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10806  Array<int> &RG = RefG->RefGeoms;
10807  int vtk_cell_type = VTKGeometry::Map[geom];
10808 
10809  for (int j = 0; j < RG.Size(); j += nv)
10810  {
10811  os << vtk_cell_type << '\n';
10812  }
10813  }
10814  // write attributes (materials)
10815  os << "CELL_DATA " << nc << '\n'
10816  << "SCALARS material int\n"
10817  << "LOOKUP_TABLE default\n";
10818  for (int i = 0; i < GetNE(); i++)
10819  {
10821  int nv = Geometries.GetVertices(geom)->GetNPoints();
10822  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10823  int attr = GetAttribute(i);
10824  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10825  {
10826  os << attr << '\n';
10827  }
10828  }
10829 
10830  if (Dim > 1)
10831  {
10832  Array<int> coloring;
10833  srand((unsigned)time(0));
10834  double a = double(rand()) / (double(RAND_MAX) + 1.);
10835  int el0 = (int)floor(a * GetNE());
10836  GetElementColoring(coloring, el0);
10837  os << "SCALARS element_coloring int\n"
10838  << "LOOKUP_TABLE default\n";
10839  for (int i = 0; i < GetNE(); i++)
10840  {
10842  int nv = Geometries.GetVertices(geom)->GetNPoints();
10843  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10844  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10845  {
10846  os << coloring[i] + 1 << '\n';
10847  }
10848  }
10849  }
10850 
10851  // prepare to write data
10852  os << "POINT_DATA " << np << '\n' << flush;
10853 }
10854 
10855 void Mesh::GetElementColoring(Array<int> &colors, int el0)
10856 {
10857  int delete_el_to_el = (el_to_el) ? (0) : (1);
10858  const Table &el_el = ElementToElementTable();
10859  int num_el = GetNE(), stack_p, stack_top_p, max_num_col;
10860  Array<int> el_stack(num_el);
10861 
10862  const int *i_el_el = el_el.GetI();
10863  const int *j_el_el = el_el.GetJ();
10864 
10865  colors.SetSize(num_el);
10866  colors = -2;
10867  max_num_col = 1;
10868  stack_p = stack_top_p = 0;
10869  for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el)
10870  {
10871  if (colors[el] != -2)
10872  {
10873  continue;
10874  }
10875 
10876  colors[el] = -1;
10877  el_stack[stack_top_p++] = el;
10878 
10879  for ( ; stack_p < stack_top_p; stack_p++)
10880  {
10881  int i = el_stack[stack_p];
10882  int num_nb = i_el_el[i+1] - i_el_el[i];
10883  if (max_num_col < num_nb + 1)
10884  {
10885  max_num_col = num_nb + 1;
10886  }
10887  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
10888  {
10889  int k = j_el_el[j];
10890  if (colors[k] == -2)
10891  {
10892  colors[k] = -1;
10893  el_stack[stack_top_p++] = k;
10894  }
10895  }
10896  }
10897  }
10898 
10899  Array<int> col_marker(max_num_col);
10900 
10901  for (stack_p = 0; stack_p < stack_top_p; stack_p++)
10902  {
10903  int i = el_stack[stack_p], col;
10904  col_marker = 0;
10905  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
10906  {
10907  col = colors[j_el_el[j]];
10908  if (col != -1)
10909  {
10910  col_marker[col] = 1;
10911  }
10912  }
10913 
10914  for (col = 0; col < max_num_col; col++)
10915  if (col_marker[col] == 0)
10916  {
10917  break;
10918  }
10919 
10920  colors[i] = col;
10921  }
10922 
10923  if (delete_el_to_el)
10924  {
10925  delete el_to_el;
10926  el_to_el = NULL;
10927  }
10928 }
10929 
10930 void Mesh::PrintWithPartitioning(int *partitioning, std::ostream &os,
10931  int elem_attr) const
10932 {
10933  if (Dim != 3 && Dim != 2) { return; }
10934 
10935  int i, j, k, l, nv, nbe, *v;
10936 
10937  os << "MFEM mesh v1.0\n";
10938 
10939  // optional
10940  os <<
10941  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10942  "# POINT = 0\n"
10943  "# SEGMENT = 1\n"
10944  "# TRIANGLE = 2\n"
10945  "# SQUARE = 3\n"
10946  "# TETRAHEDRON = 4\n"
10947  "# CUBE = 5\n"
10948  "# PRISM = 6\n"
10949  "#\n";
10950 
10951  os << "\ndimension\n" << Dim
10952  << "\n\nelements\n" << NumOfElements << '\n';
10953  for (i = 0; i < NumOfElements; i++)
10954  {
10955  os << int((elem_attr) ? partitioning[i]+1 : elements[i]->GetAttribute())
10956  << ' ' << elements[i]->GetGeometryType();
10957  nv = elements[i]->GetNVertices();
10958  v = elements[i]->GetVertices();
10959  for (j = 0; j < nv; j++)
10960  {
10961  os << ' ' << v[j];
10962  }
10963  os << '\n';
10964  }
10965  nbe = 0;
10966  for (i = 0; i < faces_info.Size(); i++)
10967  {
10968  if ((l = faces_info[i].Elem2No) >= 0)
10969  {
10970  k = partitioning[faces_info[i].Elem1No];
10971  l = partitioning[l];
10972  if (k != l)
10973  {
10974  nbe++;
10975  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
10976  {
10977  nbe++;
10978  }
10979  }
10980  }
10981  else
10982  {
10983  nbe++;
10984  }
10985  }
10986  os << "\nboundary\n" << nbe << '\n';
10987  for (i = 0; i < faces_info.Size(); i++)
10988  {
10989  if ((l = faces_info[i].Elem2No) >= 0)
10990  {
10991  k = partitioning[faces_info[i].Elem1No];
10992  l = partitioning[l];
10993  if (k != l)
10994  {
10995  nv = faces[i]->GetNVertices();
10996  v = faces[i]->GetVertices();
10997  os << k+1 << ' ' << faces[i]->GetGeometryType();
10998  for (j = 0; j < nv; j++)
10999  {
11000  os << ' ' << v[j];
11001  }
11002  os << '\n';
11003  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
11004  {
11005  os << l+1 << ' ' << faces[i]->GetGeometryType();
11006  for (j = nv-1; j >= 0; j--)
11007  {
11008  os << ' ' << v[j];
11009  }
11010  os << '\n';
11011  }
11012  }
11013  }
11014  else
11015  {
11016  k = partitioning[faces_info[i].Elem1No];
11017  nv = faces[i]->GetNVertices();
11018  v = faces[i]->GetVertices();
11019  os << k+1 << ' ' << faces[i]->GetGeometryType();
11020  for (j = 0; j < nv; j++)
11021  {
11022  os << ' ' << v[j];
11023  }
11024  os << '\n';
11025  }
11026  }
11027  os << "\nvertices\n" << NumOfVertices << '\n';
11028  if (Nodes == NULL)
11029  {
11030  os << spaceDim << '\n';
11031  for (i = 0; i < NumOfVertices; i++)
11032  {
11033  os << vertices[i](0);
11034  for (j = 1; j < spaceDim; j++)
11035  {
11036  os << ' ' << vertices[i](j);
11037  }
11038  os << '\n';
11039  }
11040  os.flush();
11041  }
11042  else
11043  {
11044  os << "\nnodes\n";
11045  Nodes->Save(os);
11046  }
11047 }
11048 
11050  std::ostream &os,
11051  int interior_faces)
11052 {
11053  MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported\n");
11054  if (Dim != 3 && Dim != 2) { return; }
11055 
11056  int *vcount = new int[NumOfVertices];
11057  for (int i = 0; i < NumOfVertices; i++)
11058  {
11059  vcount[i] = 0;
11060  }
11061  for (int i = 0; i < NumOfElements; i++)
11062  {
11063  int nv = elements[i]->GetNVertices();
11064  const int *ind = elements[i]->GetVertices();
11065  for (int j = 0; j < nv; j++)
11066  {
11067  vcount[ind[j]]++;
11068  }
11069  }
11070 
11071  int *voff = new int[NumOfVertices+1];
11072  voff[0] = 0;
11073  for (int i = 1; i <= NumOfVertices; i++)
11074  {
11075  voff[i] = vcount[i-1] + voff[i-1];
11076  }
11077 
11078  int **vown = new int*[NumOfVertices];
11079  for (int i = 0; i < NumOfVertices; i++)
11080  {
11081  vown[i] = new int[vcount[i]];
11082  }
11083 
11084  // 2D
11085  if (Dim == 2)
11086  {
11087  Table edge_el;
11088  Transpose(ElementToEdgeTable(), edge_el);
11089 
11090  // Fake printing of the elements.
11091  for (int i = 0; i < NumOfElements; i++)
11092  {
11093  int nv = elements[i]->GetNVertices();
11094  const int *ind = elements[i]->GetVertices();
11095  for (int j = 0; j < nv; j++)
11096  {
11097  vcount[ind[j]]--;
11098  vown[ind[j]][vcount[ind[j]]] = i;
11099  }
11100  }
11101 
11102  for (int i = 0; i < NumOfVertices; i++)
11103  {
11104  vcount[i] = voff[i+1] - voff[i];
11105  }
11106 
11107  int nbe = 0;
11108  for (int i = 0; i < edge_el.Size(); i++)
11109  {
11110  const int *el = edge_el.GetRow(i);
11111  if (edge_el.RowSize(i) > 1)
11112  {
11113  int k = partitioning[el[0]];
11114  int l = partitioning[el[1]];
11115  if (interior_faces || k != l)
11116  {
11117  nbe += 2;
11118  }
11119  }
11120  else
11121  {
11122  nbe++;
11123  }
11124  }
11125 
11126  // Print the type of the mesh and the boundary elements.
11127  os << "areamesh2\n\n" << nbe << '\n';
11128 
11129  for (int i = 0; i < edge_el.Size(); i++)
11130  {
11131  const int *el = edge_el.GetRow(i);
11132  if (edge_el.RowSize(i) > 1)
11133  {
11134  int k = partitioning[el[0]];
11135  int l = partitioning[el[1]];
11136  if (interior_faces || k != l)
11137  {
11138  Array<int> ev;
11139  GetEdgeVertices(i,ev);
11140  os << k+1; // attribute
11141  for (int j = 0; j < 2; j++)
11142  for (int s = 0; s < vcount[ev[j]]; s++)
11143  if (vown[ev[j]][s] == el[0])
11144  {
11145  os << ' ' << voff[ev[j]]+s+1;
11146  }
11147  os << '\n';
11148  os << l+1; // attribute
11149  for (int j = 1; j >= 0; j--)
11150  for (int s = 0; s < vcount[ev[j]]; s++)
11151  if (vown[ev[j]][s] == el[1])
11152  {
11153  os << ' ' << voff[ev[j]]+s+1;
11154  }
11155  os << '\n';
11156  }
11157  }
11158  else
11159  {
11160  int k = partitioning[el[0]];
11161  Array<int> ev;
11162  GetEdgeVertices(i,ev);
11163  os << k+1; // attribute
11164  for (int j = 0; j < 2; j++)
11165  for (int s = 0; s < vcount[ev[j]]; s++)
11166  if (vown[ev[j]][s] == el[0])
11167  {
11168  os << ' ' << voff[ev[j]]+s+1;
11169  }
11170  os << '\n';
11171  }
11172  }
11173 
11174  // Print the elements.
11175  os << NumOfElements << '\n';
11176  for (int i = 0; i < NumOfElements; i++)
11177  {
11178  int nv = elements[i]->GetNVertices();
11179  const int *ind = elements[i]->GetVertices();
11180  os << partitioning[i]+1 << ' '; // use subdomain number as attribute
11181  os << nv << ' ';
11182  for (int j = 0; j < nv; j++)
11183  {
11184  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11185  vown[ind[j]][vcount[ind[j]]] = i;
11186  }
11187  os << '\n';
11188  }
11189 
11190  for (int i = 0; i < NumOfVertices; i++)
11191  {
11192  vcount[i] = voff[i+1] - voff[i];
11193  }
11194 
11195  // Print the vertices.
11196  os << voff[NumOfVertices] << '\n';
11197  for (int i = 0; i < NumOfVertices; i++)
11198  for (int k = 0; k < vcount[i]; k++)
11199  {
11200  for (int j = 0; j < Dim; j++)
11201  {
11202  os << vertices[i](j) << ' ';
11203  }
11204  os << '\n';
11205  }
11206  }
11207  // Dim is 3
11208  else if (meshgen == 1)
11209  {
11210  os << "NETGEN_Neutral_Format\n";
11211  // print the vertices
11212  os << voff[NumOfVertices] << '\n';
11213  for (int i = 0; i < NumOfVertices; i++)
11214  for (int k = 0; k < vcount[i]; k++)
11215  {
11216  for (int j = 0; j < Dim; j++)
11217  {
11218  os << ' ' << vertices[i](j);
11219  }
11220  os << '\n';
11221  }
11222 
11223  // print the elements
11224  os << NumOfElements << '\n';
11225  for (int i = 0; i < NumOfElements; i++)
11226  {
11227  int nv = elements[i]->GetNVertices();
11228  const int *ind = elements[i]->GetVertices();
11229  os << partitioning[i]+1; // use subdomain number as attribute
11230  for (int j = 0; j < nv; j++)
11231  {
11232  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11233  vown[ind[j]][vcount[ind[j]]] = i;
11234  }
11235  os << '\n';
11236  }
11237 
11238  for (int i = 0; i < NumOfVertices; i++)
11239  {
11240  vcount[i] = voff[i+1] - voff[i];
11241  }
11242 
11243  // print the boundary information.
11244  int nbe = 0;
11245  for (int i = 0; i < NumOfFaces; i++)
11246  {
11247  int l = faces_info[i].Elem2No;
11248  if (l >= 0)
11249  {
11250  int k = partitioning[faces_info[i].Elem1No];
11251  l = partitioning[l];
11252  if (interior_faces || k != l)
11253  {
11254  nbe += 2;
11255  }
11256  }
11257  else
11258  {
11259  nbe++;
11260  }
11261  }
11262 
11263  os << nbe << '\n';
11264  for (int i = 0; i < NumOfFaces; i++)
11265  {
11266  int l = faces_info[i].Elem2No;
11267  if (l >= 0)
11268  {
11269  int k = partitioning[faces_info[i].Elem1No];
11270  l = partitioning[l];
11271  if (interior_faces || k != l)
11272  {
11273  int nv = faces[i]->GetNVertices();
11274  const int *ind = faces[i]->GetVertices();
11275  os << k+1; // attribute
11276  for (int j = 0; j < nv; j++)
11277  for (int s = 0; s < vcount[ind[j]]; s++)
11278  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11279  {
11280  os << ' ' << voff[ind[j]]+s+1;
11281  }
11282  os << '\n';
11283  os << l+1; // attribute
11284  for (int j = nv-1; j >= 0; j--)
11285  for (int s = 0; s < vcount[ind[j]]; s++)
11286  if (vown[ind[j]][s] == faces_info[i].Elem2No)
11287  {
11288  os << ' ' << voff[ind[j]]+s+1;
11289  }
11290  os << '\n';
11291  }
11292  }
11293  else
11294  {
11295  int k = partitioning[faces_info[i].Elem1No];
11296  int nv = faces[i]->GetNVertices();
11297  const int *ind = faces[i]->GetVertices();
11298  os << k+1; // attribute
11299  for (int j = 0; j < nv; j++)
11300  for (int s = 0; s < vcount[ind[j]]; s++)
11301  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11302  {
11303  os << ' ' << voff[ind[j]]+s+1;
11304  }
11305  os << '\n';
11306  }
11307  }
11308  }
11309  // Dim is 3
11310  else if (meshgen == 2) // TrueGrid
11311  {
11312  // count the number of the boundary elements.
11313  int nbe = 0;
11314  for (int i = 0; i < NumOfFaces; i++)
11315  {
11316  int l = faces_info[i].Elem2No;
11317  if (l >= 0)
11318  {
11319  int k = partitioning[faces_info[i].Elem1No];
11320  l = partitioning[l];
11321  if (interior_faces || k != l)
11322  {
11323  nbe += 2;
11324  }
11325  }
11326  else
11327  {
11328  nbe++;
11329  }
11330  }
11331 
11332  os << "TrueGrid\n"
11333  << "1 " << voff[NumOfVertices] << " " << NumOfElements
11334  << " 0 0 0 0 0 0 0\n"
11335  << "0 0 0 1 0 0 0 0 0 0 0\n"
11336  << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
11337  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
11338  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
11339 
11340  for (int i = 0; i < NumOfVertices; i++)
11341  for (int k = 0; k < vcount[i]; k++)
11342  os << voff[i]+k << " 0.0 " << vertices[i](0) << ' '
11343  << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n";
11344 
11345  for (int i = 0; i < NumOfElements; i++)
11346  {
11347  int nv = elements[i]->GetNVertices();
11348  const int *ind = elements[i]->GetVertices();
11349  os << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute
11350  for (int j = 0; j < nv; j++)
11351  {
11352  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11353  vown[ind[j]][vcount[ind[j]]] = i;
11354  }
11355  os << '\n';
11356  }
11357 
11358  for (int i = 0; i < NumOfVertices; i++)
11359  {
11360  vcount[i] = voff[i+1] - voff[i];
11361  }
11362 
11363  // boundary elements
11364  for (int i = 0; i < NumOfFaces; i++)
11365  {
11366  int l = faces_info[i].Elem2No;
11367  if (l >= 0)
11368  {
11369  int k = partitioning[faces_info[i].Elem1No];
11370  l = partitioning[l];
11371  if (interior_faces || k != l)
11372  {
11373  int nv = faces[i]->GetNVertices();
11374  const int *ind = faces[i]->GetVertices();
11375  os << k+1; // attribute
11376  for (int j = 0; j < nv; j++)
11377  for (int s = 0; s < vcount[ind[j]]; s++)
11378  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11379  {
11380  os << ' ' << voff[ind[j]]+s+1;
11381  }
11382  os << " 1.0 1.0 1.0 1.0\n";
11383  os << l+1; // attribute
11384  for (int j = nv-1; j >= 0; j--)
11385  for (int s = 0; s < vcount[ind[j]]; s++)
11386  if (vown[ind[j]][s] == faces_info[i].Elem2No)
11387  {
11388  os << ' ' << voff[ind[j]]+s+1;
11389  }
11390  os << " 1.0 1.0 1.0 1.0\n";
11391  }
11392  }
11393  else
11394  {
11395  int k = partitioning[faces_info[i].Elem1No];
11396  int nv = faces[i]->GetNVertices();
11397  const int *ind = faces[i]->GetVertices();
11398  os << k+1; // attribute
11399  for (int j = 0; j < nv; j++)
11400  for (int s = 0; s < vcount[ind[j]]; s++)
11401  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11402  {
11403  os << ' ' << voff[ind[j]]+s+1;
11404  }
11405  os << " 1.0 1.0 1.0 1.0\n";
11406  }
11407  }
11408  }
11409 
11410  os << flush;
11411 
11412  for (int i = 0; i < NumOfVertices; i++)
11413  {
11414  delete [] vown[i];
11415  }
11416 
11417  delete [] vcount;
11418  delete [] voff;
11419  delete [] vown;
11420 }
11421 
11422 void Mesh::PrintSurfaces(const Table & Aface_face, std::ostream &os) const
11423 {
11424  int i, j;
11425 
11426  if (NURBSext)
11427  {
11428  mfem_error("Mesh::PrintSurfaces"
11429  " NURBS mesh is not supported!");
11430  return;
11431  }
11432 
11433  os << "MFEM mesh v1.0\n";
11434 
11435  // optional
11436  os <<
11437  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
11438  "# POINT = 0\n"
11439  "# SEGMENT = 1\n"
11440  "# TRIANGLE = 2\n"
11441  "# SQUARE = 3\n"
11442  "# TETRAHEDRON = 4\n"
11443  "# CUBE = 5\n"
11444  "# PRISM = 6\n"
11445  "#\n";
11446 
11447  os << "\ndimension\n" << Dim
11448  << "\n\nelements\n" << NumOfElements << '\n';
11449  for (i = 0; i < NumOfElements; i++)
11450  {
11451  PrintElement(elements[i], os);
11452  }
11453 
11454  os << "\nboundary\n" << Aface_face.Size_of_connections() << '\n';
11455  const int * const i_AF_f = Aface_face.GetI();
11456  const int * const j_AF_f = Aface_face.GetJ();
11457 
11458  for (int iAF=0; iAF < Aface_face.Size(); ++iAF)
11459  for (const int * iface = j_AF_f + i_AF_f[iAF];
11460  iface < j_AF_f + i_AF_f[iAF+1];
11461  ++iface)
11462  {
11463  os << iAF+1 << ' ';
11464  PrintElementWithoutAttr(faces[*iface],os);
11465  }
11466 
11467  os << "\nvertices\n" << NumOfVertices << '\n';
11468  if (Nodes == NULL)
11469  {
11470  os << spaceDim << '\n';
11471  for (i = 0; i < NumOfVertices; i++)
11472  {
11473  os << vertices[i](0);
11474  for (j = 1; j < spaceDim; j++)
11475  {
11476  os << ' ' << vertices[i](j);
11477  }
11478  os << '\n';
11479  }
11480  os.flush();
11481  }
11482  else
11483  {
11484  os << "\nnodes\n";
11485  Nodes->Save(os);
11486  }
11487 }
11488 
11489 void Mesh::ScaleSubdomains(double sf)
11490 {
11491  int i,j,k;
11492  Array<int> vert;
11493  DenseMatrix pointmat;
11494  int na = attributes.Size();
11495  double *cg = new double[na*spaceDim];
11496  int *nbea = new int[na];
11497 
11498  int *vn = new int[NumOfVertices];
11499  for (i = 0; i < NumOfVertices; i++)
11500  {
11501  vn[i] = 0;
11502  }
11503  for (i = 0; i < na; i++)
11504  {
11505  for (j = 0; j < spaceDim; j++)
11506  {
11507  cg[i*spaceDim+j] = 0.0;
11508  }
11509  nbea[i] = 0;
11510  }
11511 
11512  for (i = 0; i < NumOfElements; i++)
11513  {
11514  GetElementVertices(i, vert);
11515  for (k = 0; k < vert.Size(); k++)
11516  {
11517  vn[vert[k]] = 1;
11518  }
11519  }
11520 
11521  for (i = 0; i < NumOfElements; i++)
11522  {
11523  int bea = GetAttribute(i)-1;
11524  GetPointMatrix(i, pointmat);
11525  GetElementVertices(i, vert);
11526 
11527  for (k = 0; k < vert.Size(); k++)
11528  if (vn[vert[k]] == 1)
11529  {
11530  nbea[bea]++;
11531  for (j = 0; j < spaceDim; j++)
11532  {
11533  cg[bea*spaceDim+j] += pointmat(j,k);
11534  }
11535  vn[vert[k]] = 2;
11536  }
11537  }
11538 
11539  for (i = 0; i < NumOfElements; i++)
11540  {
11541  int bea = GetAttribute(i)-1;
11542  GetElementVertices (i, vert);
11543 
11544  for (k = 0; k < vert.Size(); k++)
11545  if (vn[vert[k]])
11546  {
11547  for (j = 0; j < spaceDim; j++)
11548  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
11549  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
11550  vn[vert[k]] = 0;
11551  }
11552  }
11553 
11554  delete [] cg;
11555  delete [] nbea;
11556  delete [] vn;
11557 }
11558 
11559 void Mesh::ScaleElements(double sf)
11560 {
11561  int i,j,k;
11562  Array<int> vert;
11563  DenseMatrix pointmat;
11564  int na = NumOfElements;
11565  double *cg = new double[na*spaceDim];
11566  int *nbea = new int[na];
11567 
11568  int *vn = new int[NumOfVertices];
11569  for (i = 0; i < NumOfVertices; i++)
11570  {
11571  vn[i] = 0;
11572  }
11573  for (i = 0; i < na; i++)
11574  {
11575  for (j = 0; j < spaceDim; j++)
11576  {
11577  cg[i*spaceDim+j] = 0.0;
11578  }
11579  nbea[i] = 0;
11580  }
11581 
11582  for (i = 0; i < NumOfElements; i++)
11583  {
11584  GetElementVertices(i, vert);
11585  for (k = 0; k < vert.Size(); k++)
11586  {
11587  vn[vert[k]] = 1;
11588  }
11589  }
11590 
11591  for (i = 0; i < NumOfElements; i++)
11592  {
11593  int bea = i;
11594  GetPointMatrix(i, pointmat);
11595  GetElementVertices(i, vert);
11596 
11597  for (k = 0; k < vert.Size(); k++)
11598  if (vn[vert[k]] == 1)
11599  {
11600  nbea[bea]++;
11601  for (j = 0; j < spaceDim; j++)
11602  {
11603  cg[bea*spaceDim+j] += pointmat(j,k);
11604  }
11605  vn[vert[k]] = 2;
11606  }
11607  }
11608 
11609  for (i = 0; i < NumOfElements; i++)
11610  {
11611  int bea = i;
11612  GetElementVertices(i, vert);
11613 
11614  for (k = 0; k < vert.Size(); k++)
11615  if (vn[vert[k]])
11616  {
11617  for (j = 0; j < spaceDim; j++)
11618  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
11619  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
11620  vn[vert[k]] = 0;
11621  }
11622  }
11623 
11624  delete [] cg;
11625  delete [] nbea;
11626  delete [] vn;
11627 }
11628 
11629 void Mesh::Transform(void (*f)(const Vector&, Vector&))
11630 {
11631  // TODO: support for different new spaceDim.
11632  if (Nodes == NULL)
11633  {
11634  Vector vold(spaceDim), vnew(NULL, spaceDim);
11635  for (int i = 0; i < vertices.Size(); i++)
11636  {
11637  for (int j = 0; j < spaceDim; j++)
11638  {
11639  vold(j) = vertices[i](j);
11640  }
11641  vnew.SetData(vertices[i]());
11642  (*f)(vold, vnew);
11643  }
11644  }
11645  else
11646  {
11647  GridFunction xnew(Nodes->FESpace());
11649  xnew.ProjectCoefficient(f_pert);
11650  *Nodes = xnew;
11651  }
11652 }
11653 
11655 {
11656  MFEM_VERIFY(spaceDim == deformation.GetVDim(),
11657  "incompatible vector dimensions");
11658  if (Nodes == NULL)
11659  {
11660  LinearFECollection fec;
11661  FiniteElementSpace fes(this, &fec, spaceDim, Ordering::byVDIM);
11662  GridFunction xnew(&fes);
11663  xnew.ProjectCoefficient(deformation);
11664  for (int i = 0; i < NumOfVertices; i++)
11665  for (int d = 0; d < spaceDim; d++)
11666  {
11667  vertices[i](d) = xnew(d + spaceDim*i);
11668  }
11669  }
11670  else
11671  {
11672  GridFunction xnew(Nodes->FESpace());
11673  xnew.ProjectCoefficient(deformation);
11674  *Nodes = xnew;
11675  }
11676 }
11677 
11679 {
11680  if (NURBSext || ncmesh) { return; }
11681 
11682  Array<int> v2v(GetNV());
11683  v2v = -1;
11684  for (int i = 0; i < GetNE(); i++)
11685  {
11686  Element *el = GetElement(i);
11687  int nv = el->GetNVertices();
11688  int *v = el->GetVertices();
11689  for (int j = 0; j < nv; j++)
11690  {
11691  v2v[v[j]] = 0;
11692  }
11693  }
11694  for (int i = 0; i < GetNBE(); i++)
11695  {
11696  Element *el = GetBdrElement(i);
11697  int *v = el->GetVertices();
11698  int nv = el->GetNVertices();
11699  for (int j = 0; j < nv; j++)
11700  {
11701  v2v[v[j]] = 0;
11702  }
11703  }
11704  int num_vert = 0;
11705  for (int i = 0; i < v2v.Size(); i++)
11706  {
11707  if (v2v[i] == 0)
11708  {
11709  vertices[num_vert] = vertices[i];
11710  v2v[i] = num_vert++;
11711  }
11712  }
11713 
11714  if (num_vert == v2v.Size()) { return; }
11715 
11716  Vector nodes_by_element;
11717  Array<int> vdofs;
11718  if (Nodes)
11719  {
11720  int s = 0;
11721  for (int i = 0; i < GetNE(); i++)
11722  {
11723  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11724  s += vdofs.Size();
11725  }
11726  nodes_by_element.SetSize(s);
11727  s = 0;
11728  for (int i = 0; i < GetNE(); i++)
11729  {
11730  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11731  Nodes->GetSubVector(vdofs, &nodes_by_element(s));
11732  s += vdofs.Size();
11733  }
11734  }
11735  vertices.SetSize(num_vert);
11736  NumOfVertices = num_vert;
11737  for (int i = 0; i < GetNE(); i++)
11738  {
11739  Element *el = GetElement(i);
11740  int *v = el->GetVertices();
11741  int nv = el->GetNVertices();
11742  for (int j = 0; j < nv; j++)
11743  {
11744  v[j] = v2v[v[j]];
11745  }
11746  }
11747  for (int i = 0; i < GetNBE(); i++)
11748  {
11749  Element *el = GetBdrElement(i);
11750  int *v = el->GetVertices();
11751  int nv = el->GetNVertices();
11752  for (int j = 0; j < nv; j++)
11753  {
11754  v[j] = v2v[v[j]];
11755  }
11756  }
11757  DeleteTables();
11758  if (Dim > 1)
11759  {
11760  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
11761  el_to_edge = new Table;
11763  }
11764  if (Dim > 2)
11765  {
11766  // generate el_to_face, be_to_face
11768  }
11769  // Update faces and faces_info
11770  GenerateFaces();
11771  if (Nodes)
11772  {
11773  Nodes->FESpace()->Update();
11774  Nodes->Update();
11775  int s = 0;
11776  for (int i = 0; i < GetNE(); i++)
11777  {
11778  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11779  Nodes->SetSubVector(vdofs, &nodes_by_element(s));
11780  s += vdofs.Size();
11781  }
11782  }
11783 }
11784 
11786 {
11787  if (NURBSext || ncmesh) { return; }
11788 
11789  int num_bdr_elem = 0;
11790  int new_bel_to_edge_nnz = 0;
11791  for (int i = 0; i < GetNBE(); i++)
11792  {
11794  {
11795  FreeElement(boundary[i]);
11796  }
11797  else
11798  {
11799  num_bdr_elem++;
11800  if (Dim == 3)
11801  {
11802  new_bel_to_edge_nnz += bel_to_edge->RowSize(i);
11803  }
11804  }
11805  }
11806 
11807  if (num_bdr_elem == GetNBE()) { return; }
11808 
11809  Array<Element *> new_boundary(num_bdr_elem);
11810  Array<int> new_be_to_edge, new_be_to_face;
11811  Table *new_bel_to_edge = NULL;
11812  new_boundary.SetSize(0);
11813  if (Dim == 2)
11814  {
11815  new_be_to_edge.Reserve(num_bdr_elem);
11816  }
11817  else if (Dim == 3)
11818  {
11819  new_be_to_face.Reserve(num_bdr_elem);
11820  new_bel_to_edge = new Table;
11821  new_bel_to_edge->SetDims(num_bdr_elem, new_bel_to_edge_nnz);
11822  }
11823  for (int i = 0; i < GetNBE(); i++)
11824  {
11826  {
11827  new_boundary.Append(boundary[i]);
11828  if (Dim == 2)
11829  {
11830  new_be_to_edge.Append(be_to_edge[i]);
11831  }
11832  else if (Dim == 3)
11833  {
11834  int row = new_be_to_face.Size();
11835  new_be_to_face.Append(be_to_face[i]);
11836  int *e = bel_to_edge->GetRow(i);
11837  int ne = bel_to_edge->RowSize(i);
11838  int *new_e = new_bel_to_edge->GetRow(row);
11839  for (int j = 0; j < ne; j++)
11840  {
11841  new_e[j] = e[j];
11842  }
11843  new_bel_to_edge->GetI()[row+1] = new_bel_to_edge->GetI()[row] + ne;
11844  }
11845  }
11846  }
11847 
11848  NumOfBdrElements = new_boundary.Size();
11849  mfem::Swap(boundary, new_boundary);
11850 
11851  if (Dim == 2)
11852  {
11853  mfem::Swap(be_to_edge, new_be_to_edge);
11854  }
11855  else if (Dim == 3)
11856  {
11857  mfem::Swap(be_to_face, new_be_to_face);
11858  delete bel_to_edge;
11859  bel_to_edge = new_bel_to_edge;
11860  }
11861 
11862  Array<int> attribs(num_bdr_elem);
11863  for (int i = 0; i < attribs.Size(); i++)
11864  {
11865  attribs[i] = GetBdrAttribute(i);
11866  }
11867  attribs.Sort();
11868  attribs.Unique();
11870  attribs.Copy(bdr_attributes);
11871 }
11872 
11874 {
11875 #ifdef MFEM_USE_MEMALLOC
11876  if (E)
11877  {
11878  if (E->GetType() == Element::TETRAHEDRON)
11879  {
11880  TetMemory.Free((Tetrahedron*) E);
11881  }
11882  else
11883  {
11884  delete E;
11885  }
11886  }
11887 #else
11888  delete E;
11889 #endif
11890 }
11891 
11892 std::ostream &operator<<(std::ostream &os, const Mesh &mesh)
11893 {
11894  mesh.Print(os);
11895  return os;
11896 }
11897 
11898 int Mesh::FindPoints(DenseMatrix &point_mat, Array<int>& elem_ids,
11899  Array<IntegrationPoint>& ips, bool warn,
11900  InverseElementTransformation *inv_trans)
11901 {
11902  const int npts = point_mat.Width();
11903  if (!npts) { return 0; }
11904  MFEM_VERIFY(point_mat.Height() == spaceDim,"Invalid points matrix");
11905  elem_ids.SetSize(npts);
11906  ips.SetSize(npts);
11907  elem_ids = -1;
11908  if (!GetNE()) { return 0; }
11909 
11910  double *data = point_mat.GetData();
11911  InverseElementTransformation *inv_tr = inv_trans;
11912  inv_tr = inv_tr ? inv_tr : new InverseElementTransformation;
11913 
11914  // For each point in 'point_mat', find the element whose center is closest.
11915  Vector min_dist(npts);
11916  Array<int> e_idx(npts);
11917  min_dist = std::numeric_limits<double>::max();
11918  e_idx = -1;
11919 
11920  Vector pt(spaceDim);
11921  for (int i = 0; i < GetNE(); i++)
11922  {
11923  GetElementTransformation(i)->Transform(
11925  for (int k = 0; k < npts; k++)
11926  {
11927  double dist = pt.DistanceTo(data+k*spaceDim);
11928  if (dist < min_dist(k))
11929  {
11930  min_dist(k) = dist;
11931  e_idx[k] = i;
11932  }
11933  }
11934  }
11935 
11936  // Checks if the points lie in the closest element
11937  int pts_found = 0;
11938  pt.NewDataAndSize(NULL, spaceDim);
11939  for (int k = 0; k < npts; k++)
11940  {
11941  pt.SetData(data+k*spaceDim);
11942  inv_tr->SetTransformation(*GetElementTransformation(e_idx[k]));
11943  int res = inv_tr->Transform(pt, ips[k]);
11945  {
11946  elem_ids[k] = e_idx[k];
11947  pts_found++;
11948  }
11949  }
11950  if (pts_found != npts)
11951  {
11952  Array<int> elvertices;
11953  Table *vtoel = GetVertexToElementTable();
11954  for (int k = 0; k < npts; k++)
11955  {
11956  if (elem_ids[k] != -1) { continue; }
11957  // Try all vertex-neighbors of element e_idx[k]
11958  pt.SetData(data+k*spaceDim);
11959  GetElementVertices(e_idx[k], elvertices);
11960  for (int v = 0; v < elvertices.Size(); v++)
11961  {
11962  int vv = elvertices[v];
11963  int ne = vtoel->RowSize(vv);
11964  const int* els = vtoel->GetRow(vv);
11965  for (int e = 0; e < ne; e++)
11966  {
11967  if (els[e] == e_idx[k]) { continue; }
11968  inv_tr->SetTransformation(*GetElementTransformation(els[e]));
11969  int res = inv_tr->Transform(pt, ips[k]);
11971  {
11972  elem_ids[k] = els[e];
11973  pts_found++;
11974  goto next_point;
11975  }
11976  }
11977  }
11978  // Try neighbors for non-conforming meshes
11979  if (ncmesh)
11980  {
11981  Array<int> neigh;
11982  int le = ncmesh->leaf_elements[e_idx[k]];
11983  ncmesh->FindNeighbors(le,neigh);
11984  for (int e = 0; e < neigh.Size(); e++)
11985  {
11986  int nn = neigh[e];
11987  if (ncmesh->IsGhost(ncmesh->elements[nn])) { continue; }
11988  int el = ncmesh->elements[nn].index;
11990  int res = inv_tr->Transform(pt, ips[k]);
11992  {
11993  elem_ids[k] = el;
11994  pts_found++;
11995  goto next_point;
11996  }
11997  }
11998  }
11999  next_point: ;
12000  }
12001  delete vtoel;
12002  }
12003  if (inv_trans == NULL) { delete inv_tr; }
12004 
12005  if (warn && pts_found != npts)
12006  {
12007  MFEM_WARNING((npts-pts_found) << " points were not found");
12008  }
12009  return pts_found;
12010 }
12011 
12012 
12014  int flags, MemoryType d_mt)
12015 {
12016  this->mesh = mesh;
12017  IntRule = &ir;
12018  computed_factors = flags;
12019 
12020  MFEM_ASSERT(mesh->GetNumGeometries(mesh->Dimension()) <= 1,
12021  "mixed meshes are not supported!");
12022  MFEM_ASSERT(mesh->GetNodes(), "meshes without nodes are not supported!");
12023 
12024  Compute(*mesh->GetNodes(), d_mt);
12025 }
12026 
12028  const IntegrationRule &ir,
12029  int flags, MemoryType d_mt)
12030 {
12031  this->mesh = nodes.FESpace()->GetMesh();
12032  IntRule = &ir;
12033  computed_factors = flags;
12034 
12035  Compute(nodes, d_mt);
12036 }
12037 
12038 void GeometricFactors::Compute(const GridFunction &nodes,
12039  MemoryType d_mt)
12040 {
12041 
12042  const FiniteElementSpace *fespace = nodes.FESpace();
12043  const FiniteElement *fe = fespace->GetFE(0);
12044  const int dim = fe->GetDim();
12045  const int vdim = fespace->GetVDim();
12046  const int NE = fespace->GetNE();
12047  const int ND = fe->GetDof();
12048  const int NQ = IntRule->GetNPoints();
12049 
12050  unsigned eval_flags = 0;
12051  MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
12054  {
12055  X.SetSize(vdim*NQ*NE, my_d_mt); // NQ x SDIM x NE
12056  eval_flags |= QuadratureInterpolator::VALUES;
12057  }
12059  {
12060  J.SetSize(dim*vdim*NQ*NE, my_d_mt); // NQ x SDIM x DIM x NE
12062  }
12064  {
12065  detJ.SetSize(NQ*NE, my_d_mt); // NQ x NE
12067  }
12068 
12069  const QuadratureInterpolator *qi = fespace->GetQuadratureInterpolator(*IntRule);
12070  // All X, J, and detJ use this layout:
12072 
12073  const bool use_tensor_products = UsesTensorBasis(*fespace);
12074 
12075  qi->DisableTensorProducts(!use_tensor_products);
12076  const ElementDofOrdering e_ordering = use_tensor_products ?
12079  const Operator *elem_restr = fespace->GetElementRestriction(e_ordering);
12080 
12081  if (elem_restr) // Always true as of 2021-04-27
12082  {
12083  Vector Enodes(vdim*ND*NE, my_d_mt);
12084  elem_restr->Mult(nodes, Enodes);
12085  qi->Mult(Enodes, eval_flags, X, J, detJ);
12086  }
12087  else
12088  {
12089  qi->Mult(nodes, eval_flags, X, J, detJ);
12090  }
12091 }
12092 
12094  const IntegrationRule &ir,
12095  int flags, FaceType type,
12096  MemoryType d_mt)
12097  : type(type)
12098 {
12099  this->mesh = mesh;
12100  IntRule = &ir;
12101  computed_factors = flags;
12102 
12103  const GridFunction *nodes = mesh->GetNodes();
12104  const FiniteElementSpace *fespace = nodes->FESpace();
12105  const int vdim = fespace->GetVDim();
12106  const int NF = fespace->GetNFbyType(type);
12107  const int NQ = ir.GetNPoints();
12108 
12109  const FaceRestriction *face_restr = fespace->GetFaceRestriction(
12111  type,
12113 
12114 
12115  MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
12117 
12118  Vector Fnodes(face_restr->Height(), my_d_mt);
12119  face_restr->Mult(*nodes, Fnodes);
12120 
12121  unsigned eval_flags = 0;
12122 
12124  {
12125  X.SetSize(vdim*NQ*NF, my_d_mt);
12126  eval_flags |= FaceQuadratureInterpolator::VALUES;
12127  }
12128  if (flags & FaceGeometricFactors::JACOBIANS)
12129  {
12130  J.SetSize(vdim*vdim*NQ*NF, my_d_mt);
12132  }
12134  {
12135  detJ.SetSize(NQ*NF, my_d_mt);
12137  }
12138  if (flags & FaceGeometricFactors::NORMALS)
12139  {
12140  normal.SetSize(vdim*NQ*NF, my_d_mt);
12142  }
12143 
12144  const FaceQuadratureInterpolator *qi =
12145  fespace->GetFaceQuadratureInterpolator(ir, type);
12146  // All face data vectors assume layout byNODES.
12148  const bool use_tensor_products = UsesTensorBasis(*fespace);
12149  qi->DisableTensorProducts(!use_tensor_products);
12150 
12151  qi->Mult(Fnodes, eval_flags, X, J, detJ, normal);
12152 }
12153 
12155  const double s_)
12156  : VectorCoefficient(dim), n(n_), s(s_), tip(p, dim-1)
12157 {
12158 }
12159 
12161  const IntegrationPoint &ip)
12162 {
12163  V.SetSize(vdim);
12164  T.Transform(ip, tip);
12165  V(0) = p[0];
12166  if (vdim == 2)
12167  {
12168  V(1) = s * ((ip.y + layer) / n);
12169  }
12170  else
12171  {
12172  V(1) = p[1];
12173  V(2) = s * ((ip.z + layer) / n);
12174  }
12175 }
12176 
12177 
12178 Mesh *Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
12179 {
12180  if (mesh->Dimension() != 1)
12181  {
12182  mfem::err << "Extrude1D : Not a 1D mesh!" << endl;
12183  mfem_error();
12184  }
12185 
12186  int nvy = (closed) ? (ny) : (ny + 1);
12187  int nvt = mesh->GetNV() * nvy;
12188 
12189  Mesh *mesh2d;
12190 
12191  if (closed)
12192  {
12193  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny, mesh->GetNBE()*ny);
12194  }
12195  else
12196  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny,
12197  mesh->GetNBE()*ny+2*mesh->GetNE());
12198 
12199  // vertices
12200  double vc[2];
12201  for (int i = 0; i < mesh->GetNV(); i++)
12202  {
12203  vc[0] = mesh->GetVertex(i)[0];
12204  for (int j = 0; j < nvy; j++)
12205  {
12206  vc[1] = sy * (double(j) / ny);
12207  mesh2d->AddVertex(vc);
12208  }
12209  }
12210  // elements
12211  Array<int> vert;
12212  for (int i = 0; i < mesh->GetNE(); i++)
12213  {
12214  const Element *elem = mesh->GetElement(i);
12215  elem->GetVertices(vert);
12216  const int attr = elem->GetAttribute();
12217  for (int j = 0; j < ny; j++)
12218  {
12219  int qv[4];
12220  qv[0] = vert[0] * nvy + j;
12221  qv[1] = vert[1] * nvy + j;
12222  qv[2] = vert[1] * nvy + (j + 1) % nvy;
12223  qv[3] = vert[0] * nvy + (j + 1) % nvy;
12224 
12225  mesh2d->AddQuad(qv, attr);
12226  }
12227  }
12228  // 2D boundary from the 1D boundary
12229  for (int i = 0; i < mesh->GetNBE(); i++)
12230  {
12231  const Element *elem = mesh->GetBdrElement(i);
12232  elem->GetVertices(vert);
12233  const int attr = elem->GetAttribute();
12234  for (int j = 0; j < ny; j++)
12235  {
12236  int sv[2];
12237  sv[0] = vert[0] * nvy + j;
12238  sv[1] = vert[0] * nvy + (j + 1) % nvy;
12239 
12240  if (attr%2)
12241  {
12242  Swap<int>(sv[0], sv[1]);
12243  }
12244 
12245  mesh2d->AddBdrSegment(sv, attr);
12246  }
12247  }
12248 
12249  if (!closed)
12250  {
12251  // 2D boundary from the 1D elements (bottom + top)
12252  int nba = (mesh->bdr_attributes.Size() > 0 ?
12253  mesh->bdr_attributes.Max() : 0);
12254  for (int i = 0; i < mesh->GetNE(); i++)
12255  {
12256  const Element *elem = mesh->GetElement(i);
12257  elem->GetVertices(vert);
12258  const int attr = nba + elem->GetAttribute();
12259  int sv[2];
12260  sv[0] = vert[0] * nvy;
12261  sv[1] = vert[1] * nvy;
12262 
12263  mesh2d->AddBdrSegment(sv, attr);
12264 
12265  sv[0] = vert[1] * nvy + ny;
12266  sv[1] = vert[0] * nvy + ny;
12267 
12268  mesh2d->AddBdrSegment(sv, attr);
12269  }
12270  }
12271 
12272  mesh2d->FinalizeQuadMesh(1, 0, false);
12273 
12274  GridFunction *nodes = mesh->GetNodes();
12275  if (nodes)
12276  {
12277  // duplicate the fec of the 1D mesh so that it can be deleted safely
12278  // along with its nodes, fes and fec
12279  FiniteElementCollection *fec2d = NULL;
12280  FiniteElementSpace *fes2d;
12281  const char *name = nodes->FESpace()->FEColl()->Name();
12282  string cname = name;
12283  if (cname == "Linear")
12284  {
12285  fec2d = new LinearFECollection;
12286  }
12287  else if (cname == "Quadratic")
12288  {
12289  fec2d = new QuadraticFECollection;
12290  }
12291  else if (cname == "Cubic")
12292  {
12293  fec2d = new CubicFECollection;
12294  }
12295  else if (!strncmp(name, "H1_", 3))
12296  {
12297  fec2d = new H1_FECollection(atoi(name + 7), 2);
12298  }
12299  else if (!strncmp(name, "L2_T", 4))
12300  {
12301  fec2d = new L2_FECollection(atoi(name + 10), 2, atoi(name + 4));
12302  }
12303  else if (!strncmp(name, "L2_", 3))
12304  {
12305  fec2d = new L2_FECollection(atoi(name + 7), 2);
12306  }
12307  else
12308  {
12309  delete mesh2d;
12310  mfem::err << "Extrude1D : The mesh uses unknown FE collection : "
12311  << cname << endl;
12312  mfem_error();
12313  }
12314  fes2d = new FiniteElementSpace(mesh2d, fec2d, 2);
12315  mesh2d->SetNodalFESpace(fes2d);
12316  GridFunction *nodes2d = mesh2d->GetNodes();
12317  nodes2d->MakeOwner(fec2d);
12318 
12319  NodeExtrudeCoefficient ecoeff(2, ny, sy);
12320  Vector lnodes;
12321  Array<int> vdofs2d;
12322  for (int i = 0; i < mesh->GetNE(); i++)
12323  {
12325  for (int j = ny-1; j >= 0; j--)
12326  {
12327  fes2d->GetElementVDofs(i*ny+j, vdofs2d);
12328  lnodes.SetSize(vdofs2d.Size());
12329  ecoeff.SetLayer(j);
12330  fes2d->GetFE(i*ny+j)->Project(ecoeff, T, lnodes);
12331  nodes2d->SetSubVector(vdofs2d, lnodes);
12332  }
12333  }
12334  }
12335  return mesh2d;
12336 }
12337 
12338 Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz)
12339 {
12340  if (mesh->Dimension() != 2)
12341  {
12342  mfem::err << "Extrude2D : Not a 2D mesh!" << endl;
12343  mfem_error();
12344  }
12345 
12346  int nvz = nz + 1;
12347  int nvt = mesh->GetNV() * nvz;
12348 
12349  Mesh *mesh3d = new Mesh(3, nvt, mesh->GetNE()*nz,
12350  mesh->GetNBE()*nz+2*mesh->GetNE());
12351 
12352  bool wdgMesh = false;
12353  bool hexMesh = false;
12354 
12355  // vertices
12356  double vc[3];
12357  for (int i = 0; i < mesh->GetNV(); i++)
12358  {
12359  vc[0] = mesh->GetVertex(i)[0];
12360  vc[1] = mesh->GetVertex(i)[1];
12361  for (int j = 0; j < nvz; j++)
12362  {
12363  vc[2] = sz * (double(j) / nz);
12364  mesh3d->AddVertex(vc);
12365  }
12366  }
12367  // elements
12368  Array<int> vert;
12369  for (int i = 0; i < mesh->GetNE(); i++)
12370  {
12371  const Element *elem = mesh->GetElement(i);
12372  elem->GetVertices(vert);
12373  const int attr = elem->GetAttribute();
12374  Geometry::Type geom = elem->GetGeometryType();
12375  switch (geom)
12376  {
12377  case Geometry::TRIANGLE:
12378  wdgMesh = true;
12379  for (int j = 0; j < nz; j++)
12380  {
12381  int pv[6];
12382  pv[0] = vert[0] * nvz + j;
12383  pv[1] = vert[1] * nvz + j;
12384  pv[2] = vert[2] * nvz + j;
12385  pv[3] = vert[0] * nvz + (j + 1) % nvz;
12386  pv[4] = vert[1] * nvz + (j + 1) % nvz;
12387  pv[5] = vert[2] * nvz + (j + 1) % nvz;
12388 
12389  mesh3d->AddWedge(pv, attr);
12390  }
12391  break;
12392  case Geometry::SQUARE:
12393  hexMesh = true;
12394  for (int j = 0; j < nz; j++)
12395  {
12396  int hv[8];
12397  hv[0] = vert[0] * nvz + j;
12398  hv[1] = vert[1] * nvz + j;
12399  hv[2] = vert[2] * nvz + j;
12400  hv[3] = vert[3] * nvz + j;
12401  hv[4] = vert[0] * nvz + (j + 1) % nvz;
12402  hv[5] = vert[1] * nvz + (j + 1) % nvz;
12403  hv[6] = vert[2] * nvz + (j + 1) % nvz;
12404  hv[7] = vert[3] * nvz + (j + 1) % nvz;
12405 
12406  mesh3d->AddHex(hv, attr);
12407  }
12408  break;
12409  default:
12410  mfem::err << "Extrude2D : Invalid 2D element type \'"
12411  << geom << "\'" << endl;
12412  mfem_error();
12413  break;
12414  }
12415  }
12416  // 3D boundary from the 2D boundary
12417  for (int i = 0; i < mesh->GetNBE(); i++)
12418  {
12419  const Element *elem = mesh->GetBdrElement(i);
12420  elem->GetVertices(vert);
12421  const int attr = elem->GetAttribute();
12422  for (int j = 0; j < nz; j++)
12423  {
12424  int qv[4];
12425  qv[0] = vert[0] * nvz + j;
12426  qv[1] = vert[1] * nvz + j;
12427  qv[2] = vert[1] * nvz + (j + 1) % nvz;
12428  qv[3] = vert[0] * nvz + (j + 1) % nvz;
12429 
12430  mesh3d->AddBdrQuad(qv, attr);
12431  }
12432  }
12433 
12434  // 3D boundary from the 2D elements (bottom + top)
12435  int nba = (mesh->bdr_attributes.Size() > 0 ?
12436  mesh->bdr_attributes.Max() : 0);
12437  for (int i = 0; i < mesh->GetNE(); i++)
12438  {
12439  const Element *elem = mesh->GetElement(i);
12440  elem->GetVertices(vert);
12441  const int attr = nba + elem->GetAttribute();
12442  Geometry::Type geom = elem->GetGeometryType();
12443  switch (geom)
12444  {
12445  case Geometry::TRIANGLE:
12446  {
12447  int tv[3];
12448  tv[0] = vert[0] * nvz;
12449  tv[1] = vert[2] * nvz;
12450  tv[2] = vert[1] * nvz;
12451 
12452  mesh3d->AddBdrTriangle(tv, attr);
12453 
12454  tv[0] = vert[0] * nvz + nz;
12455  tv[1] = vert[1] * nvz + nz;
12456  tv[2] = vert[2] * nvz + nz;
12457 
12458  mesh3d->AddBdrTriangle(tv, attr);
12459  }
12460  break;
12461  case Geometry::SQUARE:
12462  {
12463  int qv[4];
12464  qv[0] = vert[0] * nvz;
12465  qv[1] = vert[3] * nvz;
12466  qv[2] = vert[2] * nvz;
12467  qv[3] = vert[1] * nvz;
12468 
12469  mesh3d->AddBdrQuad(qv, attr);
12470 
12471  qv[0] = vert[0] * nvz + nz;
12472  qv[1] = vert[1] * nvz + nz;
12473  qv[2] = vert[2] * nvz + nz;
12474  qv[3] = vert[3] * nvz + nz;
12475 
12476  mesh3d->AddBdrQuad(qv, attr);
12477  }
12478  break;
12479  default:
12480  mfem::err << "Extrude2D : Invalid 2D element type \'"
12481  << geom << "\'" << endl;
12482  mfem_error();
12483  break;
12484  }
12485  }
12486 
12487  if ( hexMesh && wdgMesh )
12488  {
12489  mesh3d->FinalizeMesh(0, false);
12490  }
12491  else if ( hexMesh )
12492  {
12493  mesh3d->FinalizeHexMesh(1, 0, false);
12494  }
12495  else if ( wdgMesh )
12496  {
12497  mesh3d->FinalizeWedgeMesh(1, 0, false);
12498  }
12499 
12500  GridFunction *nodes = mesh->GetNodes();
12501  if (nodes)
12502  {
12503  // duplicate the fec of the 2D mesh so that it can be deleted safely
12504  // along with its nodes, fes and fec
12505  FiniteElementCollection *fec3d = NULL;
12506  FiniteElementSpace *fes3d;
12507  const char *name = nodes->FESpace()->FEColl()->Name();
12508  string cname = name;
12509  if (cname == "Linear")
12510  {
12511  fec3d = new LinearFECollection;
12512  }
12513  else if (cname == "Quadratic")
12514  {
12515  fec3d = new QuadraticFECollection;
12516  }
12517  else if (cname == "Cubic")
12518  {
12519  fec3d = new CubicFECollection;
12520  }
12521  else if (!strncmp(name, "H1_", 3))
12522  {
12523  fec3d = new H1_FECollection(atoi(name + 7), 3);
12524  }
12525  else if (!strncmp(name, "L2_T", 4))
12526  {
12527  fec3d = new L2_FECollection(atoi(name + 10), 3, atoi(name + 4));
12528  }
12529  else if (!strncmp(name, "L2_", 3))
12530  {
12531  fec3d = new L2_FECollection(atoi(name + 7), 3);
12532  }
12533  else
12534  {
12535  delete mesh3d;
12536  mfem::err << "Extrude3D : The mesh uses unknown FE collection : "
12537  << cname << endl;
12538  mfem_error();
12539  }
12540  fes3d = new FiniteElementSpace(mesh3d, fec3d, 3);
12541  mesh3d->SetNodalFESpace(fes3d);
12542  GridFunction *nodes3d = mesh3d->GetNodes();
12543  nodes3d->MakeOwner(fec3d);
12544 
12545  NodeExtrudeCoefficient ecoeff(3, nz, sz);
12546  Vector lnodes;
12547  Array<int> vdofs3d;
12548  for (int i = 0; i < mesh->GetNE(); i++)
12549  {
12551  for (int j = nz-1; j >= 0; j--)
12552  {
12553  fes3d->GetElementVDofs(i*nz+j, vdofs3d);
12554  lnodes.SetSize(vdofs3d.Size());
12555  ecoeff.SetLayer(j);
12556  fes3d->GetFE(i*nz+j)->Project(ecoeff, T, lnodes);
12557  nodes3d->SetSubVector(vdofs3d, lnodes);
12558  }
12559  }
12560  }
12561  return mesh3d;
12562 }
12563 
12564 #ifdef MFEM_DEBUG
12565 void Mesh::DebugDump(std::ostream &os) const
12566 {
12567  // dump vertices and edges (NCMesh "nodes")
12568  os << NumOfVertices + NumOfEdges << "\n";
12569  for (int i = 0; i < NumOfVertices; i++)
12570  {
12571  const double *v = GetVertex(i);
12572  os << i << " " << v[0] << " " << v[1] << " " << v[2]
12573  << " 0 0 " << i << " -1 0\n";
12574  }
12575 
12576  Array<int> ev;
12577  for (int i = 0; i < NumOfEdges; i++)
12578  {
12579  GetEdgeVertices(i, ev);
12580  double mid[3] = {0, 0, 0};
12581  for (int j = 0; j < 2; j++)
12582  {
12583  for (int k = 0; k < spaceDim; k++)
12584  {
12585  mid[k] += GetVertex(ev[j])[k];
12586  }
12587  }
12588  os << NumOfVertices+i << " "
12589  << mid[0]/2 << " " << mid[1]/2 << " " << mid[2]/2 << " "
12590  << ev[0] << " " << ev[1] << " -1 " << i << " 0\n";
12591  }
12592 
12593  // dump elements
12594  os << NumOfElements << "\n";
12595  for (int i = 0; i < NumOfElements; i++)
12596  {
12597  const Element* e = elements[i];
12598  os << e->GetNVertices() << " ";
12599  for (int j = 0; j < e->GetNVertices(); j++)
12600  {
12601  os << e->GetVertices()[j] << " ";
12602  }
12603  os << e->GetAttribute() << " 0 " << i << "\n";
12604  }
12605 
12606  // dump faces
12607  os << "0\n";
12608 }
12609 #endif
12610 
12611 }
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:247
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:4891
Abstract class for all finite elements.
Definition: fe_base.hpp:235
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
const IntegrationRule * IntRule
Definition: mesh.hpp:1895
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition: fespace.hpp:631
Geometry::Type GetGeometryType() const
Definition: element.hpp:52
void Loader(std::istream &input, int generate_edges=0, std::string parse_tag="")
Definition: mesh.cpp:3966
Mesh * Make3D(int nsteps, double rstep, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:370
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:599
int Size() const
Return the logical size of the array.
Definition: array.hpp:138
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:573
void SetCoordsFromPatches(Vector &Nodes)
Definition: nurbs.cpp:2966
void PrintSurfaces(const Table &Aface_face, std::ostream &out) const
Print set of disjoint surfaces:
Definition: mesh.cpp:11422
void Get(double *p, const int dim) const
Definition: intrules.hpp:51
virtual void Save(const char *fname, int precision=16) const
Definition: mesh.cpp:10289
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:6260
static const int vtk_quadratic_hex[27]
Definition: mesh.hpp:246
int * CartesianPartitioning(int nxyz[])
Definition: mesh.cpp:6989
void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
int GetDim() const
Returns the reference space dimension for the finite element.
Definition: fe_base.hpp:311
int Push(int i, int j)
Definition: table.cpp:219
int GetNDofs() const
Returns number of degrees of freedom.
Definition: fespace.hpp:584
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
FaceInformation GetFaceInformation(int f) const
Definition: mesh.cpp:1131
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
int GetNV() const
Definition: nurbs.hpp:358
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition: mesh.hpp:1486
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
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:1012
void NewDataAndSize(double *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition: vector.hpp:163
void ScaleElements(double sf)
Definition: mesh.cpp:11559
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
int DofToVDof(int dof, int vd, int ndofs=-1) const
Definition: fespace.cpp:251
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T...
Definition: array.hpp:256
Table * GetEdgeVertexTable() const
Returns the edge-to-vertex Table (3D)
Definition: mesh.cpp:6053
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:5954
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition: array.hpp:292
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:1014
void FreeElement(Element *E)
Definition: mesh.cpp:11873
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:3334
int AddQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1674
int CheckElementOrientation(bool fix_it=true)
Check (and optionally attempt to fix) the orientation of the elements.
Definition: mesh.cpp:5420
void SetVertices(const Vector &vert_coord)
Definition: mesh.cpp:7848
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:243
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:6016
void Make2D(int nx, int ny, Element::Type type, double sx, double sy, bool generate_edges, bool sfc_ordering)
Definition: mesh.cpp:3339
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition: eltrans.hpp:162
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:1925
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:78
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:1869
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:12160
static Mesh MakeSimplicial(const Mesh &orig_mesh)
Definition: mesh.cpp:4562
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:8165
bool IsNonconformingCoarse() const
Return true if the face is a nonconforming coarse face.
Definition: mesh.hpp:1435
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 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
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
class LinearPyramidFiniteElement PyramidFE
Definition: fe.cpp:44
static const int NumGeom
Definition: geom.hpp:42
Array< Slave > slaves
Definition: ncmesh.hpp:231
Array< Element * > boundary
Definition: mesh.hpp:91
void JacToPerfJac(int GeomType, const DenseMatrix &J, DenseMatrix &PJ) const
Definition: geom.cpp:867
int * GeneratePartitioning(int nparts, int part_method=1)
Definition: mesh.cpp:7033
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:6171
CoarseFineTransformations CoarseFineTr
Definition: mesh.hpp:235
int own_nodes
Definition: mesh.hpp:241
virtual void LimitNCLevel(int max_nc_level)
Definition: ncmesh.cpp:5203
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition: mesh.cpp:5908
bool Conforming() const
Definition: mesh.hpp:1650
void MoveVertices(const Vector &displacements)
Definition: mesh.cpp:7828
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:513
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:926
double Det() const
Definition: densemat.cpp:449
static FiniteElement * GetTransformationFEforElementType(Element::Type)
Definition: mesh.cpp:327
virtual DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element &#39;bel&#39;.
Definition: fespace.cpp:2812
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:12093
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:3723
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
Definition: mesh.cpp:7935
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:308
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:392
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Definition: mesh.cpp:7957
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:475
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:73
int SizeK() const
Definition: densemat.hpp:1001
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition: mesh.cpp:6250
double Norml2() const
Returns the l2 norm of the vector.
Definition: vector.cpp:812
void ReadNetgen2DMesh(std::istream &input, int &curved)
void ShiftRight(int &a, int &b, int &c)
Definition: mesh.hpp:1966
void SetDims(int rows, int nnz)
Definition: table.cpp:140
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:206
int Push(int a, int b)
Definition: table.hpp:267
Element::Type GetBdrElementType(int i) const
Returns the type of boundary element i.
Definition: mesh.cpp:6255
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:93
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:856
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:3733
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
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:547
T * GetData()
Returns the data.
Definition: array.hpp:112
unsigned int uint
Definition: gecko.hpp:204
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:1931
int GetNKV() const
Definition: nurbs.hpp:355
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:246
static const int Edges[NumEdges][2]
Definition: geom.hpp:242
void GetMeshComponents(Mesh &mesh) const
Fill Mesh::{vertices,elements,boundary} for the current finest level.
Definition: ncmesh.cpp:2303
int VectorDim() const
Definition: gridfunc.cpp:324
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:5919
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:290
Piecewise-(bi/tri)linear continuous finite elements.
Definition: fe_coll.hpp:663
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
GridFunction * Nodes
Definition: mesh.hpp:240
int Size() const
Returns the size of the vector.
Definition: vector.hpp:200
int NumOfElements
Definition: mesh.hpp:69
void Print(std::ostream &out) const
I/O: Print the mesh in &quot;MFEM NC mesh v1.0&quot; format.
Definition: ncmesh.cpp:5400
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:187
Mesh * Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
Extrude a 1D mesh.
Definition: mesh.cpp:12178
int idxtype
Definition: mesh.cpp:44
int GetElementOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:178
void Transform(void(*f)(const Vector &, Vector &))
Definition: mesh.cpp:11629
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:524
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:6194
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:7970
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:923
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:2818
virtual void SetVertices(const int *ind)
Set the indices the element according to the input.
Definition: element.cpp:17
void order(Functional *functional, uint iterations=1, uint window=2, uint period=2, uint seed=0, Progress *progress=0)
Definition: gecko.cpp:1232
double kappa
Definition: ex24.cpp:54
Evaluate the derivatives at quadrature points.
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition: mesh.hpp:1837
NodeExtrudeCoefficient(const int dim, const int n_, const double s_)
Definition: mesh.cpp:12154
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec and fes.
Definition: gridfunc.hpp:124
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:3913
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.
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:5616
Data type quadrilateral element.
void GetVertices(Vector &vert_coord) const
Definition: mesh.cpp:7837
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
Data arrays will be written in ASCII format.
The inverse transformation of a given ElementTransformation.
Definition: eltrans.hpp:185
double * GetData() const
Returns the matrix data array.
Definition: densemat.hpp:115
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)
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:6228
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:209
T Min() const
Find the minimal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:85
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
virtual int OrderJ() const =0
Return the order of the elements of the Jacobian of the transformation.
void RemoveInternalBoundaries()
Definition: mesh.cpp:11785
void DebugDump(std::ostream &out) const
Output an NCMesh-compatible debug dump.
Definition: mesh.cpp:12565
Mesh * Extrude2D(Mesh *mesh, const int nz, const double sz)
Extrude a 2D mesh.
Definition: mesh.cpp:12338
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:1069
void Print(const Mesh &mesh, const adios2stream::mode print_mode=mode::sync)
int Size_of_connections() const
Definition: table.hpp:98
Data type Wedge element.
Definition: wedge.hpp:22
void SetEmpty()
Definition: mesh.cpp:1472
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
void FinalizeHexMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a hexahedral Mesh.
Definition: mesh.cpp:2853
friend class NURBSExtension
Definition: mesh.hpp:59
Geometry::Type GetBdrElementGeometry(int i) const
Definition: mesh.hpp:1060
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:6331
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:354
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:284
void ReadCubit(const char *filename, int &curved, int &read_gf)
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:1077
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:313
void DeleteAll()
Delete the whole array.
Definition: array.hpp:846
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:104
int Dimension() const
Definition: nurbs.hpp:345
int master
master number (in Mesh numbering)
Definition: ncmesh.hpp:216
void InitRefinementTransforms()
Definition: mesh.cpp:9906
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:8006
Array< NCFaceInfo > nc_faces_info
Definition: mesh.hpp:218
Element * ReadElement(std::istream &)
Definition: mesh.cpp:3895
void KnotInsert(Array< KnotVector * > &kv)
Definition: mesh.cpp:5050
void OnMeshUpdated(Mesh *mesh)
Definition: ncmesh.cpp:2398
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:4925
Element * NewElement(int geom)
Definition: mesh.cpp:3841
Table * el_to_face
Definition: mesh.hpp:221
void SetTransformation(ElementTransformation &Trans)
Set a new forward ElementTransformation, Trans.
Definition: eltrans.hpp:292
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3076
void SetVerticesFromNodes(const GridFunction *nodes)
Helper to set vertex coordinates given a high-order curvature function.
Definition: mesh.cpp:5362
Structure for storing face geometric factors: coordinates, Jacobians, determinants of the Jacobians...
Definition: mesh.hpp:1891
ElementTransformation * GetBdrElementTransformation(int i)
Returns the transformation defining the i-th boundary element.
Definition: mesh.cpp:431
virtual void UpdateMeshPointer(Mesh *new_mesh)
Definition: fespace.cpp:3439
int AddBdrTriangle(int v1, int v2, int v3, int attr=1)
Definition: mesh.cpp:1837
Mesh * Make2D(int nsteps, double rstep, double phi, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:49
void PrintTopo(std::ostream &out, const Array< int > &e_to_k) const
Definition: mesh.cpp:10247
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:5376
void MakeRefined_(Mesh &orig_mesh, const Array< int > ref_factors, int ref_type)
Internal function used in Mesh::MakeRefined.
Definition: mesh.cpp:4333
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:3676
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe_base.hpp:320
friend class NCMesh
Definition: mesh.hpp:58
Piecewise-(bi)cubic continuous finite elements.
Definition: fe_coll.hpp:743
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:614
uint rank(Node::Index i) const
Definition: gecko.hpp:672
double Weight() const
Definition: densemat.cpp:506
PointFiniteElement PointFE
Definition: point.cpp:30
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: segment.cpp:40
void GetElementJacobian(int i, DenseMatrix &J)
Definition: mesh.cpp:60
Data type hexahedron element.
Definition: hexahedron.hpp:22
static int GetTetOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:5664
Geometry Geometries
Definition: fe.cpp:49
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:250
long GetSequence() const
Definition: mesh.hpp:1664
void GetVertexDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3033
int AddVertex(double x, double y=0.0, double z=0.0)
Definition: mesh.cpp:1613
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition: eltrans.hpp:401
bool Nonconforming() const
Definition: mesh.hpp:1651
const int * GetDofMap(Geometry::Type GeomType) const
Get the Cartesian to local H1 dof map.
Definition: fe_coll.cpp:1917
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:201
uint Index
Definition: gecko.hpp:595
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:1878
FaceType
Definition: mesh.hpp:45
Data type Pyramid element.
Definition: pyramid.hpp:22
static const int Edges[NumEdges][2]
Definition: geom.hpp:156
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
void MoveNodes(const Vector &displacements)
Definition: mesh.cpp:7896
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:10930
The point is inside the element.
Definition: eltrans.hpp:224
double f(const Vector &xvec)
Definition: lor_mms.hpp:32
void UpdateNURBS()
Definition: mesh.cpp:5124
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
const Table & GetDerefinementTable()
Definition: ncmesh.cpp:1807
void PrintVTK(std::ostream &os)
Definition: mesh.cpp:10303
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:7490
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:67
void Make3D(int nx, int ny, int nz, Element::Type type, double sx, double sy, double sz, bool sfc_ordering)
Definition: mesh.cpp:3058
unsigned matrix
Definition: ncmesh.hpp:58
void AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
Definition: mesh.cpp:6481
virtual void SetAttributes()
Definition: mesh.cpp:1559
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:751
void SetType(const int t)
Set the Quadrature1D type of points to use for subdivision.
Definition: geom.hpp:306
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition: mesh.cpp:9473
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: triangle.hpp:61
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:441
IntegrationPointTransformation Loc1
Definition: eltrans.hpp:524
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:1884
int FindCoarseElement(int i)
Definition: mesh.cpp:9918
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:1851
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:3589
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.
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:9816
static const int Map[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to linear VTK geometries.
Definition: vtk.hpp:76
Float cost() const
Definition: gecko.cpp:857
void AddQuadFaceElement(int lf, int gf, int el, int v0, int v1, int v2, int v3)
Definition: mesh.cpp:6546
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:7433
Timing object.
Definition: tic_toc.hpp:34
void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
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:5189
void ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:6798
void Reset()
Force the reevaluation of the Jacobian in the next call.
Definition: eltrans.hpp:89
A pair of objects.
Definition: sort_pairs.hpp:23
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Definition: mesh.cpp:5343
Type
Constants for the classes derived from Element.
Definition: element.hpp:41
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:68
void GetBdrPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:6278
void InitTables()
Definition: mesh.cpp:1466
void CheckDisplacements(const Vector &displacements, double &tmax)
Definition: mesh.cpp:7751
This structure stores the low level information necessary to interpret the configuration of elements ...
Definition: mesh.hpp:153
NURBSExtension * StealNURBSext()
Definition: fespace.cpp:2229
Array< DenseMatrix * > point_matrices[Geometry::NumGeom]
List of unique point matrices for each slave geometry.
Definition: ncmesh.hpp:234
VTKFormat
Data array format for VTK and VTU files.
Definition: vtk.hpp:96
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition: fe_base.hpp:390
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:156
int AddBdrSegment(int v1, int v2, int attr=1)
Definition: mesh.cpp:1823
int AddElement(Element *elem)
The parameter elem should be allocated using the NewElement() method.
Definition: mesh.cpp:1809
int GetMaxElementOrder() const
Return the maximum polynomial order.
Definition: fespace.hpp:459
void ReadLineMesh(std::istream &input)
Array< Embedding > embeddings
Fine element positions in their parents.
Definition: ncmesh.hpp:73
void GetBdrElementTopo(Array< Element * > &boundary) const
Definition: nurbs.cpp:2540
virtual void Load(std::istream &input, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition: mesh.hpp:891
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:1773
const CoarseFineTransformations & GetRefinementTransforms()
Definition: ncmesh.cpp:4350
void SetLayer(const int l)
Definition: mesh.hpp:1950
int GetAttribute() const
Return element&#39;s attribute.
Definition: element.hpp:55
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:6356
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition: array.hpp:289
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:6206
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition: fespace.hpp:925
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:9497
Data type triangle element.
Definition: triangle.hpp:23
void MarkCoarseLevel()
Definition: ncmesh.cpp:4302
const Element * GetElement(int i) const
Definition: mesh.hpp:1040
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Definition: triangle.cpp:45
void ResetLazyData()
Definition: mesh.cpp:1549
void GetElementTopo(Array< Element * > &elements) const
Definition: nurbs.cpp:2445
IntegrationRule RefPts
Definition: geom.hpp:282
signed char local
local number within &#39;element&#39;
Definition: ncmesh.hpp:191
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
Definition: densemat.hpp:1005
double Float
Definition: gecko.hpp:208
void Sort()
Sorts the array in ascending order. This requires operator&lt; to be defined for T.
Definition: array.hpp:248
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:5285
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: tetrahedron.hpp:81
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:581
Vector normal
Normals at all quadrature points.
Definition: mesh.hpp:1938
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:202
void SetData(double *d)
Definition: vector.hpp:150
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:668
int Dimension() const
Definition: mesh.hpp:1006
struct mfem::Mesh::FaceInformation::@13 element[2]
virtual MFEM_DEPRECATED void ReorientTetMesh()
Definition: mesh.cpp:6927
prob_type prob
Definition: ex25.cpp:153
int NumOfBdrElements
Definition: mesh.hpp:69
Table * el_to_edge
Definition: mesh.hpp:220
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
static const int QuadraticMap[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to legacy quadratic VTK geometries/.
Definition: vtk.hpp:78
void GetColumn(int c, Vector &col) const
Definition: densemat.cpp:1292
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: triangle.cpp:188
A class that performs interpolation from a face E-vector to quadrature point values and/or derivative...
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:453
double DistanceTo(const double *p) const
Compute the Euclidean distance to another vector.
Definition: vector.hpp:654
void ReadMFEMMesh(std::istream &input, int version, int &curved)
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: triangle.hpp:62
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:8853
virtual DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element &#39;elem&#39;.
Definition: fespace.cpp:2678
void FindPartitioningComponents(Table &elem_elem, const Array< int > &partitioning, Array< int > &component, Array< int > &num_comp)
Definition: mesh.cpp:7362
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
void MakeTopologyOnly()
Definition: ncmesh.hpp:413
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3043
bool IsOfFaceType(FaceType type) const
Return true if the face is of the same type as type.
Definition: mesh.hpp:1404
List of mesh geometries stored as Array&lt;Geometry::Type&gt;.
Definition: mesh.hpp:1092
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:10503
This structure is used as a human readable output format that decipheres the information contained in...
Definition: mesh.hpp:1356
int CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition: mesh.cpp:5797
int SpaceDimension() const
Definition: mesh.hpp:1007
GeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, MemoryType d_mt=MemoryType::DEFAULT)
Definition: mesh.cpp:12013
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: tetrahedron.hpp:82
void PrintElementsWithPartitioning(int *partitioning, std::ostream &out, int interior_faces=0)
Definition: mesh.cpp:11049
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition: mesh.hpp:1280
static const int Edges[NumEdges][2]
Definition: geom.hpp:182
void AddPointFaceElement(int lf, int gf, int el)
Used in GenerateFaces()
Definition: mesh.cpp:6449
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:3517
double * Data() const
Returns the matrix data array.
Definition: densemat.hpp:111
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:630
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:270
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:9095
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:2883
int GetMyRank() const
Definition: pmesh.hpp:353
static int CheckClosed(int type)
If the Quadrature1D type is not closed return Invalid; otherwise return type.
Definition: intrules.cpp:854
const NURBSExtension * GetNURBSext() const
Definition: fespace.hpp:443
Table * el_to_el
Definition: mesh.hpp:222
MPI_Comm GetComm() const
Definition: pmesh.hpp:351
int SpaceDimension() const
Return the space dimension of the NCMesh.
Definition: ncmesh.hpp:146
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
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe_base.hpp:323
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
static Mesh LoadFromFile(const char *filename, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition: mesh.cpp:3695
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition: mesh.cpp:11678
static void PrintElement(const Element *, std::ostream &)
Definition: mesh.cpp:3907
virtual void NURBSUniformRefinement()
Refine NURBS mesh.
Definition: mesh.cpp:5094
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int attr=1)
Definition: mesh.cpp:1737
const IntegrationRule * IntRule
Definition: mesh.hpp:1846
MemoryType
Memory types supported by MFEM.
Definition: mem_manager.hpp:31
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:1916
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition: mesh.cpp:2890
static void GetElementArrayEdgeTable(const Array< Element * > &elem_array, const DSTable &v_to_v, Table &el_to_edge)
Definition: mesh.cpp:6309
void AddAColumnInRow(int r)
Definition: table.hpp:77
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition: mesh.hpp:1541
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:679
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
Definition: mesh.cpp:2481
int AddBdrQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1851
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:7570
bool IsSlaveFace(const FaceInfo &fi) const
Definition: mesh.cpp:1051
Array< Vertex > vertices
Definition: mesh.hpp:90
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
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:3713
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Definition: mesh.cpp:1590
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
Geometry::Type GetElementGeometry(int i) const
Definition: mesh.hpp:1055
void RefineAtVertex(const Vertex &vert, double eps=0.0, int nonconforming=-1)
Refine elements sharing the specified vertex. Uses GeneralRefinement.
Definition: mesh.cpp:9516
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:3705
Array< Element * > elements
Definition: mesh.hpp:85
const Table & ElementToElementTable()
Definition: mesh.cpp:6395
double GetLength(int i, int j) const
Return the length of the segment from node i to node j.
Definition: mesh.cpp:6294
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
Linear2DFiniteElement TriangleFE
Definition: fe.cpp:32
int meshgen
Definition: mesh.hpp:77
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:228
const CoarseFineTransformations & GetRefinementTransforms()
Definition: mesh.cpp:9928
bool RefineByError(const Array< double > &elem_error, double threshold, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:9542
Table * bel_to_edge
Definition: mesh.hpp:224
Evaluate the values at quadrature points.
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition: mesh.hpp:1658
Table * GetFaceToElementTable() const
Definition: mesh.cpp:6114
int GetNE() const
Definition: nurbs.hpp:360
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
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:272
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:920
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:10495
void GetNode(int i, double *coord) const
Definition: mesh.cpp:7857
Array< int > be_to_edge
Definition: mesh.hpp:223
virtual const char * Name() const
Definition: fe_coll.hpp:65
const Table & ElementToFaceTable() const
Definition: mesh.cpp:6431
static const int Edges[NumEdges][2]
Definition: geom.hpp:260
Class for integration point with weight.
Definition: intrules.hpp:25
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
Element * ReadElementWithoutAttr(std::istream &)
Definition: mesh.cpp:3865
void Swap(Mesh &other, bool non_geometry)
Definition: mesh.cpp:9285
int GetNumFacesWithGhost() const
Return the number of faces (3D), edges (2D) or vertices (1D) including ghost faces.
Definition: mesh.cpp:5387
A standard isoparametric element transformation.
Definition: eltrans.hpp:361
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:5932
static const int vtk_quadratic_wedge[18]
Definition: mesh.hpp:245
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: mesh.cpp:348
void DisableTensorProducts(bool disable=true) const
Disable the use of tensor product evaluations, for tensor-product elements, e.g. quads and hexes...
static const int DimStart[MaxDim+2]
Definition: geom.hpp:48
const FiniteElementSpace * GetNodalFESpace() const
Definition: mesh.cpp:5338
class LinearWedgeFiniteElement WedgeFE
Definition: fe.cpp:40
virtual void Print(std::ostream &os=mfem::out) const
Definition: mesh.hpp:1671
Table * face_edge
Definition: mesh.hpp:226
void FinalizeQuadMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a quadrilateral Mesh.
Definition: mesh.cpp:1968
Array< int > leaf_elements
finest elements, in Mesh ordering (+ ghosts)
Definition: ncmesh.hpp:531
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
Definition: mesh.cpp:2983
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:193
bool DerefineByError(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
Definition: mesh.cpp:9212
Array< Master > masters
Definition: ncmesh.hpp:230
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
Definition: mesh.cpp:5986
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3064
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
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 &quot;BigEndian&quot; or &quot;LittleEndian&quot;.
Definition: vtk.cpp:602
void MakeJ()
Definition: table.cpp:91
void DegreeElevate(int rel_degree, int degree=16)
Definition: mesh.cpp:5107
int dim
Definition: ex24.cpp:53
Table * edge_vertex
Definition: mesh.hpp:227
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:7717
IsoparametricTransformation Transf
Definition: eltrans.hpp:464
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:2781
int index(int i, int j, int nx, int ny)
Definition: life.cpp:235
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:224
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
Definition: densemat.cpp:1229
const Mesh * mesh
Definition: mesh.hpp:1845
void MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
Definition: mesh.cpp:4569
Lexicographic ordering for tensor-product FiniteElements.
Array< FaceInfo > faces_info
Definition: mesh.hpp:217
double infinity()
Define a shortcut for std::numeric_limits&lt;double&gt;::infinity()
Definition: vector.hpp:46
virtual int GetNVertices() const =0
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:2399
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:215
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition: fespace.cpp:1259
STable3D * GetFacesTable()
Definition: mesh.cpp:6735
Piecewise-(bi)quadratic continuous finite elements.
Definition: fe_coll.hpp:691
int Dimension() const
Return the dimension of the NCMesh.
Definition: ncmesh.hpp:144
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
Definition: sparsemat.hpp:710
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition: mesh.hpp:273
Geometry::Type GetBdrElementBaseGeometry(int i) const
Definition: mesh.hpp:1072
virtual void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level)
Definition: ncmesh.cpp:1822
virtual void UniformRefinement3D()
Refine a mixed 3D mesh uniformly.
Definition: mesh.hpp:402
int AddBdrElement(Element *elem)
Definition: mesh.cpp:1816
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:3883
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr=1)
Definition: mesh.cpp:1709
BlockArray< Element > elements
Definition: ncmesh.hpp:502
virtual bool NonconformingDerefinement(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
NC version of GeneralDerefinement.
Definition: mesh.cpp:9164
int Dim
Definition: mesh.hpp:66
void Clear()
Clear the contents of the Mesh.
Definition: mesh.hpp:899
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:929
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:45
ElementConformity conformity
Definition: mesh.hpp:1363
double AggregateError(const Array< double > &elem_error, const int *fine, int nfine, int op)
Derefinement helper.
Definition: mesh.cpp:9145
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:932
BiLinear2DFiniteElement QuadrilateralFE
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:11898
Mesh & operator=(Mesh &&mesh)
Move assignment operstor.
Definition: mesh.cpp:3689
virtual void PrintXG(std::ostream &os=mfem::out) const
Print the mesh to the given stream using Netgen/Truegrid format.
Definition: mesh.cpp:9991
Evaluate the derivatives at quadrature points.
Vector data type.
Definition: vector.hpp:60
Data type point element.
Definition: point.hpp:22
void ReadTrueGridMesh(std::istream &input)
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:601
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:7908
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:5392
int NumberOfEntries() const
Definition: table.hpp:266
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:5568
void SetNode(int i, const double *coord)
Definition: mesh.cpp:7876
virtual long long ReduceInt(int value) const
Utility function: sum integers from all processors (Allreduce).
Definition: mesh.hpp:952
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
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:220
void XYZ_VectorFunction(const Vector &p, Vector &v)
Definition: mesh.cpp:5248
void GenerateFaces()
Definition: mesh.cpp:6573
void GetElementColoring(Array< int > &colors, int el0=0)
Definition: mesh.cpp:10855
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:3775
int spaceDim
Definition: mesh.hpp:67
Defines the coarse-fine transformations of all fine elements.
Definition: ncmesh.hpp:70
RefCoord s[3]
const std::string filename
Definition: zstr.hpp:809
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Definition: ncmesh.hpp:260
MemAlloc< Tetrahedron, 1024 > TetMemory
Definition: mesh.hpp:250
int GetNBE() const
Definition: nurbs.hpp:362
Table * GetFaceEdgeTable() const
Returns the face-to-edge Table (3D)
Definition: mesh.cpp:6025
bool IsGhost(const Element &el) const
Return true if the Element el is a ghost element.
Definition: ncmesh.hpp:593
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
TriLinear3DFiniteElement HexahedronFE
Definition: hexahedron.cpp:52
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
Definition: mesh.cpp:2547
void SetNodes(const Vector &node_coord)
Definition: mesh.cpp:7920
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
int RowSize(int i) const
Definition: table.hpp:108
friend class ParNCMesh
Definition: mesh.hpp:56
void SetNodalGridFunction(GridFunction *nodes, bool make_owner=false)
Definition: mesh.cpp:5332
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:11489
Array< int > be_to_face
Definition: mesh.hpp:225
void DegreeElevate(int rel_degree, int degree=16)
Definition: nurbs.cpp:3089
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
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
Definition: mesh.cpp:9241
int NumberOfRows() const
Definition: table.hpp:265
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:9571
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
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition: eltrans.hpp:404
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...
int index
Mesh number.
Definition: ncmesh.hpp:189
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:9405
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:953
ElementLocation location
Definition: mesh.hpp:1362
Class for parallel meshes.
Definition: pmesh.hpp:32
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:379
Abstract data type element.
Definition: element.hpp:28
int GetAttribute(int i) const
Return the attribute of element i.
Definition: mesh.hpp:1480
void AddTriangleFaceElement(int lf, int gf, int el, int v0, int v1, int v2)
Definition: mesh.cpp:6518
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
const Table & ElementToEdgeTable() const
Definition: mesh.cpp:6440
Data type line segment element.
Definition: segment.hpp:22
Linear1DFiniteElement SegmentFE
Definition: segment.cpp:49
Array< GeometricFactors * > geom_factors
Optional geometric factors.
Definition: mesh.hpp:274
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition: fespace.hpp:608
void BdrBisection(int i, const HashTable< Hashed2 > &)
Bisect a boundary triangle: boundary element with index i is bisected.
Definition: mesh.cpp:9779
MPI_Comm GetGlobalMPI_Comm()
Get MFEM&#39;s &quot;global&quot; MPI communicator.
Definition: globals.cpp:62
void GetBdrElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of boundary element i.
Definition: mesh.hpp:1113
int NumberOfElements()
Return the number of elements added to the table.
Definition: stable3d.hpp:70
void GenerateNCFaceInfo()
Definition: mesh.cpp:6674
Array< int > RefGeoms
Definition: geom.hpp:283
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition: mesh.hpp:1109
friend class Tetrahedron
Definition: mesh.hpp:249
virtual Type GetType() const =0
Returns element&#39;s type.
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition: mesh.hpp:268
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:6079
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:1044
void EnsureNodes()
Definition: mesh.cpp:5291
void ConvertToPatches(const Vector &Nodes)
Definition: nurbs.cpp:2955
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:172
void GetElementData(const Array< Element * > &elem_array, int geom, Array< int > &elem_vtx, Array< int > &attr) const
Definition: mesh.cpp:9341
const DenseMatrix * point_matrix
Definition: mesh.hpp:1371
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 refinement.
Definition: mesh.cpp:7991
Defines the position of a fine element within a coarse element.
Definition: ncmesh.hpp:49
void KnotInsert(Array< KnotVector * > &kv)
Definition: nurbs.cpp:3113
int idx_t
Definition: mesh.cpp:43
void Print(std::ostream &out) const
Definition: nurbs.cpp:1701
virtual void Refine(const Array< Refinement > &refinements)
Definition: ncmesh.cpp:1524
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:6148
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:360
Arbitrary order &quot;L2-conforming&quot; discontinuous finite elements.
Definition: fe_coll.hpp:288
Evaluate the values at quadrature points.
double f(const Vector &p)
void Printer(std::ostream &out=mfem::out, std::string section_delimiter="") const
Definition: mesh.cpp:10155
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:264
void NodesUpdated()
This function should be called after the mesh node coordinates have changed, e.g. after the mesh has ...
Definition: mesh.hpp:997
Class used to extrude the nodes of a mesh.
Definition: mesh.hpp:1942
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:215
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 NumOfFaces
Definition: mesh.hpp:70