MFEM  v4.6.0
Finite element discretization library
mesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 // Implementation of data type mesh
13 
14 #include "mesh_headers.hpp"
15 #include "../fem/fem.hpp"
16 #include "../general/sort_pairs.hpp"
17 #include "../general/binaryio.hpp"
18 #include "../general/text.hpp"
19 #include "../general/device.hpp"
20 #include "../general/tic_toc.hpp"
21 #include "../general/gecko.hpp"
22 #include "../fem/quadinterpolator.hpp"
23 
24 #include <iostream>
25 #include <sstream>
26 #include <fstream>
27 #include <limits>
28 #include <cmath>
29 #include <cstring>
30 #include <ctime>
31 #include <functional>
32 #include <map>
33 #include <set>
34 
35 // Include the METIS header, if using version 5. If using METIS 4, the needed
36 // declarations are inlined below, i.e. no header is needed.
37 #if defined(MFEM_USE_METIS) && defined(MFEM_USE_METIS_5)
38 #include "metis.h"
39 #endif
40 
41 // METIS 4 prototypes
42 #if defined(MFEM_USE_METIS) && !defined(MFEM_USE_METIS_5)
43 typedef int idx_t;
44 typedef int idxtype;
45 extern "C" {
47  int*, int*, int*, int*, int*, idxtype*);
49  int*, int*, int*, int*, int*, idxtype*);
51  int*, int*, int*, int*, int*, idxtype*);
52 }
53 #endif
54 
55 using namespace std;
56 
57 namespace mfem
58 {
59 
60 void Mesh::GetElementJacobian(int i, DenseMatrix &J, const IntegrationPoint *ip)
61 {
62  Geometry::Type geom = GetElementBaseGeometry(i);
63  ElementTransformation *eltransf = GetElementTransformation(i);
64  if (ip == NULL)
65  {
66  eltransf->SetIntPoint(&Geometries.GetCenter(geom));
67  }
68  else
69  {
70  eltransf->SetIntPoint(ip);
71  }
72  Geometries.JacToPerfJac(geom, eltransf->Jacobian(), J);
73 }
74 
75 void Mesh::GetElementCenter(int i, Vector &center)
76 {
77  center.SetSize(spaceDim);
78  int geom = GetElementBaseGeometry(i);
79  ElementTransformation *eltransf = GetElementTransformation(i);
80  eltransf->Transform(Geometries.GetCenter(geom), center);
81 }
82 
83 double Mesh::GetElementSize(ElementTransformation *T, int type)
84 {
85  DenseMatrix J(spaceDim, Dim);
86 
87  Geometry::Type geom = T->GetGeometryType();
88  T->SetIntPoint(&Geometries.GetCenter(geom));
89  Geometries.JacToPerfJac(geom, T->Jacobian(), J);
90 
91  if (type == 0)
92  {
93  return pow(fabs(J.Weight()), 1./Dim);
94  }
95  else if (type == 1)
96  {
97  return J.CalcSingularvalue(Dim-1); // h_min
98  }
99  else
100  {
101  return J.CalcSingularvalue(0); // h_max
102  }
103 }
104 
105 double Mesh::GetElementSize(int i, int type)
106 {
107  return GetElementSize(GetElementTransformation(i), type);
108 }
109 
110 double Mesh::GetElementSize(int i, const Vector &dir)
111 {
112  DenseMatrix J(spaceDim, Dim);
113  Vector d_hat(Dim);
114  GetElementJacobian(i, J);
115  J.MultTranspose(dir, d_hat);
116  return sqrt((d_hat * d_hat) / (dir * dir));
117 }
118 
119 double Mesh::GetElementVolume(int i)
120 {
121  ElementTransformation *et = GetElementTransformation(i);
122  const IntegrationRule &ir = IntRules.Get(GetElementBaseGeometry(i),
123  et->OrderJ());
124  double volume = 0.0;
125  for (int j = 0; j < ir.GetNPoints(); j++)
126  {
127  const IntegrationPoint &ip = ir.IntPoint(j);
128  et->SetIntPoint(&ip);
129  volume += ip.weight * et->Weight();
130  }
131 
132  return volume;
133 }
134 
135 // Similar to VisualizationSceneSolution3d::FindNewBox in GLVis
136 void Mesh::GetBoundingBox(Vector &min, Vector &max, int ref)
137 {
138  min.SetSize(spaceDim);
139  max.SetSize(spaceDim);
140 
141  for (int d = 0; d < spaceDim; d++)
142  {
143  min(d) = infinity();
144  max(d) = -infinity();
145  }
146 
147  if (Nodes == NULL)
148  {
149  double *coord;
150  for (int i = 0; i < NumOfVertices; i++)
151  {
152  coord = GetVertex(i);
153  for (int d = 0; d < spaceDim; d++)
154  {
155  if (coord[d] < min(d)) { min(d) = coord[d]; }
156  if (coord[d] > max(d)) { max(d) = coord[d]; }
157  }
158  }
159  }
160  else
161  {
162  const bool use_boundary = false; // make this a parameter?
163  int ne = use_boundary ? GetNBE() : GetNE();
164  int fn, fo;
165  DenseMatrix pointmat;
166  RefinedGeometry *RefG;
167  IntegrationRule eir;
170 
171  for (int i = 0; i < ne; i++)
172  {
173  if (use_boundary)
174  {
175  GetBdrElementFace(i, &fn, &fo);
176  RefG = GlobGeometryRefiner.Refine(GetFaceGeometry(fn), ref);
177  Tr = GetFaceElementTransformations(fn, 5);
178  eir.SetSize(RefG->RefPts.GetNPoints());
179  Tr->Loc1.Transform(RefG->RefPts, eir);
180  Tr->Elem1->Transform(eir, pointmat);
181  }
182  else
183  {
184  T = GetElementTransformation(i);
185  RefG = GlobGeometryRefiner.Refine(GetElementBaseGeometry(i), ref);
186  T->Transform(RefG->RefPts, pointmat);
187  }
188  for (int j = 0; j < pointmat.Width(); j++)
189  {
190  for (int d = 0; d < pointmat.Height(); d++)
191  {
192  if (pointmat(d,j) < min(d)) { min(d) = pointmat(d,j); }
193  if (pointmat(d,j) > max(d)) { max(d) = pointmat(d,j); }
194  }
195  }
196  }
197  }
198 }
199 
200 void Mesh::GetCharacteristics(double &h_min, double &h_max,
201  double &kappa_min, double &kappa_max,
202  Vector *Vh, Vector *Vk)
203 {
204  int i, dim, sdim;
205  DenseMatrix J;
206  double h, kappa;
207 
208  dim = Dimension();
209  sdim = SpaceDimension();
210 
211  if (Vh) { Vh->SetSize(NumOfElements); }
212  if (Vk) { Vk->SetSize(NumOfElements); }
213 
214  h_min = kappa_min = infinity();
215  h_max = kappa_max = -h_min;
216  if (dim == 0) { if (Vh) { *Vh = 1.0; } if (Vk) {*Vk = 1.0; } return; }
217  J.SetSize(sdim, dim);
218  for (i = 0; i < NumOfElements; i++)
219  {
220  GetElementJacobian(i, J);
221  h = pow(fabs(J.Weight()), 1.0/double(dim));
222  kappa = (dim == sdim) ?
223  J.CalcSingularvalue(0) / J.CalcSingularvalue(dim-1) : -1.0;
224  if (Vh) { (*Vh)(i) = h; }
225  if (Vk) { (*Vk)(i) = kappa; }
226 
227  if (h < h_min) { h_min = h; }
228  if (h > h_max) { h_max = h; }
229  if (kappa < kappa_min) { kappa_min = kappa; }
230  if (kappa > kappa_max) { kappa_max = kappa; }
231  }
232 }
233 
234 // static method
235 void Mesh::PrintElementsByGeometry(int dim,
236  const Array<int> &num_elems_by_geom,
237  std::ostream &os)
238 {
239  for (int g = Geometry::DimStart[dim], first = 1;
240  g < Geometry::DimStart[dim+1]; g++)
241  {
242  if (!num_elems_by_geom[g]) { continue; }
243  if (!first) { os << " + "; }
244  else { first = 0; }
245  os << num_elems_by_geom[g] << ' ' << Geometry::Name[g] << "(s)";
246  }
247 }
248 
249 void Mesh::PrintCharacteristics(Vector *Vh, Vector *Vk, std::ostream &os)
250 {
251  double h_min, h_max, kappa_min, kappa_max;
252 
253  os << "Mesh Characteristics:";
254 
255  this->GetCharacteristics(h_min, h_max, kappa_min, kappa_max, Vh, Vk);
256 
257  Array<int> num_elems_by_geom(Geometry::NumGeom);
258  num_elems_by_geom = 0;
259  for (int i = 0; i < GetNE(); i++)
260  {
261  num_elems_by_geom[GetElementBaseGeometry(i)]++;
262  }
263 
264  os << '\n'
265  << "Dimension : " << Dimension() << '\n'
266  << "Space dimension : " << SpaceDimension();
267  if (Dim == 0)
268  {
269  os << '\n'
270  << "Number of vertices : " << GetNV() << '\n'
271  << "Number of elements : " << GetNE() << '\n'
272  << "Number of bdr elem : " << GetNBE() << '\n';
273  }
274  else if (Dim == 1)
275  {
276  os << '\n'
277  << "Number of vertices : " << GetNV() << '\n'
278  << "Number of elements : " << GetNE() << '\n'
279  << "Number of bdr elem : " << GetNBE() << '\n'
280  << "h_min : " << h_min << '\n'
281  << "h_max : " << h_max << '\n';
282  }
283  else if (Dim == 2)
284  {
285  os << '\n'
286  << "Number of vertices : " << GetNV() << '\n'
287  << "Number of edges : " << GetNEdges() << '\n'
288  << "Number of elements : " << GetNE() << " -- ";
289  PrintElementsByGeometry(2, num_elems_by_geom, os);
290  os << '\n'
291  << "Number of bdr elem : " << GetNBE() << '\n'
292  << "Euler Number : " << EulerNumber2D() << '\n'
293  << "h_min : " << h_min << '\n'
294  << "h_max : " << h_max << '\n'
295  << "kappa_min : " << kappa_min << '\n'
296  << "kappa_max : " << kappa_max << '\n';
297  }
298  else
299  {
300  Array<int> num_bdr_elems_by_geom(Geometry::NumGeom);
301  num_bdr_elems_by_geom = 0;
302  for (int i = 0; i < GetNBE(); i++)
303  {
304  num_bdr_elems_by_geom[GetBdrElementBaseGeometry(i)]++;
305  }
306  Array<int> num_faces_by_geom(Geometry::NumGeom);
307  num_faces_by_geom = 0;
308  for (int i = 0; i < GetNFaces(); i++)
309  {
310  num_faces_by_geom[GetFaceGeometry(i)]++;
311  }
312 
313  os << '\n'
314  << "Number of vertices : " << GetNV() << '\n'
315  << "Number of edges : " << GetNEdges() << '\n'
316  << "Number of faces : " << GetNFaces() << " -- ";
317  PrintElementsByGeometry(Dim-1, num_faces_by_geom, os);
318  os << '\n'
319  << "Number of elements : " << GetNE() << " -- ";
320  PrintElementsByGeometry(Dim, num_elems_by_geom, os);
321  os << '\n'
322  << "Number of bdr elem : " << GetNBE() << " -- ";
323  PrintElementsByGeometry(Dim-1, num_bdr_elems_by_geom, os);
324  os << '\n'
325  << "Euler Number : " << EulerNumber() << '\n'
326  << "h_min : " << h_min << '\n'
327  << "h_max : " << h_max << '\n'
328  << "kappa_min : " << kappa_min << '\n'
329  << "kappa_max : " << kappa_max << '\n';
330  }
331  os << '\n' << std::flush;
332 }
333 
334 FiniteElement *Mesh::GetTransformationFEforElementType(Element::Type ElemType)
335 {
336  switch (ElemType)
337  {
338  case Element::POINT : return &PointFE;
339  case Element::SEGMENT : return &SegmentFE;
340  case Element::TRIANGLE : return &TriangleFE;
341  case Element::QUADRILATERAL : return &QuadrilateralFE;
342  case Element::TETRAHEDRON : return &TetrahedronFE;
343  case Element::HEXAHEDRON : return &HexahedronFE;
344  case Element::WEDGE : return &WedgeFE;
345  case Element::PYRAMID : return &PyramidFE;
346  default:
347  MFEM_ABORT("Unknown element type \"" << ElemType << "\"");
348  break;
349  }
350  MFEM_ABORT("Unknown element type");
351  return NULL;
352 }
353 
354 
355 void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr)
356 {
357  ElTr->Attribute = GetAttribute(i);
358  ElTr->ElementNo = i;
359  ElTr->ElementType = ElementTransformation::ELEMENT;
360  ElTr->mesh = this;
361  ElTr->Reset();
362  if (Nodes == NULL)
363  {
364  GetPointMatrix(i, ElTr->GetPointMat());
365  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
366  }
367  else
368  {
369  DenseMatrix &pm = ElTr->GetPointMat();
370  Array<int> vdofs;
371  Nodes->FESpace()->GetElementVDofs(i, vdofs);
372  Nodes->HostRead();
373  const GridFunction &nodes = *Nodes;
374  int n = vdofs.Size()/spaceDim;
375  pm.SetSize(spaceDim, n);
376  for (int k = 0; k < spaceDim; k++)
377  {
378  for (int j = 0; j < n; j++)
379  {
380  pm(k,j) = nodes(vdofs[n*k+j]);
381  }
382  }
383  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
384  }
385 }
386 
387 void Mesh::GetElementTransformation(int i, const Vector &nodes,
389 {
390  ElTr->Attribute = GetAttribute(i);
391  ElTr->ElementNo = i;
392  ElTr->ElementType = ElementTransformation::ELEMENT;
393  ElTr->mesh = this;
394  DenseMatrix &pm = ElTr->GetPointMat();
395  ElTr->Reset();
396  nodes.HostRead();
397  if (Nodes == NULL)
398  {
399  MFEM_ASSERT(nodes.Size() == spaceDim*GetNV(), "");
400  int nv = elements[i]->GetNVertices();
401  const int *v = elements[i]->GetVertices();
402  int n = vertices.Size();
403  pm.SetSize(spaceDim, nv);
404  for (int k = 0; k < spaceDim; k++)
405  {
406  for (int j = 0; j < nv; j++)
407  {
408  pm(k, j) = nodes(k*n+v[j]);
409  }
410  }
411  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
412  }
413  else
414  {
415  MFEM_ASSERT(nodes.Size() == Nodes->Size(), "");
416  Array<int> vdofs;
417  Nodes->FESpace()->GetElementVDofs(i, vdofs);
418  int n = vdofs.Size()/spaceDim;
419  pm.SetSize(spaceDim, n);
420  for (int k = 0; k < spaceDim; k++)
421  {
422  for (int j = 0; j < n; j++)
423  {
424  pm(k,j) = nodes(vdofs[n*k+j]);
425  }
426  }
427  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
428  }
429 }
430 
431 ElementTransformation *Mesh::GetElementTransformation(int i)
432 {
433  GetElementTransformation(i, &Transformation);
434 
435  return &Transformation;
436 }
437 
438 ElementTransformation *Mesh::GetBdrElementTransformation(int i)
439 {
440  GetBdrElementTransformation(i, &BdrTransformation);
441  return &BdrTransformation;
442 }
443 
444 void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr)
445 {
446  ElTr->Attribute = GetBdrAttribute(i);
447  ElTr->ElementNo = i; // boundary element number
448  ElTr->ElementType = ElementTransformation::BDR_ELEMENT;
449  ElTr->mesh = this;
450  DenseMatrix &pm = ElTr->GetPointMat();
451  ElTr->Reset();
452  if (Nodes == NULL)
453  {
454  GetBdrPointMatrix(i, pm);
455  ElTr->SetFE(GetTransformationFEforElementType(GetBdrElementType(i)));
456  }
457  else
458  {
459  const FiniteElement *bdr_el = Nodes->FESpace()->GetBE(i);
460  Nodes->HostRead();
461  const GridFunction &nodes = *Nodes;
462  if (bdr_el)
463  {
464  Array<int> vdofs;
465  Nodes->FESpace()->GetBdrElementVDofs(i, vdofs);
466  int n = vdofs.Size()/spaceDim;
467  pm.SetSize(spaceDim, n);
468  for (int k = 0; k < spaceDim; k++)
469  {
470  for (int j = 0; j < n; j++)
471  {
472  pm(k,j) = nodes(vdofs[n*k+j]);
473  }
474  }
475  ElTr->SetFE(bdr_el);
476  }
477  else // L2 Nodes (e.g., periodic mesh)
478  {
479  int elem_id, face_info;
480  GetBdrElementAdjacentElement2(i, elem_id, face_info);
481 
482  GetLocalFaceTransformation(GetBdrElementType(i),
483  GetElementType(elem_id),
484  FaceElemTr.Loc1.Transf, face_info);
485  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
486 
487  Geometry::Type face_geom = GetBdrElementBaseGeometry(i);
488  const FiniteElement *face_el =
489  Nodes->FESpace()->GetTraceElement(elem_id, face_geom);
490  MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
491  "Mesh requires nodal Finite Element.");
492  IntegrationRule eir(face_el->GetDof());
493  FaceElemTr.Loc1.Transf.ElementNo = elem_id;
494  FaceElemTr.Loc1.Transf.mesh = this;
495  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
496  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
497  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
498 
499  ElTr->SetFE(face_el);
500  }
501  }
502 }
503 
504 void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr)
505 {
506  FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute();
507  FTr->ElementNo = FaceNo;
508  FTr->ElementType = ElementTransformation::FACE;
509  FTr->mesh = this;
510  DenseMatrix &pm = FTr->GetPointMat();
511  FTr->Reset();
512  if (Nodes == NULL)
513  {
514  const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
515  const int nv = (Dim == 1) ? 1 : faces[FaceNo]->GetNVertices();
516  pm.SetSize(spaceDim, nv);
517  for (int i = 0; i < spaceDim; i++)
518  {
519  for (int j = 0; j < nv; j++)
520  {
521  pm(i, j) = vertices[v[j]](i);
522  }
523  }
524  FTr->SetFE(GetTransformationFEforElementType(GetFaceElementType(FaceNo)));
525  }
526  else // curved mesh
527  {
528  const FiniteElement *face_el = Nodes->FESpace()->GetFaceElement(FaceNo);
529  Nodes->HostRead();
530  const GridFunction &nodes = *Nodes;
531  if (face_el)
532  {
533  Array<int> vdofs;
534  Nodes->FESpace()->GetFaceVDofs(FaceNo, vdofs);
535  int n = vdofs.Size()/spaceDim;
536  pm.SetSize(spaceDim, n);
537  for (int i = 0; i < spaceDim; i++)
538  {
539  for (int j = 0; j < n; j++)
540  {
541  pm(i, j) = nodes(vdofs[n*i+j]);
542  }
543  }
544  FTr->SetFE(face_el);
545  }
546  else // L2 Nodes (e.g., periodic mesh), go through the volume of Elem1
547  {
548  FaceInfo &face_info = faces_info[FaceNo];
549 
550  Geometry::Type face_geom = GetFaceGeometry(FaceNo);
551  Element::Type face_type = GetFaceElementType(FaceNo);
552 
553  GetLocalFaceTransformation(face_type,
554  GetElementType(face_info.Elem1No),
555  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
556  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
557 
558  face_el = Nodes->FESpace()->GetTraceElement(face_info.Elem1No,
559  face_geom);
560  MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
561  "Mesh requires nodal Finite Element.");
562 
563  IntegrationRule eir(face_el->GetDof());
564  FaceElemTr.Loc1.Transf.ElementNo = face_info.Elem1No;
565  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
566  FaceElemTr.Loc1.Transf.mesh = this;
567  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
568  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
569 
570  FTr->SetFE(face_el);
571  }
572  }
573 }
574 
575 ElementTransformation *Mesh::GetFaceTransformation(int FaceNo)
576 {
577  GetFaceTransformation(FaceNo, &FaceTransformation);
578  return &FaceTransformation;
579 }
580 
581 void Mesh::GetEdgeTransformation(int EdgeNo, IsoparametricTransformation *EdTr)
582 {
583  if (Dim == 2)
584  {
585  GetFaceTransformation(EdgeNo, EdTr);
586  return;
587  }
588  if (Dim == 1)
589  {
590  mfem_error("Mesh::GetEdgeTransformation not defined in 1D \n");
591  }
592 
593  EdTr->Attribute = 1;
594  EdTr->ElementNo = EdgeNo;
595  EdTr->ElementType = ElementTransformation::EDGE;
596  EdTr->mesh = this;
597  DenseMatrix &pm = EdTr->GetPointMat();
598  EdTr->Reset();
599  if (Nodes == NULL)
600  {
601  Array<int> v;
602  GetEdgeVertices(EdgeNo, v);
603  const int nv = 2;
604  pm.SetSize(spaceDim, nv);
605  for (int i = 0; i < spaceDim; i++)
606  {
607  for (int j = 0; j < nv; j++)
608  {
609  pm(i, j) = vertices[v[j]](i);
610  }
611  }
612  EdTr->SetFE(GetTransformationFEforElementType(Element::SEGMENT));
613  }
614  else
615  {
616  const FiniteElement *edge_el = Nodes->FESpace()->GetEdgeElement(EdgeNo);
617  Nodes->HostRead();
618  const GridFunction &nodes = *Nodes;
619  if (edge_el)
620  {
621  Array<int> vdofs;
622  Nodes->FESpace()->GetEdgeVDofs(EdgeNo, vdofs);
623  int n = vdofs.Size()/spaceDim;
624  pm.SetSize(spaceDim, n);
625  for (int i = 0; i < spaceDim; i++)
626  {
627  for (int j = 0; j < n; j++)
628  {
629  pm(i, j) = nodes(vdofs[n*i+j]);
630  }
631  }
632  EdTr->SetFE(edge_el);
633  }
634  else
635  {
636  MFEM_ABORT("Not implemented.");
637  }
638  }
639 }
640 
641 ElementTransformation *Mesh::GetEdgeTransformation(int EdgeNo)
642 {
643  GetEdgeTransformation(EdgeNo, &EdgeTransformation);
644  return &EdgeTransformation;
645 }
646 
647 
648 void Mesh::GetLocalPtToSegTransformation(
649  IsoparametricTransformation &Transf, int i)
650 {
651  const IntegrationRule *SegVert;
652  DenseMatrix &locpm = Transf.GetPointMat();
653  Transf.Reset();
654 
655  Transf.SetFE(&PointFE);
656  SegVert = Geometries.GetVertices(Geometry::SEGMENT);
657  locpm.SetSize(1, 1);
658  locpm(0, 0) = SegVert->IntPoint(i/64).x;
659  // (i/64) is the local face no. in the segment
660  // (i%64) is the orientation of the point (not used)
661 }
662 
663 void Mesh::GetLocalSegToTriTransformation(
664  IsoparametricTransformation &Transf, int i)
665 {
666  const int *tv, *so;
667  const IntegrationRule *TriVert;
668  DenseMatrix &locpm = Transf.GetPointMat();
669  Transf.Reset();
670 
671  Transf.SetFE(&SegmentFE);
672  tv = tri_t::Edges[i/64]; // (i/64) is the local face no. in the triangle
673  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
674  TriVert = Geometries.GetVertices(Geometry::TRIANGLE);
675  locpm.SetSize(2, 2);
676  for (int j = 0; j < 2; j++)
677  {
678  locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x;
679  locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y;
680  }
681 }
682 
683 void Mesh::GetLocalSegToQuadTransformation(
684  IsoparametricTransformation &Transf, int i)
685 {
686  const int *qv, *so;
687  const IntegrationRule *QuadVert;
688  DenseMatrix &locpm = Transf.GetPointMat();
689  Transf.Reset();
690 
691  Transf.SetFE(&SegmentFE);
692  qv = quad_t::Edges[i/64]; // (i/64) is the local face no. in the quad
693  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
694  QuadVert = Geometries.GetVertices(Geometry::SQUARE);
695  locpm.SetSize(2, 2);
696  for (int j = 0; j < 2; j++)
697  {
698  locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x;
699  locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y;
700  }
701 }
702 
703 void Mesh::GetLocalTriToTetTransformation(
704  IsoparametricTransformation &Transf, int i)
705 {
706  DenseMatrix &locpm = Transf.GetPointMat();
707  Transf.Reset();
708 
709  Transf.SetFE(&TriangleFE);
710  // (i/64) is the local face no. in the tet
711  const int *tv = tet_t::FaceVert[i/64];
712  // (i%64) is the orientation of the tetrahedron face
713  // w.r.t. the face element
714  const int *to = tri_t::Orient[i%64];
715  const IntegrationRule *TetVert =
716  Geometries.GetVertices(Geometry::TETRAHEDRON);
717  locpm.SetSize(3, 3);
718  for (int j = 0; j < 3; j++)
719  {
720  const IntegrationPoint &vert = TetVert->IntPoint(tv[to[j]]);
721  locpm(0, j) = vert.x;
722  locpm(1, j) = vert.y;
723  locpm(2, j) = vert.z;
724  }
725 }
726 
727 void Mesh::GetLocalTriToWdgTransformation(
728  IsoparametricTransformation &Transf, int i)
729 {
730  DenseMatrix &locpm = Transf.GetPointMat();
731  Transf.Reset();
732 
733  Transf.SetFE(&TriangleFE);
734  // (i/64) is the local face no. in the pri
735  MFEM_VERIFY(i < 128, "Local face index " << i/64
736  << " is not a triangular face of a wedge.");
737  const int *pv = pri_t::FaceVert[i/64];
738  // (i%64) is the orientation of the wedge face
739  // w.r.t. the face element
740  const int *to = tri_t::Orient[i%64];
741  const IntegrationRule *PriVert =
742  Geometries.GetVertices(Geometry::PRISM);
743  locpm.SetSize(3, 3);
744  for (int j = 0; j < 3; j++)
745  {
746  const IntegrationPoint &vert = PriVert->IntPoint(pv[to[j]]);
747  locpm(0, j) = vert.x;
748  locpm(1, j) = vert.y;
749  locpm(2, j) = vert.z;
750  }
751 }
752 
753 void Mesh::GetLocalTriToPyrTransformation(
754  IsoparametricTransformation &Transf, int i)
755 {
756  DenseMatrix &locpm = Transf.GetPointMat();
757 
758  Transf.SetFE(&TriangleFE);
759  // (i/64) is the local face no. in the pyr
760  MFEM_VERIFY(i >= 64, "Local face index " << i/64
761  << " is not a triangular face of a pyramid.");
762  const int *pv = pyr_t::FaceVert[i/64];
763  // (i%64) is the orientation of the pyramid face
764  // w.r.t. the face element
765  const int *to = tri_t::Orient[i%64];
766  const IntegrationRule *PyrVert =
767  Geometries.GetVertices(Geometry::PYRAMID);
768  locpm.SetSize(3, 3);
769  for (int j = 0; j < 3; j++)
770  {
771  const IntegrationPoint &vert = PyrVert->IntPoint(pv[to[j]]);
772  locpm(0, j) = vert.x;
773  locpm(1, j) = vert.y;
774  locpm(2, j) = vert.z;
775  }
776 }
777 
778 void Mesh::GetLocalQuadToHexTransformation(
779  IsoparametricTransformation &Transf, int i)
780 {
781  DenseMatrix &locpm = Transf.GetPointMat();
782  Transf.Reset();
783 
784  Transf.SetFE(&QuadrilateralFE);
785  // (i/64) is the local face no. in the hex
786  const int *hv = hex_t::FaceVert[i/64];
787  // (i%64) is the orientation of the quad
788  const int *qo = quad_t::Orient[i%64];
789  const IntegrationRule *HexVert = Geometries.GetVertices(Geometry::CUBE);
790  locpm.SetSize(3, 4);
791  for (int j = 0; j < 4; j++)
792  {
793  const IntegrationPoint &vert = HexVert->IntPoint(hv[qo[j]]);
794  locpm(0, j) = vert.x;
795  locpm(1, j) = vert.y;
796  locpm(2, j) = vert.z;
797  }
798 }
799 
800 void Mesh::GetLocalQuadToWdgTransformation(
801  IsoparametricTransformation &Transf, int i)
802 {
803  DenseMatrix &locpm = Transf.GetPointMat();
804  Transf.Reset();
805 
806  Transf.SetFE(&QuadrilateralFE);
807  // (i/64) is the local face no. in the pri
808  MFEM_VERIFY(i >= 128, "Local face index " << i/64
809  << " is not a quadrilateral face of a wedge.");
810  const int *pv = pri_t::FaceVert[i/64];
811  // (i%64) is the orientation of the quad
812  const int *qo = quad_t::Orient[i%64];
813  const IntegrationRule *PriVert = Geometries.GetVertices(Geometry::PRISM);
814  locpm.SetSize(3, 4);
815  for (int j = 0; j < 4; j++)
816  {
817  const IntegrationPoint &vert = PriVert->IntPoint(pv[qo[j]]);
818  locpm(0, j) = vert.x;
819  locpm(1, j) = vert.y;
820  locpm(2, j) = vert.z;
821  }
822 }
823 
824 void Mesh::GetLocalQuadToPyrTransformation(
825  IsoparametricTransformation &Transf, int i)
826 {
827  DenseMatrix &locpm = Transf.GetPointMat();
828 
829  Transf.SetFE(&QuadrilateralFE);
830  // (i/64) is the local face no. in the pyr
831  MFEM_VERIFY(i < 64, "Local face index " << i/64
832  << " is not a quadrilateral face of a pyramid.");
833  const int *pv = pyr_t::FaceVert[i/64];
834  // (i%64) is the orientation of the quad
835  const int *qo = quad_t::Orient[i%64];
836  const IntegrationRule *PyrVert = Geometries.GetVertices(Geometry::PYRAMID);
837  locpm.SetSize(3, 4);
838  for (int j = 0; j < 4; j++)
839  {
840  const IntegrationPoint &vert = PyrVert->IntPoint(pv[qo[j]]);
841  locpm(0, j) = vert.x;
842  locpm(1, j) = vert.y;
843  locpm(2, j) = vert.z;
844  }
845 }
846 
847 const GeometricFactors* Mesh::GetGeometricFactors(const IntegrationRule& ir,
848  const int flags,
849  MemoryType d_mt)
850 {
851  for (int i = 0; i < geom_factors.Size(); i++)
852  {
853  GeometricFactors *gf = geom_factors[i];
854  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags)
855  {
856  return gf;
857  }
858  }
859 
860  this->EnsureNodes();
861 
862  GeometricFactors *gf = new GeometricFactors(this, ir, flags, d_mt);
863  geom_factors.Append(gf);
864  return gf;
865 }
866 
867 const FaceGeometricFactors* Mesh::GetFaceGeometricFactors(
868  const IntegrationRule& ir,
869  const int flags, FaceType type, MemoryType d_mt)
870 {
871  for (int i = 0; i < face_geom_factors.Size(); i++)
872  {
873  FaceGeometricFactors *gf = face_geom_factors[i];
874  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags &&
875  gf->type==type)
876  {
877  return gf;
878  }
879  }
880 
881  this->EnsureNodes();
882 
883  FaceGeometricFactors *gf = new FaceGeometricFactors(this, ir, flags, type,
884  d_mt);
885  face_geom_factors.Append(gf);
886  return gf;
887 }
888 
889 void Mesh::DeleteGeometricFactors()
890 {
891  for (int i = 0; i < geom_factors.Size(); i++)
892  {
893  delete geom_factors[i];
894  }
895  geom_factors.SetSize(0);
896  for (int i = 0; i < face_geom_factors.Size(); i++)
897  {
898  delete face_geom_factors[i];
899  }
900  face_geom_factors.SetSize(0);
901 }
902 
903 void Mesh::GetLocalFaceTransformation(
904  int face_type, int elem_type, IsoparametricTransformation &Transf, int info)
905 {
906  switch (face_type)
907  {
908  case Element::POINT:
909  GetLocalPtToSegTransformation(Transf, info);
910  break;
911 
912  case Element::SEGMENT:
913  if (elem_type == Element::TRIANGLE)
914  {
915  GetLocalSegToTriTransformation(Transf, info);
916  }
917  else
918  {
919  MFEM_ASSERT(elem_type == Element::QUADRILATERAL, "");
920  GetLocalSegToQuadTransformation(Transf, info);
921  }
922  break;
923 
924  case Element::TRIANGLE:
925  if (elem_type == Element::TETRAHEDRON)
926  {
927  GetLocalTriToTetTransformation(Transf, info);
928  }
929  else if (elem_type == Element::WEDGE)
930  {
931  GetLocalTriToWdgTransformation(Transf, info);
932  }
933  else if (elem_type == Element::PYRAMID)
934  {
935  GetLocalTriToPyrTransformation(Transf, info);
936  }
937  else
938  {
939  MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
940  "face type " << face_type
941  << " and element type " << elem_type << "\n");
942  }
943  break;
944 
945  case Element::QUADRILATERAL:
946  if (elem_type == Element::HEXAHEDRON)
947  {
948  GetLocalQuadToHexTransformation(Transf, info);
949  }
950  else if (elem_type == Element::WEDGE)
951  {
952  GetLocalQuadToWdgTransformation(Transf, info);
953  }
954  else if (elem_type == Element::PYRAMID)
955  {
956  GetLocalQuadToPyrTransformation(Transf, info);
957  }
958  else
959  {
960  MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
961  "face type " << face_type
962  << " and element type " << elem_type << "\n");
963  }
964  break;
965  }
966 }
967 
968 FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo,
969  int mask)
970 {
971  FaceInfo &face_info = faces_info[FaceNo];
972 
973  int cmask = 0;
974  FaceElemTr.SetConfigurationMask(cmask);
975  FaceElemTr.Elem1 = NULL;
976  FaceElemTr.Elem2 = NULL;
977 
978  // setup the transformation for the first element
979  FaceElemTr.Elem1No = face_info.Elem1No;
980  if (mask & FaceElementTransformations::HAVE_ELEM1)
981  {
982  GetElementTransformation(FaceElemTr.Elem1No, &Transformation);
983  FaceElemTr.Elem1 = &Transformation;
984  cmask |= 1;
985  }
986 
987  // setup the transformation for the second element
988  // return NULL in the Elem2 field if there's no second element, i.e.
989  // the face is on the "boundary"
990  FaceElemTr.Elem2No = face_info.Elem2No;
991  if ((mask & FaceElementTransformations::HAVE_ELEM2) &&
992  FaceElemTr.Elem2No >= 0)
993  {
994 #ifdef MFEM_DEBUG
995  if (NURBSext && (mask & FaceElementTransformations::HAVE_ELEM1))
996  { MFEM_ABORT("NURBS mesh not supported!"); }
997 #endif
998  GetElementTransformation(FaceElemTr.Elem2No, &Transformation2);
999  FaceElemTr.Elem2 = &Transformation2;
1000  cmask |= 2;
1001  }
1002 
1003  // setup the face transformation
1004  if (mask & FaceElementTransformations::HAVE_FACE)
1005  {
1006  GetFaceTransformation(FaceNo, &FaceElemTr);
1007  cmask |= 16;
1008  }
1009  else
1010  {
1011  FaceElemTr.SetGeometryType(GetFaceGeometry(FaceNo));
1012  }
1013 
1014  // setup Loc1 & Loc2
1015  int face_type = GetFaceElementType(FaceNo);
1016  if (mask & FaceElementTransformations::HAVE_LOC1)
1017  {
1018  int elem_type = GetElementType(face_info.Elem1No);
1019  GetLocalFaceTransformation(face_type, elem_type,
1020  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
1021  cmask |= 4;
1022  }
1023  if ((mask & FaceElementTransformations::HAVE_LOC2) &&
1024  FaceElemTr.Elem2No >= 0)
1025  {
1026  int elem_type = GetElementType(face_info.Elem2No);
1027  GetLocalFaceTransformation(face_type, elem_type,
1028  FaceElemTr.Loc2.Transf, face_info.Elem2Inf);
1029 
1030  // NC meshes: prepend slave edge/face transformation to Loc2
1031  if (Nonconforming() && IsSlaveFace(face_info))
1032  {
1033  ApplyLocalSlaveTransformation(FaceElemTr, face_info, false);
1034  }
1035  cmask |= 8;
1036  }
1037 
1038  FaceElemTr.SetConfigurationMask(cmask);
1039 
1040  // This check can be useful for internal debugging, however it will fail on
1041  // periodic boundary faces, so we keep it disabled in general.
1042 #if 0
1043 #ifdef MFEM_DEBUG
1044  double dist = FaceElemTr.CheckConsistency();
1045  if (dist >= 1e-12)
1046  {
1047  mfem::out << "\nInternal error: face id = " << FaceNo
1048  << ", dist = " << dist << '\n';
1049  FaceElemTr.CheckConsistency(1); // print coordinates
1050  MFEM_ABORT("internal error");
1051  }
1052 #endif
1053 #endif
1054 
1055  return &FaceElemTr;
1056 }
1057 
1058 bool Mesh::IsSlaveFace(const FaceInfo &fi) const
1059 {
1060  return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
1061 }
1062 
1063 void Mesh::ApplyLocalSlaveTransformation(FaceElementTransformations &FT,
1064  const FaceInfo &fi, bool is_ghost)
1065 {
1066 #ifdef MFEM_THREAD_SAFE
1067  DenseMatrix composition;
1068 #else
1069  static DenseMatrix composition;
1070 #endif
1071  MFEM_ASSERT(fi.NCFace >= 0, "");
1072  MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error");
1073  if (!is_ghost)
1074  {
1075  // side 1 -> child side, side 2 -> parent side
1077  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1078  // In 2D, we need to flip the point matrix since it is aligned with the
1079  // parent side.
1080  if (Dim == 2)
1081  {
1082  // swap points (columns) 0 and 1
1083  std::swap(composition(0,0), composition(0,1));
1084  std::swap(composition(1,0), composition(1,1));
1085  }
1086  LT.SetPointMat(composition);
1087  }
1088  else // is_ghost == true
1089  {
1090  // side 1 -> parent side, side 2 -> child side
1092  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1093  // In 2D, there is no need to flip the point matrix since it is already
1094  // aligned with the parent side, see also ParNCMesh::GetFaceNeighbors.
1095  // In 3D the point matrix was flipped during construction in
1096  // ParNCMesh::GetFaceNeighbors and due to that it is already aligned with
1097  // the parent side.
1098  LT.SetPointMat(composition);
1099  }
1100 }
1101 
1102 FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
1103 {
1105  int fn = GetBdrFace(BdrElemNo);
1106 
1107  // Check if the face is interior, shared, or nonconforming.
1108  if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
1109  {
1110  return NULL;
1111  }
1112  tr = GetFaceElementTransformations(fn, 21);
1113  tr->Attribute = boundary[BdrElemNo]->GetAttribute();
1114  tr->ElementNo = BdrElemNo;
1115  tr->ElementType = ElementTransformation::BDR_FACE;
1116  tr->mesh = this;
1117  return tr;
1118 }
1119 
1120 int Mesh::GetBdrFace(int BdrElemNo) const
1121 {
1122  int fn;
1123  if (Dim == 3)
1124  {
1125  fn = be_to_face[BdrElemNo];
1126  }
1127  else if (Dim == 2)
1128  {
1129  fn = be_to_edge[BdrElemNo];
1130  }
1131  else
1132  {
1133  fn = boundary[BdrElemNo]->GetVertices()[0];
1134  }
1135  return fn;
1136 }
1137 
1138 Mesh::FaceInformation Mesh::GetFaceInformation(int f) const
1139 {
1140  FaceInformation face;
1141  int e1, e2;
1142  int inf1, inf2;
1143  int ncface;
1144  GetFaceElements(f, &e1, &e2);
1145  GetFaceInfos(f, &inf1, &inf2, &ncface);
1146  face.element[0].index = e1;
1147  face.element[0].location = ElementLocation::Local;
1148  face.element[0].orientation = inf1%64;
1149  face.element[0].local_face_id = inf1/64;
1150  face.element[1].local_face_id = inf2/64;
1151  face.ncface = ncface;
1152  face.point_matrix = nullptr;
1153  // The following figures out face.location, face.conformity,
1154  // face.element[1].index, and face.element[1].orientation.
1155  if (f < GetNumFaces()) // Non-ghost face
1156  {
1157  if (e2>=0)
1158  {
1159  if (ncface==-1)
1160  {
1161  face.tag = FaceInfoTag::LocalConforming;
1162  face.topology = FaceTopology::Conforming;
1163  face.element[1].location = ElementLocation::Local;
1164  face.element[0].conformity = ElementConformity::Coincident;
1165  face.element[1].conformity = ElementConformity::Coincident;
1166  face.element[1].index = e2;
1167  face.element[1].orientation = inf2%64;
1168  }
1169  else // ncface >= 0
1170  {
1171  face.tag = FaceInfoTag::LocalSlaveNonconforming;
1172  face.topology = FaceTopology::Nonconforming;
1173  face.element[1].location = ElementLocation::Local;
1174  face.element[0].conformity = ElementConformity::Coincident;
1175  face.element[1].conformity = ElementConformity::Superset;
1176  face.element[1].index = e2;
1177  MFEM_ASSERT(inf2%64==0, "unexpected slave face orientation.");
1178  face.element[1].orientation = inf2%64;
1179  face.point_matrix = nc_faces_info[ncface].PointMatrix;
1180  }
1181  }
1182  else // e2<0
1183  {
1184  if (ncface==-1)
1185  {
1186  if (inf2<0)
1187  {
1188  face.tag = FaceInfoTag::Boundary;
1189  face.topology = FaceTopology::Boundary;
1190  face.element[1].location = ElementLocation::NA;
1191  face.element[0].conformity = ElementConformity::Coincident;
1192  face.element[1].conformity = ElementConformity::NA;
1193  face.element[1].index = -1;
1194  face.element[1].orientation = -1;
1195  }
1196  else // inf2 >= 0
1197  {
1198  face.tag = FaceInfoTag::SharedConforming;
1199  face.topology = FaceTopology::Conforming;
1200  face.element[0].conformity = ElementConformity::Coincident;
1201  face.element[1].conformity = ElementConformity::Coincident;
1202  face.element[1].location = ElementLocation::FaceNbr;
1203  face.element[1].index = -1 - e2;
1204  face.element[1].orientation = inf2%64;
1205  }
1206  }
1207  else // ncface >= 0
1208  {
1209  if (inf2 < 0)
1210  {
1211  face.tag = FaceInfoTag::MasterNonconforming;
1212  face.topology = FaceTopology::Nonconforming;
1213  face.element[1].location = ElementLocation::NA;
1214  face.element[0].conformity = ElementConformity::Coincident;
1215  face.element[1].conformity = ElementConformity::Subset;
1216  face.element[1].index = -1;
1217  face.element[1].orientation = -1;
1218  }
1219  else
1220  {
1221  face.tag = FaceInfoTag::SharedSlaveNonconforming;
1222  face.topology = FaceTopology::Nonconforming;
1223  face.element[1].location = ElementLocation::FaceNbr;
1224  face.element[0].conformity = ElementConformity::Coincident;
1225  face.element[1].conformity = ElementConformity::Superset;
1226  face.element[1].index = -1 - e2;
1227  face.element[1].orientation = inf2%64;
1228  }
1229  face.point_matrix = nc_faces_info[ncface].PointMatrix;
1230  }
1231  }
1232  }
1233  else // Ghost face
1234  {
1235  if (e1==-1)
1236  {
1237  face.tag = FaceInfoTag::GhostMaster;
1238  face.topology = FaceTopology::NA;
1239  face.element[1].location = ElementLocation::NA;
1240  face.element[0].conformity = ElementConformity::NA;
1241  face.element[1].conformity = ElementConformity::NA;
1242  face.element[1].index = -1;
1243  face.element[1].orientation = -1;
1244  }
1245  else
1246  {
1247  face.tag = FaceInfoTag::GhostSlave;
1248  face.topology = FaceTopology::Nonconforming;
1249  face.element[1].location = ElementLocation::FaceNbr;
1250  face.element[0].conformity = ElementConformity::Superset;
1251  face.element[1].conformity = ElementConformity::Coincident;
1252  face.element[1].index = -1 - e2;
1253  face.element[1].orientation = inf2%64;
1254  face.point_matrix = nc_faces_info[ncface].PointMatrix;
1255  }
1256  }
1257  return face;
1258 }
1259 
1260 Mesh::FaceInformation::operator Mesh::FaceInfo() const
1261 {
1262  FaceInfo res {-1, -1, -1, -1, -1};
1263  switch (tag)
1264  {
1265  case FaceInfoTag::LocalConforming:
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::LocalSlaveNonconforming:
1273  res.Elem1No = element[0].index;
1274  res.Elem2No = element[1].index;
1275  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1276  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1277  res.NCFace = ncface;
1278  break;
1279  case FaceInfoTag::Boundary:
1280  res.Elem1No = element[0].index;
1281  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1282  break;
1283  case FaceInfoTag::SharedConforming:
1284  res.Elem1No = element[0].index;
1285  res.Elem2No = -1 - element[1].index;
1286  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1287  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1288  break;
1289  case FaceInfoTag::MasterNonconforming:
1290  res.Elem1No = element[0].index;
1291  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1292  break;
1293  case FaceInfoTag::SharedSlaveNonconforming:
1294  res.Elem1No = element[0].index;
1295  res.Elem2No = -1 - element[1].index;
1296  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1297  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1298  break;
1299  case FaceInfoTag::GhostMaster:
1300  break;
1301  case FaceInfoTag::GhostSlave:
1302  res.Elem1No = element[0].index;
1303  res.Elem2No = -1 - element[1].index;
1304  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1305  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1306  break;
1307  }
1308  return res;
1309 }
1310 
1311 std::ostream& operator<<(std::ostream& os, const Mesh::FaceInformation& info)
1312 {
1313  os << "face topology=";
1314  switch (info.topology)
1315  {
1316  case Mesh::FaceTopology::Boundary:
1317  os << "Boundary";
1318  break;
1319  case Mesh::FaceTopology::Conforming:
1320  os << "Conforming";
1321  break;
1322  case Mesh::FaceTopology::Nonconforming:
1323  os << "Non-conforming";
1324  break;
1325  case Mesh::FaceTopology::NA:
1326  os << "NA";
1327  break;
1328  }
1329  os << '\n';
1330  os << "element[0].location=";
1331  switch (info.element[0].location)
1332  {
1333  case Mesh::ElementLocation::Local:
1334  os << "Local";
1335  break;
1336  case Mesh::ElementLocation::FaceNbr:
1337  os << "FaceNbr";
1338  break;
1339  case Mesh::ElementLocation::NA:
1340  os << "NA";
1341  break;
1342  }
1343  os << '\n';
1344  os << "element[1].location=";
1345  switch (info.element[1].location)
1346  {
1347  case Mesh::ElementLocation::Local:
1348  os << "Local";
1349  break;
1350  case Mesh::ElementLocation::FaceNbr:
1351  os << "FaceNbr";
1352  break;
1353  case Mesh::ElementLocation::NA:
1354  os << "NA";
1355  break;
1356  }
1357  os << '\n';
1358  os << "element[0].conformity=";
1359  switch (info.element[0].conformity)
1360  {
1361  case Mesh::ElementConformity::Coincident:
1362  os << "Coincident";
1363  break;
1364  case Mesh::ElementConformity::Superset:
1365  os << "Superset";
1366  break;
1367  case Mesh::ElementConformity::Subset:
1368  os << "Subset";
1369  break;
1370  case Mesh::ElementConformity::NA:
1371  os << "NA";
1372  break;
1373  }
1374  os << '\n';
1375  os << "element[1].conformity=";
1376  switch (info.element[1].conformity)
1377  {
1378  case Mesh::ElementConformity::Coincident:
1379  os << "Coincident";
1380  break;
1381  case Mesh::ElementConformity::Superset:
1382  os << "Superset";
1383  break;
1384  case Mesh::ElementConformity::Subset:
1385  os << "Subset";
1386  break;
1387  case Mesh::ElementConformity::NA:
1388  os << "NA";
1389  break;
1390  }
1391  os << '\n';
1392  os << "element[0].index=" << info.element[0].index << '\n'
1393  << "element[1].index=" << info.element[1].index << '\n'
1394  << "element[0].local_face_id=" << info.element[0].local_face_id << '\n'
1395  << "element[1].local_face_id=" << info.element[1].local_face_id << '\n'
1396  << "element[0].orientation=" << info.element[0].orientation << '\n'
1397  << "element[1].orientation=" << info.element[1].orientation << '\n'
1398  << "ncface=" << info.ncface << std::endl;
1399  return os;
1400 }
1401 
1402 void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2) const
1403 {
1404  *Elem1 = faces_info[Face].Elem1No;
1405  *Elem2 = faces_info[Face].Elem2No;
1406 }
1407 
1408 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const
1409 {
1410  *Inf1 = faces_info[Face].Elem1Inf;
1411  *Inf2 = faces_info[Face].Elem2Inf;
1412 }
1413 
1414 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2, int *NCFace) const
1415 {
1416  *Inf1 = faces_info[Face].Elem1Inf;
1417  *Inf2 = faces_info[Face].Elem2Inf;
1418  *NCFace = faces_info[Face].NCFace;
1419 }
1420 
1421 Geometry::Type Mesh::GetFaceGeometry(int Face) const
1422 {
1423  switch (Dim)
1424  {
1425  case 1: return Geometry::POINT;
1426  case 2: return Geometry::SEGMENT;
1427  case 3:
1428  if (Face < NumOfFaces) // local (non-ghost) face
1429  {
1430  return faces[Face]->GetGeometryType();
1431  }
1432  // ghost face
1433  const int nc_face_id = faces_info[Face].NCFace;
1434  MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported");
1435  return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType();
1436  }
1437  return Geometry::INVALID;
1438 }
1439 
1440 Element::Type Mesh::GetFaceElementType(int Face) const
1441 {
1442  return (Dim == 1) ? Element::POINT : faces[Face]->GetType();
1443 }
1444 
1445 Array<int> Mesh::GetFaceToBdrElMap() const
1446 {
1447  Array<int> face_to_be(Dim == 2 ? NumOfEdges : NumOfFaces);
1448  face_to_be = -1;
1449  for (int i = 0; i < NumOfBdrElements; i++)
1450  {
1451  face_to_be[GetBdrElementEdgeIndex(i)] = i;
1452  }
1453  return face_to_be;
1454 }
1455 
1456 void Mesh::Init()
1457 {
1458  // in order of declaration:
1459  Dim = spaceDim = 0;
1460  NumOfVertices = -1;
1461  NumOfElements = NumOfBdrElements = 0;
1462  NumOfEdges = NumOfFaces = 0;
1463  nbInteriorFaces = -1;
1464  nbBoundaryFaces = -1;
1465  meshgen = mesh_geoms = 0;
1466  sequence = 0;
1467  Nodes = NULL;
1468  own_nodes = 1;
1469  NURBSext = NULL;
1470  ncmesh = NULL;
1471  last_operation = Mesh::NONE;
1472 }
1473 
1474 void Mesh::InitTables()
1475 {
1476  el_to_edge =
1477  el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
1478  face_to_elem = NULL;
1479 }
1480 
1481 void Mesh::SetEmpty()
1482 {
1483  Init();
1484  InitTables();
1485 }
1486 
1487 void Mesh::DestroyTables()
1488 {
1489  delete el_to_edge;
1490  delete el_to_face;
1491  delete el_to_el;
1492  DeleteGeometricFactors();
1493 
1494  if (Dim == 3)
1495  {
1496  delete bel_to_edge;
1497  }
1498 
1499  delete face_edge;
1500  delete edge_vertex;
1501 
1502  delete face_to_elem;
1503  face_to_elem = NULL;
1504 }
1505 
1506 void Mesh::DestroyPointers()
1507 {
1508  if (own_nodes) { delete Nodes; }
1509 
1510  delete ncmesh;
1511 
1512  delete NURBSext;
1513 
1514  for (int i = 0; i < NumOfElements; i++)
1515  {
1516  FreeElement(elements[i]);
1517  }
1518 
1519  for (int i = 0; i < NumOfBdrElements; i++)
1520  {
1521  FreeElement(boundary[i]);
1522  }
1523 
1524  for (int i = 0; i < faces.Size(); i++)
1525  {
1526  FreeElement(faces[i]);
1527  }
1528 
1529  DestroyTables();
1530 }
1531 
1532 void Mesh::Destroy()
1533 {
1534  DestroyPointers();
1535 
1536  elements.DeleteAll();
1537  vertices.DeleteAll();
1538  boundary.DeleteAll();
1539  faces.DeleteAll();
1540  faces_info.DeleteAll();
1541  nc_faces_info.DeleteAll();
1542  be_to_edge.DeleteAll();
1543  be_to_face.DeleteAll();
1544 
1545  // TODO:
1546  // IsoparametricTransformations
1547  // Transformation, Transformation2, BdrTransformation, FaceTransformation,
1548  // EdgeTransformation;
1549  // FaceElementTransformations FaceElemTr;
1550 
1551  CoarseFineTr.Clear();
1552 
1553 #ifdef MFEM_USE_MEMALLOC
1554  TetMemory.Clear();
1555 #endif
1556 
1557  attributes.DeleteAll();
1558  bdr_attributes.DeleteAll();
1559 }
1560 
1561 void Mesh::ResetLazyData()
1562 {
1563  delete el_to_el; el_to_el = NULL;
1564  delete face_edge; face_edge = NULL;
1565  delete face_to_elem; face_to_elem = NULL;
1566  delete edge_vertex; edge_vertex = NULL;
1567  DeleteGeometricFactors();
1568  nbInteriorFaces = -1;
1569  nbBoundaryFaces = -1;
1570 }
1571 
1572 void Mesh::SetAttributes()
1573 {
1574  Array<int> attribs;
1575 
1576  attribs.SetSize(GetNBE());
1577  for (int i = 0; i < attribs.Size(); i++)
1578  {
1579  attribs[i] = GetBdrAttribute(i);
1580  }
1581  attribs.Sort();
1582  attribs.Unique();
1583  attribs.Copy(bdr_attributes);
1584  if (bdr_attributes.Size() > 0 && bdr_attributes[0] <= 0)
1585  {
1586  MFEM_WARNING("Non-positive attributes on the boundary!");
1587  }
1588 
1589  attribs.SetSize(GetNE());
1590  for (int i = 0; i < attribs.Size(); i++)
1591  {
1592  attribs[i] = GetAttribute(i);
1593  }
1594  attribs.Sort();
1595  attribs.Unique();
1596  attribs.Copy(attributes);
1597  if (attributes.Size() > 0 && attributes[0] <= 0)
1598  {
1599  MFEM_WARNING("Non-positive attributes in the domain!");
1600  }
1601 }
1602 
1603 void Mesh::InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
1604 {
1605  SetEmpty();
1606 
1607  Dim = Dim_;
1608  spaceDim = spaceDim_;
1609 
1610  NumOfVertices = 0;
1611  vertices.SetSize(NVert); // just allocate space for vertices
1612 
1613  NumOfElements = 0;
1614  elements.SetSize(NElem); // just allocate space for Element *
1615 
1616  NumOfBdrElements = 0;
1617  boundary.SetSize(NBdrElem); // just allocate space for Element *
1618 }
1619 
1620 template<typename T>
1621 static void CheckEnlarge(Array<T> &array, int size)
1622 {
1623  if (size >= array.Size()) { array.SetSize(size + 1); }
1624 }
1625 
1626 int Mesh::AddVertex(double x, double y, double z)
1627 {
1628  CheckEnlarge(vertices, NumOfVertices);
1629  double *v = vertices[NumOfVertices]();
1630  v[0] = x;
1631  v[1] = y;
1632  v[2] = z;
1633  return NumOfVertices++;
1634 }
1635 
1636 int Mesh::AddVertex(const double *coords)
1637 {
1638  CheckEnlarge(vertices, NumOfVertices);
1639  vertices[NumOfVertices].SetCoords(spaceDim, coords);
1640  return NumOfVertices++;
1641 }
1642 
1643 int Mesh::AddVertex(const Vector &coords)
1644 {
1645  MFEM_ASSERT(coords.Size() >= spaceDim,
1646  "invalid 'coords' size: " << coords.Size());
1647  return AddVertex(coords.GetData());
1648 }
1649 
1650 void Mesh::AddVertexParents(int i, int p1, int p2)
1651 {
1652  tmp_vertex_parents.Append(Triple<int, int, int>(i, p1, p2));
1653 
1654  // if vertex coordinates are defined, make sure the hanging vertex has the
1655  // correct position
1656  if (i < vertices.Size())
1657  {
1658  double *vi = vertices[i](), *vp1 = vertices[p1](), *vp2 = vertices[p2]();
1659  for (int j = 0; j < 3; j++)
1660  {
1661  vi[j] = (vp1[j] + vp2[j]) * 0.5;
1662  }
1663  }
1664 }
1665 
1666 int Mesh::AddSegment(int v1, int v2, int attr)
1667 {
1668  CheckEnlarge(elements, NumOfElements);
1669  elements[NumOfElements] = new Segment(v1, v2, attr);
1670  return NumOfElements++;
1671 }
1672 
1673 int Mesh::AddSegment(const int *vi, int attr)
1674 {
1675  CheckEnlarge(elements, NumOfElements);
1676  elements[NumOfElements] = new Segment(vi, attr);
1677  return NumOfElements++;
1678 }
1679 
1680 int Mesh::AddTriangle(int v1, int v2, int v3, int attr)
1681 {
1682  CheckEnlarge(elements, NumOfElements);
1683  elements[NumOfElements] = new Triangle(v1, v2, v3, attr);
1684  return NumOfElements++;
1685 }
1686 
1687 int Mesh::AddTriangle(const int *vi, int attr)
1688 {
1689  CheckEnlarge(elements, NumOfElements);
1690  elements[NumOfElements] = new Triangle(vi, attr);
1691  return NumOfElements++;
1692 }
1693 
1694 int Mesh::AddQuad(int v1, int v2, int v3, int v4, int attr)
1695 {
1696  CheckEnlarge(elements, NumOfElements);
1697  elements[NumOfElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1698  return NumOfElements++;
1699 }
1700 
1701 int Mesh::AddQuad(const int *vi, int attr)
1702 {
1703  CheckEnlarge(elements, NumOfElements);
1704  elements[NumOfElements] = new Quadrilateral(vi, attr);
1705  return NumOfElements++;
1706 }
1707 
1708 int Mesh::AddTet(int v1, int v2, int v3, int v4, int attr)
1709 {
1710  int vi[4] = {v1, v2, v3, v4};
1711  return AddTet(vi, attr);
1712 }
1713 
1714 int Mesh::AddTet(const int *vi, int attr)
1715 {
1716  CheckEnlarge(elements, NumOfElements);
1717 #ifdef MFEM_USE_MEMALLOC
1718  Tetrahedron *tet;
1719  tet = TetMemory.Alloc();
1720  tet->SetVertices(vi);
1721  tet->SetAttribute(attr);
1722  elements[NumOfElements] = tet;
1723 #else
1724  elements[NumOfElements] = new Tetrahedron(vi, attr);
1725 #endif
1726  return NumOfElements++;
1727 }
1728 
1729 int Mesh::AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr)
1730 {
1731  CheckEnlarge(elements, NumOfElements);
1732  elements[NumOfElements] = new Wedge(v1, v2, v3, v4, v5, v6, attr);
1733  return NumOfElements++;
1734 }
1735 
1736 int Mesh::AddWedge(const int *vi, int attr)
1737 {
1738  CheckEnlarge(elements, NumOfElements);
1739  elements[NumOfElements] = new Wedge(vi, attr);
1740  return NumOfElements++;
1741 }
1742 
1743 int Mesh::AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr)
1744 {
1745  CheckEnlarge(elements, NumOfElements);
1746  elements[NumOfElements] = new Pyramid(v1, v2, v3, v4, v5, attr);
1747  return NumOfElements++;
1748 }
1749 
1750 int Mesh::AddPyramid(const int *vi, int attr)
1751 {
1752  CheckEnlarge(elements, NumOfElements);
1753  elements[NumOfElements] = new Pyramid(vi, attr);
1754  return NumOfElements++;
1755 }
1756 
1757 int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
1758  int attr)
1759 {
1760  CheckEnlarge(elements, NumOfElements);
1761  elements[NumOfElements] =
1762  new Hexahedron(v1, v2, v3, v4, v5, v6, v7, v8, attr);
1763  return NumOfElements++;
1764 }
1765 
1766 int Mesh::AddHex(const int *vi, int attr)
1767 {
1768  CheckEnlarge(elements, NumOfElements);
1769  elements[NumOfElements] = new Hexahedron(vi, attr);
1770  return NumOfElements++;
1771 }
1772 
1773 void Mesh::AddHexAsTets(const int *vi, int attr)
1774 {
1775  static const int hex_to_tet[6][4] =
1776  {
1777  { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
1778  { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
1779  };
1780  int ti[4];
1781 
1782  for (int i = 0; i < 6; i++)
1783  {
1784  for (int j = 0; j < 4; j++)
1785  {
1786  ti[j] = vi[hex_to_tet[i][j]];
1787  }
1788  AddTet(ti, attr);
1789  }
1790 }
1791 
1792 void Mesh::AddHexAsWedges(const int *vi, int attr)
1793 {
1794  static const int hex_to_wdg[2][6] =
1795  {
1796  { 0, 1, 2, 4, 5, 6 }, { 0, 2, 3, 4, 6, 7 }
1797  };
1798  int ti[6];
1799 
1800  for (int i = 0; i < 2; i++)
1801  {
1802  for (int j = 0; j < 6; j++)
1803  {
1804  ti[j] = vi[hex_to_wdg[i][j]];
1805  }
1806  AddWedge(ti, attr);
1807  }
1808 }
1809 
1810 void Mesh::AddHexAsPyramids(const int *vi, int attr)
1811 {
1812  static const int hex_to_pyr[6][5] =
1813  {
1814  { 0, 1, 2, 3, 8 }, { 0, 4, 5, 1, 8 }, { 1, 5, 6, 2, 8 },
1815  { 2, 6, 7, 3, 8 }, { 3, 7, 4, 0, 8 }, { 7, 6, 5, 4, 8 }
1816  };
1817  int ti[5];
1818 
1819  for (int i = 0; i < 6; i++)
1820  {
1821  for (int j = 0; j < 5; j++)
1822  {
1823  ti[j] = vi[hex_to_pyr[i][j]];
1824  }
1825  AddPyramid(ti, attr);
1826  }
1827 }
1828 
1829 int Mesh::AddElement(Element *elem)
1830 {
1831  CheckEnlarge(elements, NumOfElements);
1832  elements[NumOfElements] = elem;
1833  return NumOfElements++;
1834 }
1835 
1836 int Mesh::AddBdrElement(Element *elem)
1837 {
1838  CheckEnlarge(boundary, NumOfBdrElements);
1839  boundary[NumOfBdrElements] = elem;
1840  return NumOfBdrElements++;
1841 }
1842 
1843 int Mesh::AddBdrSegment(int v1, int v2, int attr)
1844 {
1845  CheckEnlarge(boundary, NumOfBdrElements);
1846  boundary[NumOfBdrElements] = new Segment(v1, v2, attr);
1847  return NumOfBdrElements++;
1848 }
1849 
1850 int Mesh::AddBdrSegment(const int *vi, int attr)
1851 {
1852  CheckEnlarge(boundary, NumOfBdrElements);
1853  boundary[NumOfBdrElements] = new Segment(vi, attr);
1854  return NumOfBdrElements++;
1855 }
1856 
1857 int Mesh::AddBdrTriangle(int v1, int v2, int v3, int attr)
1858 {
1859  CheckEnlarge(boundary, NumOfBdrElements);
1860  boundary[NumOfBdrElements] = new Triangle(v1, v2, v3, attr);
1861  return NumOfBdrElements++;
1862 }
1863 
1864 int Mesh::AddBdrTriangle(const int *vi, int attr)
1865 {
1866  CheckEnlarge(boundary, NumOfBdrElements);
1867  boundary[NumOfBdrElements] = new Triangle(vi, attr);
1868  return NumOfBdrElements++;
1869 }
1870 
1871 int Mesh::AddBdrQuad(int v1, int v2, int v3, int v4, int attr)
1872 {
1873  CheckEnlarge(boundary, NumOfBdrElements);
1874  boundary[NumOfBdrElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1875  return NumOfBdrElements++;
1876 }
1877 
1878 int Mesh::AddBdrQuad(const int *vi, int attr)
1879 {
1880  CheckEnlarge(boundary, NumOfBdrElements);
1881  boundary[NumOfBdrElements] = new Quadrilateral(vi, attr);
1882  return NumOfBdrElements++;
1883 }
1884 
1885 void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
1886 {
1887  static const int quad_to_tri[2][3] = { { 0, 1, 2 }, { 0, 2, 3 } };
1888  int ti[3];
1889 
1890  for (int i = 0; i < 2; i++)
1891  {
1892  for (int j = 0; j < 3; j++)
1893  {
1894  ti[j] = vi[quad_to_tri[i][j]];
1895  }
1896  AddBdrTriangle(ti, attr);
1897  }
1898 }
1899 
1900 int Mesh::AddBdrPoint(int v, int attr)
1901 {
1902  CheckEnlarge(boundary, NumOfBdrElements);
1903  boundary[NumOfBdrElements] = new Point(&v, attr);
1904  return NumOfBdrElements++;
1905 }
1906 
1907 void Mesh::GenerateBoundaryElements()
1908 {
1909  int i, j;
1910  Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
1911 
1912  // GenerateFaces();
1913 
1914  for (i = 0; i < boundary.Size(); i++)
1915  {
1916  FreeElement(boundary[i]);
1917  }
1918 
1919  if (Dim == 3)
1920  {
1921  delete bel_to_edge;
1922  bel_to_edge = NULL;
1923  }
1924 
1925  // count the 'NumOfBdrElements'
1926  NumOfBdrElements = 0;
1927  for (i = 0; i < faces_info.Size(); i++)
1928  {
1929  if (faces_info[i].Elem2No < 0) { NumOfBdrElements++; }
1930  }
1931 
1932  boundary.SetSize(NumOfBdrElements);
1933  be2face.SetSize(NumOfBdrElements);
1934  for (j = i = 0; i < faces_info.Size(); i++)
1935  {
1936  if (faces_info[i].Elem2No < 0)
1937  {
1938  boundary[j] = faces[i]->Duplicate(this);
1939  be2face[j++] = i;
1940  }
1941  }
1942  // In 3D, 'bel_to_edge' is destroyed but it's not updated.
1943 }
1944 
1945 void Mesh::FinalizeCheck()
1946 {
1947  MFEM_VERIFY(vertices.Size() == NumOfVertices ||
1948  vertices.Size() == 0,
1949  "incorrect number of vertices: preallocated: " << vertices.Size()
1950  << ", actually added: " << NumOfVertices);
1951  MFEM_VERIFY(elements.Size() == NumOfElements,
1952  "incorrect number of elements: preallocated: " << elements.Size()
1953  << ", actually added: " << NumOfElements);
1954  MFEM_VERIFY(boundary.Size() == NumOfBdrElements,
1955  "incorrect number of boundary elements: preallocated: "
1956  << boundary.Size() << ", actually added: " << NumOfBdrElements);
1957 }
1958 
1959 void Mesh::FinalizeTriMesh(int generate_edges, int refine, bool fix_orientation)
1960 {
1961  FinalizeCheck();
1962  CheckElementOrientation(fix_orientation);
1963 
1964  if (refine)
1965  {
1966  MarkTriMeshForRefinement();
1967  }
1968 
1969  if (generate_edges)
1970  {
1971  el_to_edge = new Table;
1972  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1973  GenerateFaces();
1974  CheckBdrElementOrientation();
1975  }
1976  else
1977  {
1978  NumOfEdges = 0;
1979  }
1980 
1981  NumOfFaces = 0;
1982 
1983  SetAttributes();
1984 
1985  SetMeshGen();
1986 }
1987 
1988 void Mesh::FinalizeQuadMesh(int generate_edges, int refine,
1989  bool fix_orientation)
1990 {
1991  FinalizeCheck();
1992  if (fix_orientation)
1993  {
1994  CheckElementOrientation(fix_orientation);
1995  }
1996 
1997  if (generate_edges)
1998  {
1999  el_to_edge = new Table;
2000  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2001  GenerateFaces();
2002  CheckBdrElementOrientation();
2003  }
2004  else
2005  {
2006  NumOfEdges = 0;
2007  }
2008 
2009  NumOfFaces = 0;
2010 
2011  SetAttributes();
2012 
2013  SetMeshGen();
2014 }
2015 
2016 
2017 class GeckoProgress : public Gecko::Progress
2018 {
2019  double limit;
2020  mutable StopWatch sw;
2021 public:
2022  GeckoProgress(double limit) : limit(limit) { sw.Start(); }
2023  virtual bool quit() const { return limit > 0 && sw.UserTime() > limit; }
2024 };
2025 
2026 class GeckoVerboseProgress : public GeckoProgress
2027 {
2028  using Float = Gecko::Float;
2029  using Graph = Gecko::Graph;
2030  using uint = Gecko::uint;
2031 public:
2032  GeckoVerboseProgress(double limit) : GeckoProgress(limit) {}
2033 
2034  virtual void beginorder(const Graph* graph, Float cost) const
2035  { mfem::out << "Begin Gecko ordering, cost = " << cost << std::endl; }
2036  virtual void endorder(const Graph* graph, Float cost) const
2037  { mfem::out << "End ordering, cost = " << cost << std::endl; }
2038 
2039  virtual void beginiter(const Graph* graph,
2040  uint iter, uint maxiter, uint window) const
2041  {
2042  mfem::out << "Iteration " << iter << "/" << maxiter << ", window "
2043  << window << std::flush;
2044  }
2045  virtual void enditer(const Graph* graph, Float mincost, Float cost) const
2046  { mfem::out << ", cost = " << cost << endl; }
2047 };
2048 
2049 
2050 double Mesh::GetGeckoElementOrdering(Array<int> &ordering,
2051  int iterations, int window,
2052  int period, int seed, bool verbose,
2053  double time_limit)
2054 {
2055  Gecko::Graph graph;
2056  Gecko::FunctionalGeometric functional; // edge product cost
2057 
2058  GeckoProgress progress(time_limit);
2059  GeckoVerboseProgress vprogress(time_limit);
2060 
2061  // insert elements as nodes in the graph
2062  for (int elemid = 0; elemid < GetNE(); ++elemid)
2063  {
2064  graph.insert_node();
2065  }
2066 
2067  // insert graph edges for element neighbors
2068  // NOTE: indices in Gecko are 1 based hence the +1 on insertion
2069  const Table &my_el_to_el = ElementToElementTable();
2070  for (int elemid = 0; elemid < GetNE(); ++elemid)
2071  {
2072  const int *neighid = my_el_to_el.GetRow(elemid);
2073  for (int i = 0; i < my_el_to_el.RowSize(elemid); ++i)
2074  {
2075  graph.insert_arc(elemid + 1, neighid[i] + 1);
2076  }
2077  }
2078 
2079  // get the ordering from Gecko and copy it into the Array<int>
2080  graph.order(&functional, iterations, window, period, seed,
2081  verbose ? &vprogress : &progress);
2082 
2083  ordering.SetSize(GetNE());
2084  Gecko::Node::Index NE = GetNE();
2085  for (Gecko::Node::Index gnodeid = 1; gnodeid <= NE; ++gnodeid)
2086  {
2087  ordering[gnodeid - 1] = graph.rank(gnodeid);
2088  }
2089 
2090  return graph.cost();
2091 }
2092 
2093 
2094 struct HilbertCmp
2095 {
2096  int coord;
2097  bool dir;
2098  const Array<double> &points;
2099  double mid;
2100 
2101  HilbertCmp(int coord, bool dir, const Array<double> &points, double mid)
2102  : coord(coord), dir(dir), points(points), mid(mid) {}
2103 
2104  bool operator()(int i) const
2105  {
2106  return (points[3*i + coord] < mid) != dir;
2107  }
2108 };
2109 
2110 static void HilbertSort2D(int coord1, // major coordinate to sort points by
2111  bool dir1, // sort coord1 ascending/descending?
2112  bool dir2, // sort coord2 ascending/descending?
2113  const Array<double> &points, int *beg, int *end,
2114  double xmin, double ymin, double xmax, double ymax)
2115 {
2116  if (end - beg <= 1) { return; }
2117 
2118  double xmid = (xmin + xmax)*0.5;
2119  double ymid = (ymin + ymax)*0.5;
2120 
2121  int coord2 = (coord1 + 1) % 2; // the 'other' coordinate
2122 
2123  // sort (partition) points into four quadrants
2124  int *p0 = beg, *p4 = end;
2125  int *p2 = std::partition(p0, p4, HilbertCmp(coord1, dir1, points, xmid));
2126  int *p1 = std::partition(p0, p2, HilbertCmp(coord2, dir2, points, ymid));
2127  int *p3 = std::partition(p2, p4, HilbertCmp(coord2, !dir2, points, ymid));
2128 
2129  if (p1 != p4)
2130  {
2131  HilbertSort2D(coord2, dir2, dir1, points, p0, p1,
2132  ymin, xmin, ymid, xmid);
2133  }
2134  if (p1 != p0 || p2 != p4)
2135  {
2136  HilbertSort2D(coord1, dir1, dir2, points, p1, p2,
2137  xmin, ymid, xmid, ymax);
2138  }
2139  if (p2 != p0 || p3 != p4)
2140  {
2141  HilbertSort2D(coord1, dir1, dir2, points, p2, p3,
2142  xmid, ymid, xmax, ymax);
2143  }
2144  if (p3 != p0)
2145  {
2146  HilbertSort2D(coord2, !dir2, !dir1, points, p3, p4,
2147  ymid, xmax, ymin, xmid);
2148  }
2149 }
2150 
2151 static void HilbertSort3D(int coord1, bool dir1, bool dir2, bool dir3,
2152  const Array<double> &points, int *beg, int *end,
2153  double xmin, double ymin, double zmin,
2154  double xmax, double ymax, double zmax)
2155 {
2156  if (end - beg <= 1) { return; }
2157 
2158  double xmid = (xmin + xmax)*0.5;
2159  double ymid = (ymin + ymax)*0.5;
2160  double zmid = (zmin + zmax)*0.5;
2161 
2162  int coord2 = (coord1 + 1) % 3;
2163  int coord3 = (coord1 + 2) % 3;
2164 
2165  // sort (partition) points into eight octants
2166  int *p0 = beg, *p8 = end;
2167  int *p4 = std::partition(p0, p8, HilbertCmp(coord1, dir1, points, xmid));
2168  int *p2 = std::partition(p0, p4, HilbertCmp(coord2, dir2, points, ymid));
2169  int *p6 = std::partition(p4, p8, HilbertCmp(coord2, !dir2, points, ymid));
2170  int *p1 = std::partition(p0, p2, HilbertCmp(coord3, dir3, points, zmid));
2171  int *p3 = std::partition(p2, p4, HilbertCmp(coord3, !dir3, points, zmid));
2172  int *p5 = std::partition(p4, p6, HilbertCmp(coord3, dir3, points, zmid));
2173  int *p7 = std::partition(p6, p8, HilbertCmp(coord3, !dir3, points, zmid));
2174 
2175  if (p1 != p8)
2176  {
2177  HilbertSort3D(coord3, dir3, dir1, dir2, points, p0, p1,
2178  zmin, xmin, ymin, zmid, xmid, ymid);
2179  }
2180  if (p1 != p0 || p2 != p8)
2181  {
2182  HilbertSort3D(coord2, dir2, dir3, dir1, points, p1, p2,
2183  ymin, zmid, xmin, ymid, zmax, xmid);
2184  }
2185  if (p2 != p0 || p3 != p8)
2186  {
2187  HilbertSort3D(coord2, dir2, dir3, dir1, points, p2, p3,
2188  ymid, zmid, xmin, ymax, zmax, xmid);
2189  }
2190  if (p3 != p0 || p4 != p8)
2191  {
2192  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p3, p4,
2193  xmin, ymax, zmid, xmid, ymid, zmin);
2194  }
2195  if (p4 != p0 || p5 != p8)
2196  {
2197  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p4, p5,
2198  xmid, ymax, zmid, xmax, ymid, zmin);
2199  }
2200  if (p5 != p0 || p6 != p8)
2201  {
2202  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p5, p6,
2203  ymax, zmid, xmax, ymid, zmax, xmid);
2204  }
2205  if (p6 != p0 || p7 != p8)
2206  {
2207  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p6, p7,
2208  ymid, zmid, xmax, ymin, zmax, xmid);
2209  }
2210  if (p7 != p0)
2211  {
2212  HilbertSort3D(coord3, !dir3, !dir1, dir2, points, p7, p8,
2213  zmid, xmax, ymin, zmin, xmid, ymid);
2214  }
2215 }
2216 
2217 void Mesh::GetHilbertElementOrdering(Array<int> &ordering)
2218 {
2219  MFEM_VERIFY(spaceDim <= 3, "");
2220 
2221  Vector min, max, center;
2222  GetBoundingBox(min, max);
2223 
2224  Array<int> indices(GetNE());
2225  Array<double> points(3*GetNE());
2226 
2227  if (spaceDim < 3) { points = 0.0; }
2228 
2229  // calculate element centers
2230  for (int i = 0; i < GetNE(); i++)
2231  {
2232  GetElementCenter(i, center);
2233  for (int j = 0; j < spaceDim; j++)
2234  {
2235  points[3*i + j] = center(j);
2236  }
2237  indices[i] = i;
2238  }
2239 
2240  if (spaceDim == 1)
2241  {
2242  indices.Sort([&](int a, int b)
2243  { return points[3*a] < points[3*b]; });
2244  }
2245  else if (spaceDim == 2)
2246  {
2247  // recursively partition the points in 2D
2248  HilbertSort2D(0, false, false,
2249  points, indices.begin(), indices.end(),
2250  min(0), min(1), max(0), max(1));
2251  }
2252  else
2253  {
2254  // recursively partition the points in 3D
2255  HilbertSort3D(0, false, false, false,
2256  points, indices.begin(), indices.end(),
2257  min(0), min(1), min(2), max(0), max(1), max(2));
2258  }
2259 
2260  // return ordering in the format required by ReorderElements
2261  ordering.SetSize(GetNE());
2262  for (int i = 0; i < GetNE(); i++)
2263  {
2264  ordering[indices[i]] = i;
2265  }
2266 }
2267 
2268 
2269 void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
2270 {
2271  if (NURBSext)
2272  {
2273  MFEM_WARNING("element reordering of NURBS meshes is not supported.");
2274  return;
2275  }
2276  if (ncmesh)
2277  {
2278  MFEM_WARNING("element reordering of non-conforming meshes is not"
2279  " supported.");
2280  return;
2281  }
2282  MFEM_VERIFY(ordering.Size() == GetNE(), "invalid reordering array.")
2283 
2284  // Data members that need to be updated:
2285 
2286  // - elements - reorder of the pointers and the vertex ids if reordering
2287  // the vertices
2288  // - vertices - if reordering the vertices
2289  // - boundary - update the vertex ids, if reordering the vertices
2290  // - faces - regenerate
2291  // - faces_info - regenerate
2292 
2293  // Deleted by DeleteTables():
2294  // - el_to_edge - rebuild in 2D and 3D only
2295  // - el_to_face - rebuild in 3D only
2296  // - bel_to_edge - rebuild in 3D only
2297  // - el_to_el - no need to rebuild
2298  // - face_edge - no need to rebuild
2299  // - edge_vertex - no need to rebuild
2300  // - geom_factors - no need to rebuild
2301 
2302  // - be_to_edge - 2D only
2303  // - be_to_face - 3D only
2304 
2305  // - Nodes
2306 
2307  // Save the locations of the Nodes so we can rebuild them later
2308  Array<Vector*> old_elem_node_vals;
2309  FiniteElementSpace *nodes_fes = NULL;
2310  if (Nodes)
2311  {
2312  old_elem_node_vals.SetSize(GetNE());
2313  nodes_fes = Nodes->FESpace();
2314  Array<int> old_dofs;
2315  Vector vals;
2316  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2317  {
2318  nodes_fes->GetElementVDofs(old_elid, old_dofs);
2319  Nodes->GetSubVector(old_dofs, vals);
2320  old_elem_node_vals[old_elid] = new Vector(vals);
2321  }
2322  }
2323 
2324  // Get the newly ordered elements
2325  Array<Element *> new_elements(GetNE());
2326  for (int old_elid = 0; old_elid < ordering.Size(); ++old_elid)
2327  {
2328  int new_elid = ordering[old_elid];
2329  new_elements[new_elid] = elements[old_elid];
2330  }
2331  mfem::Swap(elements, new_elements);
2332  new_elements.DeleteAll();
2333 
2334  if (reorder_vertices)
2335  {
2336  // Get the new vertex ordering permutation vectors and fill the new
2337  // vertices
2338  Array<int> vertex_ordering(GetNV());
2339  vertex_ordering = -1;
2340  Array<Vertex> new_vertices(GetNV());
2341  int new_vertex_ind = 0;
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  int old_vertex_ind = elem_vert[vi];
2349  if (vertex_ordering[old_vertex_ind] == -1)
2350  {
2351  vertex_ordering[old_vertex_ind] = new_vertex_ind;
2352  new_vertices[new_vertex_ind] = vertices[old_vertex_ind];
2353  new_vertex_ind++;
2354  }
2355  }
2356  }
2357  mfem::Swap(vertices, new_vertices);
2358  new_vertices.DeleteAll();
2359 
2360  // Replace the vertex ids in the elements with the reordered vertex
2361  // numbers
2362  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2363  {
2364  int *elem_vert = elements[new_elid]->GetVertices();
2365  int nv = elements[new_elid]->GetNVertices();
2366  for (int vi = 0; vi < nv; ++vi)
2367  {
2368  elem_vert[vi] = vertex_ordering[elem_vert[vi]];
2369  }
2370  }
2371 
2372  // Replace the vertex ids in the boundary with reordered vertex numbers
2373  for (int belid = 0; belid < GetNBE(); ++belid)
2374  {
2375  int *be_vert = boundary[belid]->GetVertices();
2376  int nv = boundary[belid]->GetNVertices();
2377  for (int vi = 0; vi < nv; ++vi)
2378  {
2379  be_vert[vi] = vertex_ordering[be_vert[vi]];
2380  }
2381  }
2382  }
2383 
2384  // Destroy tables that need to be rebuild
2385  DeleteTables();
2386 
2387  if (Dim > 1)
2388  {
2389  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
2390  el_to_edge = new Table;
2391  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2392  }
2393  if (Dim > 2)
2394  {
2395  // generate el_to_face, be_to_face
2396  GetElementToFaceTable();
2397  }
2398  // Update faces and faces_info
2399  GenerateFaces();
2400 
2401  // Build the nodes from the saved locations if they were around before
2402  if (Nodes)
2403  {
2404  // To force FE space update, we need to increase 'sequence':
2405  sequence++;
2406  last_operation = Mesh::NONE;
2407  nodes_fes->Update(false); // want_transform = false
2408  Nodes->Update(); // just needed to update Nodes->sequence
2409  Array<int> new_dofs;
2410  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2411  {
2412  int new_elid = ordering[old_elid];
2413  nodes_fes->GetElementVDofs(new_elid, new_dofs);
2414  Nodes->SetSubVector(new_dofs, *(old_elem_node_vals[old_elid]));
2415  delete old_elem_node_vals[old_elid];
2416  }
2417  }
2418 }
2419 
2420 
2421 void Mesh::MarkForRefinement()
2422 {
2423  if (meshgen & 1)
2424  {
2425  if (Dim == 2)
2426  {
2427  MarkTriMeshForRefinement();
2428  }
2429  else if (Dim == 3)
2430  {
2431  DSTable v_to_v(NumOfVertices);
2432  GetVertexToVertexTable(v_to_v);
2433  MarkTetMeshForRefinement(v_to_v);
2434  }
2435  }
2436 }
2437 
2438 void Mesh::MarkTriMeshForRefinement()
2439 {
2440  // Mark the longest triangle edge by rotating the indices so that
2441  // vertex 0 - vertex 1 is the longest edge in the triangle.
2442  DenseMatrix pmat;
2443  for (int i = 0; i < NumOfElements; i++)
2444  {
2445  if (elements[i]->GetType() == Element::TRIANGLE)
2446  {
2447  GetPointMatrix(i, pmat);
2448  static_cast<Triangle*>(elements[i])->MarkEdge(pmat);
2449  }
2450  }
2451 }
2452 
2453 void Mesh::GetEdgeOrdering(DSTable &v_to_v, Array<int> &order)
2454 {
2455  NumOfEdges = v_to_v.NumberOfEntries();
2456  order.SetSize(NumOfEdges);
2457  Array<Pair<double, int> > length_idx(NumOfEdges);
2458 
2459  for (int i = 0; i < NumOfVertices; i++)
2460  {
2461  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
2462  {
2463  int j = it.Index();
2464  length_idx[j].one = GetLength(i, it.Column());
2465  length_idx[j].two = j;
2466  }
2467  }
2468 
2469  // Sort by increasing edge-length.
2470  length_idx.Sort();
2471 
2472  for (int i = 0; i < NumOfEdges; i++)
2473  {
2474  order[length_idx[i].two] = i;
2475  }
2476 }
2477 
2478 void Mesh::MarkTetMeshForRefinement(DSTable &v_to_v)
2479 {
2480  // Mark the longest tetrahedral edge by rotating the indices so that
2481  // vertex 0 - vertex 1 is the longest edge in the element.
2482  Array<int> order;
2483  GetEdgeOrdering(v_to_v, order);
2484 
2485  for (int i = 0; i < NumOfElements; i++)
2486  {
2487  if (elements[i]->GetType() == Element::TETRAHEDRON)
2488  {
2489  elements[i]->MarkEdge(v_to_v, order);
2490  }
2491  }
2492  for (int i = 0; i < NumOfBdrElements; i++)
2493  {
2494  if (boundary[i]->GetType() == Element::TRIANGLE)
2495  {
2496  boundary[i]->MarkEdge(v_to_v, order);
2497  }
2498  }
2499 }
2500 
2501 void Mesh::PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
2502 {
2503  if (*old_v_to_v && *old_elem_vert)
2504  {
2505  return;
2506  }
2507 
2508  FiniteElementSpace *fes = Nodes->FESpace();
2509 
2510  if (*old_v_to_v == NULL)
2511  {
2512  bool need_v_to_v = false;
2513  Array<int> dofs;
2514  for (int i = 0; i < GetNEdges(); i++)
2515  {
2516  // Since edge indices may change, we need to permute edge interior dofs
2517  // any time an edge index changes and there is at least one dof on that
2518  // edge.
2519  fes->GetEdgeInteriorDofs(i, dofs);
2520  if (dofs.Size() > 0)
2521  {
2522  need_v_to_v = true;
2523  break;
2524  }
2525  }
2526  if (need_v_to_v)
2527  {
2528  *old_v_to_v = new DSTable(NumOfVertices);
2529  GetVertexToVertexTable(*(*old_v_to_v));
2530  }
2531  }
2532  if (*old_elem_vert == NULL)
2533  {
2534  bool need_elem_vert = false;
2535  Array<int> dofs;
2536  for (int i = 0; i < GetNE(); i++)
2537  {
2538  // Since element indices do not change, we need to permute element
2539  // interior dofs only when there are at least 2 interior dofs in an
2540  // element (assuming the nodal dofs are non-directional).
2541  fes->GetElementInteriorDofs(i, dofs);
2542  if (dofs.Size() > 1)
2543  {
2544  need_elem_vert = true;
2545  break;
2546  }
2547  }
2548  if (need_elem_vert)
2549  {
2550  *old_elem_vert = new Table;
2551  (*old_elem_vert)->MakeI(GetNE());
2552  for (int i = 0; i < GetNE(); i++)
2553  {
2554  (*old_elem_vert)->AddColumnsInRow(i, elements[i]->GetNVertices());
2555  }
2556  (*old_elem_vert)->MakeJ();
2557  for (int i = 0; i < GetNE(); i++)
2558  {
2559  (*old_elem_vert)->AddConnections(i, elements[i]->GetVertices(),
2560  elements[i]->GetNVertices());
2561  }
2562  (*old_elem_vert)->ShiftUpI();
2563  }
2564  }
2565 }
2566 
2567 void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
2568 {
2569  FiniteElementSpace *fes = Nodes->FESpace();
2570  const FiniteElementCollection *fec = fes->FEColl();
2571  Array<int> old_dofs, new_dofs;
2572 
2573  // assuming that all edges have the same number of dofs
2574  if (NumOfEdges) { fes->GetEdgeInteriorDofs(0, old_dofs); }
2575  const int num_edge_dofs = old_dofs.Size();
2576 
2577  // Save the original nodes
2578  const Vector onodes = *Nodes;
2579 
2580  // vertex dofs do not need to be moved
2581  fes->GetVertexDofs(0, old_dofs);
2582  int offset = NumOfVertices * old_dofs.Size();
2583 
2584  // edge dofs:
2585  // edge enumeration may be different but edge orientation is the same
2586  if (num_edge_dofs > 0)
2587  {
2588  DSTable new_v_to_v(NumOfVertices);
2589  GetVertexToVertexTable(new_v_to_v);
2590 
2591  for (int i = 0; i < NumOfVertices; i++)
2592  {
2593  for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it)
2594  {
2595  const int old_i = (*old_v_to_v)(i, it.Column());
2596  const int new_i = it.Index();
2597  if (new_i == old_i) { continue; }
2598 
2599  old_dofs.SetSize(num_edge_dofs);
2600  new_dofs.SetSize(num_edge_dofs);
2601  for (int j = 0; j < num_edge_dofs; j++)
2602  {
2603  old_dofs[j] = offset + old_i * num_edge_dofs + j;
2604  new_dofs[j] = offset + new_i * num_edge_dofs + j;
2605  }
2606  fes->DofsToVDofs(old_dofs);
2607  fes->DofsToVDofs(new_dofs);
2608  for (int j = 0; j < old_dofs.Size(); j++)
2609  {
2610  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2611  }
2612  }
2613  }
2614  offset += NumOfEdges * num_edge_dofs;
2615  }
2616 
2617  // face dofs:
2618  // both enumeration and orientation of the faces may be different
2619  if (fes->GetNFDofs() > 0)
2620  {
2621  // generate the old face-vertex table using the unmodified 'faces'
2622  Table old_face_vertex;
2623  old_face_vertex.MakeI(NumOfFaces);
2624  for (int i = 0; i < NumOfFaces; i++)
2625  {
2626  old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices());
2627  }
2628  old_face_vertex.MakeJ();
2629  for (int i = 0; i < NumOfFaces; i++)
2630  old_face_vertex.AddConnections(i, faces[i]->GetVertices(),
2631  faces[i]->GetNVertices());
2632  old_face_vertex.ShiftUpI();
2633 
2634  // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info'
2635  STable3D *faces_tbl = GetElementToFaceTable(1);
2636  GenerateFaces();
2637 
2638  // compute the new face dof offsets
2639  Array<int> new_fdofs(NumOfFaces+1);
2640  new_fdofs[0] = 0;
2641  for (int i = 0; i < NumOfFaces; i++) // i = old face index
2642  {
2643  const int *old_v = old_face_vertex.GetRow(i);
2644  int new_i; // new face index
2645  switch (old_face_vertex.RowSize(i))
2646  {
2647  case 3:
2648  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2649  break;
2650  case 4:
2651  default:
2652  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2653  break;
2654  }
2655  fes->GetFaceInteriorDofs(i, old_dofs);
2656  new_fdofs[new_i+1] = old_dofs.Size();
2657  }
2658  new_fdofs.PartialSum();
2659 
2660  // loop over the old face numbers
2661  for (int i = 0; i < NumOfFaces; i++)
2662  {
2663  const int *old_v = old_face_vertex.GetRow(i), *new_v;
2664  const int *dof_ord;
2665  int new_i, new_or;
2666  switch (old_face_vertex.RowSize(i))
2667  {
2668  case 3:
2669  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2670  new_v = faces[new_i]->GetVertices();
2671  new_or = GetTriOrientation(old_v, new_v);
2672  dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, new_or);
2673  break;
2674  case 4:
2675  default:
2676  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2677  new_v = faces[new_i]->GetVertices();
2678  new_or = GetQuadOrientation(old_v, new_v);
2679  dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, new_or);
2680  break;
2681  }
2682 
2683  fes->GetFaceInteriorDofs(i, old_dofs);
2684  new_dofs.SetSize(old_dofs.Size());
2685  for (int j = 0; j < old_dofs.Size(); j++)
2686  {
2687  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2688  const int old_j = dof_ord[j];
2689  new_dofs[old_j] = offset + new_fdofs[new_i] + j;
2690  }
2691  fes->DofsToVDofs(old_dofs);
2692  fes->DofsToVDofs(new_dofs);
2693  for (int j = 0; j < old_dofs.Size(); j++)
2694  {
2695  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2696  }
2697  }
2698 
2699  offset += fes->GetNFDofs();
2700  delete faces_tbl;
2701  }
2702 
2703  // element dofs:
2704  // element orientation may be different
2705  if (old_elem_vert) // have elements with 2 or more dofs
2706  {
2707  // matters when the 'fec' is
2708  // (this code is executed only for triangles/tets)
2709  // - Pk on triangles, k >= 4
2710  // - Qk on quads, k >= 3
2711  // - Pk on tets, k >= 5
2712  // - Qk on hexes, k >= 3
2713  // - DG spaces
2714  // - ...
2715 
2716  // loop over all elements
2717  for (int i = 0; i < GetNE(); i++)
2718  {
2719  const int *old_v = old_elem_vert->GetRow(i);
2720  const int *new_v = elements[i]->GetVertices();
2721  const int *dof_ord;
2722  int new_or;
2723  const Geometry::Type geom = elements[i]->GetGeometryType();
2724  switch (geom)
2725  {
2726  case Geometry::SEGMENT:
2727  new_or = (old_v[0] == new_v[0]) ? +1 : -1;
2728  break;
2729  case Geometry::TRIANGLE:
2730  new_or = GetTriOrientation(old_v, new_v);
2731  break;
2732  case Geometry::SQUARE:
2733  new_or = GetQuadOrientation(old_v, new_v);
2734  break;
2735  case Geometry::TETRAHEDRON:
2736  new_or = GetTetOrientation(old_v, new_v);
2737  break;
2738  default:
2739  new_or = 0;
2740  MFEM_ABORT(Geometry::Name[geom] << " elements (" << fec->Name()
2741  << " FE collection) are not supported yet!");
2742  break;
2743  }
2744  dof_ord = fec->DofOrderForOrientation(geom, new_or);
2745  MFEM_VERIFY(dof_ord != NULL,
2746  "FE collection '" << fec->Name()
2747  << "' does not define reordering for "
2748  << Geometry::Name[geom] << " elements!");
2749  fes->GetElementInteriorDofs(i, old_dofs);
2750  new_dofs.SetSize(old_dofs.Size());
2751  for (int j = 0; j < new_dofs.Size(); j++)
2752  {
2753  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2754  const int old_j = dof_ord[j];
2755  new_dofs[old_j] = offset + j;
2756  }
2757  offset += new_dofs.Size();
2758  fes->DofsToVDofs(old_dofs);
2759  fes->DofsToVDofs(new_dofs);
2760  for (int j = 0; j < old_dofs.Size(); j++)
2761  {
2762  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2763  }
2764  }
2765  }
2766 
2767  // Update Tables, faces, etc
2768  if (Dim > 2)
2769  {
2770  if (fes->GetNFDofs() == 0)
2771  {
2772  // needed for FE spaces that have face dofs, even if
2773  // the 'Nodes' do not have face dofs.
2774  GetElementToFaceTable();
2775  GenerateFaces();
2776  }
2777  CheckBdrElementOrientation();
2778  }
2779  if (el_to_edge)
2780  {
2781  // update 'el_to_edge', 'be_to_edge' (2D), 'bel_to_edge' (3D)
2782  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2783  if (Dim == 2)
2784  {
2785  // update 'faces' and 'faces_info'
2786  GenerateFaces();
2787  CheckBdrElementOrientation();
2788  }
2789  }
2790  // To force FE space update, we need to increase 'sequence':
2791  sequence++;
2792  last_operation = Mesh::NONE;
2793  fes->Update(false); // want_transform = false
2794  Nodes->Update(); // just needed to update Nodes->sequence
2795 }
2796 
2797 void Mesh::SetPatchAttribute(int i, int attr)
2798 {
2799  MFEM_ASSERT(NURBSext, "SetPatchAttribute is only for NURBS meshes");
2800  NURBSext->SetPatchAttribute(i, attr);
2801  const Array<int>& elems = NURBSext->GetPatchElements(i);
2802  for (auto e : elems)
2803  {
2804  SetAttribute(e, attr);
2805  }
2806 }
2807 
2808 int Mesh::GetPatchAttribute(int i) const
2809 {
2810  MFEM_ASSERT(NURBSext, "GetPatchAttribute is only for NURBS meshes");
2811  return NURBSext->GetPatchAttribute(i);
2812 }
2813 
2814 void Mesh::SetPatchBdrAttribute(int i, int attr)
2815 {
2816  MFEM_ASSERT(NURBSext, "SetPatchBdrAttribute is only for NURBS meshes");
2817  NURBSext->SetPatchBdrAttribute(i, attr);
2818 
2819  const Array<int>& bdryelems = NURBSext->GetPatchBdrElements(i);
2820  for (auto be : bdryelems)
2821  {
2822  SetBdrAttribute(be, attr);
2823  }
2824 }
2825 
2826 int Mesh::GetPatchBdrAttribute(int i) const
2827 {
2828  MFEM_ASSERT(NURBSext, "GetBdrPatchBdrAttribute is only for NURBS meshes");
2829  return NURBSext->GetPatchBdrAttribute(i);
2830 }
2831 
2832 void Mesh::FinalizeTetMesh(int generate_edges, int refine, bool fix_orientation)
2833 {
2834  FinalizeCheck();
2835  CheckElementOrientation(fix_orientation);
2836 
2837  if (NumOfBdrElements == 0)
2838  {
2839  GetElementToFaceTable();
2840  GenerateFaces();
2841  GenerateBoundaryElements();
2842  }
2843 
2844  if (refine)
2845  {
2846  DSTable v_to_v(NumOfVertices);
2847  GetVertexToVertexTable(v_to_v);
2848  MarkTetMeshForRefinement(v_to_v);
2849  }
2850 
2851  GetElementToFaceTable();
2852  GenerateFaces();
2853 
2854  CheckBdrElementOrientation();
2855 
2856  if (generate_edges == 1)
2857  {
2858  el_to_edge = new Table;
2859  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2860  }
2861  else
2862  {
2863  el_to_edge = NULL; // Not really necessary -- InitTables was called
2864  bel_to_edge = NULL;
2865  NumOfEdges = 0;
2866  }
2867 
2868  SetAttributes();
2869 
2870  SetMeshGen();
2871 }
2872 
2873 void Mesh::FinalizeWedgeMesh(int generate_edges, int refine,
2874  bool fix_orientation)
2875 {
2876  FinalizeCheck();
2877  CheckElementOrientation(fix_orientation);
2878 
2879  if (NumOfBdrElements == 0)
2880  {
2881  GetElementToFaceTable();
2882  GenerateFaces();
2883  GenerateBoundaryElements();
2884  }
2885 
2886  GetElementToFaceTable();
2887  GenerateFaces();
2888 
2889  CheckBdrElementOrientation();
2890 
2891  if (generate_edges == 1)
2892  {
2893  el_to_edge = new Table;
2894  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2895  }
2896  else
2897  {
2898  el_to_edge = NULL; // Not really necessary -- InitTables was called
2899  bel_to_edge = NULL;
2900  NumOfEdges = 0;
2901  }
2902 
2903  SetAttributes();
2904 
2905  SetMeshGen();
2906 }
2907 
2908 void Mesh::FinalizeHexMesh(int generate_edges, int refine, bool fix_orientation)
2909 {
2910  FinalizeCheck();
2911  CheckElementOrientation(fix_orientation);
2912 
2913  GetElementToFaceTable();
2914  GenerateFaces();
2915 
2916  if (NumOfBdrElements == 0)
2917  {
2918  GenerateBoundaryElements();
2919  }
2920 
2921  CheckBdrElementOrientation();
2922 
2923  if (generate_edges)
2924  {
2925  el_to_edge = new Table;
2926  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2927  }
2928  else
2929  {
2930  NumOfEdges = 0;
2931  }
2932 
2933  SetAttributes();
2934 
2935  SetMeshGen();
2936 }
2937 
2938 void Mesh::FinalizeMesh(int refine, bool fix_orientation)
2939 {
2940  FinalizeTopology();
2941 
2942  Finalize(refine, fix_orientation);
2943 }
2944 
2945 void Mesh::FinalizeTopology(bool generate_bdr)
2946 {
2947  // Requirements: the following should be defined:
2948  // 1) Dim
2949  // 2) NumOfElements, elements
2950  // 3) NumOfBdrElements, boundary
2951  // 4) NumOfVertices
2952  // Optional:
2953  // 2) ncmesh may be defined
2954  // 3) el_to_edge may be allocated (it will be re-computed)
2955 
2956  FinalizeCheck();
2957  bool generate_edges = true;
2958 
2959  if (spaceDim == 0) { spaceDim = Dim; }
2960  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
2961 
2962  // if the user defined any hanging nodes (see AddVertexParent),
2963  // we're initializing a non-conforming mesh
2964  if (tmp_vertex_parents.Size())
2965  {
2966  MFEM_VERIFY(ncmesh == NULL, "");
2967  ncmesh = new NCMesh(this);
2968 
2969  // we need to recreate the Mesh because NCMesh reorders the vertices
2970  // (see NCMesh::UpdateVertices())
2971  InitFromNCMesh(*ncmesh);
2972  ncmesh->OnMeshUpdated(this);
2973  GenerateNCFaceInfo();
2974 
2975  SetAttributes();
2976 
2977  tmp_vertex_parents.DeleteAll();
2978  return;
2979  }
2980 
2981  // set the mesh type: 'meshgen', ...
2982  SetMeshGen();
2983 
2984  // generate the faces
2985  if (Dim > 2)
2986  {
2987  GetElementToFaceTable();
2988  GenerateFaces();
2989  if (NumOfBdrElements == 0 && generate_bdr)
2990  {
2991  GenerateBoundaryElements();
2992  GetElementToFaceTable(); // update be_to_face
2993  }
2994  }
2995  else
2996  {
2997  NumOfFaces = 0;
2998  }
2999 
3000  // generate edges if requested
3001  if (Dim > 1 && generate_edges)
3002  {
3003  // el_to_edge may already be allocated (P2 VTK meshes)
3004  if (!el_to_edge) { el_to_edge = new Table; }
3005  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3006  if (Dim == 2)
3007  {
3008  GenerateFaces(); // 'Faces' in 2D refers to the edges
3009  if (NumOfBdrElements == 0 && generate_bdr)
3010  {
3011  GenerateBoundaryElements();
3012  }
3013  }
3014  }
3015  else
3016  {
3017  NumOfEdges = 0;
3018  }
3019 
3020  if (Dim == 1)
3021  {
3022  GenerateFaces();
3023  if (NumOfBdrElements == 0 && generate_bdr)
3024  {
3025  GenerateBoundaryElements();
3026  }
3027  }
3028 
3029  if (ncmesh)
3030  {
3031  // tell NCMesh the numbering of edges/faces
3032  ncmesh->OnMeshUpdated(this);
3033 
3034  // update faces_info with NC relations
3035  GenerateNCFaceInfo();
3036  }
3037 
3038  // generate the arrays 'attributes' and 'bdr_attributes'
3039  SetAttributes();
3040 }
3041 
3042 void Mesh::Finalize(bool refine, bool fix_orientation)
3043 {
3044  if (NURBSext || ncmesh)
3045  {
3046  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
3047  MFEM_ASSERT(CheckBdrElementOrientation() == 0, "");
3048  return;
3049  }
3050 
3051  // Requirements:
3052  // 1) FinalizeTopology() or equivalent was called
3053  // 2) if (Nodes == NULL), vertices must be defined
3054  // 3) if (Nodes != NULL), Nodes must be defined
3055 
3056  const bool check_orientation = true; // for regular elements, not boundary
3057  const bool curved = (Nodes != NULL);
3058  const bool may_change_topology =
3059  ( refine && (Dim > 1 && (meshgen & 1)) ) ||
3060  ( check_orientation && fix_orientation &&
3061  (Dim == 2 || (Dim == 3 && (meshgen & 1))) );
3062 
3063  DSTable *old_v_to_v = NULL;
3064  Table *old_elem_vert = NULL;
3065 
3066  if (curved && may_change_topology)
3067  {
3068  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
3069  }
3070 
3071  if (check_orientation)
3072  {
3073  // check and optionally fix element orientation
3074  CheckElementOrientation(fix_orientation);
3075  }
3076  if (refine)
3077  {
3078  MarkForRefinement(); // may change topology!
3079  }
3080 
3081  if (may_change_topology)
3082  {
3083  if (curved)
3084  {
3085  DoNodeReorder(old_v_to_v, old_elem_vert); // updates the mesh topology
3086  delete old_elem_vert;
3087  delete old_v_to_v;
3088  }
3089  else
3090  {
3091  FinalizeTopology(); // Re-computes some data unnecessarily.
3092  }
3093 
3094  // TODO: maybe introduce Mesh::NODE_REORDER operation and FESpace::
3095  // NodeReorderMatrix and do Nodes->Update() instead of DoNodeReorder?
3096  }
3097 
3098  // check and fix boundary element orientation
3099  CheckBdrElementOrientation();
3100 
3101 #ifdef MFEM_DEBUG
3102  // For non-orientable surfaces/manifolds, the check below will fail, so we
3103  // only perform it when Dim == spaceDim.
3104  if (Dim >= 2 && Dim == spaceDim)
3105  {
3106  const int num_faces = GetNumFaces();
3107  for (int i = 0; i < num_faces; i++)
3108  {
3109  MFEM_VERIFY(faces_info[i].Elem2No < 0 ||
3110  faces_info[i].Elem2Inf%2 != 0, "Invalid mesh topology."
3111  " Interior face with incompatible orientations.");
3112  }
3113  }
3114 #endif
3115 }
3116 
3117 void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
3118  double sx, double sy, double sz, bool sfc_ordering)
3119 {
3120  int x, y, z;
3121 
3122  int NVert, NElem, NBdrElem;
3123 
3124  NVert = (nx+1) * (ny+1) * (nz+1);
3125  NElem = nx * ny * nz;
3126  NBdrElem = 2*(nx*ny+nx*nz+ny*nz);
3127  if (type == Element::TETRAHEDRON)
3128  {
3129  NElem *= 6;
3130  NBdrElem *= 2;
3131  }
3132  else if (type == Element::WEDGE)
3133  {
3134  NElem *= 2;
3135  NBdrElem += 2*nx*ny;
3136  }
3137  else if (type == Element::PYRAMID)
3138  {
3139  NElem *= 6;
3140  NVert += nx * ny * nz;
3141  }
3142 
3143  InitMesh(3, 3, NVert, NElem, NBdrElem);
3144 
3145  double coord[3];
3146  int ind[9];
3147 
3148  // Sets vertices and the corresponding coordinates
3149  for (z = 0; z <= nz; z++)
3150  {
3151  coord[2] = ((double) z / nz) * sz;
3152  for (y = 0; y <= ny; y++)
3153  {
3154  coord[1] = ((double) y / ny) * sy;
3155  for (x = 0; x <= nx; x++)
3156  {
3157  coord[0] = ((double) x / nx) * sx;
3158  AddVertex(coord);
3159  }
3160  }
3161  }
3162  if (type == Element::PYRAMID)
3163  {
3164  for (z = 0; z < nz; z++)
3165  {
3166  coord[2] = (((double) z + 0.5) / nz) * sz;
3167  for (y = 0; y < ny; y++)
3168  {
3169  coord[1] = (((double) y + 0.5 ) / ny) * sy;
3170  for (x = 0; x < nx; x++)
3171  {
3172  coord[0] = (((double) x + 0.5 ) / nx) * sx;
3173  AddVertex(coord);
3174  }
3175  }
3176  }
3177  }
3178 
3179 #define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
3180 #define VTXP(XC, YC, ZC) ((nx+1)*(ny+1)*(nz+1)+(XC)+((YC)+(ZC)*ny)*nx)
3181 
3182  // Sets elements and the corresponding indices of vertices
3183  if (sfc_ordering && type == Element::HEXAHEDRON)
3184  {
3185  Array<int> sfc;
3186  NCMesh::GridSfcOrdering3D(nx, ny, nz, sfc);
3187  MFEM_VERIFY(sfc.Size() == 3*nx*ny*nz, "");
3188 
3189  for (int k = 0; k < nx*ny*nz; k++)
3190  {
3191  x = sfc[3*k + 0];
3192  y = sfc[3*k + 1];
3193  z = sfc[3*k + 2];
3194 
3195  // *INDENT-OFF*
3196  ind[0] = VTX(x , y , z );
3197  ind[1] = VTX(x+1, y , z );
3198  ind[2] = VTX(x+1, y+1, z );
3199  ind[3] = VTX(x , y+1, z );
3200  ind[4] = VTX(x , y , z+1);
3201  ind[5] = VTX(x+1, y , z+1);
3202  ind[6] = VTX(x+1, y+1, z+1);
3203  ind[7] = VTX(x , y+1, z+1);
3204  // *INDENT-ON*
3205 
3206  AddHex(ind, 1);
3207  }
3208  }
3209  else
3210  {
3211  for (z = 0; z < nz; z++)
3212  {
3213  for (y = 0; y < ny; y++)
3214  {
3215  for (x = 0; x < nx; x++)
3216  {
3217  // *INDENT-OFF*
3218  ind[0] = VTX(x , y , z );
3219  ind[1] = VTX(x+1, y , z );
3220  ind[2] = VTX(x+1, y+1, z );
3221  ind[3] = VTX(x , y+1, z );
3222  ind[4] = VTX(x , y , z+1);
3223  ind[5] = VTX(x+1, y , z+1);
3224  ind[6] = VTX(x+1, y+1, z+1);
3225  ind[7] = VTX( x, y+1, z+1);
3226  // *INDENT-ON*
3227  if (type == Element::TETRAHEDRON)
3228  {
3229  AddHexAsTets(ind, 1);
3230  }
3231  else if (type == Element::WEDGE)
3232  {
3233  AddHexAsWedges(ind, 1);
3234  }
3235  else if (type == Element::PYRAMID)
3236  {
3237  ind[8] = VTXP(x, y, z);
3238  AddHexAsPyramids(ind, 1);
3239  }
3240  else
3241  {
3242  AddHex(ind, 1);
3243  }
3244  }
3245  }
3246  }
3247  }
3248 
3249  // Sets boundary elements and the corresponding indices of vertices
3250  // bottom, bdr. attribute 1
3251  for (y = 0; y < ny; y++)
3252  {
3253  for (x = 0; x < nx; x++)
3254  {
3255  // *INDENT-OFF*
3256  ind[0] = VTX(x , y , 0);
3257  ind[1] = VTX(x , y+1, 0);
3258  ind[2] = VTX(x+1, y+1, 0);
3259  ind[3] = VTX(x+1, y , 0);
3260  // *INDENT-ON*
3261  if (type == Element::TETRAHEDRON)
3262  {
3263  AddBdrQuadAsTriangles(ind, 1);
3264  }
3265  else if (type == Element::WEDGE)
3266  {
3267  AddBdrQuadAsTriangles(ind, 1);
3268  }
3269  else
3270  {
3271  AddBdrQuad(ind, 1);
3272  }
3273  }
3274  }
3275  // top, bdr. attribute 6
3276  for (y = 0; y < ny; y++)
3277  {
3278  for (x = 0; x < nx; x++)
3279  {
3280  // *INDENT-OFF*
3281  ind[0] = VTX(x , y , nz);
3282  ind[1] = VTX(x+1, y , nz);
3283  ind[2] = VTX(x+1, y+1, nz);
3284  ind[3] = VTX(x , y+1, nz);
3285  // *INDENT-ON*
3286  if (type == Element::TETRAHEDRON)
3287  {
3288  AddBdrQuadAsTriangles(ind, 6);
3289  }
3290  else if (type == Element::WEDGE)
3291  {
3292  AddBdrQuadAsTriangles(ind, 6);
3293  }
3294  else
3295  {
3296  AddBdrQuad(ind, 6);
3297  }
3298  }
3299  }
3300  // left, bdr. attribute 5
3301  for (z = 0; z < nz; z++)
3302  {
3303  for (y = 0; y < ny; y++)
3304  {
3305  // *INDENT-OFF*
3306  ind[0] = VTX(0 , y , z );
3307  ind[1] = VTX(0 , y , z+1);
3308  ind[2] = VTX(0 , y+1, z+1);
3309  ind[3] = VTX(0 , y+1, z );
3310  // *INDENT-ON*
3311  if (type == Element::TETRAHEDRON)
3312  {
3313  AddBdrQuadAsTriangles(ind, 5);
3314  }
3315  else
3316  {
3317  AddBdrQuad(ind, 5);
3318  }
3319  }
3320  }
3321  // right, bdr. attribute 3
3322  for (z = 0; z < nz; z++)
3323  {
3324  for (y = 0; y < ny; y++)
3325  {
3326  // *INDENT-OFF*
3327  ind[0] = VTX(nx, y , z );
3328  ind[1] = VTX(nx, y+1, z );
3329  ind[2] = VTX(nx, y+1, z+1);
3330  ind[3] = VTX(nx, y , z+1);
3331  // *INDENT-ON*
3332  if (type == Element::TETRAHEDRON)
3333  {
3334  AddBdrQuadAsTriangles(ind, 3);
3335  }
3336  else
3337  {
3338  AddBdrQuad(ind, 3);
3339  }
3340  }
3341  }
3342  // front, bdr. attribute 2
3343  for (x = 0; x < nx; x++)
3344  {
3345  for (z = 0; z < nz; z++)
3346  {
3347  // *INDENT-OFF*
3348  ind[0] = VTX(x , 0, z );
3349  ind[1] = VTX(x+1, 0, z );
3350  ind[2] = VTX(x+1, 0, z+1);
3351  ind[3] = VTX(x , 0, z+1);
3352  // *INDENT-ON*
3353  if (type == Element::TETRAHEDRON)
3354  {
3355  AddBdrQuadAsTriangles(ind, 2);
3356  }
3357  else
3358  {
3359  AddBdrQuad(ind, 2);
3360  }
3361  }
3362  }
3363  // back, bdr. attribute 4
3364  for (x = 0; x < nx; x++)
3365  {
3366  for (z = 0; z < nz; z++)
3367  {
3368  // *INDENT-OFF*
3369  ind[0] = VTX(x , ny, z );
3370  ind[1] = VTX(x , ny, z+1);
3371  ind[2] = VTX(x+1, ny, z+1);
3372  ind[3] = VTX(x+1, ny, z );
3373  // *INDENT-ON*
3374  if (type == Element::TETRAHEDRON)
3375  {
3376  AddBdrQuadAsTriangles(ind, 4);
3377  }
3378  else
3379  {
3380  AddBdrQuad(ind, 4);
3381  }
3382  }
3383  }
3384 
3385 #undef VTX
3386 
3387 #if 0
3388  ofstream test_stream("debug.mesh");
3389  Print(test_stream);
3390  test_stream.close();
3391 #endif
3392 
3393  FinalizeTopology();
3394 
3395  // Finalize(...) can be called after this method, if needed
3396 }
3397 
3398 void Mesh::Make2D(int nx, int ny, Element::Type type,
3399  double sx, double sy,
3400  bool generate_edges, bool sfc_ordering)
3401 {
3402  int i, j, k;
3403 
3404  SetEmpty();
3405 
3406  Dim = spaceDim = 2;
3407 
3408  // Creates quadrilateral mesh
3409  if (type == Element::QUADRILATERAL)
3410  {
3411  NumOfVertices = (nx+1) * (ny+1);
3412  NumOfElements = nx * ny;
3413  NumOfBdrElements = 2 * nx + 2 * ny;
3414 
3415  vertices.SetSize(NumOfVertices);
3416  elements.SetSize(NumOfElements);
3417  boundary.SetSize(NumOfBdrElements);
3418 
3419  double cx, cy;
3420  int ind[4];
3421 
3422  // Sets vertices and the corresponding coordinates
3423  k = 0;
3424  for (j = 0; j < ny+1; j++)
3425  {
3426  cy = ((double) j / ny) * sy;
3427  for (i = 0; i < nx+1; i++)
3428  {
3429  cx = ((double) i / nx) * sx;
3430  vertices[k](0) = cx;
3431  vertices[k](1) = cy;
3432  k++;
3433  }
3434  }
3435 
3436  // Sets elements and the corresponding indices of vertices
3437  if (sfc_ordering)
3438  {
3439  Array<int> sfc;
3440  NCMesh::GridSfcOrdering2D(nx, ny, sfc);
3441  MFEM_VERIFY(sfc.Size() == 2*nx*ny, "");
3442 
3443  for (k = 0; k < nx*ny; k++)
3444  {
3445  i = sfc[2*k + 0];
3446  j = sfc[2*k + 1];
3447  ind[0] = i + j*(nx+1);
3448  ind[1] = i + 1 +j*(nx+1);
3449  ind[2] = i + 1 + (j+1)*(nx+1);
3450  ind[3] = i + (j+1)*(nx+1);
3451  elements[k] = new Quadrilateral(ind);
3452  }
3453  }
3454  else
3455  {
3456  k = 0;
3457  for (j = 0; j < ny; j++)
3458  {
3459  for (i = 0; i < nx; i++)
3460  {
3461  ind[0] = i + j*(nx+1);
3462  ind[1] = i + 1 +j*(nx+1);
3463  ind[2] = i + 1 + (j+1)*(nx+1);
3464  ind[3] = i + (j+1)*(nx+1);
3465  elements[k] = new Quadrilateral(ind);
3466  k++;
3467  }
3468  }
3469  }
3470 
3471  // Sets boundary elements and the corresponding indices of vertices
3472  int m = (nx+1)*ny;
3473  for (i = 0; i < nx; i++)
3474  {
3475  boundary[i] = new Segment(i, i+1, 1);
3476  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3477  }
3478  m = nx+1;
3479  for (j = 0; j < ny; j++)
3480  {
3481  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3482  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3483  }
3484  }
3485  // Creates triangular mesh
3486  else if (type == Element::TRIANGLE)
3487  {
3488  NumOfVertices = (nx+1) * (ny+1);
3489  NumOfElements = 2 * nx * ny;
3490  NumOfBdrElements = 2 * nx + 2 * ny;
3491 
3492  vertices.SetSize(NumOfVertices);
3493  elements.SetSize(NumOfElements);
3494  boundary.SetSize(NumOfBdrElements);
3495 
3496  double cx, cy;
3497  int ind[3];
3498 
3499  // Sets vertices and the corresponding coordinates
3500  k = 0;
3501  for (j = 0; j < ny+1; j++)
3502  {
3503  cy = ((double) j / ny) * sy;
3504  for (i = 0; i < nx+1; i++)
3505  {
3506  cx = ((double) i / nx) * sx;
3507  vertices[k](0) = cx;
3508  vertices[k](1) = cy;
3509  k++;
3510  }
3511  }
3512 
3513  // Sets the elements and the corresponding indices of vertices
3514  k = 0;
3515  for (j = 0; j < ny; j++)
3516  {
3517  for (i = 0; i < nx; i++)
3518  {
3519  ind[0] = i + j*(nx+1);
3520  ind[1] = i + 1 + (j+1)*(nx+1);
3521  ind[2] = i + (j+1)*(nx+1);
3522  elements[k] = new Triangle(ind);
3523  k++;
3524  ind[1] = i + 1 + j*(nx+1);
3525  ind[2] = i + 1 + (j+1)*(nx+1);
3526  elements[k] = new Triangle(ind);
3527  k++;
3528  }
3529  }
3530 
3531  // Sets boundary elements and the corresponding indices of vertices
3532  int m = (nx+1)*ny;
3533  for (i = 0; i < nx; i++)
3534  {
3535  boundary[i] = new Segment(i, i+1, 1);
3536  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3537  }
3538  m = nx+1;
3539  for (j = 0; j < ny; j++)
3540  {
3541  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3542  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3543  }
3544 
3545  // MarkTriMeshForRefinement(); // done in Finalize(...)
3546  }
3547  else
3548  {
3549  MFEM_ABORT("Unsupported element type.");
3550  }
3551 
3552  SetMeshGen();
3553  CheckElementOrientation();
3554 
3555  if (generate_edges == 1)
3556  {
3557  el_to_edge = new Table;
3558  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3559  GenerateFaces();
3560  CheckBdrElementOrientation();
3561  }
3562  else
3563  {
3564  NumOfEdges = 0;
3565  }
3566 
3567  NumOfFaces = 0;
3568 
3569  attributes.Append(1);
3570  bdr_attributes.Append(1); bdr_attributes.Append(2);
3571  bdr_attributes.Append(3); bdr_attributes.Append(4);
3572 
3573  // Finalize(...) can be called after this method, if needed
3574 }
3575 
3576 void Mesh::Make1D(int n, double sx)
3577 {
3578  int j, ind[1];
3579 
3580  SetEmpty();
3581 
3582  Dim = 1;
3583  spaceDim = 1;
3584 
3585  NumOfVertices = n + 1;
3586  NumOfElements = n;
3587  NumOfBdrElements = 2;
3588  vertices.SetSize(NumOfVertices);
3589  elements.SetSize(NumOfElements);
3590  boundary.SetSize(NumOfBdrElements);
3591 
3592  // Sets vertices and the corresponding coordinates
3593  for (j = 0; j < n+1; j++)
3594  {
3595  vertices[j](0) = ((double) j / n) * sx;
3596  }
3597 
3598  // Sets elements and the corresponding indices of vertices
3599  for (j = 0; j < n; j++)
3600  {
3601  elements[j] = new Segment(j, j+1, 1);
3602  }
3603 
3604  // Sets the boundary elements
3605  ind[0] = 0;
3606  boundary[0] = new Point(ind, 1);
3607  ind[0] = n;
3608  boundary[1] = new Point(ind, 2);
3609 
3610  NumOfEdges = 0;
3611  NumOfFaces = 0;
3612 
3613  SetMeshGen();
3614  GenerateFaces();
3615 
3616  attributes.Append(1);
3617  bdr_attributes.Append(1); bdr_attributes.Append(2);
3618 }
3619 
3620 Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
3621 {
3622  Dim = mesh.Dim;
3623  spaceDim = mesh.spaceDim;
3624 
3625  NumOfVertices = mesh.NumOfVertices;
3626  NumOfElements = mesh.NumOfElements;
3627  NumOfBdrElements = mesh.NumOfBdrElements;
3628  NumOfEdges = mesh.NumOfEdges;
3629  NumOfFaces = mesh.NumOfFaces;
3630  nbInteriorFaces = mesh.nbInteriorFaces;
3631  nbBoundaryFaces = mesh.nbBoundaryFaces;
3632 
3633  meshgen = mesh.meshgen;
3634  mesh_geoms = mesh.mesh_geoms;
3635 
3636  // Create the new Mesh instance without a record of its refinement history
3637  sequence = 0;
3638  last_operation = Mesh::NONE;
3639 
3640  // Duplicate the elements
3641  elements.SetSize(NumOfElements);
3642  for (int i = 0; i < NumOfElements; i++)
3643  {
3644  elements[i] = mesh.elements[i]->Duplicate(this);
3645  }
3646 
3647  // Copy the vertices
3648  mesh.vertices.Copy(vertices);
3649 
3650  // Duplicate the boundary
3651  boundary.SetSize(NumOfBdrElements);
3652  for (int i = 0; i < NumOfBdrElements; i++)
3653  {
3654  boundary[i] = mesh.boundary[i]->Duplicate(this);
3655  }
3656 
3657  // Copy the element-to-face Table, el_to_face
3658  el_to_face = (mesh.el_to_face) ? new Table(*mesh.el_to_face) : NULL;
3659 
3660  // Copy the boundary-to-face Array, be_to_face.
3661  mesh.be_to_face.Copy(be_to_face);
3662 
3663  // Copy the element-to-edge Table, el_to_edge
3664  el_to_edge = (mesh.el_to_edge) ? new Table(*mesh.el_to_edge) : NULL;
3665 
3666  // Copy the boundary-to-edge Table, bel_to_edge (3D)
3667  bel_to_edge = (mesh.bel_to_edge) ? new Table(*mesh.bel_to_edge) : NULL;
3668 
3669  // Copy the boundary-to-edge Array, be_to_edge (2D)
3670  mesh.be_to_edge.Copy(be_to_edge);
3671 
3672  // Duplicate the faces and faces_info.
3673  faces.SetSize(mesh.faces.Size());
3674  for (int i = 0; i < faces.Size(); i++)
3675  {
3676  Element *face = mesh.faces[i]; // in 1D the faces are NULL
3677  faces[i] = (face) ? face->Duplicate(this) : NULL;
3678  }
3679  mesh.faces_info.Copy(faces_info);
3680  mesh.nc_faces_info.Copy(nc_faces_info);
3681 
3682  // Do NOT copy the element-to-element Table, el_to_el
3683  el_to_el = NULL;
3684 
3685  // Do NOT copy the face-to-edge Table, face_edge
3686  face_edge = NULL;
3687  face_to_elem = NULL;
3688 
3689  // Copy the edge-to-vertex Table, edge_vertex
3690  edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
3691 
3692  // Copy the attributes and bdr_attributes
3693  mesh.attributes.Copy(attributes);
3694  mesh.bdr_attributes.Copy(bdr_attributes);
3695 
3696  // Deep copy the NURBSExtension.
3697 #ifdef MFEM_USE_MPI
3698  ParNURBSExtension *pNURBSext =
3699  dynamic_cast<ParNURBSExtension *>(mesh.NURBSext);
3700  if (pNURBSext)
3701  {
3702  NURBSext = new ParNURBSExtension(*pNURBSext);
3703  }
3704  else
3705 #endif
3706  {
3707  NURBSext = mesh.NURBSext ? new NURBSExtension(*mesh.NURBSext) : NULL;
3708  }
3709 
3710  // Deep copy the NCMesh.
3711 #ifdef MFEM_USE_MPI
3712  if (dynamic_cast<const ParMesh*>(&mesh))
3713  {
3714  ncmesh = NULL; // skip; will be done in ParMesh copy ctor
3715  }
3716  else
3717 #endif
3718  {
3719  ncmesh = mesh.ncmesh ? new NCMesh(*mesh.ncmesh) : NULL;
3720  }
3721 
3722  // Duplicate the Nodes, including the FiniteElementCollection and the
3723  // FiniteElementSpace
3724  if (mesh.Nodes && copy_nodes)
3725  {
3726  FiniteElementSpace *fes = mesh.Nodes->FESpace();
3727  const FiniteElementCollection *fec = fes->FEColl();
3728  FiniteElementCollection *fec_copy =
3729  FiniteElementCollection::New(fec->Name());
3730  FiniteElementSpace *fes_copy =
3731  new FiniteElementSpace(*fes, this, fec_copy);
3732  Nodes = new GridFunction(fes_copy);
3733  Nodes->MakeOwner(fec_copy);
3734  *Nodes = *mesh.Nodes;
3735  own_nodes = 1;
3736  }
3737  else
3738  {
3739  Nodes = mesh.Nodes;
3740  own_nodes = 0;
3741  }
3742 }
3743 
3744 Mesh::Mesh(Mesh &&mesh) : Mesh()
3745 {
3746  Swap(mesh, true);
3747 }
3748 
3750 {
3751  Swap(mesh, true);
3752  return *this;
3753 }
3754 
3755 Mesh Mesh::LoadFromFile(const std::string &filename, int generate_edges,
3756  int refine, bool fix_orientation)
3757 {
3758  Mesh mesh;
3759  named_ifgzstream imesh(filename);
3760  if (!imesh) { MFEM_ABORT("Mesh file not found: " << filename << '\n'); }
3761  else { mesh.Load(imesh, generate_edges, refine, fix_orientation); }
3762  return mesh;
3763 }
3764 
3765 Mesh Mesh::MakeCartesian1D(int n, double sx)
3766 {
3767  Mesh mesh;
3768  mesh.Make1D(n, sx);
3769  // mesh.Finalize(); not needed in this case
3770  return mesh;
3771 }
3772 
3774  int nx, int ny, Element::Type type, bool generate_edges,
3775  double sx, double sy, bool sfc_ordering)
3776 {
3777  Mesh mesh;
3778  mesh.Make2D(nx, ny, type, sx, sy, generate_edges, sfc_ordering);
3779  mesh.Finalize(true); // refine = true
3780  return mesh;
3781 }
3782 
3784  int nx, int ny, int nz, Element::Type type,
3785  double sx, double sy, double sz, bool sfc_ordering)
3786 {
3787  Mesh mesh;
3788  mesh.Make3D(nx, ny, nz, type, sx, sy, sz, sfc_ordering);
3789  mesh.Finalize(true); // refine = true
3790  return mesh;
3791 }
3792 
3793 Mesh Mesh::MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
3794 {
3795  Mesh mesh;
3796  Array<int> ref_factors(orig_mesh.GetNE());
3797  ref_factors = ref_factor;
3798  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3799  return mesh;
3800 }
3801 
3802 Mesh Mesh::MakeRefined(Mesh &orig_mesh, const Array<int> &ref_factors,
3803  int ref_type)
3804 {
3805  Mesh mesh;
3806  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3807  return mesh;
3808 }
3809 
3810 Mesh::Mesh(const std::string &filename, int generate_edges, int refine,
3811  bool fix_orientation)
3812 {
3813  // Initialization as in the default constructor
3814  SetEmpty();
3815 
3816  named_ifgzstream imesh(filename);
3817  if (!imesh)
3818  {
3819  // Abort with an error message.
3820  MFEM_ABORT("Mesh file not found: " << filename << '\n');
3821  }
3822  else
3823  {
3824  Load(imesh, generate_edges, refine, fix_orientation);
3825  }
3826 }
3827 
3828 Mesh::Mesh(std::istream &input, int generate_edges, int refine,
3829  bool fix_orientation)
3830 {
3831  SetEmpty();
3832  Load(input, generate_edges, refine, fix_orientation);
3833 }
3834 
3835 void Mesh::ChangeVertexDataOwnership(double *vertex_data, int len_vertex_data,
3836  bool zerocopy)
3837 {
3838  // A dimension of 3 is now required since we use mfem::Vertex objects as PODs
3839  // and these object have a hardcoded double[3] entry
3840  MFEM_VERIFY(len_vertex_data >= NumOfVertices * 3,
3841  "Not enough vertices in external array : "
3842  "len_vertex_data = "<< len_vertex_data << ", "
3843  "NumOfVertices * 3 = " << NumOfVertices * 3);
3844  // Allow multiple calls to this method with the same vertex_data
3845  if (vertex_data == (double *)(vertices.GetData()))
3846  {
3847  MFEM_ASSERT(!vertices.OwnsData(), "invalid ownership");
3848  return;
3849  }
3850  if (!zerocopy)
3851  {
3852  memcpy(vertex_data, vertices.GetData(),
3853  NumOfVertices * 3 * sizeof(double));
3854  }
3855  // Vertex is POD double[3]
3856  vertices.MakeRef(reinterpret_cast<Vertex*>(vertex_data), NumOfVertices);
3857 }
3858 
3859 Mesh::Mesh(double *vertices_, int num_vertices,
3860  int *element_indices, Geometry::Type element_type,
3861  int *element_attributes, int num_elements,
3862  int *boundary_indices, Geometry::Type boundary_type,
3863  int *boundary_attributes, int num_boundary_elements,
3864  int dimension, int space_dimension)
3865 {
3866  if (space_dimension == -1)
3867  {
3868  space_dimension = dimension;
3869  }
3870 
3871  InitMesh(dimension, space_dimension, /*num_vertices*/ 0, num_elements,
3872  num_boundary_elements);
3873 
3874  int element_index_stride = Geometry::NumVerts[element_type];
3875  int boundary_index_stride = num_boundary_elements > 0 ?
3876  Geometry::NumVerts[boundary_type] : 0;
3877 
3878  // assuming Vertex is POD
3879  vertices.MakeRef(reinterpret_cast<Vertex*>(vertices_), num_vertices);
3880  NumOfVertices = num_vertices;
3881 
3882  for (int i = 0; i < num_elements; i++)
3883  {
3884  elements[i] = NewElement(element_type);
3885  elements[i]->SetVertices(element_indices + i * element_index_stride);
3886  elements[i]->SetAttribute(element_attributes[i]);
3887  }
3888  NumOfElements = num_elements;
3889 
3890  for (int i = 0; i < num_boundary_elements; i++)
3891  {
3892  boundary[i] = NewElement(boundary_type);
3893  boundary[i]->SetVertices(boundary_indices + i * boundary_index_stride);
3894  boundary[i]->SetAttribute(boundary_attributes[i]);
3895  }
3896  NumOfBdrElements = num_boundary_elements;
3897 
3898  FinalizeTopology();
3899 }
3900 
3902 {
3903  switch (geom)
3904  {
3905  case Geometry::POINT: return (new Point);
3906  case Geometry::SEGMENT: return (new Segment);
3907  case Geometry::TRIANGLE: return (new Triangle);
3908  case Geometry::SQUARE: return (new Quadrilateral);
3909  case Geometry::TETRAHEDRON:
3910 #ifdef MFEM_USE_MEMALLOC
3911  return TetMemory.Alloc();
3912 #else
3913  return (new Tetrahedron);
3914 #endif
3915  case Geometry::CUBE: return (new Hexahedron);
3916  case Geometry::PRISM: return (new Wedge);
3917  case Geometry::PYRAMID: return (new Pyramid);
3918  default:
3919  MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
3920  }
3921 
3922  return NULL;
3923 }
3924 
3926 {
3927  int geom, nv, *v;
3928  Element *el;
3929 
3930  input >> geom;
3931  el = NewElement(geom);
3932  MFEM_VERIFY(el, "Unsupported element type: " << geom);
3933  nv = el->GetNVertices();
3934  v = el->GetVertices();
3935  for (int i = 0; i < nv; i++)
3936  {
3937  input >> v[i];
3938  }
3939 
3940  return el;
3941 }
3942 
3943 void Mesh::PrintElementWithoutAttr(const Element *el, std::ostream &os)
3944 {
3945  os << el->GetGeometryType();
3946  const int nv = el->GetNVertices();
3947  const int *v = el->GetVertices();
3948  for (int j = 0; j < nv; j++)
3949  {
3950  os << ' ' << v[j];
3951  }
3952  os << '\n';
3953 }
3954 
3955 Element *Mesh::ReadElement(std::istream &input)
3956 {
3957  int attr;
3958  Element *el;
3959 
3960  input >> attr;
3961  el = ReadElementWithoutAttr(input);
3962  el->SetAttribute(attr);
3963 
3964  return el;
3965 }
3966 
3967 void Mesh::PrintElement(const Element *el, std::ostream &os)
3968 {
3969  os << el->GetAttribute() << ' ';
3970  PrintElementWithoutAttr(el, os);
3971 }
3972 
3974 {
3975  meshgen = mesh_geoms = 0;
3976  for (int i = 0; i < NumOfElements; i++)
3977  {
3978  const Element::Type type = GetElement(i)->GetType();
3979  switch (type)
3980  {
3981  case Element::TETRAHEDRON:
3983  case Element::TRIANGLE:
3984  mesh_geoms |= (1 << Geometry::TRIANGLE);
3985  case Element::SEGMENT:
3986  mesh_geoms |= (1 << Geometry::SEGMENT);
3987  case Element::POINT:
3988  mesh_geoms |= (1 << Geometry::POINT);
3989  meshgen |= 1;
3990  break;
3991 
3992  case Element::HEXAHEDRON:
3993  mesh_geoms |= (1 << Geometry::CUBE);
3995  mesh_geoms |= (1 << Geometry::SQUARE);
3996  mesh_geoms |= (1 << Geometry::SEGMENT);
3997  mesh_geoms |= (1 << Geometry::POINT);
3998  meshgen |= 2;
3999  break;
4000 
4001  case Element::WEDGE:
4002  mesh_geoms |= (1 << Geometry::PRISM);
4003  mesh_geoms |= (1 << Geometry::SQUARE);
4004  mesh_geoms |= (1 << Geometry::TRIANGLE);
4005  mesh_geoms |= (1 << Geometry::SEGMENT);
4006  mesh_geoms |= (1 << Geometry::POINT);
4007  meshgen |= 4;
4008  break;
4009 
4010  case Element::PYRAMID:
4011  mesh_geoms |= (1 << Geometry::PYRAMID);
4012  mesh_geoms |= (1 << Geometry::SQUARE);
4013  mesh_geoms |= (1 << Geometry::TRIANGLE);
4014  mesh_geoms |= (1 << Geometry::SEGMENT);
4015  mesh_geoms |= (1 << Geometry::POINT);
4016  meshgen |= 8;
4017  break;
4018 
4019  default:
4020  MFEM_ABORT("invalid element type: " << type);
4021  break;
4022  }
4023  }
4024 }
4025 
4026 void Mesh::Loader(std::istream &input, int generate_edges,
4027  std::string parse_tag)
4028 {
4029  int curved = 0, read_gf = 1;
4030  bool finalize_topo = true;
4031 
4032  if (!input)
4033  {
4034  MFEM_ABORT("Input stream is not open");
4035  }
4036 
4037  Clear();
4038 
4039  string mesh_type;
4040  input >> ws;
4041  getline(input, mesh_type);
4042  filter_dos(mesh_type);
4043 
4044  // MFEM's conforming mesh formats
4045  int mfem_version = 0;
4046  if (mesh_type == "MFEM mesh v1.0") { mfem_version = 10; } // serial
4047  else if (mesh_type == "MFEM mesh v1.2") { mfem_version = 12; } // parallel
4048 
4049  // MFEM nonconforming mesh format
4050  // (NOTE: previous v1.1 is now under this branch for backward compatibility)
4051  int mfem_nc_version = 0;
4052  if (mesh_type == "MFEM NC mesh v1.0") { mfem_nc_version = 10; }
4053  else if (mesh_type == "MFEM mesh v1.1") { mfem_nc_version = 1 /*legacy*/; }
4054 
4055  if (mfem_version)
4056  {
4057  // Formats mfem_v12 and newer have a tag indicating the end of the mesh
4058  // section in the stream. A user provided parse tag can also be provided
4059  // via the arguments. For example, if this is called from parallel mesh
4060  // object, it can indicate to read until parallel mesh section begins.
4061  if (mfem_version == 12 && parse_tag.empty())
4062  {
4063  parse_tag = "mfem_mesh_end";
4064  }
4065  ReadMFEMMesh(input, mfem_version, curved);
4066  }
4067  else if (mfem_nc_version)
4068  {
4069  MFEM_ASSERT(ncmesh == NULL, "internal error");
4070  int is_nc = 1;
4071 
4072 #ifdef MFEM_USE_MPI
4073  ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
4074  if (pmesh)
4075  {
4076  MFEM_VERIFY(mfem_nc_version >= 10,
4077  "Legacy nonconforming format (MFEM mesh v1.1) cannot be "
4078  "used to load a parallel nonconforming mesh, sorry.");
4079 
4080  ncmesh = new ParNCMesh(pmesh->GetComm(),
4081  input, mfem_nc_version, curved, is_nc);
4082  }
4083  else
4084 #endif
4085  {
4086  ncmesh = new NCMesh(input, mfem_nc_version, curved, is_nc);
4087  }
4089 
4090  if (!is_nc)
4091  {
4092  // special case for backward compatibility with MFEM <=4.2:
4093  // if the "vertex_parents" section is missing in the v1.1 format,
4094  // the mesh is treated as conforming
4095  delete ncmesh;
4096  ncmesh = NULL;
4097  }
4098  }
4099  else if (mesh_type == "linemesh") // 1D mesh
4100  {
4101  ReadLineMesh(input);
4102  }
4103  else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2")
4104  {
4105  if (mesh_type == "curved_areamesh2")
4106  {
4107  curved = 1;
4108  }
4109  ReadNetgen2DMesh(input, curved);
4110  }
4111  else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format")
4112  {
4113  ReadNetgen3DMesh(input);
4114  }
4115  else if (mesh_type == "TrueGrid")
4116  {
4117  ReadTrueGridMesh(input);
4118  }
4119  else if (mesh_type.rfind("# vtk DataFile Version") == 0)
4120  {
4121  int major_vtk_version = mesh_type[mesh_type.length()-3] - '0';
4122  // int minor_vtk_version = mesh_type[mesh_type.length()-1] - '0';
4123  MFEM_VERIFY(major_vtk_version >= 2 && major_vtk_version <= 4,
4124  "Unsupported VTK format");
4125  ReadVTKMesh(input, curved, read_gf, finalize_topo);
4126  }
4127  else if (mesh_type.rfind("<VTKFile ") == 0 || mesh_type.rfind("<?xml") == 0)
4128  {
4129  ReadXML_VTKMesh(input, curved, read_gf, finalize_topo, mesh_type);
4130  }
4131  else if (mesh_type == "MFEM NURBS mesh v1.0")
4132  {
4133  ReadNURBSMesh(input, curved, read_gf);
4134  }
4135  else if (mesh_type == "MFEM INLINE mesh v1.0")
4136  {
4137  ReadInlineMesh(input, generate_edges);
4138  return; // done with inline mesh construction
4139  }
4140  else if (mesh_type == "$MeshFormat") // Gmsh
4141  {
4142  ReadGmshMesh(input, curved, read_gf);
4143  }
4144  else if
4145  ((mesh_type.size() > 2 &&
4146  mesh_type[0] == 'C' && mesh_type[1] == 'D' && mesh_type[2] == 'F') ||
4147  (mesh_type.size() > 3 &&
4148  mesh_type[1] == 'H' && mesh_type[2] == 'D' && mesh_type[3] == 'F'))
4149  {
4150  named_ifgzstream *mesh_input = dynamic_cast<named_ifgzstream *>(&input);
4151  if (mesh_input)
4152  {
4153 #ifdef MFEM_USE_NETCDF
4154  ReadCubit(mesh_input->filename.c_str(), curved, read_gf);
4155 #else
4156  MFEM_ABORT("NetCDF support requires configuration with"
4157  " MFEM_USE_NETCDF=YES");
4158  return;
4159 #endif
4160  }
4161  else
4162  {
4163  MFEM_ABORT("Can not determine Cubit mesh filename!"
4164  " Use mfem::named_ifgzstream for input.");
4165  return;
4166  }
4167  }
4168  else
4169  {
4170  MFEM_ABORT("Unknown input mesh format: " << mesh_type);
4171  return;
4172  }
4173 
4174  // at this point the following should be defined:
4175  // 1) Dim
4176  // 2) NumOfElements, elements
4177  // 3) NumOfBdrElements, boundary
4178  // 4) NumOfVertices, with allocated space in vertices
4179  // 5) curved
4180  // 5a) if curved == 0, vertices must be defined
4181  // 5b) if curved != 0 and read_gf != 0,
4182  // 'input' must point to a GridFunction
4183  // 5c) if curved != 0 and read_gf == 0,
4184  // vertices and Nodes must be defined
4185  // optional:
4186  // 1) el_to_edge may be allocated (as in the case of P2 VTK meshes)
4187  // 2) ncmesh may be allocated
4188 
4189  // FinalizeTopology() will:
4190  // - assume that generate_edges is true
4191  // - assume that refine is false
4192  // - does not check the orientation of regular and boundary elements
4193  if (finalize_topo)
4194  {
4195  // don't generate any boundary elements, especially in parallel
4196  bool generate_bdr = false;
4197 
4198  FinalizeTopology(generate_bdr);
4199  }
4200 
4201  if (curved && read_gf)
4202  {
4203  Nodes = new GridFunction(this, input);
4204 
4205  own_nodes = 1;
4206  spaceDim = Nodes->VectorDim();
4207  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
4208 
4209  // Set vertex coordinates from the 'Nodes'
4211  }
4212 
4213  // If a parse tag was supplied, keep reading the stream until the tag is
4214  // encountered.
4215  if (mfem_version == 12)
4216  {
4217  string line;
4218  do
4219  {
4220  skip_comment_lines(input, '#');
4221  MFEM_VERIFY(input.good(), "Required mesh-end tag not found");
4222  getline(input, line);
4223  filter_dos(line);
4224  // mfem v1.2 may not have parse_tag in it, e.g. if trying to read a
4225  // serial mfem v1.2 mesh as parallel with "mfem_serial_mesh_end" as
4226  // parse_tag. That's why, regardless of parse_tag, we stop reading if
4227  // we find "mfem_mesh_end" which is required by mfem v1.2 format.
4228  if (line == "mfem_mesh_end") { break; }
4229  }
4230  while (line != parse_tag);
4231  }
4232  else if (mfem_nc_version >= 10)
4233  {
4234  string ident;
4235  skip_comment_lines(input, '#');
4236  input >> ident;
4237  MFEM_VERIFY(ident == "mfem_mesh_end",
4238  "invalid mesh: end of file tag not found");
4239  }
4240 
4241  // Finalize(...) should be called after this, if needed.
4242 }
4243 
4244 Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
4245 {
4246  int i, j, ie, ib, iv, *v, nv;
4247  Element *el;
4248  Mesh *m;
4249 
4250  SetEmpty();
4251 
4252  Dim = mesh_array[0]->Dimension();
4253  spaceDim = mesh_array[0]->SpaceDimension();
4254 
4255  if (mesh_array[0]->NURBSext)
4256  {
4257  // assuming the pieces form a partition of a NURBS mesh
4258  NURBSext = new NURBSExtension(mesh_array, num_pieces);
4259 
4262 
4264 
4265  // NumOfBdrElements = NURBSext->GetNBE();
4266  // NURBSext->GetBdrElementTopo(boundary);
4267 
4268  Array<int> lvert_vert, lelem_elem;
4269 
4270  // Here, for visualization purposes, we copy the boundary elements from
4271  // the individual pieces which include the interior boundaries. This
4272  // creates 'boundary' array that is different from the one generated by
4273  // the NURBSExtension which, in particular, makes the boundary-dof table
4274  // invalid. This, in turn, causes GetBdrElementTransformation to not
4275  // function properly.
4276  NumOfBdrElements = 0;
4277  for (i = 0; i < num_pieces; i++)
4278  {
4279  NumOfBdrElements += mesh_array[i]->GetNBE();
4280  }
4281  boundary.SetSize(NumOfBdrElements);
4282  vertices.SetSize(NumOfVertices);
4283  ib = 0;
4284  for (i = 0; i < num_pieces; i++)
4285  {
4286  m = mesh_array[i];
4287  m->NURBSext->GetVertexLocalToGlobal(lvert_vert);
4288  m->NURBSext->GetElementLocalToGlobal(lelem_elem);
4289  // copy the element attributes
4290  for (j = 0; j < m->GetNE(); j++)
4291  {
4292  elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j));
4293  }
4294  // copy the boundary
4295  for (j = 0; j < m->GetNBE(); j++)
4296  {
4297  el = m->GetBdrElement(j)->Duplicate(this);
4298  v = el->GetVertices();
4299  nv = el->GetNVertices();
4300  for (int k = 0; k < nv; k++)
4301  {
4302  v[k] = lvert_vert[v[k]];
4303  }
4304  boundary[ib++] = el;
4305  }
4306  // copy the vertices
4307  for (j = 0; j < m->GetNV(); j++)
4308  {
4309  vertices[lvert_vert[j]].SetCoords(m->SpaceDimension(),
4310  m->GetVertex(j));
4311  }
4312  }
4313  }
4314  else // not a NURBS mesh
4315  {
4316  NumOfElements = 0;
4317  NumOfBdrElements = 0;
4318  NumOfVertices = 0;
4319  for (i = 0; i < num_pieces; i++)
4320  {
4321  m = mesh_array[i];
4322  NumOfElements += m->GetNE();
4323  NumOfBdrElements += m->GetNBE();
4324  NumOfVertices += m->GetNV();
4325  }
4326  elements.SetSize(NumOfElements);
4327  boundary.SetSize(NumOfBdrElements);
4328  vertices.SetSize(NumOfVertices);
4329  ie = ib = iv = 0;
4330  for (i = 0; i < num_pieces; i++)
4331  {
4332  m = mesh_array[i];
4333  // copy the elements
4334  for (j = 0; j < m->GetNE(); j++)
4335  {
4336  el = m->GetElement(j)->Duplicate(this);
4337  v = el->GetVertices();
4338  nv = el->GetNVertices();
4339  for (int k = 0; k < nv; k++)
4340  {
4341  v[k] += iv;
4342  }
4343  elements[ie++] = el;
4344  }
4345  // copy the boundary elements
4346  for (j = 0; j < m->GetNBE(); j++)
4347  {
4348  el = m->GetBdrElement(j)->Duplicate(this);
4349  v = el->GetVertices();
4350  nv = el->GetNVertices();
4351  for (int k = 0; k < nv; k++)
4352  {
4353  v[k] += iv;
4354  }
4355  boundary[ib++] = el;
4356  }
4357  // copy the vertices
4358  for (j = 0; j < m->GetNV(); j++)
4359  {
4360  vertices[iv++].SetCoords(m->SpaceDimension(), m->GetVertex(j));
4361  }
4362  }
4363  }
4364 
4365  FinalizeTopology();
4366 
4367  // copy the nodes (curvilinear meshes)
4368  GridFunction *g = mesh_array[0]->GetNodes();
4369  if (g)
4370  {
4371  Array<GridFunction *> gf_array(num_pieces);
4372  for (i = 0; i < num_pieces; i++)
4373  {
4374  gf_array[i] = mesh_array[i]->GetNodes();
4375  }
4376  Nodes = new GridFunction(this, gf_array, num_pieces);
4377  own_nodes = 1;
4378  }
4379 
4380 #ifdef MFEM_DEBUG
4381  CheckElementOrientation(false);
4383 #endif
4384 }
4385 
4386 Mesh::Mesh(Mesh *orig_mesh, int ref_factor, int ref_type)
4387 {
4388  Array<int> ref_factors(orig_mesh->GetNE());
4389  ref_factors = ref_factor;
4390  MakeRefined_(*orig_mesh, ref_factors, ref_type);
4391 }
4392 
4393 void Mesh::MakeRefined_(Mesh &orig_mesh, const Array<int> ref_factors,
4394  int ref_type)
4395 {
4396  SetEmpty();
4397  Dim = orig_mesh.Dimension();
4398  spaceDim = orig_mesh.SpaceDimension();
4399 
4400  int orig_ne = orig_mesh.GetNE();
4401  MFEM_VERIFY(ref_factors.Size() == orig_ne && orig_ne > 0,
4402  "Number of refinement factors must equal number of elements")
4403  MFEM_VERIFY(ref_factors.Min() >= 1, "Refinement factor must be >= 1");
4404  const int q_type = BasisType::GetQuadrature1D(ref_type);
4405  MFEM_VERIFY(Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid,
4406  "Invalid refinement type. Must use closed basis type.");
4407 
4408  int min_ref = ref_factors.Min();
4409  int max_ref = ref_factors.Max();
4410 
4411  bool var_order = (min_ref != max_ref);
4412 
4413  // variable order space can only be constructed over an NC mesh
4414  if (var_order) { orig_mesh.EnsureNCMesh(true); }
4415 
4416  // Construct a scalar H1 FE space of order ref_factor and use its dofs as
4417  // the indices of the new, refined vertices.
4418  H1_FECollection rfec(min_ref, Dim, ref_type);
4419  FiniteElementSpace rfes(&orig_mesh, &rfec);
4420 
4421  if (var_order)
4422  {
4423  rfes.SetRelaxedHpConformity(false);
4424  for (int i = 0; i < orig_ne; i++)
4425  {
4426  rfes.SetElementOrder(i, ref_factors[i]);
4427  }
4428  rfes.Update(false);
4429  }
4430 
4431  // Set the number of vertices, set the actual coordinates later
4432  NumOfVertices = rfes.GetNDofs();
4433  vertices.SetSize(NumOfVertices);
4434 
4435  Array<int> rdofs;
4436  DenseMatrix phys_pts;
4437 
4438  GeometryRefiner refiner;
4439  refiner.SetType(q_type);
4440 
4441  // Add refined elements and set vertex coordinates
4442  for (int el = 0; el < orig_ne; el++)
4443  {
4444  Geometry::Type geom = orig_mesh.GetElementGeometry(el);
4445  int attrib = orig_mesh.GetAttribute(el);
4446  int nvert = Geometry::NumVerts[geom];
4447  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el]);
4448 
4449  rfes.GetElementDofs(el, rdofs);
4450  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4451  const FiniteElement *rfe = rfes.GetFE(el);
4452  orig_mesh.GetElementTransformation(el)->Transform(rfe->GetNodes(),
4453  phys_pts);
4454  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[el]);
4455  for (int i = 0; i < phys_pts.Width(); i++)
4456  {
4457  vertices[rdofs[i]].SetCoords(spaceDim, phys_pts.GetColumn(i));
4458  }
4459  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4460  {
4461  Element *elem = NewElement(geom);
4462  elem->SetAttribute(attrib);
4463  int *v = elem->GetVertices();
4464  for (int k = 0; k < nvert; k++)
4465  {
4466  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4467  v[k] = rdofs[c2h_map[cid]];
4468  }
4469  AddElement(elem);
4470  }
4471  }
4472 
4473  if (Dim > 2)
4474  {
4475  GetElementToFaceTable(false);
4476  GenerateFaces();
4477  }
4478 
4479  // Add refined boundary elements
4480  for (int el = 0; el < orig_mesh.GetNBE(); el++)
4481  {
4482  int i, info;
4483  orig_mesh.GetBdrElementAdjacentElement(el, i, info);
4484  Geometry::Type geom = orig_mesh.GetBdrElementBaseGeometry(el);
4485  int attrib = orig_mesh.GetBdrAttribute(el);
4486  int nvert = Geometry::NumVerts[geom];
4487  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[i]);
4488 
4489  rfes.GetBdrElementDofs(el, rdofs);
4490  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4491  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[i]);
4492  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4493  {
4494  Element *elem = NewElement(geom);
4495  elem->SetAttribute(attrib);
4496  int *v = elem->GetVertices();
4497  for (int k = 0; k < nvert; k++)
4498  {
4499  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4500  v[k] = rdofs[c2h_map[cid]];
4501  }
4502  AddBdrElement(elem);
4503  }
4504  }
4505  FinalizeTopology(false);
4506  sequence = orig_mesh.GetSequence() + 1;
4508 
4509  // Set up the nodes of the new mesh (if the original mesh has nodes). The new
4510  // mesh is always straight-sided (i.e. degree 1 finite element space), but
4511  // the nodes are required for e.g. periodic meshes.
4512  if (orig_mesh.GetNodes())
4513  {
4514  bool discont = orig_mesh.GetNodalFESpace()->IsDGSpace();
4515  Ordering::Type dof_ordering = orig_mesh.GetNodalFESpace()->GetOrdering();
4516  Mesh::SetCurvature(1, discont, spaceDim, dof_ordering);
4517  FiniteElementSpace *nodal_fes = Nodes->FESpace();
4518  const FiniteElementCollection *nodal_fec = nodal_fes->FEColl();
4519  H1_FECollection vertex_fec(1, Dim);
4520  Array<int> dofs;
4521  int el_counter = 0;
4522  for (int iel = 0; iel < orig_ne; iel++)
4523  {
4524  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(iel);
4525  int nvert = Geometry::NumVerts[geom];
4526  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[iel]);
4527  rfes.GetElementDofs(iel, rdofs);
4528  const FiniteElement *rfe = rfes.GetFE(iel);
4529  orig_mesh.GetElementTransformation(iel)->Transform(rfe->GetNodes(),
4530  phys_pts);
4531  const int *node_map = NULL;
4532  const H1_FECollection *h1_fec =
4533  dynamic_cast<const H1_FECollection *>(nodal_fec);
4534  if (h1_fec != NULL) { node_map = h1_fec->GetDofMap(geom); }
4535  const int *vertex_map = vertex_fec.GetDofMap(geom);
4536  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[iel]);
4537  for (int jel = 0; jel < RG.RefGeoms.Size()/nvert; jel++)
4538  {
4539  nodal_fes->GetElementVDofs(el_counter++, dofs);
4540  for (int iv_lex=0; iv_lex<nvert; ++iv_lex)
4541  {
4542  // convert from lexicographic to vertex index
4543  int iv = vertex_map[iv_lex];
4544  // index of vertex of current element in phys_pts matrix
4545  int pt_idx = c2h_map[RG.RefGeoms[iv+nvert*jel]];
4546  // index of current vertex into DOF array
4547  int node_idx = node_map ? node_map[iv_lex] : iv_lex;
4548  for (int d=0; d<spaceDim; ++d)
4549  {
4550  (*Nodes)[dofs[node_idx + d*nvert]] = phys_pts(d,pt_idx);
4551  }
4552  }
4553  }
4554  }
4555  }
4556 
4557  // Setup the data for the coarse-fine refinement transformations
4558  CoarseFineTr.embeddings.SetSize(GetNE());
4559  // First, compute total number of point matrices that we need per geometry
4560  // and the offsets into that array
4561  using GeomRef = std::pair<Geometry::Type, int>;
4562  std::map<GeomRef, int> point_matrices_offsets;
4563  int n_point_matrices[Geometry::NumGeom] = {}; // initialize to zero
4564  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4565  {
4566  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4567  // Have we seen this pair of (goemetry, refinement level) before?
4568  GeomRef id(geom, ref_factors[el_coarse]);
4569  if (point_matrices_offsets.find(id) == point_matrices_offsets.end())
4570  {
4571  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el_coarse]);
4572  int nvert = Geometry::NumVerts[geom];
4573  int nref_el = RG.RefGeoms.Size()/nvert;
4574  // If not, then store the offset and add to the size required
4575  point_matrices_offsets[id] = n_point_matrices[geom];
4576  n_point_matrices[geom] += nref_el;
4577  }
4578  }
4579 
4580  // Set up the sizes
4581  for (int geom = 0; geom < Geometry::NumGeom; ++geom)
4582  {
4583  int nmatrices = n_point_matrices[geom];
4584  int nvert = Geometry::NumVerts[geom];
4585  CoarseFineTr.point_matrices[geom].SetSize(Dim, nvert, nmatrices);
4586  }
4587 
4588  // Compute the point matrices and embeddings
4589  int el_fine = 0;
4590  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4591  {
4592  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4593  int ref = ref_factors[el_coarse];
4594  int offset = point_matrices_offsets[GeomRef(geom, ref)];
4595  int nvert = Geometry::NumVerts[geom];
4596  RefinedGeometry &RG = *refiner.Refine(geom, ref);
4597  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4598  {
4599  DenseMatrix &Pj = CoarseFineTr.point_matrices[geom](offset + j);
4600  for (int k = 0; k < nvert; k++)
4601  {
4602  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4603  const IntegrationPoint &ip = RG.RefPts[cid];
4604  ip.Get(Pj.GetColumn(k), Dim);
4605  }
4606 
4607  Embedding &emb = CoarseFineTr.embeddings[el_fine];
4608  emb.parent = el_coarse;
4609  emb.matrix = offset + j;
4610  ++el_fine;
4611  }
4612  }
4613 
4614  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4615 
4616  // The check below is disabled because is fails for parallel meshes with
4617  // interior "boundary" element that, when such "boundary" element is between
4618  // two elements on different processors.
4619  // MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4620 }
4621 
4622 Mesh Mesh::MakeSimplicial(const Mesh &orig_mesh)
4623 {
4624  Mesh mesh;
4625  mesh.MakeSimplicial_(orig_mesh, NULL);
4626  return mesh;
4627 }
4628 
4629 void Mesh::MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
4630 {
4631  MFEM_VERIFY(const_cast<Mesh&>(orig_mesh).CheckElementOrientation(false) == 0,
4632  "Mesh::MakeSimplicial requires a properly oriented input mesh");
4633  MFEM_VERIFY(orig_mesh.Conforming(),
4634  "Mesh::MakeSimplicial does not support non-conforming meshes.")
4635 
4636  int dim = orig_mesh.Dimension();
4637  int sdim = orig_mesh.SpaceDimension();
4638 
4639  if (dim == 1)
4640  {
4641  Mesh copy(orig_mesh);
4642  Swap(copy, true);
4643  return;
4644  }
4645 
4646  int nv = orig_mesh.GetNV();
4647  int ne = orig_mesh.GetNE();
4648  int nbe = orig_mesh.GetNBE();
4649 
4650  static int num_subdivisions[Geometry::NUM_GEOMETRIES];
4651  num_subdivisions[Geometry::POINT] = 1;
4652  num_subdivisions[Geometry::SEGMENT] = 1;
4653  num_subdivisions[Geometry::TRIANGLE] = 1;
4654  num_subdivisions[Geometry::TETRAHEDRON] = 1;
4655  num_subdivisions[Geometry::SQUARE] = 2;
4656  num_subdivisions[Geometry::PRISM] = 3;
4657  num_subdivisions[Geometry::CUBE] = 6;
4658  // NOTE: some hexes may be subdivided into only 5 tets, so this is an
4659  // estimate only. The actual number of created tets may be less, so the
4660  // elements array will need to be shrunk after mesh creation.
4661  int new_ne = 0, new_nbe = 0;
4662  for (int i=0; i<ne; ++i)
4663  {
4664  new_ne += num_subdivisions[orig_mesh.GetElementBaseGeometry(i)];
4665  }
4666  for (int i=0; i<nbe; ++i)
4667  {
4668  new_nbe += num_subdivisions[orig_mesh.GetBdrElementBaseGeometry(i)];
4669  }
4670 
4671  InitMesh(dim, sdim, nv, new_ne, new_nbe);
4672 
4673  // Vertices of the new mesh are same as the original mesh
4674  NumOfVertices = nv;
4675  for (int i=0; i<nv; ++i)
4676  {
4677  vertices[i].SetCoords(dim, orig_mesh.vertices[i]());
4678  }
4679 
4680  // We need a global vertex numbering to identify which diagonals to split
4681  // (quad faces are split using the diagonal originating from the smallest
4682  // global vertex number). Use the supplied global numbering, if it is
4683  // non-NULL, otherwise use the local numbering.
4684  Array<int> vglobal_id;
4685  if (vglobal == NULL)
4686  {
4687  vglobal_id.SetSize(nv);
4688  for (int i=0; i<nv; ++i) { vglobal_id[i] = i; }
4689  vglobal = vglobal_id.GetData();
4690  }
4691 
4692  constexpr int nv_tri = 3, nv_quad = 4, nv_tet = 4, nv_prism = 6, nv_hex = 8;
4693  constexpr int quad_ntris = 2, prism_ntets = 3;
4694  static const int quad_trimap[2][nv_tri*quad_ntris] =
4695  {
4696  {
4697  0, 0,
4698  1, 2,
4699  2, 3
4700  },{
4701  0, 1,
4702  1, 2,
4703  3, 3
4704  }
4705  };
4706  static const int prism_rot[nv_prism*nv_prism] =
4707  {
4708  0, 1, 2, 3, 4, 5,
4709  1, 2, 0, 4, 5, 3,
4710  2, 0, 1, 5, 3, 4,
4711  3, 5, 4, 0, 2, 1,
4712  4, 3, 5, 1, 0, 2,
4713  5, 4, 3, 2, 1, 0
4714  };
4715  static const int prism_f[nv_quad] = {1, 2, 5, 4};
4716  static const int prism_tetmaps[2][nv_prism*prism_ntets] =
4717  {
4718  {
4719  0, 0, 0,
4720  1, 1, 4,
4721  2, 5, 5,
4722  5, 4, 3
4723  },{
4724  0, 0, 0,
4725  1, 4, 4,
4726  2, 2, 5,
4727  4, 5, 3
4728  }
4729  };
4730  static const int hex_rot[nv_hex*nv_hex] =
4731  {
4732  0, 1, 2, 3, 4, 5, 6, 7,
4733  1, 0, 4, 5, 2, 3, 7, 6,
4734  2, 1, 5, 6, 3, 0, 4, 7,
4735  3, 0, 1, 2, 7, 4, 5, 6,
4736  4, 0, 3, 7, 5, 1, 2, 6,
4737  5, 1, 0, 4, 6, 2, 3, 7,
4738  6, 2, 1, 5, 7, 3, 0, 4,
4739  7, 3, 2, 6, 4, 0, 1, 5
4740  };
4741  static const int hex_f0[nv_quad] = {1, 2, 6, 5};
4742  static const int hex_f1[nv_quad] = {2, 3, 7, 6};
4743  static const int hex_f2[nv_quad] = {4, 5, 6, 7};
4744  static const int num_rot[8] = {0, 1, 2, 0, 0, 2, 1, 0};
4745  static const int hex_tetmap0[nv_tet*5] =
4746  {
4747  0, 0, 0, 0, 2,
4748  1, 2, 2, 5, 7,
4749  2, 7, 3, 7, 5,
4750  5, 5, 7, 4, 6
4751  };
4752  static const int hex_tetmap1[nv_tet*6] =
4753  {
4754  0, 0, 1, 0, 0, 1,
4755  5, 1, 6, 7, 7, 7,
4756  7, 7, 7, 2, 1, 6,
4757  4, 5, 5, 3, 2, 2
4758  };
4759  static const int hex_tetmap2[nv_tet*6] =
4760  {
4761  0, 0, 0, 0, 0, 0,
4762  4, 3, 7, 1, 3, 6,
4763  5, 7, 4, 2, 6, 5,
4764  6, 6, 6, 5, 2, 2
4765  };
4766  static const int hex_tetmap3[nv_tet*6] =
4767  {
4768  0, 0, 0, 0, 1, 1,
4769  2, 3, 7, 5, 5, 6,
4770  3, 7, 4, 6, 6, 2,
4771  6, 6, 6, 4, 0, 0
4772  };
4773  static const int *hex_tetmaps[4] =
4774  {
4775  hex_tetmap0, hex_tetmap1, hex_tetmap2, hex_tetmap3
4776  };
4777 
4778  auto find_min = [](const int*a, int n) { return std::min_element(a,a+n)-a; };
4779 
4780  for (int i=0; i<ne; ++i)
4781  {
4782  const int *v = orig_mesh.elements[i]->GetVertices();
4783  const int attrib = orig_mesh.GetAttribute(i);
4784  const Geometry::Type orig_geom = orig_mesh.GetElementBaseGeometry(i);
4785 
4786  if (num_subdivisions[orig_geom] == 1)
4787  {
4788  // (num_subdivisions[orig_geom] == 1) implies that the element does
4789  // not need to be further split (it is either a segment, triangle,
4790  // or tetrahedron), and so it is left unchanged.
4791  Element *e = NewElement(orig_geom);
4792  e->SetAttribute(attrib);
4793  e->SetVertices(v);
4794  AddElement(e);
4795  }
4796  else if (orig_geom == Geometry::SQUARE)
4797  {
4798  for (int itri=0; itri<quad_ntris; ++itri)
4799  {
4801  e->SetAttribute(attrib);
4802  int *v2 = e->GetVertices();
4803  for (int iv=0; iv<nv_tri; ++iv)
4804  {
4805  v2[iv] = v[quad_trimap[0][itri + iv*quad_ntris]];
4806  }
4807  AddElement(e);
4808  }
4809  }
4810  else if (orig_geom == Geometry::PRISM)
4811  {
4812  int vg[nv_prism];
4813  for (int iv=0; iv<nv_prism; ++iv) { vg[iv] = vglobal[v[iv]]; }
4814  // Rotate the vertices of the prism so that the smallest vertex index
4815  // is in the first place
4816  int irot = find_min(vg, nv_prism);
4817  for (int iv=0; iv<nv_prism; ++iv)
4818  {
4819  int jv = prism_rot[iv + irot*nv_prism];
4820  vg[iv] = v[jv];
4821  }
4822  // Two cases according to which diagonal splits third quad face
4823  int q[nv_quad];
4824  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[prism_f[iv]]]; }
4825  int j = find_min(q, nv_quad);
4826  const int *tetmap = (j == 0 || j == 2) ? prism_tetmaps[0] : prism_tetmaps[1];
4827  for (int itet=0; itet<prism_ntets; ++itet)
4828  {
4830  e->SetAttribute(attrib);
4831  int *v2 = e->GetVertices();
4832  for (int iv=0; iv<nv_tet; ++iv)
4833  {
4834  v2[iv] = vg[tetmap[itet + iv*prism_ntets]];
4835  }
4836  AddElement(e);
4837  }
4838  }
4839  else if (orig_geom == Geometry::CUBE)
4840  {
4841  int vg[nv_hex];
4842  for (int iv=0; iv<nv_hex; ++iv) { vg[iv] = vglobal[v[iv]]; }
4843 
4844  // Rotate the vertices of the hex so that the smallest vertex index is
4845  // in the first place
4846  int irot = find_min(vg, nv_hex);
4847  for (int iv=0; iv<nv_hex; ++iv)
4848  {
4849  int jv = hex_rot[iv + irot*nv_hex];
4850  vg[iv] = v[jv];
4851  }
4852 
4853  int q[nv_quad];
4854  // Bitmask is three binary digits, each digit is 1 if the diagonal of
4855  // the corresponding face goes through the 7th vertex, and 0 if not.
4856  int bitmask = 0;
4857  int j;
4858  // First quad face
4859  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f0[iv]]]; }
4860  j = find_min(q, nv_quad);
4861  if (j == 0 || j == 2) { bitmask += 4; }
4862  // Second quad face
4863  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f1[iv]]]; }
4864  j = find_min(q, nv_quad);
4865  if (j == 1 || j == 3) { bitmask += 2; }
4866  // Third quad face
4867  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f2[iv]]]; }
4868  j = find_min(q, nv_quad);
4869  if (j == 0 || j == 2) { bitmask += 1; }
4870 
4871  // Apply rotations
4872  int nrot = num_rot[bitmask];
4873  for (int k=0; k<nrot; ++k)
4874  {
4875  int vtemp;
4876  vtemp = vg[1];
4877  vg[1] = vg[4];
4878  vg[4] = vg[3];
4879  vg[3] = vtemp;
4880  vtemp = vg[5];
4881  vg[5] = vg[7];
4882  vg[7] = vg[2];
4883  vg[2] = vtemp;
4884  }
4885 
4886  // Sum up nonzero bits in bitmask
4887  int ndiags = ((bitmask&4) >> 2) + ((bitmask&2) >> 1) + (bitmask&1);
4888  int ntets = (ndiags == 0) ? 5 : 6;
4889  const int *tetmap = hex_tetmaps[ndiags];
4890  for (int itet=0; itet<ntets; ++itet)
4891  {
4893  e->SetAttribute(attrib);
4894  int *v2 = e->GetVertices();
4895  for (int iv=0; iv<nv_tet; ++iv)
4896  {
4897  v2[iv] = vg[tetmap[itet + iv*ntets]];
4898  }
4899  AddElement(e);
4900  }
4901  }
4902  }
4903  // In 3D, shrink the element array because some hexes have only 5 tets
4904  if (dim == 3) { elements.SetSize(NumOfElements); }
4905 
4906  for (int i=0; i<nbe; ++i)
4907  {
4908  const int *v = orig_mesh.boundary[i]->GetVertices();
4909  const int attrib = orig_mesh.GetBdrAttribute(i);
4910  const Geometry::Type orig_geom = orig_mesh.GetBdrElementBaseGeometry(i);
4911  if (num_subdivisions[orig_geom] == 1)
4912  {
4913  Element *be = NewElement(orig_geom);
4914  be->SetAttribute(attrib);
4915  be->SetVertices(v);
4916  AddBdrElement(be);
4917  }
4918  else if (orig_geom == Geometry::SQUARE)
4919  {
4920  int vg[nv_quad];
4921  for (int iv=0; iv<nv_quad; ++iv) { vg[iv] = vglobal[v[iv]]; }
4922  // Split quad according the smallest (global) vertex
4923  int iv_min = find_min(vg, nv_quad);
4924  int isplit = (iv_min == 0 || iv_min == 2) ? 0 : 1;
4925  for (int itri=0; itri<quad_ntris; ++itri)
4926  {
4928  be->SetAttribute(attrib);
4929  int *v2 = be->GetVertices();
4930  for (int iv=0; iv<nv_tri; ++iv)
4931  {
4932  v2[iv] = v[quad_trimap[isplit][itri + iv*quad_ntris]];
4933  }
4934  AddBdrElement(be);
4935  }
4936  }
4937  else
4938  {
4939  MFEM_ABORT("Unreachable");
4940  }
4941  }
4942 
4943  FinalizeTopology(false);
4944  sequence = orig_mesh.GetSequence();
4945  last_operation = orig_mesh.last_operation;
4946 
4947  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4948  MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4949 }
4950 
4951 Mesh Mesh::MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v)
4952 {
4953  Mesh periodic_mesh(orig_mesh, true); // Make a copy of the original mesh
4954  const FiniteElementSpace *nodal_fes = orig_mesh.GetNodalFESpace();
4955  int nodal_order = nodal_fes ? nodal_fes->GetMaxElementOrder() : 1;
4956  periodic_mesh.SetCurvature(nodal_order, true);
4957 
4958  // renumber element vertices
4959  for (int i = 0; i < periodic_mesh.GetNE(); i++)
4960  {
4961  Element *el = periodic_mesh.GetElement(i);
4962  int *v = el->GetVertices();
4963  int nv = el->GetNVertices();
4964  for (int j = 0; j < nv; j++)
4965  {
4966  v[j] = v2v[v[j]];
4967  }
4968  }
4969  // renumber boundary element vertices
4970  for (int i = 0; i < periodic_mesh.GetNBE(); i++)
4971  {
4972  Element *el = periodic_mesh.GetBdrElement(i);
4973  int *v = el->GetVertices();
4974  int nv = el->GetNVertices();
4975  for (int j = 0; j < nv; j++)
4976  {
4977  v[j] = v2v[v[j]];
4978  }
4979  }
4980 
4981  periodic_mesh.RemoveUnusedVertices();
4982  return periodic_mesh;
4983 }
4984 
4986  const std::vector<Vector> &translations, double tol) const
4987 {
4988  int sdim = SpaceDimension();
4989 
4990  Vector coord(sdim), at(sdim), dx(sdim);
4991  Vector xMax(sdim), xMin(sdim), xDiff(sdim);
4992  xMax = xMin = xDiff = 0.0;
4993 
4994  // Get a list of all vertices on the boundary
4995  set<int> bdr_v;
4996  for (int be = 0; be < GetNBE(); be++)
4997  {
4998  Array<int> dofs;
4999  GetBdrElementVertices(be,dofs);
5000 
5001  for (int i = 0; i < dofs.Size(); i++)
5002  {
5003  bdr_v.insert(dofs[i]);
5004 
5005  coord = GetVertex(dofs[i]);
5006  for (int j = 0; j < sdim; j++)
5007  {
5008  xMax[j] = max(xMax[j], coord[j]);
5009  xMin[j] = min(xMin[j], coord[j]);
5010  }
5011  }
5012  }
5013  add(xMax, -1.0, xMin, xDiff);
5014  double dia = xDiff.Norml2(); // compute mesh diameter
5015 
5016  // We now identify coincident vertices. Several originally distinct vertices
5017  // may become coincident under the periodic mapping. One of these vertices
5018  // will be identified as the "primary" vertex, and all other coincident
5019  // vertices will be considered as "replicas".
5020 
5021  // replica2primary[v] is the index of the primary vertex of replica `v`
5022  map<int, int> replica2primary;
5023  // primary2replicas[v] is a set of indices of replicas of primary vertex `v`
5024  map<int, set<int>> primary2replicas;
5025 
5026  // We begin with the assumption that all vertices are primary, and that there
5027  // are no replicas.
5028  for (int v : bdr_v) { primary2replicas[v]; }
5029 
5030  // Make `r` and all of `r`'s replicas be replicas of `p`. Delete `r` from the
5031  // list of primary vertices.
5032  auto make_replica = [&replica2primary, &primary2replicas](int r, int p)
5033  {
5034  if (r == p) { return; }
5035  primary2replicas[p].insert(r);
5036  replica2primary[r] = p;
5037  for (int s : primary2replicas[r])
5038  {
5039  primary2replicas[p].insert(s);
5040  replica2primary[s] = p;
5041  }
5042  primary2replicas.erase(r);
5043  };
5044 
5045  for (unsigned int i = 0; i < translations.size(); i++)
5046  {
5047  for (int vi : bdr_v)
5048  {
5049  coord = GetVertex(vi);
5050  add(coord, translations[i], at);
5051 
5052  for (int vj : bdr_v)
5053  {
5054  coord = GetVertex(vj);
5055  add(at, -1.0, coord, dx);
5056  if (dx.Norml2() > dia*tol) { continue; }
5057 
5058  // The two vertices vi and vj are coincident.
5059 
5060  // Are vertices `vi` and `vj` already primary?
5061  bool pi = primary2replicas.find(vi) != primary2replicas.end();
5062  bool pj = primary2replicas.find(vj) != primary2replicas.end();
5063 
5064  if (pi && pj)
5065  {
5066  // Both vertices are currently primary
5067  // Demote `vj` to be a replica of `vi`
5068  make_replica(vj, vi);
5069  }
5070  else if (pi && !pj)
5071  {
5072  // `vi` is primary and `vj` is a replica
5073  int owner_of_vj = replica2primary[vj];
5074  // Make `vi` and its replicas be replicas of `vj`'s owner
5075  make_replica(vi, owner_of_vj);
5076  }
5077  else if (!pi && pj)
5078  {
5079  // `vi` is currently a replica and `vj` is currently primary
5080  // Make `vj` and its replicas be replicas of `vi`'s owner
5081  int owner_of_vi = replica2primary[vi];
5082  make_replica(vj, owner_of_vi);
5083  }
5084  else
5085  {
5086  // Both vertices are currently replicas
5087  // Make `vj`'s owner and all of its owner's replicas be replicas
5088  // of `vi`'s owner
5089  int owner_of_vi = replica2primary[vi];
5090  int owner_of_vj = replica2primary[vj];
5091  make_replica(owner_of_vj, owner_of_vi);
5092  }
5093  break;
5094  }
5095  }
5096  }
5097 
5098  std::vector<int> v2v(GetNV());
5099  for (size_t i = 0; i < v2v.size(); i++)
5100  {
5101  v2v[i] = i;
5102  }
5103  for (auto &&r2p : replica2primary)
5104  {
5105  v2v[r2p.first] = r2p.second;
5106  }
5107  return v2v;
5108 }
5109 
5110 void Mesh::RefineNURBSFromFile(std::string ref_file)
5111 {
5112  MFEM_VERIFY(NURBSext,"Mesh::RefineNURBSFromFile: Not a NURBS mesh!");
5113  mfem::out<<"Refining NURBS from refinement file: "<<ref_file<<endl;
5114 
5115  int nkv;
5116  ifstream input(ref_file);
5117  input >> nkv;
5118 
5119  // Check if the number of knot vectors in the refinement file and mesh match
5120  if ( nkv != NURBSext->GetNKV())
5121  {
5122  mfem::out<<endl;
5123  mfem::out<<"Knot vectors in ref_file: "<<nkv<<endl;
5124  mfem::out<<"Knot vectors in NURBSExt: "<<NURBSext->GetNKV()<<endl;
5125  MFEM_ABORT("Refine file does not have the correct number of knot vectors");
5126  }
5127 
5128  // Read knot vectors from file
5129  Array<Vector *> knotVec(nkv);
5130  for (int kv = 0; kv < nkv; kv++)
5131  {
5132  knotVec[kv] = new Vector();
5133  knotVec[kv]-> Load(input);
5134  }
5135  input.close();
5136 
5137  // Insert knots
5138  KnotInsert(knotVec);
5139 
5140  // Delete knots
5141  for (int kv = 0; kv < nkv; kv++)
5142  {
5143  delete knotVec[kv];
5144  }
5145 }
5146 
5148 {
5149  if (NURBSext == NULL)
5150  {
5151  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5152  }
5153 
5154  if (kv.Size() != NURBSext->GetNKV())
5155  {
5156  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5157  }
5158 
5160 
5161  NURBSext->KnotInsert(kv);
5162 
5163  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5164  sequence++;
5165 
5166  UpdateNURBS();
5167 }
5168 
5170 {
5171  if (NURBSext == NULL)
5172  {
5173  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5174  }
5175 
5176  if (kv.Size() != NURBSext->GetNKV())
5177  {
5178  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5179  }
5180 
5182 
5183  NURBSext->KnotInsert(kv);
5184 
5185  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5186  sequence++;
5187 
5188  UpdateNURBS();
5189 }
5190 
5192 {
5193  // do not check for NURBSext since this method is protected
5195 
5197 
5198  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5199  sequence++;
5200 
5201  UpdateNURBS();
5202 }
5203 
5204 void Mesh::DegreeElevate(int rel_degree, int degree)
5205 {
5206  if (NURBSext == NULL)
5207  {
5208  mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!");
5209  }
5210 
5212 
5213  NURBSext->DegreeElevate(rel_degree, degree);
5214 
5215  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5216  sequence++;
5217 
5218  UpdateNURBS();
5219 }
5220 
5222 {
5223  ResetLazyData();
5224 
5226 
5227  Dim = NURBSext->Dimension();
5228  spaceDim = Dim;
5229 
5230  if (NumOfElements != NURBSext->GetNE())
5231  {
5232  for (int i = 0; i < elements.Size(); i++)
5233  {
5234  FreeElement(elements[i]);
5235  }
5238  }
5239 
5240  if (NumOfBdrElements != NURBSext->GetNBE())
5241  {
5242  for (int i = 0; i < boundary.Size(); i++)
5243  {
5244  FreeElement(boundary[i]);
5245  }
5248  }
5249 
5250  Nodes->FESpace()->Update();
5251  Nodes->Update();
5253 
5254  if (NumOfVertices != NURBSext->GetNV())
5255  {
5257  vertices.SetSize(NumOfVertices);
5258  int vd = Nodes->VectorDim();
5259  for (int i = 0; i < vd; i++)
5260  {
5261  Vector vert_val;
5262  Nodes->GetNodalValues(vert_val, i+1);
5263  for (int j = 0; j < NumOfVertices; j++)
5264  {
5265  vertices[j](i) = vert_val(j);
5266  }
5267  }
5268  }
5269 
5270  if (el_to_edge)
5271  {
5273  }
5274 
5275  if (el_to_face)
5276  {
5278  }
5279  GenerateFaces();
5280 }
5281 
5282 void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot)
5283 {
5284  SetEmpty();
5285 
5286  // Read MFEM NURBS mesh v1.0 format
5287  string ident;
5288 
5289  skip_comment_lines(input, '#');
5290 
5291  input >> ident; // 'dimension'
5292  input >> Dim;
5293  spaceDim = Dim;
5294 
5295  skip_comment_lines(input, '#');
5296 
5297  input >> ident; // 'elements'
5298  input >> NumOfElements;
5299  elements.SetSize(NumOfElements);
5300  for (int j = 0; j < NumOfElements; j++)
5301  {
5302  elements[j] = ReadElement(input);
5303  }
5304 
5305  skip_comment_lines(input, '#');
5306 
5307  input >> ident; // 'boundary'
5308  input >> NumOfBdrElements;
5309  boundary.SetSize(NumOfBdrElements);
5310  for (int j = 0; j < NumOfBdrElements; j++)
5311  {
5312  boundary[j] = ReadElement(input);
5313  }
5314 
5315  skip_comment_lines(input, '#');
5316 
5317  input >> ident; // 'edges'
5318  input >> NumOfEdges;
5319  if (NumOfEdges > 0)
5320  {
5321  edge_vertex = new Table(NumOfEdges, 2);
5322  edge_to_knot.SetSize(NumOfEdges);
5323  for (int j = 0; j < NumOfEdges; j++)
5324  {
5325  int *v = edge_vertex->GetRow(j);
5326  input >> edge_to_knot[j] >> v[0] >> v[1];
5327  if (v[0] > v[1])
5328  {
5329  edge_to_knot[j] = -1 - edge_to_knot[j];
5330  }
5331  }
5332  }
5333  else
5334  {
5335  edge_to_knot.SetSize(0);
5336  }
5337 
5338  skip_comment_lines(input, '#');
5339 
5340  input >> ident; // 'vertices'
5341  input >> NumOfVertices;
5342  vertices.SetSize(0);
5343 
5344  FinalizeTopology();
5345  CheckBdrElementOrientation(); // check and fix boundary element orientation
5346 
5347  /* Generate knot 2 edge mapping -- if edges are not specified in the mesh file
5348  See data/two-squares-nurbs-autoedge.mesh for an example */
5349  if (edge_to_knot.Size() == 0)
5350  {
5351  edge_vertex = new Table(NumOfEdges, 2);
5352  edge_to_knot.SetSize(NumOfEdges);
5353  constexpr int notset = -9999999;
5354  edge_to_knot = notset;
5355  Array<int> edges;
5356  Array<int> oedge;
5357  int knot = 0;
5358 
5359  Array<int> edge0, edge1;
5360  int flip = 1;
5361  if (Dimension() == 2 )
5362  {
5363  edge0.SetSize(2);
5364  edge1.SetSize(2);
5365 
5366  edge0[0] = 0; edge1[0] = 2;
5367  edge0[1] = 1; edge1[1] = 3;
5368  flip = 1;
5369  }
5370  else if (Dimension() == 3 )
5371  {
5372  edge0.SetSize(9);
5373  edge1.SetSize(9);
5374 
5375  edge0[0] = 0; edge1[0] = 2;
5376  edge0[1] = 0; edge1[1] = 4;
5377  edge0[2] = 0; edge1[2] = 6;
5378 
5379  edge0[3] = 1; edge1[3] = 3;
5380  edge0[4] = 1; edge1[4] = 5;
5381  edge0[5] = 1; edge1[5] = 7;
5382 
5383  edge0[6] = 8; edge1[6] = 9;
5384  edge0[7] = 8; edge1[7] = 10;
5385  edge0[8] = 8; edge1[8] = 11;
5386  flip = -1;
5387  }
5388 
5389  /* Initial assignment of knots to edges. This is an algorithm that loops over the
5390  patches and assigns knot vectors to edges. It starts with assigning knot vector 0
5391  and 1 to the edges of the first patch. Then it uses: 1) patches can share edges
5392  2) knot vectors on opposing edges in a patch are equal, to create edge_to_knot */
5393  int e0, e1, v0, v1, df;
5394  int p,j,k;
5395  for (p = 0; p < GetNE(); p++)
5396  {
5397  GetElementEdges(p, edges, oedge);
5398 
5399  const int *v = elements[p]->GetVertices();
5400  for (j = 0; j < edges.Size(); j++)
5401  {
5402  int *vv = edge_vertex->GetRow(edges[j]);
5403  const int *e = elements[p]->GetEdgeVertices(j);
5404  if (oedge[j] == 1)
5405  {
5406  vv[0] = v[e[0]];
5407  vv[1] = v[e[1]];
5408  }
5409  else
5410  {
5411  vv[0] = v[e[1]];
5412  vv[1] = v[e[0]];
5413  }
5414  }
5415 
5416  for (j = 0; j < edge1.Size(); j++)
5417  {
5418  e0 = edges[edge0[j]];
5419  e1 = edges[edge1[j]];
5420  v0 = edge_to_knot[e0];
5421  v1 = edge_to_knot[e1];
5422  df = flip*oedge[edge0[j]]*oedge[edge1[j]];
5423 
5424  // Case 1: knot vector is not set
5425  if ((v0 == notset) && (v1 == notset))
5426  {
5427  edge_to_knot[e0] = knot;
5428  edge_to_knot[e1] = knot;
5429  knot++;
5430  }
5431  // Case 2 & 3: knot vector on one of the two edges
5432  // is set earlier (in another patch). We just have
5433  // to copy it for the opposing edge.
5434  else if ((v0 != notset) && (v1 == notset))
5435  {
5436  edge_to_knot[e1] = (df >= 0 ? -v0-1 : v0);
5437  }
5438  else if ((v0 == notset) && (v1 != notset))
5439  {
5440  edge_to_knot[e0] = (df >= 0 ? -v1-1 : v1);
5441  }
5442  }
5443  }
5444 
5445  /* Verify correct assignment, make sure that corresponding edges
5446  within patch point to same knot vector. If not assign the lowest number.
5447 
5448  We bound the while by GetNE() + 1 as this is probably the most unlucky
5449  case. +1 to finish without corrections. Note that this is a check and
5450  in general the initial assignment is correct. Then the while is performed
5451  only once. Only on very tricky meshes it might need corrections.*/
5452  int corrections;
5453  int passes = 0;
5454  do
5455  {
5456  corrections = 0;
5457  for (p = 0; p < GetNE(); p++)
5458  {
5459  GetElementEdges(p, edges, oedge);
5460  for (j = 0; j < edge1.Size(); j++)
5461  {
5462  e0 = edges[edge0[j]];
5463  e1 = edges[edge1[j]];
5464  v0 = edge_to_knot[e0];
5465  v1 = edge_to_knot[e1];
5466  v0 = ( v0 >= 0 ? v0 : -v0-1);
5467  v1 = ( v1 >= 0 ? v1 : -v1-1);
5468  if (v0 != v1)
5469  {
5470  corrections++;
5471  if (v0 < v1)
5472  {
5473  edge_to_knot[e1] = (oedge[edge1[j]] >= 0 ? v0 : -v0-1);
5474  }
5475  else if (v1 < v0)
5476  {
5477  edge_to_knot[e0] = (oedge[edge0[j]] >= 0 ? v1 : -v1-1);
5478  }
5479  }
5480  }
5481  }
5482 
5483  passes++;
5484  }
5485  while (corrections > 0 && passes < GetNE() + 1);
5486 
5487  // Check the validity of corrections applied
5488  if (corrections > 0 )
5489  {
5490  mfem::err<<"Edge_to_knot mapping potentially incorrect"<<endl;
5491  mfem::err<<" passes = "<<passes<<endl;
5492  mfem::err<<" corrections = "<<corrections<<endl;
5493  }
5494 
5495  /* Renumber knotvectors, such that:
5496  -- numbering is consecutive
5497  -- starts at zero */
5498  Array<int> cnt(NumOfEdges);
5499  cnt = 0;
5500  for (j = 0; j < NumOfEdges; j++)
5501  {
5502  k = edge_to_knot[j];
5503  cnt[(k >= 0 ? k : -k-1)]++;
5504  }
5505 
5506  k = 0;
5507  for (j = 0; j < cnt.Size(); j++)
5508  {
5509  cnt[j] = (cnt[j] > 0 ? k++ : -1);
5510  }
5511 
5512  for (j = 0; j < NumOfEdges; j++)
5513  {
5514  k = edge_to_knot[j];
5515  edge_to_knot[j] = (k >= 0 ? cnt[k]:-cnt[-k-1]-1);
5516  }
5517 
5518  // Print knot to edge mapping
5519  mfem::out<<"Generated edge to knot mapping:"<<endl;
5520  for (j = 0; j < NumOfEdges; j++)
5521  {
5522  int *v = edge_vertex->GetRow(j);
5523  k = edge_to_knot[j];
5524 
5525  v0 = v[0];
5526  v1 = v[1];
5527  if (k < 0)
5528  {
5529  v[0] = v1;
5530  v[1] = v0;
5531  }
5532  mfem::out<<(k >= 0 ? k:-k-1)<<" "<< v[0] <<" "<<v[1]<<endl;
5533  }
5534 
5535  // Terminate here upon failure after printing to have an idea of edge_to_knot.
5536  if (corrections > 0 ) {mfem_error("Mesh::LoadPatchTopo");}
5537  }
5538 }
5539 
5541 {
5542  if (p.Size() >= v.Size())
5543  {
5544  for (int d = 0; d < v.Size(); d++)
5545  {
5546  v(d) = p(d);
5547  }
5548  }
5549  else
5550  {
5551  int d;
5552  for (d = 0; d < p.Size(); d++)
5553  {
5554  v(d) = p(d);
5555  }
5556  for ( ; d < v.Size(); d++)
5557  {
5558  v(d) = 0.0;
5559  }
5560  }
5561 }
5562 
5563 void Mesh::GetNodes(GridFunction &nodes) const
5564 {
5565  if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
5566  {
5567  const int newSpaceDim = nodes.FESpace()->GetVDim();
5569  nodes.ProjectCoefficient(xyz);
5570  }
5571  else
5572  {
5573  nodes = *Nodes;
5574  }
5575 }
5576 
5578 {
5579  GridFunction *nodes = new GridFunction(nfes);
5580  SetNodalGridFunction(nodes, true);
5581 }
5582 
5584 {
5585  if (Nodes)
5586  {
5588  if (dynamic_cast<const H1_FECollection*>(fec)
5589  || dynamic_cast<const L2_FECollection*>(fec))
5590  {
5591  return;
5592  }
5593  else // Mesh using a legacy FE_Collection
5594  {
5595  const int order = GetNodalFESpace()->GetElementOrder(0);
5596  if (NURBSext)
5597  {
5598 #ifndef MFEM_USE_MPI
5599  const bool warn = true;
5600 #else
5601  ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
5602  const bool warn = !pmesh || pmesh->GetMyRank() == 0;
5603 #endif
5604  if (warn)
5605  {
5606  MFEM_WARNING("converting NURBS mesh to order " << order <<
5607  " H1-continuous mesh!\n "
5608  "If this is the desired behavior, you can silence"
5609  " this warning by converting\n "
5610  "the NURBS mesh to high-order mesh in advance by"
5611  " calling the method\n "
5612  "Mesh::SetCurvature().");
5613  }
5614  }
5615  SetCurvature(order, false, -1, Ordering::byVDIM);
5616  }
5617  }
5618  else // First order H1 mesh
5619  {
5620  SetCurvature(1, false, -1, Ordering::byVDIM);
5621  }
5622 }
5623 
5624 void Mesh::SetNodalGridFunction(GridFunction *nodes, bool make_owner)
5625 {
5626  GetNodes(*nodes);
5627  NewNodes(*nodes, make_owner);
5628 }
5629 
5631 {
5632  return ((Nodes) ? Nodes->FESpace() : NULL);
5633 }
5634 
5635 void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
5636 {
5637  space_dim = (space_dim == -1) ? spaceDim : space_dim;
5639  if (discont)
5640  {
5641  const int type = 1; // Gauss-Lobatto points
5642  nfec = new L2_FECollection(order, Dim, type);
5643  }
5644  else
5645  {
5646  nfec = new H1_FECollection(order, Dim);
5647  }
5648  FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
5649  ordering);
5650  SetNodalFESpace(nfes);
5651  Nodes->MakeOwner(nfec);
5652 }
5653 
5655 {
5656  MFEM_ASSERT(nodes != NULL, "");
5657  for (int i = 0; i < spaceDim; i++)
5658  {
5659  Vector vert_val;
5660  nodes->GetNodalValues(vert_val, i+1);
5661  for (int j = 0; j < NumOfVertices; j++)
5662  {
5663  vertices[j](i) = vert_val(j);
5664  }
5665  }
5666 }
5667 
5669 {
5670  switch (Dim)
5671  {
5672  case 1: return GetNV();
5673  case 2: return GetNEdges();
5674  case 3: return GetNFaces();
5675  }
5676  return 0;
5677 }
5678 
5680 {
5681  return faces_info.Size();
5682 }
5683 
5685 {
5686  const bool isInt = type==FaceType::Interior;
5687  int &nf = isInt ? nbInteriorFaces : nbBoundaryFaces;
5688  if (nf<0)
5689  {
5690  nf = 0;
5691  for (int f = 0; f < GetNumFacesWithGhost(); ++f)
5692  {
5694  if ( face.IsOfFaceType(type) )
5695  {
5696  if (face.IsNonconformingCoarse())
5697  {
5698  // We don't count nonconforming coarse faces.
5699  continue;
5700  }
5701  nf++;
5702  }
5703  }
5704  }
5705  return nf;
5706 }
5707 
5708 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5709 static const char *fixed_or_not[] = { "fixed", "NOT FIXED" };
5710 #endif
5711 
5713 {
5714  int i, j, k, wo = 0, fo = 0;
5715  double *v[4];
5716 
5717  if (Dim == 2 && spaceDim == 2)
5718  {
5719  DenseMatrix J(2, 2);
5720 
5721  for (i = 0; i < NumOfElements; i++)
5722  {
5723  int *vi = elements[i]->GetVertices();
5724  if (Nodes == NULL)
5725  {
5726  for (j = 0; j < 3; j++)
5727  {
5728  v[j] = vertices[vi[j]]();
5729  }
5730  for (j = 0; j < 2; j++)
5731  for (k = 0; k < 2; k++)
5732  {
5733  J(j, k) = v[j+1][k] - v[0][k];
5734  }
5735  }
5736  else
5737  {
5738  // only check the Jacobian at the center of the element
5739  GetElementJacobian(i, J);
5740  }
5741  if (J.Det() < 0.0)
5742  {
5743  if (fix_it)
5744  {
5745  switch (GetElementType(i))
5746  {
5747  case Element::TRIANGLE:
5748  mfem::Swap(vi[0], vi[1]);
5749  break;
5751  mfem::Swap(vi[1], vi[3]);
5752  break;
5753  default:
5754  MFEM_ABORT("Invalid 2D element type \""
5755  << GetElementType(i) << "\"");
5756  break;
5757  }
5758  fo++;
5759  }
5760  wo++;
5761  }
5762  }
5763  }
5764 
5765  if (Dim == 3)
5766  {
5767  DenseMatrix J(3, 3);
5768 
5769  for (i = 0; i < NumOfElements; i++)
5770  {
5771  int *vi = elements[i]->GetVertices();
5772  switch (GetElementType(i))
5773  {
5774  case Element::TETRAHEDRON:
5775  if (Nodes == NULL)
5776  {
5777  for (j = 0; j < 4; j++)
5778  {
5779  v[j] = vertices[vi[j]]();
5780  }
5781  for (j = 0; j < 3; j++)
5782  for (k = 0; k < 3; k++)
5783  {
5784  J(j, k) = v[j+1][k] - v[0][k];
5785  }
5786  }
5787  else
5788  {
5789  // only check the Jacobian at the center of the element
5790  GetElementJacobian(i, J);
5791  }
5792  if (J.Det() < 0.0)
5793  {
5794  wo++;
5795  if (fix_it)
5796  {
5797  mfem::Swap(vi[0], vi[1]);
5798  fo++;
5799  }
5800  }
5801  break;
5802 
5803  case Element::WEDGE:
5804  // only check the Jacobian at the center of the element
5805  GetElementJacobian(i, J);
5806  if (J.Det() < 0.0)
5807  {
5808  wo++;
5809  if (fix_it)
5810  {
5811  // how?
5812  }
5813  }
5814  break;
5815 
5816  case Element::PYRAMID:
5817  // only check the Jacobian at the center of the element
5818  GetElementJacobian(i, J);
5819  if (J.Det() < 0.0)
5820  {
5821  wo++;
5822  if (fix_it)
5823  {
5824  // how?
5825  }
5826  }
5827  break;
5828 
5829  case Element::HEXAHEDRON:
5830  // only check the Jacobian at the center of the element
5831  GetElementJacobian(i, J);
5832  if (J.Det() < 0.0)
5833  {
5834  wo++;
5835  if (fix_it)
5836  {
5837  // how?
5838  }
5839  }
5840  break;
5841 
5842  default:
5843  MFEM_ABORT("Invalid 3D element type \""
5844  << GetElementType(i) << "\"");
5845  break;
5846  }
5847  }
5848  }
5849 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5850  if (wo > 0)
5851  {
5852  mfem::out << "Elements with wrong orientation: " << wo << " / "
5853  << NumOfElements << " (" << fixed_or_not[(wo == fo) ? 0 : 1]
5854  << ")" << endl;
5855  }
5856 #else
5857  MFEM_CONTRACT_VAR(fo);
5858 #endif
5859  return wo;
5860 }
5861 
5862 int Mesh::GetTriOrientation(const int *base, const int *test)
5863 {
5864  // Static method.
5865  // This function computes the index 'j' of the permutation that transforms
5866  // test into base: test[tri_orientation[j][i]]=base[i].
5867  // tri_orientation = Geometry::Constants<Geometry::TRIANGLE>::Orient
5868  int orient;
5869 
5870  if (test[0] == base[0])
5871  if (test[1] == base[1])
5872  {
5873  orient = 0; // (0, 1, 2)
5874  }
5875  else
5876  {
5877  orient = 5; // (0, 2, 1)
5878  }
5879  else if (test[0] == base[1])
5880  if (test[1] == base[0])
5881  {
5882  orient = 1; // (1, 0, 2)
5883  }
5884  else
5885  {
5886  orient = 2; // (1, 2, 0)
5887  }
5888  else // test[0] == base[2]
5889  if (test[1] == base[0])
5890  {
5891  orient = 4; // (2, 0, 1)
5892  }
5893  else
5894  {
5895  orient = 3; // (2, 1, 0)
5896  }
5897 
5898 #ifdef MFEM_DEBUG
5899  const int *aor = tri_t::Orient[orient];
5900  for (int j = 0; j < 3; j++)
5901  if (test[aor[j]] != base[j])
5902  {
5903  mfem::err << "Mesh::GetTriOrientation(...)" << endl;
5904  mfem::err << " base = [";
5905  for (int k = 0; k < 3; k++)
5906  {
5907  mfem::err << " " << base[k];
5908  }
5909  mfem::err << " ]\n test = [";
5910  for (int k = 0; k < 3; k++)
5911  {
5912  mfem::err << " " << test[k];
5913  }
5914  mfem::err << " ]" << endl;
5915  mfem_error();
5916  }
5917 #endif
5918 
5919  return orient;
5920 }
5921 
5922 int Mesh::ComposeTriOrientations(int ori_a_b, int ori_b_c)
5923 {
5924  // Static method.
5925  // Given three, possibly different, configurations of triangular face
5926  // vertices: va, vb, and vc. This function returns the relative orientation
5927  // GetTriOrientation(va, vc) by composing previously computed orientations
5928  // ori_a_b = GetTriOrientation(va, vb) and
5929  // ori_b_c = GetTriOrientation(vb, vc) without accessing the vertices.
5930 
5931  const int oo[6][6] =
5932  {
5933  {0, 1, 2, 3, 4, 5},
5934  {1, 0, 5, 4, 3, 2},
5935  {2, 3, 4, 5, 0, 1},
5936  {3, 2, 1, 0, 5, 4},
5937  {4, 5, 0, 1, 2, 3},
5938  {5, 4, 3, 2, 1, 0}
5939  };
5940 
5941  int ori_a_c = oo[ori_a_b][ori_b_c];
5942  return ori_a_c;
5943 }
5944 
5946 {
5947  const int inv_ori[6] = {0, 1, 4, 3, 2, 5};
5948  return inv_ori[ori];
5949 }
5950 
5951 int Mesh::GetQuadOrientation(const int *base, const int *test)
5952 {
5953  int i;
5954 
5955  for (i = 0; i < 4; i++)
5956  if (test[i] == base[0])
5957  {
5958  break;
5959  }
5960 
5961 #ifdef MFEM_DEBUG
5962  int orient;
5963  if (test[(i+1)%4] == base[1])
5964  {
5965  orient = 2*i;
5966  }
5967  else
5968  {
5969  orient = 2*i+1;
5970  }
5971  const int *aor = quad_t::Orient[orient];
5972  for (int j = 0; j < 4; j++)
5973  if (test[aor[j]] != base[j])
5974  {
5975  mfem::err << "Mesh::GetQuadOrientation(...)" << endl;
5976  mfem::err << " base = [";
5977  for (int k = 0; k < 4; k++)
5978  {
5979  mfem::err << " " << base[k];
5980  }
5981  mfem::err << " ]\n test = [";
5982  for (int k = 0; k < 4; k++)
5983  {
5984  mfem::err << " " << test[k];
5985  }
5986  mfem::err << " ]" << endl;
5987  mfem_error();
5988  }
5989 #endif
5990 
5991  if (test[(i+1)%4] == base[1])
5992  {
5993  return 2*i;
5994  }
5995 
5996  return 2*i+1;
5997 }
5998 
5999 int Mesh::ComposeQuadOrientations(int ori_a_b, int ori_b_c)
6000 {
6001  // Static method.
6002  // Given three, possibly different, configurations of quadrilateral face
6003  // vertices: va, vb, and vc. This function returns the relative orientation
6004  // GetQuadOrientation(va, vc) by composing previously computed orientations
6005  // ori_a_b = GetQuadOrientation(va, vb) and
6006  // ori_b_c = GetQuadOrientation(vb, vc) without accessing the vertices.
6007 
6008  const int oo[8][8] =
6009  {
6010  {0, 1, 2, 3, 4, 5, 6, 7},
6011  {1, 0, 3, 2, 5, 4, 7, 6},
6012  {2, 7, 4, 1, 6, 3, 0, 5},
6013  {3, 6, 5, 0, 7, 2, 1, 4},
6014  {4, 5, 6, 7, 0, 1, 2, 3},
6015  {5, 4, 7, 6, 1, 0, 3, 2},
6016  {6, 3, 0, 5, 2, 7, 4, 1},
6017  {7, 2, 1, 4, 3, 6, 5, 0}
6018  };
6019 
6020  int ori_a_c = oo[ori_a_b][ori_b_c];
6021  return ori_a_c;
6022 }
6023 
6025 {
6026  const int inv_ori[8] = {0, 1, 6, 3, 4, 5, 2, 7};
6027  return inv_ori[ori];
6028 }
6029 
6030 int Mesh::GetTetOrientation(const int *base, const int *test)
6031 {
6032  // Static method.
6033  // This function computes the index 'j' of the permutation that transforms
6034  // test into base: test[tet_orientation[j][i]]=base[i].
6035  // tet_orientation = Geometry::Constants<Geometry::TETRAHEDRON>::Orient
6036  int orient;
6037 
6038  if (test[0] == base[0])
6039  if (test[1] == base[1])
6040  if (test[2] == base[2])
6041  {
6042  orient = 0; // (0, 1, 2, 3)
6043  }
6044  else
6045  {
6046  orient = 1; // (0, 1, 3, 2)
6047  }
6048  else if (test[2] == base[1])
6049  if (test[3] == base[2])
6050  {
6051  orient = 2; // (0, 2, 3, 1)
6052  }
6053  else
6054  {
6055  orient = 3; // (0, 2, 1, 3)
6056  }
6057  else // test[3] == base[1]
6058  if (test[1] == base[2])
6059  {
6060  orient = 4; // (0, 3, 1, 2)
6061  }
6062  else
6063  {
6064  orient = 5; // (0, 3, 2, 1)
6065  }
6066  else if (test[1] == base[0])
6067  if (test[2] == base[1])
6068  if (test[0] == base[2])
6069  {
6070  orient = 6; // (1, 2, 0, 3)
6071  }
6072  else
6073  {
6074  orient = 7; // (1, 2, 3, 0)
6075  }
6076  else if (test[3] == base[1])
6077  if (test[2] == base[2])
6078  {
6079  orient = 8; // (1, 3, 2, 0)
6080  }
6081  else
6082  {
6083  orient = 9; // (1, 3, 0, 2)
6084  }
6085  else // test[0] == base[1]
6086  if (test[3] == base[2])
6087  {
6088  orient = 10; // (1, 0, 3, 2)
6089  }
6090  else
6091  {
6092  orient = 11; // (1, 0, 2, 3)
6093  }
6094  else if (test[2] == base[0])
6095  if (test[3] == base[1])
6096  if (test[0] == base[2])
6097  {
6098  orient = 12; // (2, 3, 0, 1)
6099  }
6100  else
6101  {
6102  orient = 13; // (2, 3, 1, 0)
6103  }
6104  else if (test[0] == base[1])
6105  if (test[1] == base[2])
6106  {
6107  orient = 14; // (2, 0, 1, 3)
6108  }
6109  else
6110  {
6111  orient = 15; // (2, 0, 3, 1)
6112  }
6113  else // test[1] == base[1]
6114  if (test[3] == base[2])
6115  {
6116  orient = 16; // (2, 1, 3, 0)
6117  }
6118  else
6119  {
6120  orient = 17; // (2, 1, 0, 3)
6121  }
6122  else // (test[3] == base[0])
6123  if (test[0] == base[1])
6124  if (test[2] == base[2])
6125  {
6126  orient = 18; // (3, 0, 2, 1)
6127  }
6128  else
6129  {
6130  orient = 19; // (3, 0, 1, 2)
6131  }
6132  else if (test[1] == base[1])
6133  if (test[0] == base[2])
6134  {
6135  orient = 20; // (3, 1, 0, 2)
6136  }
6137  else
6138  {
6139  orient = 21; // (3, 1, 2, 0)
6140  }
6141  else // test[2] == base[1]
6142  if (test[1] == base[2])
6143  {
6144  orient = 22; // (3, 2, 1, 0)
6145  }
6146  else
6147  {
6148  orient = 23; // (3, 2, 0, 1)
6149  }
6150 
6151 #ifdef MFEM_DEBUG
6152  const int *aor = tet_t::Orient[orient];
6153  for (int j = 0; j < 4; j++)
6154  if (test[aor[j]] != base[j])
6155  {
6156  mfem_error("Mesh::GetTetOrientation(...)");
6157  }
6158 #endif
6159 
6160  return orient;
6161 }
6162 
6164 {
6165  int wo = 0; // count wrong orientations
6166 
6167  if (Dim == 2)
6168  {
6169  if (el_to_edge == NULL) // edges were not generated
6170  {
6171  el_to_edge = new Table;
6173  GenerateFaces(); // 'Faces' in 2D refers to the edges
6174  }
6175  for (int i = 0; i < NumOfBdrElements; i++)
6176  {
6177  if (faces_info[be_to_edge[i]].Elem2No < 0) // boundary face
6178  {
6179  int *bv = boundary[i]->GetVertices();
6180  int *fv = faces[be_to_edge[i]]->GetVertices();
6181  if (bv[0] != fv[0])
6182  {
6183  if (fix_it)
6184  {
6185  mfem::Swap<int>(bv[0], bv[1]);
6186  }
6187  wo++;
6188  }
6189  }
6190  }
6191  }
6192 
6193  if (Dim == 3)
6194  {
6195  for (int i = 0; i < NumOfBdrElements; i++)
6196  {
6197  const int fi = be_to_face[i];
6198 
6199  if (faces_info[fi].Elem2No >= 0) { continue; }
6200 
6201  // boundary face
6202  int *bv = boundary[i]->GetVertices();
6203  // Make sure the 'faces' are generated:
6204  MFEM_ASSERT(fi < faces.Size(), "internal error");
6205  const int *fv = faces[fi]->GetVertices();
6206  int orientation; // orientation of the bdr. elem. w.r.t. the
6207  // corresponding face element (that's the base)
6208  const Element::Type bdr_type = GetBdrElementType(i);
6209  switch (bdr_type)
6210  {
6211  case Element::TRIANGLE:
6212  {
6213  orientation = GetTriOrientation(fv, bv);
6214  break;
6215  }
6217  {
6218  orientation = GetQuadOrientation(fv, bv);
6219  break;
6220  }
6221  default:
6222  MFEM_ABORT("Invalid 2D boundary element type \""
6223  << bdr_type << "\"");
6224  orientation = 0; // suppress a warning
6225  break;
6226  }
6227 
6228  if (orientation % 2 == 0) { continue; }
6229  wo++;
6230  if (!fix_it) { continue; }
6231 
6232  switch (bdr_type)
6233  {
6234  case Element::TRIANGLE:
6235  {
6236  // swap vertices 0 and 1 so that we don't change the marked edge:
6237  // (0,1,2) -> (1,0,2)
6238  mfem::Swap<int>(bv[0], bv[1]);
6239  if (bel_to_edge)
6240  {
6241  int *be = bel_to_edge->GetRow(i);
6242  mfem::Swap<int>(be[1], be[2]);
6243  }
6244  break;
6245  }
6247  {
6248  mfem::Swap<int>(bv[0], bv[2]);
6249  if (bel_to_edge)
6250  {
6251  int *be = bel_to_edge->GetRow(i);
6252  mfem::Swap<int>(be[0], be[1]);
6253  mfem::Swap<int>(be[2], be[3]);
6254  }
6255  break;
6256  }
6257  default: // unreachable
6258  break;
6259  }
6260  }
6261  }
6262  // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
6263 #ifdef MFEM_DEBUG
6264  if (wo > 0)
6265  {
6266  mfem::out << "Boundary elements with wrong orientation: " << wo << " / "
6267  << NumOfBdrElements << " (" << fixed_or_not[fix_it ? 0 : 1]
6268  << ")" << endl;
6269  }
6270 #endif
6271  return wo;
6272 }
6273 
6275 {
6276  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
6277  int num_geoms = 0;
6278  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
6279  {
6280  if (HasGeometry(Geometry::Type(g))) { num_geoms++; }
6281  }
6282  return num_geoms;
6283 }
6284 
6286 {
6287  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
6288  el_geoms.SetSize(0);
6289  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
6290  {
6291  if (HasGeometry(Geometry::Type(g)))
6292  {
6293  el_geoms.Append(Geometry::Type(g));
6294  }
6295  }
6296 }
6297 
6298 void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const
6299 {
6300  if (el_to_edge)
6301  {
6302  el_to_edge->GetRow(i, edges);
6303  }
6304  else
6305  {
6306  mfem_error("Mesh::GetElementEdges(...) element to edge table "
6307  "is not generated.");
6308  }
6309 
6310  const int *v = elements[i]->GetVertices();
6311  const int ne = elements[i]->GetNEdges();
6312  cor.SetSize(ne);
6313  for (int j = 0; j < ne; j++)
6314  {
6315  const int *e = elements[i]->GetEdgeVertices(j);
6316  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
6317  }
6318 }
6319 
6320 void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const
6321 {
6322  if (Dim == 2)
6323  {
6324  edges.SetSize(1);
6325  cor.SetSize(1);
6326  edges[0] = be_to_edge[i];
6327  const int *v = boundary[i]->GetVertices();
6328  cor[0] = (v[0] < v[1]) ? (1) : (-1);
6329  }
6330  else if (Dim == 3)
6331  {
6332  if (bel_to_edge)
6333  {
6334  bel_to_edge->GetRow(i, edges);
6335  }
6336  else
6337  {
6338  mfem_error("Mesh::GetBdrElementEdges(...)");
6339  }
6340 
6341  const int *v = boundary[i]->GetVertices();
6342  const int ne = boundary[i]->GetNEdges();
6343  cor.SetSize(ne);
6344  for (int j = 0; j < ne; j++)
6345  {
6346  const int *e = boundary[i]->GetEdgeVertices(j);
6347  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
6348  }
6349  }
6350 }
6351 
6352 void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const
6353 {
6354  if (Dim == 2)
6355  {
6356  edges.SetSize(1);
6357  edges[0] = i;
6358  o.SetSize(1);
6359  const int *v = faces[i]->GetVertices();
6360  o[0] = (v[0] < v[1]) ? (1) : (-1);
6361  }
6362 
6363  if (Dim != 3)
6364  {
6365  return;
6366  }
6367 
6368  GetFaceEdgeTable(); // generate face_edge Table (if not generated)
6369 
6370  face_edge->GetRow(i, edges);
6371 
6372  const int *v = faces[i]->GetVertices();
6373  const int ne = faces[i]->GetNEdges();
6374  o.SetSize(ne);
6375  for (int j = 0; j < ne; j++)
6376  {
6377  const int *e = faces[i]->GetEdgeVertices(j);
6378  o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
6379  }
6380 }
6381 
6382 void Mesh::GetEdgeVertices(int i, Array<int> &vert) const
6383 {
6384  // the two vertices are sorted: vert[0] < vert[1]
6385  // this is consistent with the global edge orientation
6386  // generate edge_vertex Table (if not generated)
6387  if (!edge_vertex) { GetEdgeVertexTable(); }
6388  edge_vertex->GetRow(i, vert);
6389 }
6390 
6392 {
6393  if (face_edge)
6394  {
6395  return face_edge;
6396  }
6397 
6398  if (Dim != 3)
6399  {
6400  return NULL;
6401  }
6402 
6403 #ifdef MFEM_DEBUG
6404  if (faces.Size() != NumOfFaces)
6405  {
6406  mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!");
6407  }
6408 #endif
6409 
6410  DSTable v_to_v(NumOfVertices);
6411  GetVertexToVertexTable(v_to_v);
6412 
6413  face_edge = new Table;
6415 
6416  return (face_edge);
6417 }
6418 
6420 {
6421  if (edge_vertex)
6422  {
6423  return edge_vertex;
6424  }
6425 
6426  DSTable v_to_v(NumOfVertices);
6427  GetVertexToVertexTable(v_to_v);
6428 
6429  int nedges = v_to_v.NumberOfEntries();
6430  edge_vertex = new Table(nedges, 2);
6431  for (int i = 0; i < NumOfVertices; i++)
6432  {
6433  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
6434  {
6435  int j = it.Index();
6436  edge_vertex->Push(j, i);
6437  edge_vertex->Push(j, it.Column());
6438  }
6439  }
6440  edge_vertex->Finalize();
6441 
6442  return edge_vertex;
6443 }
6444 
6446 {
6447  int i, j, nv, *v;
6448 
6449  Table *vert_elem = new Table;
6450 
6451  vert_elem->MakeI(NumOfVertices);
6452 
6453  for (i = 0; i < NumOfElements; i++)
6454  {
6455  nv = elements[i]->GetNVertices();
6456  v = elements[i]->GetVertices();
6457  for (j = 0; j < nv; j++)
6458  {
6459  vert_elem->AddAColumnInRow(v[j]);
6460  }
6461  }
6462 
6463  vert_elem->MakeJ();
6464 
6465  for (i = 0; i < NumOfElements; i++)
6466  {
6467  nv = elements[i]->GetNVertices();
6468  v = elements[i]->GetVertices();
6469  for (j = 0; j < nv; j++)
6470  {
6471  vert_elem->AddConnection(v[j], i);
6472  }
6473  }
6474 
6475  vert_elem->ShiftUpI();
6476 
6477  return vert_elem;
6478 }
6479 
6481 {
6482  Table *face_elem = new Table;
6483 
6484  face_elem->MakeI(faces_info.Size());
6485 
6486  for (int i = 0; i < faces_info.Size(); i++)
6487  {
6488  if (faces_info[i].Elem2No >= 0)
6489  {
6490  face_elem->AddColumnsInRow(i, 2);
6491  }
6492  else
6493  {
6494  face_elem->AddAColumnInRow(i);
6495  }
6496  }
6497 
6498  face_elem->MakeJ();
6499 
6500  for (int i = 0; i < faces_info.Size(); i++)
6501  {
6502  face_elem->AddConnection(i, faces_info[i].Elem1No);
6503  if (faces_info[i].Elem2No >= 0)
6504  {
6505  face_elem->AddConnection(i, faces_info[i].Elem2No);
6506  }
6507  }
6508 
6509  face_elem->ShiftUpI();
6510 
6511  return face_elem;
6512 }
6513 
6514 void Mesh::GetElementFaces(int i, Array<int> &el_faces, Array<int> &ori) const
6515 {
6516  MFEM_VERIFY(el_to_face != NULL, "el_to_face not generated");
6517 
6518  el_to_face->GetRow(i, el_faces);
6519 
6520  int n = el_faces.Size();
6521  ori.SetSize(n);
6522 
6523  for (int j = 0; j < n; j++)
6524  {
6525  if (faces_info[el_faces[j]].Elem1No == i)
6526  {
6527  ori[j] = faces_info[el_faces[j]].Elem1Inf % 64;
6528  }
6529  else
6530  {
6531  MFEM_ASSERT(faces_info[el_faces[j]].Elem2No == i, "internal error");
6532  ori[j] = faces_info[el_faces[j]].Elem2Inf % 64;
6533  }
6534  }
6535 }
6536 
6538 {
6539  if (face_to_elem == NULL)
6540  {
6542  }
6543 
6544  Array<int> elem_faces;
6545  Array<int> ori;
6546  GetElementFaces(elem, elem_faces, ori);
6547 
6548  Array<int> nghb;
6549  for (auto f : elem_faces)
6550  {
6551  Array<int> row;
6552  face_to_elem->GetRow(f, row);
6553  for (auto r : row)
6554  {
6555  nghb.Append(r);
6556  }
6557  }
6558 
6559  nghb.Sort();
6560  nghb.Unique();
6561 
6562  return nghb;
6563 }
6564 
6565 void Mesh::GetBdrElementFace(int i, int *f, int *o) const
6566 {
6567  const int *bv, *fv;
6568 
6569  *f = be_to_face[i];
6570  bv = boundary[i]->GetVertices();
6571  fv = faces[be_to_face[i]]->GetVertices();
6572 
6573  // find the orientation of the bdr. elem. w.r.t.
6574  // the corresponding face element (that's the base)
6575  switch (GetBdrElementType(i))
6576  {
6577  case Element::TRIANGLE:
6578  *o = GetTriOrientation(fv, bv);
6579  break;
6581  *o = GetQuadOrientation(fv, bv);
6582  break;
6583  default:
6584  MFEM_ABORT("invalid geometry");
6585  }
6586 }
6587 
6589 {
6590  switch (Dim)
6591  {
6592  case 1: return boundary[i]->GetVertices()[0];
6593  case 2: return be_to_edge[i];
6594  case 3: return be_to_face[i];
6595  default: MFEM_ABORT("invalid dimension!");
6596  }
6597  return -1;
6598 }
6599 
6600 void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
6601 {
6602  int fid = GetBdrElementEdgeIndex(bdr_el);
6603 
6604  const FaceInfo &fi = faces_info[fid];
6605  MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
6606 
6607  const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
6608  const int *bv = boundary[bdr_el]->GetVertices();
6609  int ori;
6610  switch (GetBdrElementGeometry(bdr_el))
6611  {
6612  case Geometry::POINT: ori = 0; break;
6613  case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
6614  case Geometry::TRIANGLE: ori = GetTriOrientation(fv, bv); break;
6615  case Geometry::SQUARE: ori = GetQuadOrientation(fv, bv); break;
6616  default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
6617  }
6618  el = fi.Elem1No;
6619  info = fi.Elem1Inf + ori;
6620 }
6621 
6622 void Mesh::GetBdrElementAdjacentElement2(int bdr_el, int &el, int &info) const
6623 {
6624  int fid = GetBdrElementEdgeIndex(bdr_el);
6625 
6626  const FaceInfo &fi = faces_info[fid];
6627  MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
6628 
6629  const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
6630  const int *bv = boundary[bdr_el]->GetVertices();
6631  int ori;
6632  switch (GetBdrElementGeometry(bdr_el))
6633  {
6634  case Geometry::POINT: ori = 0; break;
6635  case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
6636  case Geometry::TRIANGLE: ori = GetTriOrientation(bv, fv); break;
6637  case Geometry::SQUARE: ori = GetQuadOrientation(bv, fv); break;
6638  default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
6639  }
6640  el = fi.Elem1No;
6641  info = fi.Elem1Inf + ori;
6642 }
6643 
6645 {
6646  return elements[i]->GetType();
6647 }
6648 
6650 {
6651  return boundary[i]->GetType();
6652 }
6653 
6654 void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const
6655 {
6656  int k, j, nv;
6657  const int *v;
6658 
6659  v = elements[i]->GetVertices();
6660  nv = elements[i]->GetNVertices();
6661 
6662  pointmat.SetSize(spaceDim, nv);
6663  for (k = 0; k < spaceDim; k++)
6664  {
6665  for (j = 0; j < nv; j++)
6666  {
6667  pointmat(k, j) = vertices[v[j]](k);
6668  }
6669  }
6670 }
6671 
6672 void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const
6673 {
6674  int k, j, nv;
6675  const int *v;
6676 
6677  v = boundary[i]->GetVertices();
6678  nv = boundary[i]->GetNVertices();
6679 
6680  pointmat.SetSize(spaceDim, nv);
6681  for (k = 0; k < spaceDim; k++)
6682  for (j = 0; j < nv; j++)
6683  {
6684  pointmat(k, j) = vertices[v[j]](k);
6685  }
6686 }
6687 
6688 double Mesh::GetLength(int i, int j) const
6689 {
6690  const double *vi = vertices[i]();
6691  const double *vj = vertices[j]();
6692  double length = 0.;
6693 
6694  for (int k = 0; k < spaceDim; k++)
6695  {
6696  length += (vi[k]-vj[k])*(vi[k]-vj[k]);
6697  }
6698 
6699  return sqrt(length);
6700 }
6701 
6702 // static method
6704  const DSTable &v_to_v, Table &el_to_edge)
6705 {
6706  el_to_edge.MakeI(elem_array.Size());
6707  for (int i = 0; i < elem_array.Size(); i++)
6708  {
6709  el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges());
6710  }
6711  el_to_edge.MakeJ();
6712  for (int i = 0; i < elem_array.Size(); i++)
6713  {
6714  const int *v = elem_array[i]->GetVertices();
6715  const int ne = elem_array[i]->GetNEdges();
6716  for (int j = 0; j < ne; j++)
6717  {
6718  const int *e = elem_array[i]->GetEdgeVertices(j);
6719  el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]]));
6720  }
6721  }
6722  el_to_edge.ShiftUpI();
6723 }
6724 
6726 {
6727  if (edge_vertex)
6728  {
6729  for (int i = 0; i < edge_vertex->Size(); i++)
6730  {
6731  const int *v = edge_vertex->GetRow(i);
6732  v_to_v.Push(v[0], v[1]);
6733  }
6734  }
6735  else
6736  {
6737  for (int i = 0; i < NumOfElements; i++)
6738  {
6739  const int *v = elements[i]->GetVertices();
6740  const int ne = elements[i]->GetNEdges();
6741  for (int j = 0; j < ne; j++)
6742  {
6743  const int *e = elements[i]->GetEdgeVertices(j);
6744  v_to_v.Push(v[e[0]], v[e[1]]);
6745  }
6746  }
6747  }
6748 }
6749 
6751 {
6752  int i, NumberOfEdges;
6753 
6754  DSTable v_to_v(NumOfVertices);
6755  GetVertexToVertexTable(v_to_v);
6756 
6757  NumberOfEdges = v_to_v.NumberOfEntries();
6758 
6759  // Fill the element to edge table
6760  GetElementArrayEdgeTable(elements, v_to_v, e_to_f);
6761 
6762  if (Dim == 2)
6763  {
6764  // Initialize the indices for the boundary elements.
6765  be_to_f.SetSize(NumOfBdrElements);
6766  for (i = 0; i < NumOfBdrElements; i++)
6767  {
6768  const int *v = boundary[i]->GetVertices();
6769  be_to_f[i] = v_to_v(v[0], v[1]);
6770  }
6771  }
6772  else if (Dim == 3)
6773  {
6774  if (bel_to_edge == NULL)
6775  {
6776  bel_to_edge = new Table;
6777  }
6779  }
6780  else
6781  {
6782  mfem_error("1D GetElementToEdgeTable is not yet implemented.");
6783  }
6784 
6785  // Return the number of edges
6786  return NumberOfEdges;
6787 }
6788 
6790 {
6791  if (el_to_el)
6792  {
6793  return *el_to_el;
6794  }
6795 
6796  // Note that, for ParNCMeshes, faces_info will contain also the ghost faces
6797  MFEM_ASSERT(faces_info.Size() >= GetNumFaces(), "faces were not generated!");
6798 
6799  Array<Connection> conn;
6800  conn.Reserve(2*faces_info.Size());
6801 
6802  for (int i = 0; i < faces_info.Size(); i++)
6803  {
6804  const FaceInfo &fi = faces_info[i];
6805  if (fi.Elem2No >= 0)
6806  {
6807  conn.Append(Connection(fi.Elem1No, fi.Elem2No));
6808  conn.Append(Connection(fi.Elem2No, fi.Elem1No));
6809  }
6810  else if (fi.Elem2Inf >= 0)
6811  {
6812  int nbr_elem_idx = NumOfElements - 1 - fi.Elem2No;
6813  conn.Append(Connection(fi.Elem1No, nbr_elem_idx));
6814  conn.Append(Connection(nbr_elem_idx, fi.Elem1No));
6815  }
6816  }
6817 
6818  conn.Sort();
6819  conn.Unique();
6820  el_to_el = new Table(NumOfElements, conn);
6821 
6822  return *el_to_el;
6823 }
6824 
6826 {
6827  if (el_to_face == NULL)
6828  {
6829  mfem_error("Mesh::ElementToFaceTable()");
6830  }
6831  return *el_to_face;
6832 }
6833 
6835 {
6836  if (el_to_edge == NULL)
6837  {
6838  mfem_error("Mesh::ElementToEdgeTable()");
6839  }
6840  return *el_to_edge;
6841 }
6842 
6843 void Mesh::AddPointFaceElement(int lf, int gf, int el)
6844 {
6845  if (faces[gf] == NULL) // this will be elem1
6846  {
6847  faces[gf] = new Point(&gf);
6848  faces_info[gf].Elem1No = el;
6849  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6850  faces_info[gf].Elem2No = -1; // in case there's no other side
6851  faces_info[gf].Elem2Inf = -1; // face is not shared
6852  }
6853  else // this will be elem2
6854  {
6855  /* WARNING: Without the following check the mesh faces_info data structure
6856  may contain unreliable data. Normally, the order in which elements are
6857  processed could swap which elements appear as Elem1No and Elem2No. In
6858  branched meshes, where more than two elements can meet at a given node,
6859  the indices stored in Elem1No and Elem2No will be the first and last,
6860  respectively, elements found which touch a given node. This can lead to
6861  inconsistencies in any algorithms which rely on this data structure. To
6862  properly support branched meshes this data structure should be extended
6863  to support multiple elements per face. */
6864  /*
6865  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6866  "Interior point found connecting 1D elements "
6867  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6868  << " and " << el << ".");
6869  */
6870  faces_info[gf].Elem2No = el;
6871  faces_info[gf].Elem2Inf = 64 * lf + 1;
6872  }
6873 }
6874 
6875 void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
6876 {
6877  if (faces[gf] == NULL) // this will be elem1
6878  {
6879  faces[gf] = new Segment(v0, v1);
6880  faces_info[gf].Elem1No = el;
6881  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6882  faces_info[gf].Elem2No = -1; // in case there's no other side
6883  faces_info[gf].Elem2Inf = -1; // face is not shared
6884  }
6885  else // this will be elem2
6886  {
6887  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6888  "Interior edge found between 2D elements "
6889  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6890  << " and " << el << ".");
6891  int *v = faces[gf]->GetVertices();
6892  faces_info[gf].Elem2No = el;
6893  if ( v[1] == v0 && v[0] == v1 )
6894  {
6895  faces_info[gf].Elem2Inf = 64 * lf + 1;
6896  }
6897  else if ( v[0] == v0 && v[1] == v1 )
6898  {
6899  // Temporarily allow even edge orientations: see the remark in
6900  // AddTriangleFaceElement().
6901  // Also, in a non-orientable surface mesh, the orientation will be even
6902  // for edges that connect elements with opposite orientations.
6903  faces_info[gf].Elem2Inf = 64 * lf;
6904  }
6905  else
6906  {
6907  MFEM_ABORT("internal error");
6908  }
6909  }
6910 }
6911 
6912 void Mesh::AddTriangleFaceElement(int lf, int gf, int el,
6913  int v0, int v1, int v2)
6914 {
6915  if (faces[gf] == NULL) // this will be elem1
6916  {
6917  faces[gf] = new Triangle(v0, v1, v2);
6918  faces_info[gf].Elem1No = el;
6919  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6920  faces_info[gf].Elem2No = -1; // in case there's no other side
6921  faces_info[gf].Elem2Inf = -1; // face is not shared
6922  }
6923  else // this will be elem2
6924  {
6925  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6926  "Interior triangular face found connecting elements "
6927  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6928  << " and " << el << ".");
6929  int orientation, vv[3] = { v0, v1, v2 };
6930  orientation = GetTriOrientation(faces[gf]->GetVertices(), vv);
6931  // In a valid mesh, we should have (orientation % 2 != 0), however, if
6932  // one of the adjacent elements has wrong orientation, both face
6933  // orientations can be even, until the element orientations are fixed.
6934  // MFEM_ASSERT(orientation % 2 != 0, "");
6935  faces_info[gf].Elem2No = el;
6936  faces_info[gf].Elem2Inf = 64 * lf + orientation;
6937  }
6938 }
6939 
6940 void Mesh::AddQuadFaceElement(int lf, int gf, int el,
6941  int v0, int v1, int v2, int v3)
6942 {
6943  if (faces_info[gf].Elem1No < 0) // this will be elem1
6944  {
6945  faces[gf] = new Quadrilateral(v0, v1, v2, v3);
6946  faces_info[gf].Elem1No = el;
6947  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6948  faces_info[gf].Elem2No = -1; // in case there's no other side
6949  faces_info[gf].Elem2Inf = -1; // face is not shared
6950  }
6951  else // this will be elem2
6952  {
6953  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6954  "Interior quadrilateral face found connecting elements "
6955  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6956  << " and " << el << ".");
6957  int vv[4] = { v0, v1, v2, v3 };
6958  int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv);
6959  // Temporarily allow even face orientations: see the remark in
6960  // AddTriangleFaceElement().
6961  // MFEM_ASSERT(oo % 2 != 0, "");
6962  faces_info[gf].Elem2No = el;
6963  faces_info[gf].Elem2Inf = 64 * lf + oo;
6964  }
6965 }
6966 
6968 {
6969  int i, nfaces = GetNumFaces();
6970 
6971  for (i = 0; i < faces.Size(); i++)
6972  {
6973  FreeElement(faces[i]);
6974  }
6975 
6976  // (re)generate the interior faces and the info for them
6977  faces.SetSize(nfaces);
6978  faces_info.SetSize(nfaces);
6979  for (i = 0; i < nfaces; i++)
6980  {
6981  faces[i] = NULL;
6982  faces_info[i].Elem1No = -1;
6983  faces_info[i].NCFace = -1;
6984  }
6985  for (i = 0; i < NumOfElements; i++)
6986  {
6987  const int *v = elements[i]->GetVertices();
6988  const int *ef;
6989  if (Dim == 1)
6990  {
6991  AddPointFaceElement(0, v[0], i);
6992  AddPointFaceElement(1, v[1], i);
6993  }
6994  else if (Dim == 2)
6995  {
6996  ef = el_to_edge->GetRow(i);
6997  const int ne = elements[i]->GetNEdges();
6998  for (int j = 0; j < ne; j++)
6999  {
7000  const int *e = elements[i]->GetEdgeVertices(j);
7001  AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]);
7002  }
7003  }
7004  else
7005  {
7006  ef = el_to_face->GetRow(i);
7007  switch (GetElementType(i))
7008  {
7009  case Element::TETRAHEDRON:
7010  {
7011  for (int j = 0; j < 4; j++)
7012  {
7013  const int *fv = tet_t::FaceVert[j];
7014  AddTriangleFaceElement(j, ef[j], i,
7015  v[fv[0]], v[fv[1]], v[fv[2]]);
7016  }
7017  break;
7018  }
7019  case Element::WEDGE:
7020  {
7021  for (int j = 0; j < 2; j++)
7022  {
7023  const int *fv = pri_t::FaceVert[j];
7024  AddTriangleFaceElement(j, ef[j], i,
7025  v[fv[0]], v[fv[1]], v[fv[2]]);
7026  }
7027  for (int j = 2; j < 5; j++)
7028  {
7029  const int *fv = pri_t::FaceVert[j];
7030  AddQuadFaceElement(j, ef[j], i,
7031  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7032  }
7033  break;
7034  }
7035  case Element::PYRAMID:
7036  {
7037  for (int j = 0; j < 1; j++)
7038  {
7039  const int *fv = pyr_t::FaceVert[j];
7040  AddQuadFaceElement(j, ef[j], i,
7041  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7042  }
7043  for (int j = 1; j < 5; j++)
7044  {
7045  const int *fv = pyr_t::FaceVert[j];
7046  AddTriangleFaceElement(j, ef[j], i,
7047  v[fv[0]], v[fv[1]], v[fv[2]]);
7048  }
7049  break;
7050  }
7051  case Element::HEXAHEDRON:
7052  {
7053  for (int j = 0; j < 6; j++)
7054  {
7055  const int *fv = hex_t::FaceVert[j];
7056  AddQuadFaceElement(j, ef[j], i,
7057  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7058  }
7059  break;
7060  }
7061  default:
7062  MFEM_ABORT("Unexpected type of Element.");
7063  }
7064  }
7065  }
7066 }
7067 
7069 {
7070  MFEM_VERIFY(ncmesh, "missing NCMesh.");
7071 
7072  for (int i = 0; i < faces_info.Size(); i++)
7073  {
7074  faces_info[i].NCFace = -1;
7075  }
7076 
7077  const NCMesh::NCList &list =
7078  (Dim == 2) ? ncmesh->GetEdgeList() : ncmesh->GetFaceList();
7079 
7080  nc_faces_info.SetSize(0);
7081  nc_faces_info.Reserve(list.masters.Size() + list.slaves.Size());
7082 
7083  int nfaces = GetNumFaces();
7084 
7085  // add records for master faces
7086  for (int i = 0; i < list.masters.Size(); i++)
7087  {
7088  const NCMesh::Master &master = list.masters[i];
7089  if (master.index >= nfaces) { continue; }
7090 
7091  FaceInfo &master_fi = faces_info[master.index];
7092  master_fi.NCFace = nc_faces_info.Size();
7093  nc_faces_info.Append(NCFaceInfo(false, master.local, NULL));
7094  // NOTE: one of the unused members stores local face no. to be used below
7095  MFEM_ASSERT(master_fi.Elem2No == -1, "internal error");
7096  MFEM_ASSERT(master_fi.Elem2Inf == -1, "internal error");
7097  }
7098 
7099  // add records for slave faces
7100  for (int i = 0; i < list.slaves.Size(); i++)
7101  {
7102  const NCMesh::Slave &slave = list.slaves[i];
7103 
7104  if (slave.index < 0 || // degenerate slave face
7105  slave.index >= nfaces || // ghost slave
7106  slave.master >= nfaces) // has ghost master
7107  {
7108  continue;
7109  }
7110 
7111  FaceInfo &slave_fi = faces_info[slave.index];
7112  FaceInfo &master_fi = faces_info[slave.master];
7113  NCFaceInfo &master_nc = nc_faces_info[master_fi.NCFace];
7114 
7115  slave_fi.NCFace = nc_faces_info.Size();
7116  slave_fi.Elem2No = master_fi.Elem1No;
7117  slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
7118  // NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
7119  // matrix. In 2D, the point matrix has the orientation of the parent
7120  // edge, so its columns need to be flipped when applying it, see
7121  // ApplyLocalSlaveTransformation.
7122 
7123  nc_faces_info.Append(
7124  NCFaceInfo(true, slave.master,
7125  list.point_matrices[slave.geom][slave.matrix]));
7126  }
7127 }
7128 
7130 {
7131  STable3D *faces_tbl = new STable3D(NumOfVertices);
7132  for (int i = 0; i < NumOfElements; i++)
7133  {
7134  const int *v = elements[i]->GetVertices();
7135  switch (GetElementType(i))
7136  {
7137  case Element::TETRAHEDRON:
7138  {
7139  for (int j = 0; j < 4; j++)
7140  {
7141  const int *fv = tet_t::FaceVert[j];
7142  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
7143  }
7144  break;
7145  }
7146  case Element::PYRAMID:
7147  {
7148  for (int j = 0; j < 1; j++)
7149  {
7150  const int *fv = pyr_t::FaceVert[j];
7151  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7152  }
7153  for (int j = 1; j < 5; j++)
7154  {
7155  const int *fv = pyr_t::FaceVert[j];
7156  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
7157  }
7158  break;
7159  }
7160  case Element::WEDGE:
7161  {
7162  for (int j = 0; j < 2; j++)
7163  {
7164  const int *fv = pri_t::FaceVert[j];
7165  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
7166  }
7167  for (int j = 2; j < 5; j++)
7168  {
7169  const int *fv = pri_t::FaceVert[j];
7170  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7171  }
7172  break;
7173  }
7174  case Element::HEXAHEDRON:
7175  {
7176  // find the face by the vertices with the smallest 3 numbers
7177  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
7178  for (int j = 0; j < 6; j++)
7179  {
7180  const int *fv = hex_t::FaceVert[j];
7181  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7182  }
7183  break;
7184  }
7185  default:
7186  MFEM_ABORT("Unexpected type of Element.");
7187  }
7188  }
7189  return faces_tbl;
7190 }
7191 
7193 {
7194  int i, *v;
7195  STable3D *faces_tbl;
7196 
7197  if (el_to_face != NULL)
7198  {
7199  delete el_to_face;
7200  }
7201  el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra
7202  faces_tbl = new STable3D(NumOfVertices);
7203  for (i = 0; i < NumOfElements; i++)
7204  {
7205  v = elements[i]->GetVertices();
7206  switch (GetElementType(i))
7207  {
7208  case Element::TETRAHEDRON:
7209  {
7210  for (int j = 0; j < 4; j++)
7211  {
7212  const int *fv = tet_t::FaceVert[j];
7213  el_to_face->Push(
7214  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
7215  }
7216  break;
7217  }
7218  case Element::WEDGE:
7219  {
7220  for (int j = 0; j < 2; j++)
7221  {
7222  const int *fv = pri_t::FaceVert[j];
7223  el_to_face->Push(
7224  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
7225  }
7226  for (int j = 2; j < 5; j++)
7227  {
7228  const int *fv = pri_t::FaceVert[j];
7229  el_to_face->Push(
7230  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
7231  }
7232  break;
7233  }
7234  case Element::PYRAMID:
7235  {
7236  for (int j = 0; j < 1; j++)
7237  {
7238  const int *fv = pyr_t::FaceVert[j];
7239  el_to_face->Push(
7240  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
7241  }
7242  for (int j = 1; j < 5; j++)
7243  {
7244  const int *fv = pyr_t::FaceVert[j];
7245  el_to_face->Push(
7246  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
7247  }
7248  break;
7249  }
7250  case Element::HEXAHEDRON:
7251  {
7252  // find the face by the vertices with the smallest 3 numbers
7253  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
7254  for (int j = 0; j < 6; j++)
7255  {
7256  const int *fv = hex_t::FaceVert[j];
7257  el_to_face->Push(
7258  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
7259  }
7260  break;
7261  }
7262  default:
7263  MFEM_ABORT("Unexpected type of Element.");
7264  }
7265  }
7266  el_to_face->Finalize();
7267  NumOfFaces = faces_tbl->NumberOfElements();
7269  for (i = 0; i < NumOfBdrElements; i++)
7270  {
7271  v = boundary[i]->GetVertices();
7272  switch (GetBdrElementType(i))
7273  {
7274  case Element::TRIANGLE:
7275  {
7276  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]);
7277  break;
7278  }
7280  {
7281  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
7282  break;
7283  }
7284  default:
7285  MFEM_ABORT("Unexpected type of boundary Element.");
7286  }
7287  }
7288 
7289  if (ret_ftbl)
7290  {
7291  return faces_tbl;
7292  }
7293  delete faces_tbl;
7294  return NULL;
7295 }
7296 
7297 // shift cyclically 3 integers so that the smallest is first
7298 static inline
7299 void Rotate3(int &a, int &b, int &c)
7300 {
7301  if (a < b)
7302  {
7303  if (a > c)
7304  {
7305  ShiftRight(a, b, c);
7306  }
7307  }
7308  else
7309  {
7310  if (b < c)
7311  {
7312  ShiftRight(c, b, a);
7313  }
7314  else
7315  {
7316  ShiftRight(a, b, c);
7317  }
7318  }
7319 }
7320 
7322 {
7323  if (Dim != 3 || !(meshgen & 1))
7324  {
7325  return;
7326  }
7327 
7328  ResetLazyData();
7329 
7330  DSTable *old_v_to_v = NULL;
7331  Table *old_elem_vert = NULL;
7332 
7333  if (Nodes)
7334  {
7335  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
7336  }
7337 
7338  for (int i = 0; i < NumOfElements; i++)
7339  {
7341  {
7342  int *v = elements[i]->GetVertices();
7343 
7344  Rotate3(v[0], v[1], v[2]);
7345  if (v[0] < v[3])
7346  {
7347  Rotate3(v[1], v[2], v[3]);
7348  }
7349  else
7350  {
7351  ShiftRight(v[0], v[1], v[3]);
7352  }
7353  }
7354  }
7355 
7356  for (int i = 0; i < NumOfBdrElements; i++)
7357  {
7359  {
7360  int *v = boundary[i]->GetVertices();
7361 
7362  Rotate3(v[0], v[1], v[2]);
7363  }
7364  }
7365 
7366  if (!Nodes)
7367  {
7369  GenerateFaces();
7370  if (el_to_edge)
7371  {
7373  }
7374  }
7375  else
7376  {
7377  DoNodeReorder(old_v_to_v, old_elem_vert);
7378  delete old_elem_vert;
7379  delete old_v_to_v;
7380  }
7381 }
7382 
7384 {
7385  int *partitioning;
7386  double pmin[3] = { infinity(), infinity(), infinity() };
7387  double pmax[3] = { -infinity(), -infinity(), -infinity() };
7388  // find a bounding box using the vertices
7389  for (int vi = 0; vi < NumOfVertices; vi++)
7390  {
7391  const double *p = vertices[vi]();
7392  for (int i = 0; i < spaceDim; i++)
7393  {
7394  if (p[i] < pmin[i]) { pmin[i] = p[i]; }
7395  if (p[i] > pmax[i]) { pmax[i] = p[i]; }
7396  }
7397  }
7398 
7399  partitioning = new int[NumOfElements];
7400 
7401  // determine the partitioning using the centers of the elements
7402  double ppt[3];
7403  Vector pt(ppt, spaceDim);
7404  for (int el = 0; el < NumOfElements; el++)
7405  {
7406  GetElementTransformation(el)->Transform(
7408  int part = 0;
7409  for (int i = spaceDim-1; i >= 0; i--)
7410  {
7411  int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i])));
7412  if (idx < 0) { idx = 0; }
7413  if (idx >= nxyz[i]) { idx = nxyz[i]-1; }
7414  part = part * nxyz[i] + idx;
7415  }
7416  partitioning[el] = part;
7417  }
7418 
7419  return partitioning;
7420 }
7421 
7422 void FindPartitioningComponents(Table &elem_elem,
7423  const Array<int> &partitioning,
7424  Array<int> &component,
7425  Array<int> &num_comp);
7426 
7427 int *Mesh::GeneratePartitioning(int nparts, int part_method)
7428 {
7429 #ifdef MFEM_USE_METIS
7430 
7431  int print_messages = 1;
7432  // If running in parallel, print messages only from rank 0.
7433 #ifdef MFEM_USE_MPI
7434  int init_flag, fin_flag;
7435  MPI_Initialized(&init_flag);
7436  MPI_Finalized(&fin_flag);
7437  if (init_flag && !fin_flag)
7438  {
7439  int rank;
7440  MPI_Comm_rank(GetGlobalMPI_Comm(), &rank);
7441  if (rank != 0) { print_messages = 0; }
7442  }
7443 #endif
7444 
7445  int i, *partitioning;
7446 
7448 
7449  partitioning = new int[NumOfElements];
7450 
7451  if (nparts == 1)
7452  {
7453  for (i = 0; i < NumOfElements; i++)
7454  {
7455  partitioning[i] = 0;
7456  }
7457  }
7458  else if (NumOfElements <= nparts)
7459  {
7460  for (i = 0; i < NumOfElements; i++)
7461  {
7462  partitioning[i] = i;
7463  }
7464  }
7465  else
7466  {
7467  idx_t *I, *J, n;
7468 #ifndef MFEM_USE_METIS_5
7469  idx_t wgtflag = 0;
7470  idx_t numflag = 0;
7471  idx_t options[5];
7472 #else
7473  idx_t ncon = 1;
7474  idx_t errflag;
7475  idx_t options[40];
7476 #endif
7477  idx_t edgecut;
7478 
7479  // In case METIS have been compiled with 64bit indices
7480  bool freedata = false;
7481  idx_t mparts = (idx_t) nparts;
7482  idx_t *mpartitioning;
7483 
7484  n = NumOfElements;
7485  if (sizeof(idx_t) == sizeof(int))
7486  {
7487  I = (idx_t*) el_to_el->GetI();
7488  J = (idx_t*) el_to_el->GetJ();
7489  mpartitioning = (idx_t*) partitioning;
7490  }
7491  else
7492  {
7493  int *iI = el_to_el->GetI();
7494  int *iJ = el_to_el->GetJ();
7495  int m = iI[n];
7496  I = new idx_t[n+1];
7497  J = new idx_t[m];
7498  for (int k = 0; k < n+1; k++) { I[k] = iI[k]; }
7499  for (int k = 0; k < m; k++) { J[k] = iJ[k]; }
7500  mpartitioning = new idx_t[n];
7501  freedata = true;
7502  }
7503 #ifndef MFEM_USE_METIS_5
7504  options[0] = 0;
7505 #else
7506  METIS_SetDefaultOptions(options);
7507  options[METIS_OPTION_CONTIG] = 1; // set METIS_OPTION_CONTIG
7508  // If the mesh is disconnected, disable METIS_OPTION_CONTIG.
7509  {
7510  Array<int> part(partitioning, NumOfElements);
7511  part = 0; // single part for the whole mesh
7512  Array<int> component; // size will be set to num. elem.
7513  Array<int> num_comp; // size will be set to num. parts (1)
7514  FindPartitioningComponents(*el_to_el, part, component, num_comp);
7515  if (num_comp[0] > 1) { options[METIS_OPTION_CONTIG] = 0; }
7516  }
7517 #endif
7518 
7519  // Sort the neighbor lists
7520  if (part_method >= 0 && part_method <= 2)
7521  {
7522  for (i = 0; i < n; i++)
7523  {
7524  // Sort in increasing order.
7525  // std::sort(J+I[i], J+I[i+1]);
7526 
7527  // Sort in decreasing order, as in previous versions of MFEM.
7528  std::sort(J+I[i], J+I[i+1], std::greater<idx_t>());
7529  }
7530  }
7531 
7532  // This function should be used to partition a graph into a small
7533  // number of partitions (less than 8).
7534  if (part_method == 0 || part_method == 3)
7535  {
7536 #ifndef MFEM_USE_METIS_5
7538  I,
7539  J,
7540  NULL,
7541  NULL,
7542  &wgtflag,
7543  &numflag,
7544  &mparts,
7545  options,
7546  &edgecut,
7547  mpartitioning);
7548 #else
7549  errflag = METIS_PartGraphRecursive(&n,
7550  &ncon,
7551  I,
7552  J,
7553  NULL,
7554  NULL,
7555  NULL,
7556  &mparts,
7557  NULL,
7558  NULL,
7559  options,
7560  &edgecut,
7561  mpartitioning);
7562  if (errflag != 1)
7563  {
7564  mfem_error("Mesh::GeneratePartitioning: "
7565  " error in METIS_PartGraphRecursive!");
7566  }
7567 #endif
7568  }
7569 
7570  // This function should be used to partition a graph into a large
7571  // number of partitions (greater than 8).
7572  if (part_method == 1 || part_method == 4)
7573  {
7574 #ifndef MFEM_USE_METIS_5
7576  I,
7577  J,
7578  NULL,
7579  NULL,
7580  &wgtflag,
7581  &numflag,
7582  &mparts,
7583  options,
7584  &edgecut,
7585  mpartitioning);
7586 #else
7587  errflag = METIS_PartGraphKway(&n,
7588  &ncon,
7589  I,
7590  J,
7591  NULL,
7592  NULL,
7593  NULL,
7594  &mparts,
7595  NULL,
7596  NULL,
7597  options,
7598  &edgecut,
7599  mpartitioning);
7600  if (errflag != 1)
7601  {
7602  mfem_error("Mesh::GeneratePartitioning: "
7603  " error in METIS_PartGraphKway!");
7604  }
7605 #endif
7606  }
7607 
7608  // The objective of this partitioning is to minimize the total
7609  // communication volume
7610  if (part_method == 2 || part_method == 5)
7611  {
7612 #ifndef MFEM_USE_METIS_5
7614  I,
7615  J,
7616  NULL,
7617  NULL,
7618  &wgtflag,
7619  &numflag,
7620  &mparts,
7621  options,
7622  &edgecut,
7623  mpartitioning);
7624 #else
7625  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
7626  errflag = METIS_PartGraphKway(&n,
7627  &ncon,
7628  I,
7629  J,
7630  NULL,
7631  NULL,
7632  NULL,
7633  &mparts,
7634  NULL,
7635  NULL,
7636  options,
7637  &edgecut,
7638  mpartitioning);
7639  if (errflag != 1)
7640  {
7641  mfem_error("Mesh::GeneratePartitioning: "
7642  " error in METIS_PartGraphKway!");
7643  }
7644 #endif
7645  }
7646 
7647 #ifdef MFEM_DEBUG
7648  if (print_messages)
7649  {
7650  mfem::out << "Mesh::GeneratePartitioning(...): edgecut = "
7651  << edgecut << endl;
7652  }
7653 #endif
7654  nparts = (int) mparts;
7655  if (mpartitioning != (idx_t*)partitioning)
7656  {
7657  for (int k = 0; k<NumOfElements; k++)
7658  {
7659  partitioning[k] = mpartitioning[k];
7660  }
7661  }
7662  if (freedata)
7663  {
7664  delete[] I;
7665  delete[] J;
7666  delete[] mpartitioning;
7667  }
7668  }
7669 
7670  delete el_to_el;
7671  el_to_el = NULL;
7672 
7673  // Check for empty partitionings (a "feature" in METIS)
7674  if (nparts > 1 && NumOfElements > nparts)
7675  {
7676  Array< Pair<int,int> > psize(nparts);
7677  int empty_parts;
7678 
7679  // Count how many elements are in each partition, and store the result in
7680  // psize, where psize[i].one is the number of elements, and psize[i].two
7681  // is partition index. Keep track of the number of empty parts.
7682  auto count_partition_elements = [&]()
7683  {
7684  for (i = 0; i < nparts; i++)
7685  {
7686  psize[i].one = 0;
7687  psize[i].two = i;
7688  }
7689 
7690  for (i = 0; i < NumOfElements; i++)
7691  {
7692  psize[partitioning[i]].one++;
7693  }
7694 
7695  empty_parts = 0;
7696  for (i = 0; i < nparts; i++)
7697  {
7698  if (psize[i].one == 0) { empty_parts++; }
7699  }
7700  };
7701 
7702  count_partition_elements();
7703 
7704  // This code just split the largest partitionings in two.
7705  // Do we need to replace it with something better?
7706  while (empty_parts)
7707  {
7708  if (print_messages)
7709  {
7710  mfem::err << "Mesh::GeneratePartitioning(...): METIS returned "
7711  << empty_parts << " empty parts!"
7712  << " Applying a simple fix ..." << endl;
7713  }
7714 
7715  SortPairs<int,int>(psize, nparts);
7716 
7717  for (i = nparts-1; i > nparts-1-empty_parts; i--)
7718  {
7719  psize[i].one /= 2;
7720  }
7721 
7722  for (int j = 0; j < NumOfElements; j++)
7723  {
7724  for (i = nparts-1; i > nparts-1-empty_parts; i--)
7725  {
7726  if (psize[i].one == 0 || partitioning[j] != psize[i].two)
7727  {
7728  continue;
7729  }
7730  else
7731  {
7732  partitioning[j] = psize[nparts-1-i].two;
7733  psize[i].one--;
7734  }
7735  }
7736  }
7737 
7738  // Check for empty partitionings again
7739  count_partition_elements();
7740  }
7741  }
7742 
7743  return partitioning;
7744 
7745 #else
7746 
7747  mfem_error("Mesh::GeneratePartitioning(...): "
7748  "MFEM was compiled without Metis.");
7749 
7750  return NULL;
7751 
7752 #endif
7753 }
7754 
7755 /* required: 0 <= partitioning[i] < num_part */
7757  const Array<int> &partitioning,
7758  Array<int> &component,
7759  Array<int> &num_comp)
7760 {
7761  int i, j, k;
7762  int num_elem, *i_elem_elem, *j_elem_elem;
7763 
7764  num_elem = elem_elem.Size();
7765  i_elem_elem = elem_elem.GetI();
7766  j_elem_elem = elem_elem.GetJ();
7767 
7768  component.SetSize(num_elem);
7769 
7770  Array<int> elem_stack(num_elem);
7771  int stack_p, stack_top_p, elem;
7772  int num_part;
7773 
7774  num_part = -1;
7775  for (i = 0; i < num_elem; i++)
7776  {
7777  if (partitioning[i] > num_part)
7778  {
7779  num_part = partitioning[i];
7780  }
7781  component[i] = -1;
7782  }
7783  num_part++;
7784 
7785  num_comp.SetSize(num_part);
7786  for (i = 0; i < num_part; i++)
7787  {
7788  num_comp[i] = 0;
7789  }
7790 
7791  stack_p = 0;
7792  stack_top_p = 0; // points to the first unused element in the stack
7793  for (elem = 0; elem < num_elem; elem++)
7794  {
7795  if (component[elem] >= 0)
7796  {
7797  continue;
7798  }
7799 
7800  component[elem] = num_comp[partitioning[elem]]++;
7801 
7802  elem_stack[stack_top_p++] = elem;
7803 
7804  for ( ; stack_p < stack_top_p; stack_p++)
7805  {
7806  i = elem_stack[stack_p];
7807  for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++)
7808  {
7809  k = j_elem_elem[j];
7810  if (partitioning[k] == partitioning[i])
7811  {
7812  if (component[k] < 0)
7813  {
7814  component[k] = component[i];
7815  elem_stack[stack_top_p++] = k;
7816  }
7817  else if (component[k] != component[i])
7818  {
7819  mfem_error("FindPartitioningComponents");
7820  }
7821  }
7822  }
7823  }
7824  }
7825 }
7826 
7827 void Mesh::CheckPartitioning(int *partitioning_)
7828 {
7829  int i, n_empty, n_mcomp;
7830  Array<int> component, num_comp;
7831  const Array<int> partitioning(partitioning_, GetNE());
7832 
7834 
7835  FindPartitioningComponents(*el_to_el, partitioning, component, num_comp);
7836 
7837  n_empty = n_mcomp = 0;
7838  for (i = 0; i < num_comp.Size(); i++)
7839  if (num_comp[i] == 0)
7840  {
7841  n_empty++;
7842  }
7843  else if (num_comp[i] > 1)
7844  {
7845  n_mcomp++;
7846  }
7847 
7848  if (n_empty > 0)
7849  {
7850  mfem::out << "Mesh::CheckPartitioning(...) :\n"
7851  << "The following subdomains are empty :\n";
7852  for (i = 0; i < num_comp.Size(); i++)
7853  if (num_comp[i] == 0)
7854  {
7855  mfem::out << ' ' << i;
7856  }
7857  mfem::out << endl;
7858  }
7859  if (n_mcomp > 0)
7860  {
7861  mfem::out << "Mesh::CheckPartitioning(...) :\n"
7862  << "The following subdomains are NOT connected :\n";
7863  for (i = 0; i < num_comp.Size(); i++)
7864  if (num_comp[i] > 1)
7865  {
7866  mfem::out << ' ' << i;
7867  }
7868  mfem::out << endl;
7869  }
7870  if (n_empty == 0 && n_mcomp == 0)
7871  mfem::out << "Mesh::CheckPartitioning(...) : "
7872  "All subdomains are connected." << endl;
7873 
7874  if (el_to_el)
7875  {
7876  delete el_to_el;
7877  }
7878  el_to_el = NULL;
7879 }
7880 
7881 // compute the coefficients of the polynomial in t:
7882 // c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B)
7883 // where A, B are (d x d), d=2,3
7884 void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
7885 {
7886  const double *a = A.Data();
7887  const double *b = B.Data();
7888 
7889  c.SetSize(A.Width()+1);
7890  switch (A.Width())
7891  {
7892  case 2:
7893  {
7894  // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ |b0 b2|
7895  // |a1 a3| + \ |a1 b3| |b1 a3| / * t + |b1 b3| * t^2
7896  c(0) = a[0]*a[3]-a[1]*a[2];
7897  c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2];
7898  c(2) = b[0]*b[3]-b[1]*b[2];
7899  }
7900  break;
7901 
7902  case 3:
7903  {
7904  /* |a0 a3 a6|
7905  * det(A+t*B) = |a1 a4 a7| +
7906  * |a2 a5 a8|
7907 
7908  * / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \
7909  * + | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t +
7910  * \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| /
7911 
7912  * / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \
7913  * + | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 +
7914  * \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| /
7915 
7916  * |b0 b3 b6|
7917  * + |b1 b4 b7| * t^3
7918  * |b2 b5 b8| */
7919  c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) +
7920  a[1] * (a[5] * a[6] - a[3] * a[8]) +
7921  a[2] * (a[3] * a[7] - a[4] * a[6]));
7922 
7923  c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) +
7924  b[1] * (a[5] * a[6] - a[3] * a[8]) +
7925  b[2] * (a[3] * a[7] - a[4] * a[6]) +
7926 
7927  a[0] * (b[4] * a[8] - b[5] * a[7]) +
7928  a[1] * (b[5] * a[6] - b[3] * a[8]) +
7929  a[2] * (b[3] * a[7] - b[4] * a[6]) +
7930 
7931  a[0] * (a[4] * b[8] - a[5] * b[7]) +
7932  a[1] * (a[5] * b[6] - a[3] * b[8]) +
7933  a[2] * (a[3] * b[7] - a[4] * b[6]));
7934 
7935  c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) +
7936  a[1] * (b[5] * b[6] - b[3] * b[8]) +
7937  a[2] * (b[3] * b[7] - b[4] * b[6]) +
7938 
7939  b[0] * (a[4] * b[8] - a[5] * b[7]) +
7940  b[1] * (a[5] * b[6] - a[3] * b[8]) +
7941  b[2] * (a[3] * b[7] - a[4] * b[6]) +
7942 
7943  b[0] * (b[4] * a[8] - b[5] * a[7]) +
7944  b[1] * (b[5] * a[6] - b[3] * a[8]) +
7945  b[2] * (b[3] * a[7] - b[4] * a[6]));
7946 
7947  c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) +
7948  b[1] * (b[5] * b[6] - b[3] * b[8]) +
7949  b[2] * (b[3] * b[7] - b[4] * b[6]));
7950  }
7951  break;
7952 
7953  default:
7954  mfem_error("DetOfLinComb(...)");
7955  }
7956 }
7957 
7958 // compute the real roots of
7959 // z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3;
7960 // the roots are returned in x, sorted in increasing order;
7961 // it is assumed that x is at least of size d;
7962 // return the number of roots counting multiplicity;
7963 // return -1 if all z(i) are 0.
7964 int FindRoots(const Vector &z, Vector &x)
7965 {
7966  int d = z.Size()-1;
7967  if (d > 3 || d < 0)
7968  {
7969  mfem_error("FindRoots(...)");
7970  }
7971 
7972  while (z(d) == 0.0)
7973  {
7974  if (d == 0)
7975  {
7976  return (-1);
7977  }
7978  d--;
7979  }
7980  switch (d)
7981  {
7982  case 0:
7983  {
7984  return 0;
7985  }
7986 
7987  case 1:
7988  {
7989  x(0) = -z(0)/z(1);
7990  return 1;
7991  }
7992 
7993  case 2:
7994  {
7995  double a = z(2), b = z(1), c = z(0);
7996  double D = b*b-4*a*c;
7997  if (D < 0.0)
7998  {
7999  return 0;
8000  }
8001  if (D == 0.0)
8002  {
8003  x(0) = x(1) = -0.5 * b / a;
8004  return 2; // root with multiplicity 2
8005  }
8006  if (b == 0.0)
8007  {
8008  x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a));
8009  return 2;
8010  }
8011  else
8012  {
8013  double t;
8014  if (b > 0.0)
8015  {
8016  t = -0.5 * (b + sqrt(D));
8017  }
8018  else
8019  {
8020  t = -0.5 * (b - sqrt(D));
8021  }
8022  x(0) = t / a;
8023  x(1) = c / t;
8024  if (x(0) > x(1))
8025  {
8026  Swap<double>(x(0), x(1));
8027  }
8028  return 2;
8029  }
8030  }
8031 
8032  case 3:
8033  {
8034  double a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3);
8035 
8036  // find the real roots of x^3 + a x^2 + b x + c = 0
8037  double Q = (a * a - 3 * b) / 9;
8038  double R = (2 * a * a * a - 9 * a * b + 27 * c) / 54;
8039  double Q3 = Q * Q * Q;
8040  double R2 = R * R;
8041 
8042  if (R2 == Q3)
8043  {
8044  if (Q == 0)
8045  {
8046  x(0) = x(1) = x(2) = - a / 3;
8047  }
8048  else
8049  {
8050  double sqrtQ = sqrt(Q);
8051 
8052  if (R > 0)
8053  {
8054  x(0) = -2 * sqrtQ - a / 3;
8055  x(1) = x(2) = sqrtQ - a / 3;
8056  }
8057  else
8058  {
8059  x(0) = x(1) = - sqrtQ - a / 3;
8060  x(2) = 2 * sqrtQ - a / 3;
8061  }
8062  }
8063  return 3;
8064  }
8065  else if (R2 < Q3)
8066  {
8067  double theta = acos(R / sqrt(Q3));
8068  double A = -2 * sqrt(Q);
8069  double x0, x1, x2;
8070  x0 = A * cos(theta / 3) - a / 3;
8071  x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3;
8072  x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3;
8073 
8074  /* Sort x0, x1, x2 */
8075  if (x0 > x1)
8076  {
8077  Swap<double>(x0, x1);
8078  }
8079  if (x1 > x2)
8080  {
8081  Swap<double>(x1, x2);
8082  if (x0 > x1)
8083  {
8084  Swap<double>(x0, x1);
8085  }
8086  }
8087  x(0) = x0;
8088  x(1) = x1;
8089  x(2) = x2;
8090  return 3;
8091  }
8092  else
8093  {
8094  double A;
8095  if (R >= 0.0)
8096  {
8097  A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0);
8098  }
8099  else
8100  {
8101  A = pow(sqrt(R2 - Q3) - R, 1.0/3.0);
8102  }
8103  x(0) = A + Q / A - a / 3;
8104  return 1;
8105  }
8106  }
8107  }
8108  return 0;
8109 }
8110 
8111 void FindTMax(Vector &c, Vector &x, double &tmax,
8112  const double factor, const int Dim)
8113 {
8114  const double c0 = c(0);
8115  c(0) = c0 * (1.0 - pow(factor, -Dim));
8116  int nr = FindRoots(c, x);
8117  for (int j = 0; j < nr; j++)
8118  {
8119  if (x(j) > tmax)
8120  {
8121  break;
8122  }
8123  if (x(j) >= 0.0)
8124  {
8125  tmax = x(j);
8126  break;
8127  }
8128  }
8129  c(0) = c0 * (1.0 - pow(factor, Dim));
8130  nr = FindRoots(c, x);
8131  for (int j = 0; j < nr; j++)
8132  {
8133  if (x(j) > tmax)
8134  {
8135  break;
8136  }
8137  if (x(j) >= 0.0)
8138  {
8139  tmax = x(j);
8140  break;
8141  }
8142  }
8143 }
8144 
8145 void Mesh::CheckDisplacements(const Vector &displacements, double &tmax)
8146 {
8147  int nvs = vertices.Size();
8148  DenseMatrix P, V, DS, PDS(spaceDim), VDS(spaceDim);
8149  Vector c(spaceDim+1), x(spaceDim);
8150  const double factor = 2.0;
8151 
8152  // check for tangling assuming constant speed
8153  if (tmax < 1.0)
8154  {
8155  tmax = 1.0;
8156  }
8157  for (int i = 0; i < NumOfElements; i++)
8158  {
8159  Element *el = elements[i];
8160  int nv = el->GetNVertices();
8161  int *v = el->GetVertices();
8162  P.SetSize(spaceDim, nv);
8163  V.SetSize(spaceDim, nv);
8164  for (int j = 0; j < spaceDim; j++)
8165  for (int k = 0; k < nv; k++)
8166  {
8167  P(j, k) = vertices[v[k]](j);
8168  V(j, k) = displacements(v[k]+j*nvs);
8169  }
8170  DS.SetSize(nv, spaceDim);
8171  const FiniteElement *fe =
8173  // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1
8174  switch (el->GetType())
8175  {
8176  case Element::TRIANGLE:
8177  case Element::TETRAHEDRON:
8178  {
8179  // DS is constant
8180  fe->CalcDShape(Geometries.GetCenter(fe->GetGeomType()), DS);
8181  Mult(P, DS, PDS);
8182  Mult(V, DS, VDS);
8183  DetOfLinComb(PDS, VDS, c);
8184  if (c(0) <= 0.0)
8185  {
8186  tmax = 0.0;
8187  }
8188  else
8189  {
8190  FindTMax(c, x, tmax, factor, Dim);
8191  }
8192  }
8193  break;
8194 
8196  {
8197  const IntegrationRule &ir = fe->GetNodes();
8198  for (int j = 0; j < nv; j++)
8199  {
8200  fe->CalcDShape(ir.IntPoint(j), DS);
8201  Mult(P, DS, PDS);
8202  Mult(V, DS, VDS);
8203  DetOfLinComb(PDS, VDS, c);
8204  if (c(0) <= 0.0)
8205  {
8206  tmax = 0.0;
8207  }
8208  else
8209  {
8210  FindTMax(c, x, tmax, factor, Dim);
8211  }
8212  }
8213  }
8214  break;
8215 
8216  default:
8217  mfem_error("Mesh::CheckDisplacements(...)");
8218  }
8219  }
8220 }
8221 
8222 void Mesh::MoveVertices(const Vector &displacements)
8223 {
8224  for (int i = 0, nv = vertices.Size(); i < nv; i++)
8225  for (int j = 0; j < spaceDim; j++)
8226  {
8227  vertices[i](j) += displacements(j*nv+i);
8228  }
8229 }
8230 
8231 void Mesh::GetVertices(Vector &vert_coord) const
8232 {
8233  int nv = vertices.Size();
8234  vert_coord.SetSize(nv*spaceDim);
8235  for (int i = 0; i < nv; i++)
8236  for (int j = 0; j < spaceDim; j++)
8237  {
8238  vert_coord(j*nv+i) = vertices[i](j);
8239  }
8240 }
8241 
8242 void Mesh::SetVertices(const Vector &vert_coord)
8243 {
8244  for (int i = 0, nv = vertices.Size(); i < nv; i++)
8245  for (int j = 0; j < spaceDim; j++)
8246  {
8247  vertices[i](j) = vert_coord(j*nv+i);
8248  }
8249 }
8250 
8251 void Mesh::GetNode(int i, double *coord) const
8252 {
8253  if (Nodes)
8254  {
8255  FiniteElementSpace *fes = Nodes->FESpace();
8256  for (int j = 0; j < spaceDim; j++)
8257  {
8258  coord[j] = AsConst(*Nodes)(fes->DofToVDof(i, j));
8259  }
8260  }
8261  else
8262  {
8263  for (int j = 0; j < spaceDim; j++)
8264  {
8265  coord[j] = vertices[i](j);
8266  }
8267  }
8268 }
8269 
8270 void Mesh::SetNode(int i, const double *coord)
8271 {
8272  if (Nodes)
8273  {
8274  FiniteElementSpace *fes = Nodes->FESpace();
8275  for (int j = 0; j < spaceDim; j++)
8276  {
8277  (*Nodes)(fes->DofToVDof(i, j)) = coord[j];
8278  }
8279  }
8280  else
8281  {
8282  for (int j = 0; j < spaceDim; j++)
8283  {
8284  vertices[i](j) = coord[j];
8285  }
8286 
8287  }
8288 }
8289 
8290 void Mesh::MoveNodes(const Vector &displacements)
8291 {
8292  if (Nodes)
8293  {
8294  (*Nodes) += displacements;
8295  }
8296  else
8297  {
8298  MoveVertices(displacements);
8299  }
8300 }
8301 
8302 void Mesh::GetNodes(Vector &node_coord) const
8303 {
8304  if (Nodes)
8305  {
8306  node_coord = (*Nodes);
8307  }
8308  else
8309  {
8310  GetVertices(node_coord);
8311  }
8312 }
8313 
8314 void Mesh::SetNodes(const Vector &node_coord)
8315 {
8316  if (Nodes)
8317  {
8318  (*Nodes) = node_coord;
8319  }
8320  else
8321  {
8322  SetVertices(node_coord);
8323  }
8324 
8325  // Invalidate the old geometric factors
8326  NodesUpdated();
8327 }
8328 
8329 void Mesh::NewNodes(GridFunction &nodes, bool make_owner)
8330 {
8331  if (own_nodes) { delete Nodes; }
8332  Nodes = &nodes;
8333  spaceDim = Nodes->FESpace()->GetVDim();
8334  own_nodes = (int)make_owner;
8335 
8336  if (NURBSext != nodes.FESpace()->GetNURBSext())
8337  {
8338  delete NURBSext;
8339  NURBSext = nodes.FESpace()->StealNURBSext();
8340  }
8341 
8342  if (ncmesh)
8343  {
8345  }
8346 
8347  // Invalidate the old geometric factors
8348  NodesUpdated();
8349 }
8350 
8351 void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_)
8352 {
8353  mfem::Swap<GridFunction*>(Nodes, nodes);
8354  mfem::Swap<int>(own_nodes, own_nodes_);
8355  // TODO:
8356  // if (nodes)
8357  // nodes->FESpace()->MakeNURBSextOwner();
8358  // NURBSext = (Nodes) ? Nodes->FESpace()->StealNURBSext() : NULL;
8359 
8360  // Invalidate the old geometric factors
8361  NodesUpdated();
8362 }
8363 
8364 void Mesh::AverageVertices(const int *indexes, int n, int result)
8365 {
8366  int j, k;
8367 
8368  for (k = 0; k < spaceDim; k++)
8369  {
8370  vertices[result](k) = vertices[indexes[0]](k);
8371  }
8372 
8373  for (j = 1; j < n; j++)
8374  for (k = 0; k < spaceDim; k++)
8375  {
8376  vertices[result](k) += vertices[indexes[j]](k);
8377  }
8378 
8379  for (k = 0; k < spaceDim; k++)
8380  {
8381  vertices[result](k) *= (1.0 / n);
8382  }
8383 }
8384 
8386 {
8387  if (Nodes)
8388  {
8389  Nodes->FESpace()->Update();
8390  Nodes->Update();
8391 
8392  // update vertex coordinates for compatibility (e.g., GetVertex())
8394 
8395  // Invalidate the old geometric factors
8396  NodesUpdated();
8397  }
8398 }
8399 
8400 void Mesh::UniformRefinement2D_base(bool update_nodes)
8401 {
8402  ResetLazyData();
8403 
8404  if (el_to_edge == NULL)
8405  {
8406  el_to_edge = new Table;
8408  }
8409 
8410  int quad_counter = 0;
8411  for (int i = 0; i < NumOfElements; i++)
8412  {
8413  if (elements[i]->GetType() == Element::QUADRILATERAL)
8414  {
8415  quad_counter++;
8416  }
8417  }
8418 
8419  const int oedge = NumOfVertices;
8420  const int oelem = oedge + NumOfEdges;
8421 
8422  Array<Element*> new_elements;
8423  Array<Element*> new_boundary;
8424 
8425  vertices.SetSize(oelem + quad_counter);
8426  new_elements.SetSize(4 * NumOfElements);
8427  quad_counter = 0;
8428 
8429  for (int i = 0, j = 0; i < NumOfElements; i++)
8430  {
8431  const Element::Type el_type = elements[i]->GetType();
8432  const int attr = elements[i]->GetAttribute();
8433  int *v = elements[i]->GetVertices();
8434  const int *e = el_to_edge->GetRow(i);
8435  int vv[2];
8436 
8437  if (el_type == Element::TRIANGLE)
8438  {
8439  for (int ei = 0; ei < 3; ei++)
8440  {
8441  for (int k = 0; k < 2; k++)
8442  {
8443  vv[k] = v[tri_t::Edges[ei][k]];
8444  }
8445  AverageVertices(vv, 2, oedge+e[ei]);
8446  }
8447 
8448  new_elements[j++] =
8449  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
8450  new_elements[j++] =
8451  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
8452  new_elements[j++] =
8453  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
8454  new_elements[j++] =
8455  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
8456  }
8457  else if (el_type == Element::QUADRILATERAL)
8458  {
8459  const int qe = quad_counter;
8460  quad_counter++;
8461  AverageVertices(v, 4, oelem+qe);
8462 
8463  for (int ei = 0; ei < 4; ei++)
8464  {
8465  for (int k = 0; k < 2; k++)
8466  {
8467  vv[k] = v[quad_t::Edges[ei][k]];
8468  }
8469  AverageVertices(vv, 2, oedge+e[ei]);
8470  }
8471 
8472  new_elements[j++] =
8473  new Quadrilateral(v[0], oedge+e[0], oelem+qe, oedge+e[3], attr);
8474  new_elements[j++] =
8475  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oelem+qe, attr);
8476  new_elements[j++] =
8477  new Quadrilateral(oelem+qe, oedge+e[1], v[2], oedge+e[2], attr);
8478  new_elements[j++] =
8479  new Quadrilateral(oedge+e[3], oelem+qe, oedge+e[2], v[3], attr);
8480  }
8481  else
8482  {
8483  MFEM_ABORT("unknown element type: " << el_type);
8484  }
8485  FreeElement(elements[i]);
8486  }
8487  mfem::Swap(elements, new_elements);
8488 
8489  // refine boundary elements
8490  new_boundary.SetSize(2 * NumOfBdrElements);
8491  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
8492  {
8493  const int attr = boundary[i]->GetAttribute();
8494  int *v = boundary[i]->GetVertices();
8495 
8496  new_boundary[j++] = new Segment(v[0], oedge+be_to_edge[i], attr);
8497  new_boundary[j++] = new Segment(oedge+be_to_edge[i], v[1], attr);
8498 
8499  FreeElement(boundary[i]);
8500  }
8501  mfem::Swap(boundary, new_boundary);
8502 
8503  static const double A = 0.0, B = 0.5, C = 1.0;
8504  static double tri_children[2*3*4] =
8505  {
8506  A,A, B,A, A,B,
8507  B,B, A,B, B,A,
8508  B,A, C,A, B,B,
8509  A,B, B,B, A,C
8510  };
8511  static double quad_children[2*4*4] =
8512  {
8513  A,A, B,A, B,B, A,B, // lower-left
8514  B,A, C,A, C,B, B,B, // lower-right
8515  B,B, C,B, C,C, B,C, // upper-right
8516  A,B, B,B, B,C, A,C // upper-left
8517  };
8518 
8520  .UseExternalData(tri_children, 2, 3, 4);
8522  .UseExternalData(quad_children, 2, 4, 4);
8523  CoarseFineTr.embeddings.SetSize(elements.Size());
8524 
8525  for (int i = 0; i < elements.Size(); i++)
8526  {
8527  Embedding &emb = CoarseFineTr.embeddings[i];
8528  emb.parent = i / 4;
8529  emb.matrix = i % 4;
8530  }
8531 
8532  NumOfVertices = vertices.Size();
8535  NumOfFaces = 0;
8536 
8538  GenerateFaces();
8539 
8541  sequence++;
8542 
8543  if (update_nodes) { UpdateNodes(); }
8544 
8545 #ifdef MFEM_DEBUG
8546  if (!Nodes || update_nodes)
8547  {
8548  CheckElementOrientation(false);
8549  }
8551 #endif
8552 }
8553 
8554 static inline double sqr(const double &x)
8555 {
8556  return x*x;
8557 }
8558 
8560  bool update_nodes)
8561 {
8562  ResetLazyData();
8563 
8564  if (el_to_edge == NULL)
8565  {
8566  el_to_edge = new Table;
8568  }
8569 
8570  if (el_to_face == NULL)
8571  {
8573  }
8574 
8575  Array<int> f2qf_loc;
8576  Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
8577  f2qf.SetSize(0);
8578 
8579  int NumOfQuadFaces = 0;
8581  {
8583  {
8584  f2qf.SetSize(faces.Size());
8585  for (int i = 0; i < faces.Size(); i++)
8586  {
8587  if (faces[i]->GetType() == Element::QUADRILATERAL)
8588  {
8589  f2qf[i] = NumOfQuadFaces;
8590  NumOfQuadFaces++;
8591  }
8592  }
8593  }
8594  else
8595  {
8596  NumOfQuadFaces = faces.Size();
8597  }
8598  }
8599 
8600  int hex_counter = 0;
8602  {
8603  for (int i = 0; i < elements.Size(); i++)
8604  {
8605  if (elements[i]->GetType() == Element::HEXAHEDRON)
8606  {
8607  hex_counter++;
8608  }
8609  }
8610  }
8611 
8612  int pyr_counter = 0;
8614  {
8615  for (int i = 0; i < elements.Size(); i++)
8616  {
8617  if (elements[i]->GetType() == Element::PYRAMID)
8618  {
8619  pyr_counter++;
8620  }
8621  }
8622  }
8623 
8624  // Map from edge-index to vertex-index, needed for ReorientTetMesh() for
8625  // parallel meshes.
8626  // Note: with the removal of ReorientTetMesh() this may no longer
8627  // be needed. Unfortunately, it's hard to be sure.
8628  Array<int> e2v;
8630  {
8631  e2v.SetSize(NumOfEdges);
8632 
8633  DSTable *v_to_v_ptr = v_to_v_p;
8634  if (!v_to_v_p)
8635  {
8636  v_to_v_ptr = new DSTable(NumOfVertices);
8637  GetVertexToVertexTable(*v_to_v_ptr);
8638  }
8639 
8640  Array<Pair<int,int> > J_v2v(NumOfEdges); // (second vertex id, edge id)
8641  J_v2v.SetSize(0);
8642  for (int i = 0; i < NumOfVertices; i++)
8643  {
8644  Pair<int,int> *row_start = J_v2v.end();
8645  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
8646  {
8647  J_v2v.Append(Pair<int,int>(it.Column(), it.Index()));
8648  }
8649  std::sort(row_start, J_v2v.end());
8650  }
8651 
8652  for (int i = 0; i < J_v2v.Size(); i++)
8653  {
8654  e2v[J_v2v[i].two] = i;
8655  }
8656 
8657  if (!v_to_v_p)
8658  {
8659  delete v_to_v_ptr;
8660  }
8661  else
8662  {
8663  for (int i = 0; i < NumOfVertices; i++)
8664  {
8665  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
8666  {
8667  it.SetIndex(e2v[it.Index()]);
8668  }
8669  }
8670  }
8671  }
8672 
8673  // Offsets for new vertices from edges, faces (quads only), and elements
8674  // (hexes only); each of these entities generates one new vertex.
8675  const int oedge = NumOfVertices;
8676  const int oface = oedge + NumOfEdges;
8677  const int oelem = oface + NumOfQuadFaces;
8678 
8679  Array<Element*> new_elements;
8680  Array<Element*> new_boundary;
8681 
8682  vertices.SetSize(oelem + hex_counter);
8683  new_elements.SetSize(8 * NumOfElements + 2 * pyr_counter);
8684  CoarseFineTr.embeddings.SetSize(new_elements.Size());
8685 
8686  hex_counter = 0;
8687  for (int i = 0, j = 0; i < NumOfElements; i++)
8688  {
8689  const Element::Type el_type = elements[i]->GetType();
8690  const int attr = elements[i]->GetAttribute();
8691  int *v = elements[i]->GetVertices();
8692  const int *e = el_to_edge->GetRow(i);
8693  int vv[4], ev[12];
8694 
8695  if (e2v.Size())
8696  {
8697  const int ne = el_to_edge->RowSize(i);
8698  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
8699  e = ev;
8700  }
8701 
8702  switch (el_type)
8703  {
8704  case Element::TETRAHEDRON:
8705  {
8706  for (int ei = 0; ei < 6; ei++)
8707  {
8708  for (int k = 0; k < 2; k++)
8709  {
8710  vv[k] = v[tet_t::Edges[ei][k]];
8711  }
8712  AverageVertices(vv, 2, oedge+e[ei]);
8713  }
8714 
8715  // Algorithm for choosing refinement type:
8716  // 0: smallest octahedron diagonal
8717  // 1: best aspect ratio
8718  const int rt_algo = 1;
8719  // Refinement type:
8720  // 0: (v0,v1)-(v2,v3), 1: (v0,v2)-(v1,v3), 2: (v0,v3)-(v1,v2)
8721  // 0: e0-e5, 1: e1-e4, 2: e2-e3
8722  int rt;
8724  T->SetIntPoint(&Geometries.GetCenter(Geometry::TETRAHEDRON));
8725  const DenseMatrix &J = T->Jacobian();
8726  if (rt_algo == 0)
8727  {
8728  // smallest octahedron diagonal
8729  double len_sqr, min_len;
8730 
8731  min_len = sqr(J(0,0)-J(0,1)-J(0,2)) +
8732  sqr(J(1,0)-J(1,1)-J(1,2)) +
8733  sqr(J(2,0)-J(2,1)-J(2,2));
8734  rt = 0;
8735 
8736  len_sqr = sqr(J(0,1)-J(0,0)-J(0,2)) +
8737  sqr(J(1,1)-J(1,0)-J(1,2)) +
8738  sqr(J(2,1)-J(2,0)-J(2,2));
8739  if (len_sqr < min_len) { min_len = len_sqr; rt = 1; }
8740 
8741  len_sqr = sqr(J(0,2)-J(0,0)-J(0,1)) +
8742  sqr(J(1,2)-J(1,0)-J(1,1)) +
8743  sqr(J(2,2)-J(2,0)-J(2,1));
8744  if (len_sqr < min_len) { rt = 2; }
8745  }
8746  else
8747  {
8748  // best aspect ratio
8749  double Em_data[18], Js_data[9], Jp_data[9];
8750  DenseMatrix Em(Em_data, 3, 6);
8751  DenseMatrix Js(Js_data, 3, 3), Jp(Jp_data, 3, 3);
8752  double ar1, ar2, kappa, kappa_min;
8753 
8754  for (int s = 0; s < 3; s++)
8755  {
8756  for (int t = 0; t < 3; t++)
8757  {
8758  Em(t,s) = 0.5*J(t,s);
8759  }
8760  }
8761  for (int t = 0; t < 3; t++)
8762  {
8763  Em(t,3) = 0.5*(J(t,0)+J(t,1));
8764  Em(t,4) = 0.5*(J(t,0)+J(t,2));
8765  Em(t,5) = 0.5*(J(t,1)+J(t,2));
8766  }
8767 
8768  // rt = 0; Em: {0,5,1,2}, {0,5,2,4}
8769  for (int t = 0; t < 3; t++)
8770  {
8771  Js(t,0) = Em(t,5)-Em(t,0);
8772  Js(t,1) = Em(t,1)-Em(t,0);
8773  Js(t,2) = Em(t,2)-Em(t,0);
8774  }
8776  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8777  for (int t = 0; t < 3; t++)
8778  {
8779  Js(t,0) = Em(t,5)-Em(t,0);
8780  Js(t,1) = Em(t,2)-Em(t,0);
8781  Js(t,2) = Em(t,4)-Em(t,0);
8782  }
8784  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8785  kappa_min = std::max(ar1, ar2);
8786  rt = 0;
8787 
8788  // rt = 1; Em: {1,0,4,2}, {1,2,4,5}
8789  for (int t = 0; t < 3; t++)
8790  {
8791  Js(t,0) = Em(t,0)-Em(t,1);
8792  Js(t,1) = Em(t,4)-Em(t,1);
8793  Js(t,2) = Em(t,2)-Em(t,1);
8794  }
8796  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8797  for (int t = 0; t < 3; t++)
8798  {
8799  Js(t,0) = Em(t,2)-Em(t,1);
8800  Js(t,1) = Em(t,4)-Em(t,1);
8801  Js(t,2) = Em(t,5)-Em(t,1);
8802  }
8804  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8805  kappa = std::max(ar1, ar2);
8806  if (kappa < kappa_min) { kappa_min = kappa; rt = 1; }
8807 
8808  // rt = 2; Em: {2,0,1,3}, {2,1,5,3}
8809  for (int t = 0; t < 3; t++)
8810  {
8811  Js(t,0) = Em(t,0)-Em(t,2);
8812  Js(t,1) = Em(t,1)-Em(t,2);
8813  Js(t,2) = Em(t,3)-Em(t,2);
8814  }
8816  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8817  for (int t = 0; t < 3; t++)
8818  {
8819  Js(t,0) = Em(t,1)-Em(t,2);
8820  Js(t,1) = Em(t,5)-Em(t,2);
8821  Js(t,2) = Em(t,3)-Em(t,2);
8822  }
8824  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8825  kappa = std::max(ar1, ar2);
8826  if (kappa < kappa_min) { rt = 2; }
8827  }
8828 
8829  static const int mv_all[3][4][4] =
8830  {
8831  { {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1} }, // rt = 0
8832  { {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0} }, // rt = 1
8833  { {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3} } // rt = 2
8834  };
8835  const int (&mv)[4][4] = mv_all[rt];
8836 
8837 #ifndef MFEM_USE_MEMALLOC
8838  new_elements[j+0] =
8839  new Tetrahedron(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
8840  new_elements[j+1] =
8841  new Tetrahedron(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
8842  new_elements[j+2] =
8843  new Tetrahedron(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
8844  new_elements[j+3] =
8845  new Tetrahedron(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
8846 
8847  for (int k = 0; k < 4; k++)
8848  {
8849  new_elements[j+4+k] =
8850  new Tetrahedron(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
8851  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
8852  }
8853 #else
8854  Tetrahedron *tet;
8855  new_elements[j+0] = tet = TetMemory.Alloc();
8856  tet->Init(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
8857 
8858  new_elements[j+1] = tet = TetMemory.Alloc();
8859  tet->Init(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
8860 
8861  new_elements[j+2] = tet = TetMemory.Alloc();
8862  tet->Init(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
8863 
8864  new_elements[j+3] = tet = TetMemory.Alloc();
8865  tet->Init(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
8866 
8867  for (int k = 0; k < 4; k++)
8868  {
8869  new_elements[j+4+k] = tet = TetMemory.Alloc();
8870  tet->Init(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
8871  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
8872  }
8873 #endif
8874  for (int k = 0; k < 4; k++)
8875  {
8876  CoarseFineTr.embeddings[j+k].parent = i;
8877  CoarseFineTr.embeddings[j+k].matrix = k;
8878  }
8879  for (int k = 0; k < 4; k++)
8880  {
8881  CoarseFineTr.embeddings[j+4+k].parent = i;
8882  CoarseFineTr.embeddings[j+4+k].matrix = 4*(rt+1)+k;
8883  }
8884 
8885  j += 8;
8886  }
8887  break;
8888 
8889  case Element::WEDGE:
8890  {
8891  const int *f = el_to_face->GetRow(i);
8892 
8893  for (int fi = 2; fi < 5; fi++)
8894  {
8895  for (int k = 0; k < 4; k++)
8896  {
8897  vv[k] = v[pri_t::FaceVert[fi][k]];
8898  }
8899  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
8900  }
8901 
8902  for (int ei = 0; ei < 9; ei++)
8903  {
8904  for (int k = 0; k < 2; k++)
8905  {
8906  vv[k] = v[pri_t::Edges[ei][k]];
8907  }
8908  AverageVertices(vv, 2, oedge+e[ei]);
8909  }
8910 
8911  const int qf2 = f2qf[f[2]];
8912  const int qf3 = f2qf[f[3]];
8913  const int qf4 = f2qf[f[4]];
8914 
8915  new_elements[j++] =
8916  new Wedge(v[0], oedge+e[0], oedge+e[2],
8917  oedge+e[6], oface+qf2, oface+qf4, attr);
8918 
8919  new_elements[j++] =
8920  new Wedge(oedge+e[1], oedge+e[2], oedge+e[0],
8921  oface+qf3, oface+qf4, oface+qf2, attr);
8922 
8923  new_elements[j++] =
8924  new Wedge(oedge+e[0], v[1], oedge+e[1],
8925  oface+qf2, oedge+e[7], oface+qf3, attr);
8926 
8927  new_elements[j++] =
8928  new Wedge(oedge+e[2], oedge+e[1], v[2],
8929  oface+qf4, oface+qf3, oedge+e[8], attr);
8930 
8931  new_elements[j++] =
8932  new Wedge(oedge+e[6], oface+qf2, oface+qf4,
8933  v[3], oedge+e[3], oedge+e[5], attr);
8934 
8935  new_elements[j++] =
8936  new Wedge(oface+qf3, oface+qf4, oface+qf2,
8937  oedge+e[4], oedge+e[5], oedge+e[3], attr);
8938 
8939  new_elements[j++] =
8940  new Wedge(oface+qf2, oedge+e[7], oface+qf3,
8941  oedge+e[3], v[4], oedge+e[4], attr);
8942 
8943  new_elements[j++] =
8944  new Wedge(oface+qf4, oface+qf3, oedge+e[8],
8945  oedge+e[5], oedge+e[4], v[5], attr);
8946  }
8947  break;
8948 
8949  case Element::PYRAMID:
8950  {
8951  const int *f = el_to_face->GetRow(i);
8952  // pyr_counter++;
8953 
8954  for (int fi = 0; fi < 1; fi++)
8955  {
8956  for (int k = 0; k < 4; k++)
8957  {
8958  vv[k] = v[pyr_t::FaceVert[fi][k]];
8959  }
8960  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
8961  }
8962 
8963  for (int ei = 0; ei < 8; ei++)
8964  {
8965  for (int k = 0; k < 2; k++)
8966  {
8967  vv[k] = v[pyr_t::Edges[ei][k]];
8968  }
8969  AverageVertices(vv, 2, oedge+e[ei]);
8970  }
8971 
8972  const int qf0 = f2qf[f[0]];
8973 
8974  new_elements[j++] =
8975  new Pyramid(v[0], oedge+e[0], oface+qf0,
8976  oedge+e[3], oedge+e[4], attr);
8977 
8978  new_elements[j++] =
8979  new Pyramid(oedge+e[0], v[1], oedge+e[1],
8980  oface+qf0, oedge+e[5], attr);
8981 
8982  new_elements[j++] =
8983  new Pyramid(oface+qf0, oedge+e[1], v[2],
8984  oedge+e[2], oedge+e[6], attr);
8985 
8986  new_elements[j++] =
8987  new Pyramid(oedge+e[3], oface+qf0, oedge+e[2],
8988  v[3], oedge+e[7], attr);
8989 
8990  new_elements[j++] =
8991  new Pyramid(oedge+e[4], oedge+e[5], oedge+e[6],
8992  oedge+e[7], v[4], attr);
8993 
8994  new_elements[j++] =
8995  new Pyramid(oedge+e[7], oedge+e[6], oedge+e[5],
8996  oedge+e[4], oface+qf0, attr);
8997 
8998 #ifndef MFEM_USE_MEMALLOC
8999  new_elements[j++] =
9000  new Tetrahedron(oedge+e[0], oedge+e[4], oedge+e[5],
9001  oface+qf0, attr);
9002 
9003  new_elements[j++] =
9004  new Tetrahedron(oedge+e[1], oedge+e[5], oedge+e[6],
9005  oface+qf0, attr);
9006 
9007  new_elements[j++] =
9008  new Tetrahedron(oedge+e[2], oedge+e[6], oedge+e[7],
9009  oface+qf0, attr);
9010 
9011  new_elements[j++] =
9012  new Tetrahedron(oedge+e[3], oedge+e[7], oedge+e[4],
9013  oface+qf0, attr);
9014 #else
9015  Tetrahedron *tet;
9016  new_elements[j++] = tet = TetMemory.Alloc();
9017  tet->Init(oedge+e[0], oedge+e[4], oedge+e[5],
9018  oface+qf0, attr);
9019 
9020  new_elements[j++] = tet = TetMemory.Alloc();
9021  tet->Init(oedge+e[1], oedge+e[5], oedge+e[6],
9022  oface+qf0, attr);
9023 
9024  new_elements[j++] = tet = TetMemory.Alloc();
9025  tet->Init(oedge+e[2], oedge+e[6], oedge+e[7],
9026  oface+qf0, attr);
9027 
9028  new_elements[j++] = tet = TetMemory.Alloc();
9029  tet->Init(oedge+e[3], oedge+e[7], oedge+e[4],
9030  oface+qf0, attr);
9031 #endif
9032  }
9033  break;
9034 
9035  case Element::HEXAHEDRON:
9036  {
9037  const int *f = el_to_face->GetRow(i);
9038  const int he = hex_counter;
9039  hex_counter++;
9040 
9041  const int *qf;
9042  int qf_data[6];
9043  if (f2qf.Size() == 0)
9044  {
9045  qf = f;
9046  }
9047  else
9048  {
9049  for (int k = 0; k < 6; k++) { qf_data[k] = f2qf[f[k]]; }
9050  qf = qf_data;
9051  }
9052 
9053  AverageVertices(v, 8, oelem+he);
9054 
9055  for (int fi = 0; fi < 6; fi++)
9056  {
9057  for (int k = 0; k < 4; k++)
9058  {
9059  vv[k] = v[hex_t::FaceVert[fi][k]];
9060  }
9061  AverageVertices(vv, 4, oface + qf[fi]);
9062  }
9063 
9064  for (int ei = 0; ei < 12; ei++)
9065  {
9066  for (int k = 0; k < 2; k++)
9067  {
9068  vv[k] = v[hex_t::Edges[ei][k]];
9069  }
9070  AverageVertices(vv, 2, oedge+e[ei]);
9071  }
9072 
9073  new_elements[j++] =
9074  new Hexahedron(v[0], oedge+e[0], oface+qf[0],
9075  oedge+e[3], oedge+e[8], oface+qf[1],
9076  oelem+he, oface+qf[4], attr);
9077  new_elements[j++] =
9078  new Hexahedron(oedge+e[0], v[1], oedge+e[1],
9079  oface+qf[0], oface+qf[1], oedge+e[9],
9080  oface+qf[2], oelem+he, attr);
9081  new_elements[j++] =
9082  new Hexahedron(oface+qf[0], oedge+e[1], v[2],
9083  oedge+e[2], oelem+he, oface+qf[2],
9084  oedge+e[10], oface+qf[3], attr);
9085  new_elements[j++] =
9086  new Hexahedron(oedge+e[3], oface+qf[0], oedge+e[2],
9087  v[3], oface+qf[4], oelem+he,
9088  oface+qf[3], oedge+e[11], attr);
9089  new_elements[j++] =
9090  new Hexahedron(oedge+e[8], oface+qf[1], oelem+he,
9091  oface+qf[4], v[4], oedge+e[4],
9092  oface+qf[5], oedge+e[7], attr);
9093  new_elements[j++] =
9094  new Hexahedron(oface+qf[1], oedge+e[9], oface+qf[2],
9095  oelem+he, oedge+e[4], v[5],
9096  oedge+e[5], oface+qf[5], attr);
9097  new_elements[j++] =
9098  new Hexahedron(oelem+he, oface+qf[2], oedge+e[10],
9099  oface+qf[3], oface+qf[5], oedge+e[5],
9100  v[6], oedge+e[6], attr);
9101  new_elements[j++] =
9102  new Hexahedron(oface+qf[4], oelem+he, oface+qf[3],
9103  oedge+e[11], oedge+e[7], oface+qf[5],
9104  oedge+e[6], v[7], attr);
9105  }
9106  break;
9107 
9108  default:
9109  MFEM_ABORT("Unknown 3D element type \"" << el_type << "\"");
9110  break;
9111  }
9112  FreeElement(elements[i]);
9113  }
9114  mfem::Swap(elements, new_elements);
9115 
9116  // refine boundary elements
9117  new_boundary.SetSize(4 * NumOfBdrElements);
9118  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
9119  {
9120  const Element::Type bdr_el_type = boundary[i]->GetType();
9121  const int attr = boundary[i]->GetAttribute();
9122  int *v = boundary[i]->GetVertices();
9123  const int *e = bel_to_edge->GetRow(i);
9124  int ev[4];
9125 
9126  if (e2v.Size())
9127  {
9128  const int ne = bel_to_edge->RowSize(i);
9129  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
9130  e = ev;
9131  }
9132 
9133  if (bdr_el_type == Element::TRIANGLE)
9134  {
9135  new_boundary[j++] =
9136  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
9137  new_boundary[j++] =
9138  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
9139  new_boundary[j++] =
9140  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
9141  new_boundary[j++] =
9142  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
9143  }
9144  else if (bdr_el_type == Element::QUADRILATERAL)
9145  {
9146  const int qf =
9147  (f2qf.Size() == 0) ? be_to_face[i] : f2qf[be_to_face[i]];
9148 
9149  new_boundary[j++] =
9150  new Quadrilateral(v[0], oedge+e[0], oface+qf, oedge+e[3], attr);
9151  new_boundary[j++] =
9152  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oface+qf, attr);
9153  new_boundary[j++] =
9154  new Quadrilateral(oface+qf, oedge+e[1], v[2], oedge+e[2], attr);
9155  new_boundary[j++] =
9156  new Quadrilateral(oedge+e[3], oface+qf, oedge+e[2], v[3], attr);
9157  }
9158  else
9159  {
9160  MFEM_ABORT("boundary Element is not a triangle or a quad!");
9161  }
9162  FreeElement(boundary[i]);
9163  }
9164  mfem::Swap(boundary, new_boundary);
9165 
9166  static const double A = 0.0, B = 0.5, C = 1.0, D = -1.0;
9167  static double tet_children[3*4*16] =
9168  {
9169  A,A,A, B,A,A, A,B,A, A,A,B,
9170  B,A,A, C,A,A, B,B,A, B,A,B,
9171  A,B,A, B,B,A, A,C,A, A,B,B,
9172  A,A,B, B,A,B, A,B,B, A,A,C,
9173  // edge coordinates:
9174  // 0 -> B,A,A 1 -> A,B,A 2 -> A,A,B
9175  // 3 -> B,B,A 4 -> B,A,B 5 -> A,B,B
9176  // rt = 0: {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1}
9177  B,A,A, A,B,B, A,B,A, A,A,B,
9178  B,A,A, A,B,B, A,A,B, B,A,B,
9179  B,A,A, A,B,B, B,A,B, B,B,A,
9180  B,A,A, A,B,B, B,B,A, A,B,A,
9181  // rt = 1: {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0}
9182  A,B,A, B,A,A, B,A,B, A,A,B,
9183  A,B,A, A,A,B, B,A,B, A,B,B,
9184  A,B,A, A,B,B, B,A,B, B,B,A,
9185  A,B,A, B,B,A, B,A,B, B,A,A,
9186  // rt = 2: {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3}
9187  A,A,B, B,A,A, A,B,A, B,B,A,
9188  A,A,B, A,B,A, A,B,B, B,B,A,
9189  A,A,B, A,B,B, B,A,B, B,B,A,
9190  A,A,B, B,A,B, B,A,A, B,B,A
9191  };
9192  static double pyr_children[3*5*10] =
9193  {
9194  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B,
9195  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B,
9196  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B,
9197  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B,
9198  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C,
9199  A,B,B, B,B,B, B,A,B, A,A,B, B,B,A,
9200  B,A,A, A,A,B, B,A,B, B,B,A, D,D,D,
9201  C,B,A, B,A,B, B,B,B, B,B,A, D,D,D,
9202  B,C,A, B,B,B, A,B,B, B,B,A, D,D,D,
9203  A,B,A, A,B,B, A,A,B, B,B,A, D,D,D
9204  };
9205  static double pri_children[3*6*8] =
9206  {
9207  A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
9208  B,B,A, A,B,A, B,A,A, B,B,B, A,B,B, B,A,B,
9209  B,A,A, C,A,A, B,B,A, B,A,B, C,A,B, B,B,B,
9210  A,B,A, B,B,A, A,C,A, A,B,B, B,B,B, A,C,B,
9211  A,A,B, B,A,B, A,B,B, A,A,C, B,A,C, A,B,C,
9212  B,B,B, A,B,B, B,A,B, B,B,C, A,B,C, B,A,C,
9213  B,A,B, C,A,B, B,B,B, B,A,C, C,A,C, B,B,C,
9214  A,B,B, B,B,B, A,C,B, A,B,C, B,B,C, A,C,C
9215  };
9216  static double hex_children[3*8*8] =
9217  {
9218  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B, B,A,B, B,B,B, A,B,B,
9219  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B, C,A,B, C,B,B, B,B,B,
9220  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B, C,B,B, C,C,B, B,C,B,
9221  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B, B,B,B, B,C,B, A,C,B,
9222  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C, B,A,C, B,B,C, A,B,C,
9223  B,A,B, C,A,B, C,B,B, B,B,B, B,A,C, C,A,C, C,B,C, B,B,C,
9224  B,B,B, C,B,B, C,C,B, B,C,B, B,B,C, C,B,C, C,C,C, B,C,C,
9225  A,B,B, B,B,B, B,C,B, A,C,B, A,B,C, B,B,C, B,C,C, A,C,C
9226  };
9227 
9229  .UseExternalData(tet_children, 3, 4, 16);
9231  .UseExternalData(pyr_children, 3, 5, 10);
9233  .UseExternalData(pri_children, 3, 6, 8);
9235  .UseExternalData(hex_children, 3, 8, 8);
9236 
9237  for (int i = 0; i < elements.Size(); i++)
9238  {
9239  // tetrahedron elements are handled above:
9240  if (elements[i]->GetType() == Element::TETRAHEDRON) { continue; }
9241 
9242  Embedding &emb = CoarseFineTr.embeddings[i];
9243  emb.parent = i / 8;
9244  emb.matrix = i % 8;
9245  }
9246 
9247  NumOfVertices = vertices.Size();
9248  NumOfElements = 8 * NumOfElements + 2 * pyr_counter;
9250 
9252  GenerateFaces();
9253 
9254 #ifdef MFEM_DEBUG
9256 #endif
9257 
9259 
9261  sequence++;
9262 
9263  if (update_nodes) { UpdateNodes(); }
9264 }
9265 
9266 void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
9267 {
9268  int i, j, ind, nedges;
9269  Array<int> v;
9270 
9271  ResetLazyData();
9272 
9273  if (ncmesh)
9274  {
9275  MFEM_ABORT("Local and nonconforming refinements cannot be mixed.");
9276  }
9277 
9279 
9280  if (Dim == 1) // --------------------------------------------------------
9281  {
9282  int cne = NumOfElements, cnv = NumOfVertices;
9283  NumOfVertices += marked_el.Size();
9284  NumOfElements += marked_el.Size();
9285  vertices.SetSize(NumOfVertices);
9286  elements.SetSize(NumOfElements);
9288 
9289  for (j = 0; j < marked_el.Size(); j++)
9290  {
9291  i = marked_el[j];
9292  Segment *c_seg = (Segment *)elements[i];
9293  int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
9294  int new_v = cnv + j, new_e = cne + j;
9295  AverageVertices(vert, 2, new_v);
9296  elements[new_e] = new Segment(new_v, vert[1], attr);
9297  vert[1] = new_v;
9298 
9301  }
9302 
9303  static double seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
9305  UseExternalData(seg_children, 1, 2, 3);
9306 
9307  GenerateFaces();
9308 
9309  } // end of 'if (Dim == 1)'
9310  else if (Dim == 2) // ---------------------------------------------------
9311  {
9312  // 1. Get table of vertex to vertex connections.
9313  DSTable v_to_v(NumOfVertices);
9314  GetVertexToVertexTable(v_to_v);
9315 
9316  // 2. Get edge to element connections in arrays edge1 and edge2
9317  nedges = v_to_v.NumberOfEntries();
9318  int *edge1 = new int[nedges];
9319  int *edge2 = new int[nedges];
9320  int *middle = new int[nedges];
9321 
9322  for (i = 0; i < nedges; i++)
9323  {
9324  edge1[i] = edge2[i] = middle[i] = -1;
9325  }
9326 
9327  for (i = 0; i < NumOfElements; i++)
9328  {
9329  elements[i]->GetVertices(v);
9330  for (j = 1; j < v.Size(); j++)
9331  {
9332  ind = v_to_v(v[j-1], v[j]);
9333  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
9334  }
9335  ind = v_to_v(v[0], v[v.Size()-1]);
9336  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
9337  }
9338 
9339  // 3. Do the red refinement.
9340  for (i = 0; i < marked_el.Size(); i++)
9341  {
9342  RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
9343  }
9344 
9345  // 4. Do the green refinement (to get conforming mesh).
9346  int need_refinement;
9347  do
9348  {
9349  need_refinement = 0;
9350  for (i = 0; i < nedges; i++)
9351  {
9352  if (middle[i] != -1 && edge1[i] != -1)
9353  {
9354  need_refinement = 1;
9355  GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
9356  }
9357  }
9358  }
9359  while (need_refinement == 1);
9360 
9361  // 5. Update the boundary elements.
9362  int v1[2], v2[2], bisect, temp;
9363  temp = NumOfBdrElements;
9364  for (i = 0; i < temp; i++)
9365  {
9366  boundary[i]->GetVertices(v);
9367  bisect = v_to_v(v[0], v[1]);
9368  if (middle[bisect] != -1) // the element was refined (needs updating)
9369  {
9370  if (boundary[i]->GetType() == Element::SEGMENT)
9371  {
9372  v1[0] = v[0]; v1[1] = middle[bisect];
9373  v2[0] = middle[bisect]; v2[1] = v[1];
9374 
9375  boundary[i]->SetVertices(v1);
9376  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
9377  }
9378  else
9379  mfem_error("Only bisection of segment is implemented"
9380  " for bdr elem.");
9381  }
9382  }
9383  NumOfBdrElements = boundary.Size();
9384 
9385  // 6. Free the allocated memory.
9386  delete [] edge1;
9387  delete [] edge2;
9388  delete [] middle;
9389 
9390  if (el_to_edge != NULL)
9391  {
9393  GenerateFaces();
9394  }
9395 
9396  }
9397  else if (Dim == 3) // ---------------------------------------------------
9398  {
9399  // 1. Hash table of vertex to vertex connections corresponding to refined
9400  // edges.
9401  HashTable<Hashed2> v_to_v;
9402 
9403  MFEM_VERIFY(GetNE() == 0 ||
9404  ((Tetrahedron*)elements[0])->GetRefinementFlag() != 0,
9405  "tetrahedral mesh is not marked for refinement:"
9406  " call Finalize(true)");
9407 
9408  // 2. Do the red refinement.
9409  int ii;
9410  switch (type)
9411  {
9412  case 1:
9413  for (i = 0; i < marked_el.Size(); i++)
9414  {
9415  Bisection(marked_el[i], v_to_v);
9416  }
9417  break;
9418  case 2:
9419  for (i = 0; i < marked_el.Size(); i++)
9420  {
9421  Bisection(marked_el[i], v_to_v);
9422 
9423  Bisection(NumOfElements - 1, v_to_v);
9424  Bisection(marked_el[i], v_to_v);
9425  }
9426  break;
9427  case 3:
9428  for (i = 0; i < marked_el.Size(); i++)
9429  {
9430  Bisection(marked_el[i], v_to_v);
9431 
9432  ii = NumOfElements - 1;
9433  Bisection(ii, v_to_v);
9434  Bisection(NumOfElements - 1, v_to_v);
9435  Bisection(ii, v_to_v);
9436 
9437  Bisection(marked_el[i], v_to_v);
9438  Bisection(NumOfElements-1, v_to_v);
9439  Bisection(marked_el[i], v_to_v);
9440  }
9441  break;
9442  }
9443 
9444  // 3. Do the green refinement (to get conforming mesh).
9445  int need_refinement;
9446  // int need_refinement, onoe, max_gen = 0;
9447  do
9448  {
9449  // int redges[2], type, flag;
9450  need_refinement = 0;
9451  // onoe = NumOfElements;
9452  // for (i = 0; i < onoe; i++)
9453  for (i = 0; i < NumOfElements; i++)
9454  {
9455  // ((Tetrahedron *)elements[i])->
9456  // ParseRefinementFlag(redges, type, flag);
9457  // if (flag > max_gen) max_gen = flag;
9458  if (elements[i]->NeedRefinement(v_to_v))
9459  {
9460  need_refinement = 1;
9461  Bisection(i, v_to_v);
9462  }
9463  }
9464  }
9465  while (need_refinement == 1);
9466 
9467  // mfem::out << "Maximum generation: " << max_gen << endl;
9468 
9469  // 4. Update the boundary elements.
9470  do
9471  {
9472  need_refinement = 0;
9473  for (i = 0; i < NumOfBdrElements; i++)
9474  if (boundary[i]->NeedRefinement(v_to_v))
9475  {
9476  need_refinement = 1;
9477  BdrBisection(i, v_to_v);
9478  }
9479  }
9480  while (need_refinement == 1);
9481 
9482  NumOfVertices = vertices.Size();
9483  NumOfBdrElements = boundary.Size();
9484 
9485  // 5. Update element-to-edge and element-to-face relations.
9486  if (el_to_edge != NULL)
9487  {
9489  }
9490  if (el_to_face != NULL)
9491  {
9493  GenerateFaces();
9494  }
9495 
9496  } // end 'if (Dim == 3)'
9497 
9499  sequence++;
9500 
9501  UpdateNodes();
9502 
9503 #ifdef MFEM_DEBUG
9504  CheckElementOrientation(false);
9505 #endif
9506 }
9507 
9509  int nc_limit)
9510 {
9511  MFEM_VERIFY(!NURBSext, "Nonconforming refinement of NURBS meshes is "
9512  "not supported. Project the NURBS to Nodes first.");
9513 
9514  ResetLazyData();
9515 
9516  if (!ncmesh)
9517  {
9518  // start tracking refinement hierarchy
9519  ncmesh = new NCMesh(this);
9520  }
9521 
9522  if (!refinements.Size())
9523  {
9525  return;
9526  }
9527 
9528  // do the refinements
9530  ncmesh->Refine(refinements);
9531 
9532  if (nc_limit > 0)
9533  {
9534  ncmesh->LimitNCLevel(nc_limit);
9535  }
9536 
9537  // create a second mesh containing the finest elements from 'ncmesh'
9538  Mesh* mesh2 = new Mesh(*ncmesh);
9539  ncmesh->OnMeshUpdated(mesh2);
9540 
9541  // now swap the meshes, the second mesh will become the old coarse mesh
9542  // and this mesh will be the new fine mesh
9543  Swap(*mesh2, false);
9544  delete mesh2;
9545 
9547 
9549  sequence++;
9550 
9551  if (Nodes) // update/interpolate curved mesh
9552  {
9553  Nodes->FESpace()->Update();
9554  Nodes->Update();
9555  }
9556 }
9557 
9558 double Mesh::AggregateError(const Array<double> &elem_error,
9559  const int *fine, int nfine, int op)
9560 {
9561  double error = elem_error[fine[0]];
9562 
9563  for (int i = 1; i < nfine; i++)
9564  {
9565  MFEM_VERIFY(fine[i] < elem_error.Size(), "");
9566 
9567  double err_fine = elem_error[fine[i]];
9568  switch (op)
9569  {
9570  case 0: error = std::min(error, err_fine); break;
9571  case 1: error += err_fine; break;
9572  case 2: error = std::max(error, err_fine); break;
9573  }
9574  }
9575  return error;
9576 }
9577 
9579  double threshold, int nc_limit, int op)
9580 {
9581  MFEM_VERIFY(ncmesh, "Only supported for non-conforming meshes.");
9582  MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. "
9583  "Project the NURBS to Nodes first.");
9584 
9585  ResetLazyData();
9586 
9587  const Table &dt = ncmesh->GetDerefinementTable();
9588 
9589  Array<int> level_ok;
9590  if (nc_limit > 0)
9591  {
9592  ncmesh->CheckDerefinementNCLevel(dt, level_ok, nc_limit);
9593  }
9594 
9595  Array<int> derefs;
9596  for (int i = 0; i < dt.Size(); i++)
9597  {
9598  if (nc_limit > 0 && !level_ok[i]) { continue; }
9599 
9600  double error =
9601  AggregateError(elem_error, dt.GetRow(i), dt.RowSize(i), op);
9602 
9603  if (error < threshold) { derefs.Append(i); }
9604  }
9605 
9606  if (!derefs.Size()) { return false; }
9607 
9608  ncmesh->Derefine(derefs);
9609 
9610  Mesh* mesh2 = new Mesh(*ncmesh);
9611  ncmesh->OnMeshUpdated(mesh2);
9612 
9613  Swap(*mesh2, false);
9614  delete mesh2;
9615 
9617 
9619  sequence++;
9620 
9621  UpdateNodes();
9622 
9623  return true;
9624 }
9625 
9626 bool Mesh::DerefineByError(Array<double> &elem_error, double threshold,
9627  int nc_limit, int op)
9628 {
9629  // NOTE: the error array is not const because it will be expanded in parallel
9630  // by ghost element errors
9631  if (Nonconforming())
9632  {
9633  return NonconformingDerefinement(elem_error, threshold, nc_limit, op);
9634  }
9635  else
9636  {
9637  MFEM_ABORT("Derefinement is currently supported for non-conforming "
9638  "meshes only.");
9639  return false;
9640  }
9641 }
9642 
9643 bool Mesh::DerefineByError(const Vector &elem_error, double threshold,
9644  int nc_limit, int op)
9645 {
9646  Array<double> tmp(elem_error.Size());
9647  for (int i = 0; i < tmp.Size(); i++)
9648  {
9649  tmp[i] = elem_error(i);
9650  }
9651  return DerefineByError(tmp, threshold, nc_limit, op);
9652 }
9653 
9654 
9655 void Mesh::InitFromNCMesh(const NCMesh &ncmesh_)
9656 {
9657  Dim = ncmesh_.Dimension();
9658  spaceDim = ncmesh_.SpaceDimension();
9659 
9660  DeleteTables();
9661 
9662  ncmesh_.GetMeshComponents(*this);
9663 
9664  NumOfVertices = vertices.Size();
9665  NumOfElements = elements.Size();
9666  NumOfBdrElements = boundary.Size();
9667 
9668  SetMeshGen(); // set the mesh type: 'meshgen', ...
9669 
9670  NumOfEdges = NumOfFaces = 0;
9672 
9673  if (Dim > 1)
9674  {
9675  el_to_edge = new Table;
9677  }
9678  if (Dim > 2)
9679  {
9681  }
9682  GenerateFaces();
9683 #ifdef MFEM_DEBUG
9685 #endif
9686 
9687  // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
9688  // outside after this method.
9689 }
9690 
9691 Mesh::Mesh(const NCMesh &ncmesh_)
9692 {
9693  Init();
9694  InitTables();
9695  InitFromNCMesh(ncmesh_);
9696  SetAttributes();
9697 }
9698 
9699 void Mesh::Swap(Mesh& other, bool non_geometry)
9700 {
9701  mfem::Swap(Dim, other.Dim);
9702  mfem::Swap(spaceDim, other.spaceDim);
9703 
9709 
9710  mfem::Swap(meshgen, other.meshgen);
9712 
9713  mfem::Swap(elements, other.elements);
9714  mfem::Swap(vertices, other.vertices);
9715  mfem::Swap(boundary, other.boundary);
9716  mfem::Swap(faces, other.faces);
9719 
9722  mfem::Swap(el_to_el, other.el_to_el);
9726  mfem::Swap(face_edge, other.face_edge);
9729 
9732 
9734 
9735 #ifdef MFEM_USE_MEMALLOC
9736  TetMemory.Swap(other.TetMemory);
9737 #endif
9738 
9739  if (non_geometry)
9740  {
9741  mfem::Swap(NURBSext, other.NURBSext);
9742  mfem::Swap(ncmesh, other.ncmesh);
9743 
9744  mfem::Swap(Nodes, other.Nodes);
9745  if (Nodes) { Nodes->FESpace()->UpdateMeshPointer(this); }
9746  if (other.Nodes) { other.Nodes->FESpace()->UpdateMeshPointer(&other); }
9747  mfem::Swap(own_nodes, other.own_nodes);
9748 
9750 
9751  mfem::Swap(sequence, other.sequence);
9753  }
9754 }
9755 
9756 void Mesh::GetElementData(const Array<Element*> &elem_array, int geom,
9757  Array<int> &elem_vtx, Array<int> &attr) const
9758 {
9759  // protected method
9760  const int nv = Geometry::NumVerts[geom];
9761  int num_elems = 0;
9762  for (int i = 0; i < elem_array.Size(); i++)
9763  {
9764  if (elem_array[i]->GetGeometryType() == geom)
9765  {
9766  num_elems++;
9767  }
9768  }
9769  elem_vtx.SetSize(nv*num_elems);
9770  attr.SetSize(num_elems);
9771  elem_vtx.SetSize(0);
9772  attr.SetSize(0);
9773  for (int i = 0; i < elem_array.Size(); i++)
9774  {
9775  Element *el = elem_array[i];
9776  if (el->GetGeometryType() != geom) { continue; }
9777 
9778  Array<int> loc_vtx(el->GetVertices(), nv);
9779  elem_vtx.Append(loc_vtx);
9780  attr.Append(el->GetAttribute());
9781  }
9782 }
9783 
9784 static Array<int>& AllElements(Array<int> &list, int nelem)
9785 {
9786  list.SetSize(nelem);
9787  for (int i = 0; i < nelem; i++) { list[i] = i; }
9788  return list;
9789 }
9790 
9791 void Mesh::UniformRefinement(int ref_algo)
9792 {
9793  Array<int> list;
9794 
9795  if (NURBSext)
9796  {
9798  }
9799  else if (ncmesh)
9800  {
9801  GeneralRefinement(AllElements(list, GetNE()));
9802  }
9803  else if (ref_algo == 1 && meshgen == 1 && Dim == 3)
9804  {
9805  // algorithm "B" for an all-tet mesh
9806  LocalRefinement(AllElements(list, GetNE()));
9807  }
9808  else
9809  {
9810  switch (Dim)
9811  {
9812  case 1: LocalRefinement(AllElements(list, GetNE())); break;
9813  case 2: UniformRefinement2D(); break;
9814  case 3: UniformRefinement3D(); break;
9815  default: MFEM_ABORT("internal error");
9816  }
9817  }
9818 }
9819 
9821  int nonconforming, int nc_limit)
9822 {
9823  if (ncmesh)
9824  {
9825  nonconforming = 1;
9826  }
9827  else if (Dim == 1 || (Dim == 3 && (meshgen & 1)))
9828  {
9829  nonconforming = 0;
9830  }
9831  else if (nonconforming < 0)
9832  {
9833  // determine if nonconforming refinement is suitable
9834  if ((meshgen & 2) || (meshgen & 4) || (meshgen & 8))
9835  {
9836  nonconforming = 1; // tensor product elements and wedges
9837  }
9838  else
9839  {
9840  nonconforming = 0; // simplices
9841  }
9842  }
9843 
9844  if (nonconforming)
9845  {
9846  // non-conforming refinement (hanging nodes)
9847  NonconformingRefinement(refinements, nc_limit);
9848  }
9849  else
9850  {
9851  Array<int> el_to_refine(refinements.Size());
9852  for (int i = 0; i < refinements.Size(); i++)
9853  {
9854  el_to_refine[i] = refinements[i].index;
9855  }
9856 
9857  // infer 'type' of local refinement from first element's 'ref_type'
9858  int type, rt = (refinements.Size() ? refinements[0].ref_type : 7);
9859  if (rt == 1 || rt == 2 || rt == 4)
9860  {
9861  type = 1; // bisection
9862  }
9863  else if (rt == 3 || rt == 5 || rt == 6)
9864  {
9865  type = 2; // quadrisection
9866  }
9867  else
9868  {
9869  type = 3; // octasection
9870  }
9871 
9872  // red-green refinement and bisection, no hanging nodes
9873  LocalRefinement(el_to_refine, type);
9874  }
9875 }
9876 
9877 void Mesh::GeneralRefinement(const Array<int> &el_to_refine, int nonconforming,
9878  int nc_limit)
9879 {
9880  Array<Refinement> refinements(el_to_refine.Size());
9881  for (int i = 0; i < el_to_refine.Size(); i++)
9882  {
9883  refinements[i] = Refinement(el_to_refine[i]);
9884  }
9885  GeneralRefinement(refinements, nonconforming, nc_limit);
9886 }
9887 
9888 void Mesh::EnsureNCMesh(bool simplices_nonconforming)
9889 {
9890  MFEM_VERIFY(!NURBSext, "Cannot convert a NURBS mesh to an NC mesh. "
9891  "Please project the NURBS to Nodes first, with SetCurvature().");
9892 
9893 #ifdef MFEM_USE_MPI
9894  MFEM_VERIFY(ncmesh != NULL || dynamic_cast<const ParMesh*>(this) == NULL,
9895  "Sorry, converting a conforming ParMesh to an NC mesh is "
9896  "not possible.");
9897 #endif
9898 
9899  if (!ncmesh)
9900  {
9901  if ((meshgen & 0x2) /* quads/hexes */ ||
9902  (meshgen & 0x4) /* wedges */ ||
9903  (simplices_nonconforming && (meshgen & 0x1)) /* simplices */)
9904  {
9905  ncmesh = new NCMesh(this);
9906  ncmesh->OnMeshUpdated(this);
9908  }
9909  }
9910 }
9911 
9912 void Mesh::RandomRefinement(double prob, bool aniso, int nonconforming,
9913  int nc_limit)
9914 {
9915  Array<Refinement> refs;
9916  for (int i = 0; i < GetNE(); i++)
9917  {
9918  if ((double) rand() / RAND_MAX < prob)
9919  {
9920  int type = 7;
9921  if (aniso)
9922  {
9923  type = (Dim == 3) ? (rand() % 7 + 1) : (rand() % 3 + 1);
9924  }
9925  refs.Append(Refinement(i, type));
9926  }
9927  }
9928  GeneralRefinement(refs, nonconforming, nc_limit);
9929 }
9930 
9931 void Mesh::RefineAtVertex(const Vertex& vert, double eps, int nonconforming)
9932 {
9933  Array<int> v;
9934  Array<Refinement> refs;
9935  for (int i = 0; i < GetNE(); i++)
9936  {
9937  GetElementVertices(i, v);
9938  bool refine = false;
9939  for (int j = 0; j < v.Size(); j++)
9940  {
9941  double dist = 0.0;
9942  for (int l = 0; l < spaceDim; l++)
9943  {
9944  double d = vert(l) - vertices[v[j]](l);
9945  dist += d*d;
9946  }
9947  if (dist <= eps*eps) { refine = true; break; }
9948  }
9949  if (refine)
9950  {
9951  refs.Append(Refinement(i));
9952  }
9953  }
9954  GeneralRefinement(refs, nonconforming);
9955 }
9956 
9957 bool Mesh::RefineByError(const Array<double> &elem_error, double threshold,
9958  int nonconforming, int nc_limit)
9959 {
9960  MFEM_VERIFY(elem_error.Size() == GetNE(), "");
9961  Array<Refinement> refs;
9962  for (int i = 0; i < GetNE(); i++)
9963  {
9964  if (elem_error[i] > threshold)
9965  {
9966  refs.Append(Refinement(i));
9967  }
9968  }
9969  if (ReduceInt(refs.Size()))
9970  {
9971  GeneralRefinement(refs, nonconforming, nc_limit);
9972  return true;
9973  }
9974  return false;
9975 }
9976 
9977 bool Mesh::RefineByError(const Vector &elem_error, double threshold,
9978  int nonconforming, int nc_limit)
9979 {
9980  Array<double> tmp(const_cast<double*>(elem_error.GetData()),
9981  elem_error.Size());
9982  return RefineByError(tmp, threshold, nonconforming, nc_limit);
9983 }
9984 
9985 
9986 void Mesh::Bisection(int i, const DSTable &v_to_v,
9987  int *edge1, int *edge2, int *middle)
9988 {
9989  int *vert;
9990  int v[2][4], v_new, bisect, t;
9991  Element *el = elements[i];
9992  Vertex V;
9993 
9994  t = el->GetType();
9995  if (t == Element::TRIANGLE)
9996  {
9997  Triangle *tri = (Triangle *) el;
9998 
9999  vert = tri->GetVertices();
10000 
10001  // 1. Get the index for the new vertex in v_new.
10002  bisect = v_to_v(vert[0], vert[1]);
10003  MFEM_ASSERT(bisect >= 0, "");
10004 
10005  if (middle[bisect] == -1)
10006  {
10007  v_new = NumOfVertices++;
10008  for (int d = 0; d < spaceDim; d++)
10009  {
10010  V(d) = 0.5 * (vertices[vert[0]](d) + vertices[vert[1]](d));
10011  }
10012  vertices.Append(V);
10013 
10014  // Put the element that may need refinement (because of this
10015  // bisection) in edge1, or -1 if no more refinement is needed.
10016  if (edge1[bisect] == i)
10017  {
10018  edge1[bisect] = edge2[bisect];
10019  }
10020 
10021  middle[bisect] = v_new;
10022  }
10023  else
10024  {
10025  v_new = middle[bisect];
10026 
10027  // This edge will require no more refinement.
10028  edge1[bisect] = -1;
10029  }
10030 
10031  // 2. Set the node indices for the new elements in v[0] and v[1] so that
10032  // the edge marked for refinement is between the first two nodes.
10033  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
10034  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
10035 
10036  tri->SetVertices(v[0]); // changes vert[0..2] !!!
10037 
10038  Triangle* tri_new = new Triangle(v[1], tri->GetAttribute());
10039  elements.Append(tri_new);
10040 
10041  int tr = tri->GetTransform();
10042  tri_new->ResetTransform(tr);
10043 
10044  // record the sequence of refinements
10045  tri->PushTransform(4);
10046  tri_new->PushTransform(5);
10047 
10048  int coarse = FindCoarseElement(i);
10049  CoarseFineTr.embeddings[i].parent = coarse;
10051 
10052  // 3. edge1 and edge2 may have to be changed for the second triangle.
10053  if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
10054  {
10055  bisect = v_to_v(v[1][0], v[1][1]);
10056  MFEM_ASSERT(bisect >= 0, "");
10057 
10058  if (edge1[bisect] == i)
10059  {
10060  edge1[bisect] = NumOfElements;
10061  }
10062  else if (edge2[bisect] == i)
10063  {
10064  edge2[bisect] = NumOfElements;
10065  }
10066  }
10067  NumOfElements++;
10068  }
10069  else
10070  {
10071  MFEM_ABORT("Bisection for now works only for triangles.");
10072  }
10073 }
10074 
10076 {
10077  int *vert;
10078  int v[2][4], v_new, bisect, t;
10079  Element *el = elements[i];
10080  Vertex V;
10081 
10082  t = el->GetType();
10083  if (t == Element::TETRAHEDRON)
10084  {
10085  Tetrahedron *tet = (Tetrahedron *) el;
10086 
10087  MFEM_VERIFY(tet->GetRefinementFlag() != 0,
10088  "TETRAHEDRON element is not marked for refinement.");
10089 
10090  vert = tet->GetVertices();
10091 
10092  // 1. Get the index for the new vertex in v_new.
10093  bisect = v_to_v.FindId(vert[0], vert[1]);
10094  if (bisect == -1)
10095  {
10096  v_new = NumOfVertices + v_to_v.GetId(vert[0],vert[1]);
10097  for (int j = 0; j < 3; j++)
10098  {
10099  V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j));
10100  }
10101  vertices.Append(V);
10102  }
10103  else
10104  {
10105  v_new = NumOfVertices + bisect;
10106  }
10107 
10108  // 2. Set the node indices for the new elements in v[2][4] so that
10109  // the edge marked for refinement is between the first two nodes.
10110  int type, old_redges[2], flag;
10111  tet->ParseRefinementFlag(old_redges, type, flag);
10112 
10113  int new_type, new_redges[2][2];
10114  v[0][3] = v_new;
10115  v[1][3] = v_new;
10116  new_redges[0][0] = 2;
10117  new_redges[0][1] = 1;
10118  new_redges[1][0] = 2;
10119  new_redges[1][1] = 1;
10120  int tr1 = -1, tr2 = -1;
10121  switch (old_redges[0])
10122  {
10123  case 2:
10124  v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3];
10125  if (type == Tetrahedron::TYPE_PF) { new_redges[0][1] = 4; }
10126  tr1 = 0;
10127  break;
10128  case 3:
10129  v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2];
10130  tr1 = 2;
10131  break;
10132  case 5:
10133  v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0];
10134  tr1 = 4;
10135  }
10136  switch (old_redges[1])
10137  {
10138  case 1:
10139  v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3];
10140  if (type == Tetrahedron::TYPE_PF) { new_redges[1][0] = 3; }
10141  tr2 = 1;
10142  break;
10143  case 4:
10144  v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2];
10145  tr2 = 3;
10146  break;
10147  case 5:
10148  v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1];
10149  tr2 = 5;
10150  }
10151 
10152  int attr = tet->GetAttribute();
10153  tet->SetVertices(v[0]);
10154 
10155 #ifdef MFEM_USE_MEMALLOC
10156  Tetrahedron *tet2 = TetMemory.Alloc();
10157  tet2->SetVertices(v[1]);
10158  tet2->SetAttribute(attr);
10159 #else
10160  Tetrahedron *tet2 = new Tetrahedron(v[1], attr);
10161 #endif
10162  tet2->ResetTransform(tet->GetTransform());
10163  elements.Append(tet2);
10164 
10165  // record the sequence of refinements
10166  tet->PushTransform(tr1);
10167  tet2->PushTransform(tr2);
10168 
10169  int coarse = FindCoarseElement(i);
10170  CoarseFineTr.embeddings[i].parent = coarse;
10172 
10173  // 3. Set the bisection flag
10174  switch (type)
10175  {
10176  case Tetrahedron::TYPE_PU:
10177  new_type = Tetrahedron::TYPE_PF; break;
10178  case Tetrahedron::TYPE_PF:
10179  new_type = Tetrahedron::TYPE_A; break;
10180  default:
10181  new_type = Tetrahedron::TYPE_PU;
10182  }
10183 
10184  tet->CreateRefinementFlag(new_redges[0], new_type, flag+1);
10185  tet2->CreateRefinementFlag(new_redges[1], new_type, flag+1);
10186 
10187  NumOfElements++;
10188  }
10189  else
10190  {
10191  MFEM_ABORT("Bisection with HashTable for now works only for tetrahedra.");
10192  }
10193 }
10194 
10195 void Mesh::BdrBisection(int i, const HashTable<Hashed2> &v_to_v)
10196 {
10197  int *vert;
10198  int v[2][3], v_new, bisect, t;
10199  Element *bdr_el = boundary[i];
10200 
10201  t = bdr_el->GetType();
10202  if (t == Element::TRIANGLE)
10203  {
10204  Triangle *tri = (Triangle *) bdr_el;
10205 
10206  vert = tri->GetVertices();
10207 
10208  // 1. Get the index for the new vertex in v_new.
10209  bisect = v_to_v.FindId(vert[0], vert[1]);
10210  MFEM_ASSERT(bisect >= 0, "");
10211  v_new = NumOfVertices + bisect;
10212  MFEM_ASSERT(v_new != -1, "");
10213 
10214  // 2. Set the node indices for the new elements in v[0] and v[1] so that
10215  // the edge marked for refinement is between the first two nodes.
10216  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
10217  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
10218 
10219  tri->SetVertices(v[0]);
10220 
10221  boundary.Append(new Triangle(v[1], tri->GetAttribute()));
10222 
10223  NumOfBdrElements++;
10224  }
10225  else
10226  {
10227  MFEM_ABORT("Bisection of boundary elements with HashTable works only for"
10228  " triangles!");
10229  }
10230 }
10231 
10232 void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
10233  int *edge1, int *edge2, int *middle)
10234 {
10235  Array<int> v;
10236  int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3];
10237  Vertex V;
10238 
10239  if (elements[i]->GetType() == Element::TRIANGLE)
10240  {
10241  Triangle *tri0 = (Triangle*) elements[i];
10242  tri0->GetVertices(v);
10243 
10244  // 1. Get the indices for the new vertices in array v_new
10245  bisect[0] = v_to_v(v[0],v[1]);
10246  bisect[1] = v_to_v(v[1],v[2]);
10247  bisect[2] = v_to_v(v[0],v[2]);
10248  MFEM_ASSERT(bisect[0] >= 0 && bisect[1] >= 0 && bisect[2] >= 0, "");
10249 
10250  for (j = 0; j < 3; j++) // for the 3 edges fix v_new
10251  {
10252  if (middle[bisect[j]] == -1)
10253  {
10254  v_new[j] = NumOfVertices++;
10255  for (int d = 0; d < spaceDim; d++)
10256  {
10257  V(d) = (vertices[v[j]](d) + vertices[v[(j+1)%3]](d))/2.;
10258  }
10259  vertices.Append(V);
10260 
10261  // Put the element that may need refinement (because of this
10262  // bisection) in edge1, or -1 if no more refinement is needed.
10263  if (edge1[bisect[j]] == i)
10264  {
10265  edge1[bisect[j]] = edge2[bisect[j]];
10266  }
10267 
10268  middle[bisect[j]] = v_new[j];
10269  }
10270  else
10271  {
10272  v_new[j] = middle[bisect[j]];
10273 
10274  // This edge will require no more refinement.
10275  edge1[bisect[j]] = -1;
10276  }
10277  }
10278 
10279  // 2. Set the node indices for the new elements in v1, v2, v3 & v4 so that
10280  // the edges marked for refinement be between the first two nodes.
10281  v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2];
10282  v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1];
10283  v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2];
10284  v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0];
10285 
10286  Triangle* tri1 = new Triangle(v1, tri0->GetAttribute());
10287  Triangle* tri2 = new Triangle(v2, tri0->GetAttribute());
10288  Triangle* tri3 = new Triangle(v3, tri0->GetAttribute());
10289 
10290  elements.Append(tri1);
10291  elements.Append(tri2);
10292  elements.Append(tri3);
10293 
10294  tri0->SetVertices(v4);
10295 
10296  // record the sequence of refinements
10297  unsigned code = tri0->GetTransform();
10298  tri1->ResetTransform(code);
10299  tri2->ResetTransform(code);
10300  tri3->ResetTransform(code);
10301 
10302  tri0->PushTransform(3);
10303  tri1->PushTransform(0);
10304  tri2->PushTransform(1);
10305  tri3->PushTransform(2);
10306 
10307  // set parent indices
10308  int coarse = FindCoarseElement(i);
10313 
10314  NumOfElements += 3;
10315  }
10316  else
10317  {
10318  MFEM_ABORT("Uniform refinement for now works only for triangles.");
10319  }
10320 }
10321 
10323 {
10324  // initialize CoarseFineTr
10325  CoarseFineTr.Clear();
10327  for (int i = 0; i < NumOfElements; i++)
10328  {
10329  elements[i]->ResetTransform(0);
10331  }
10332 }
10333 
10335 {
10336  int coarse;
10337  while ((coarse = CoarseFineTr.embeddings[i].parent) != i)
10338  {
10339  i = coarse;
10340  }
10341  return coarse;
10342 }
10343 
10345 {
10346  MFEM_VERIFY(GetLastOperation() == Mesh::REFINE, "");
10347 
10348  if (ncmesh)
10349  {
10350  return ncmesh->GetRefinementTransforms();
10351  }
10352 
10353  Mesh::GeometryList elem_geoms(*this);
10354  for (int i = 0; i < elem_geoms.Size(); i++)
10355  {
10356  const Geometry::Type geom = elem_geoms[i];
10357  if (CoarseFineTr.point_matrices[geom].SizeK()) { continue; }
10358 
10359  if (geom == Geometry::TRIANGLE ||
10360  geom == Geometry::TETRAHEDRON)
10361  {
10362  std::map<unsigned, int> mat_no;
10363  mat_no[0] = 1; // identity
10364 
10365  // assign matrix indices to element transformations
10366  for (int j = 0; j < elements.Size(); j++)
10367  {
10368  int index = 0;
10369  unsigned code = elements[j]->GetTransform();
10370  if (code)
10371  {
10372  int &matrix = mat_no[code];
10373  if (!matrix) { matrix = mat_no.size(); }
10374  index = matrix-1;
10375  }
10376  CoarseFineTr.embeddings[j].matrix = index;
10377  }
10378 
10379  DenseTensor &pmats = CoarseFineTr.point_matrices[geom];
10380  pmats.SetSize(Dim, Dim+1, mat_no.size());
10381 
10382  // calculate the point matrices used
10383  std::map<unsigned, int>::iterator it;
10384  for (it = mat_no.begin(); it != mat_no.end(); ++it)
10385  {
10386  if (geom == Geometry::TRIANGLE)
10387  {
10388  Triangle::GetPointMatrix(it->first, pmats(it->second-1));
10389  }
10390  else
10391  {
10392  Tetrahedron::GetPointMatrix(it->first, pmats(it->second-1));
10393  }
10394  }
10395  }
10396  else
10397  {
10398  MFEM_ABORT("Don't know how to construct CoarseFineTransformations for"
10399  " geom = " << geom);
10400  }
10401  }
10402 
10403  // NOTE: quads and hexes already have trivial transformations ready
10404  return CoarseFineTr;
10405 }
10406 
10407 void Mesh::PrintXG(std::ostream &os) const
10408 {
10409  MFEM_ASSERT(Dim==spaceDim, "2D Manifold meshes not supported");
10410  int i, j;
10411  Array<int> v;
10412 
10413  if (Dim == 2)
10414  {
10415  // Print the type of the mesh.
10416  if (Nodes == NULL)
10417  {
10418  os << "areamesh2\n\n";
10419  }
10420  else
10421  {
10422  os << "curved_areamesh2\n\n";
10423  }
10424 
10425  // Print the boundary elements.
10426  os << NumOfBdrElements << '\n';
10427  for (i = 0; i < NumOfBdrElements; i++)
10428  {
10429  boundary[i]->GetVertices(v);
10430 
10431  os << boundary[i]->GetAttribute();
10432  for (j = 0; j < v.Size(); j++)
10433  {
10434  os << ' ' << v[j] + 1;
10435  }
10436  os << '\n';
10437  }
10438 
10439  // Print the elements.
10440  os << NumOfElements << '\n';
10441  for (i = 0; i < NumOfElements; i++)
10442  {
10443  elements[i]->GetVertices(v);
10444 
10445  os << elements[i]->GetAttribute() << ' ' << v.Size();
10446  for (j = 0; j < v.Size(); j++)
10447  {
10448  os << ' ' << v[j] + 1;
10449  }
10450  os << '\n';
10451  }
10452 
10453  if (Nodes == NULL)
10454  {
10455  // Print the vertices.
10456  os << NumOfVertices << '\n';
10457  for (i = 0; i < NumOfVertices; i++)
10458  {
10459  os << vertices[i](0);
10460  for (j = 1; j < Dim; j++)
10461  {
10462  os << ' ' << vertices[i](j);
10463  }
10464  os << '\n';
10465  }
10466  }
10467  else
10468  {
10469  os << NumOfVertices << '\n';
10470  Nodes->Save(os);
10471  }
10472  }
10473  else // ===== Dim != 2 =====
10474  {
10475  if (Nodes)
10476  {
10477  mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D");
10478  }
10479 
10480  if (meshgen == 1)
10481  {
10482  int nv;
10483  const int *ind;
10484 
10485  os << "NETGEN_Neutral_Format\n";
10486  // print the vertices
10487  os << NumOfVertices << '\n';
10488  for (i = 0; i < NumOfVertices; i++)
10489  {
10490  for (j = 0; j < Dim; j++)
10491  {
10492  os << ' ' << vertices[i](j);
10493  }
10494  os << '\n';
10495  }
10496 
10497  // print the elements
10498  os << NumOfElements << '\n';
10499  for (i = 0; i < NumOfElements; i++)
10500  {
10501  nv = elements[i]->GetNVertices();
10502  ind = elements[i]->GetVertices();
10503  os << elements[i]->GetAttribute();
10504  for (j = 0; j < nv; j++)
10505  {
10506  os << ' ' << ind[j]+1;
10507  }
10508  os << '\n';
10509  }
10510 
10511  // print the boundary information.
10512  os << NumOfBdrElements << '\n';
10513  for (i = 0; i < NumOfBdrElements; i++)
10514  {
10515  nv = boundary[i]->GetNVertices();
10516  ind = boundary[i]->GetVertices();
10517  os << boundary[i]->GetAttribute();
10518  for (j = 0; j < nv; j++)
10519  {
10520  os << ' ' << ind[j]+1;
10521  }
10522  os << '\n';
10523  }
10524  }
10525  else if (meshgen == 2) // TrueGrid
10526  {
10527  int nv;
10528  const int *ind;
10529 
10530  os << "TrueGrid\n"
10531  << "1 " << NumOfVertices << " " << NumOfElements
10532  << " 0 0 0 0 0 0 0\n"
10533  << "0 0 0 1 0 0 0 0 0 0 0\n"
10534  << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
10535  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
10536  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
10537 
10538  for (i = 0; i < NumOfVertices; i++)
10539  os << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1)
10540  << ' ' << vertices[i](2) << " 0.0\n";
10541 
10542  for (i = 0; i < NumOfElements; i++)
10543  {
10544  nv = elements[i]->GetNVertices();
10545  ind = elements[i]->GetVertices();
10546  os << i+1 << ' ' << elements[i]->GetAttribute();
10547  for (j = 0; j < nv; j++)
10548  {
10549  os << ' ' << ind[j]+1;
10550  }
10551  os << '\n';
10552  }
10553 
10554  for (i = 0; i < NumOfBdrElements; i++)
10555  {
10556  nv = boundary[i]->GetNVertices();
10557  ind = boundary[i]->GetVertices();
10558  os << boundary[i]->GetAttribute();
10559  for (j = 0; j < nv; j++)
10560  {
10561  os << ' ' << ind[j]+1;
10562  }
10563  os << " 1.0 1.0 1.0 1.0\n";
10564  }
10565  }
10566  }
10567 
10568  os << flush;
10569 }
10570 
10571 void Mesh::Printer(std::ostream &os, std::string section_delimiter) const
10572 {
10573  int i, j;
10574 
10575  if (NURBSext)
10576  {
10577  // general format
10578  NURBSext->Print(os);
10579  os << '\n';
10580  Nodes->Save(os);
10581 
10582  // patch-wise format
10583  // NURBSext->ConvertToPatches(*Nodes);
10584  // NURBSext->Print(os);
10585 
10586  return;
10587  }
10588 
10589  if (Nonconforming())
10590  {
10591  // nonconforming mesh format
10592  ncmesh->Print(os);
10593 
10594  if (Nodes)
10595  {
10596  os << "\n# mesh curvature GridFunction";
10597  os << "\nnodes\n";
10598  Nodes->Save(os);
10599  }
10600 
10601  os << "\nmfem_mesh_end" << endl;
10602  return;
10603  }
10604 
10605  // serial/parallel conforming mesh format
10606  os << (section_delimiter.empty()
10607  ? "MFEM mesh v1.0\n" : "MFEM mesh v1.2\n");
10608 
10609  // optional
10610  os <<
10611  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10612  "# POINT = 0\n"
10613  "# SEGMENT = 1\n"
10614  "# TRIANGLE = 2\n"
10615  "# SQUARE = 3\n"
10616  "# TETRAHEDRON = 4\n"
10617  "# CUBE = 5\n"
10618  "# PRISM = 6\n"
10619  "# PYRAMID = 7\n"
10620  "#\n";
10621 
10622  os << "\ndimension\n" << Dim;
10623 
10624  os << "\n\nelements\n" << NumOfElements << '\n';
10625  for (i = 0; i < NumOfElements; i++)
10626  {
10627  PrintElement(elements[i], os);
10628  }
10629 
10630  os << "\nboundary\n" << NumOfBdrElements << '\n';
10631  for (i = 0; i < NumOfBdrElements; i++)
10632  {
10633  PrintElement(boundary[i], os);
10634  }
10635 
10636  os << "\nvertices\n" << NumOfVertices << '\n';
10637  if (Nodes == NULL)
10638  {
10639  os << spaceDim << '\n';
10640  for (i = 0; i < NumOfVertices; i++)
10641  {
10642  os << vertices[i](0);
10643  for (j = 1; j < spaceDim; j++)
10644  {
10645  os << ' ' << vertices[i](j);
10646  }
10647  os << '\n';
10648  }
10649  os.flush();
10650  }
10651  else
10652  {
10653  os << "\nnodes\n";
10654  Nodes->Save(os);
10655  }
10656 
10657  if (!section_delimiter.empty())
10658  {
10659  os << section_delimiter << endl; // only with format v1.2
10660  }
10661 }
10662 
10663 void Mesh::PrintTopo(std::ostream &os,const Array<int> &e_to_k) const
10664 {
10665  int i;
10666  Array<int> vert;
10667 
10668  os << "MFEM NURBS mesh v1.0\n";
10669 
10670  // optional
10671  os <<
10672  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10673  "# SEGMENT = 1\n"
10674  "# SQUARE = 3\n"
10675  "# CUBE = 5\n"
10676  "#\n";
10677 
10678  os << "\ndimension\n" << Dim
10679  << "\n\nelements\n" << NumOfElements << '\n';
10680  for (i = 0; i < NumOfElements; i++)
10681  {
10682  PrintElement(elements[i], os);
10683  }
10684 
10685  os << "\nboundary\n" << NumOfBdrElements << '\n';
10686  for (i = 0; i < NumOfBdrElements; i++)
10687  {
10688  PrintElement(boundary[i], os);
10689  }
10690 
10691  os << "\nedges\n" << NumOfEdges << '\n';
10692  for (i = 0; i < NumOfEdges; i++)
10693  {
10694  edge_vertex->GetRow(i, vert);
10695  int ki = e_to_k[i];
10696  if (ki < 0)
10697  {
10698  ki = -1 - ki;
10699  }
10700  os << ki << ' ' << vert[0] << ' ' << vert[1] << '\n';
10701  }
10702  os << "\nvertices\n" << NumOfVertices << '\n';
10703 }
10704 
10705 void Mesh::Save(const std::string &fname, int precision) const
10706 {
10707  ofstream ofs(fname);
10708  ofs.precision(precision);
10709  Print(ofs);
10710 }
10711 
10712 #ifdef MFEM_USE_ADIOS2
10713 void Mesh::Print(adios2stream &os) const
10714 {
10715  os.Print(*this);
10716 }
10717 #endif
10718 
10719 void Mesh::PrintVTK(std::ostream &os)
10720 {
10721  os <<
10722  "# vtk DataFile Version 3.0\n"
10723  "Generated by MFEM\n"
10724  "ASCII\n"
10725  "DATASET UNSTRUCTURED_GRID\n";
10726 
10727  if (Nodes == NULL)
10728  {
10729  os << "POINTS " << NumOfVertices << " double\n";
10730  for (int i = 0; i < NumOfVertices; i++)
10731  {
10732  os << vertices[i](0);
10733  int j;
10734  for (j = 1; j < spaceDim; j++)
10735  {
10736  os << ' ' << vertices[i](j);
10737  }
10738  for ( ; j < 3; j++)
10739  {
10740  os << ' ' << 0.0;
10741  }
10742  os << '\n';
10743  }
10744  }
10745  else
10746  {
10747  Array<int> vdofs(3);
10748  os << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n";
10749  for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++)
10750  {
10751  vdofs.SetSize(1);
10752  vdofs[0] = i;
10753  Nodes->FESpace()->DofsToVDofs(vdofs);
10754  os << (*Nodes)(vdofs[0]);
10755  int j;
10756  for (j = 1; j < spaceDim; j++)
10757  {
10758  os << ' ' << (*Nodes)(vdofs[j]);
10759  }
10760  for ( ; j < 3; j++)
10761  {
10762  os << ' ' << 0.0;
10763  }
10764  os << '\n';
10765  }
10766  }
10767 
10768  int order = -1;
10769  if (Nodes == NULL)
10770  {
10771  int size = 0;
10772  for (int i = 0; i < NumOfElements; i++)
10773  {
10774  size += elements[i]->GetNVertices() + 1;
10775  }
10776  os << "CELLS " << NumOfElements << ' ' << size << '\n';
10777  for (int i = 0; i < NumOfElements; i++)
10778  {
10779  const int *v = elements[i]->GetVertices();
10780  const int nv = elements[i]->GetNVertices();
10781  os << nv;
10782  Geometry::Type geom = elements[i]->GetGeometryType();
10783  const int *perm = VTKGeometry::VertexPermutation[geom];
10784  for (int j = 0; j < nv; j++)
10785  {
10786  os << ' ' << v[perm ? perm[j] : j];
10787  }
10788  os << '\n';
10789  }
10790  order = 1;
10791  }
10792  else
10793  {
10794  Array<int> dofs;
10795  int size = 0;
10796  for (int i = 0; i < NumOfElements; i++)
10797  {
10798  Nodes->FESpace()->GetElementDofs(i, dofs);
10799  MFEM_ASSERT(Dim != 0 || dofs.Size() == 1,
10800  "Point meshes should have a single dof per element");
10801  size += dofs.Size() + 1;
10802  }
10803  os << "CELLS " << NumOfElements << ' ' << size << '\n';
10804  const char *fec_name = Nodes->FESpace()->FEColl()->Name();
10805 
10806  if (!strcmp(fec_name, "Linear") ||
10807  !strcmp(fec_name, "H1_0D_P1") ||
10808  !strcmp(fec_name, "H1_1D_P1") ||
10809  !strcmp(fec_name, "H1_2D_P1") ||
10810  !strcmp(fec_name, "H1_3D_P1"))
10811  {
10812  order = 1;
10813  }
10814  else if (!strcmp(fec_name, "Quadratic") ||
10815  !strcmp(fec_name, "H1_1D_P2") ||
10816  !strcmp(fec_name, "H1_2D_P2") ||
10817  !strcmp(fec_name, "H1_3D_P2"))
10818  {
10819  order = 2;
10820  }
10821  if (order == -1)
10822  {
10823  mfem::err << "Mesh::PrintVTK : can not save '"
10824  << fec_name << "' elements!" << endl;
10825  mfem_error();
10826  }
10827  for (int i = 0; i < NumOfElements; i++)
10828  {
10829  Nodes->FESpace()->GetElementDofs(i, dofs);
10830  os << dofs.Size();
10831  if (order == 1)
10832  {
10833  for (int j = 0; j < dofs.Size(); j++)
10834  {
10835  os << ' ' << dofs[j];
10836  }
10837  }
10838  else if (order == 2)
10839  {
10840  const int *vtk_mfem;
10841  switch (elements[i]->GetGeometryType())
10842  {
10843  case Geometry::SEGMENT:
10844  case Geometry::TRIANGLE:
10845  case Geometry::SQUARE:
10846  vtk_mfem = vtk_quadratic_hex; break; // identity map
10847  case Geometry::TETRAHEDRON:
10848  vtk_mfem = vtk_quadratic_tet; break;
10849  case Geometry::PRISM:
10850  vtk_mfem = vtk_quadratic_wedge; break;
10851  case Geometry::CUBE:
10852  default:
10853  vtk_mfem = vtk_quadratic_hex; break;
10854  }
10855  for (int j = 0; j < dofs.Size(); j++)
10856  {
10857  os << ' ' << dofs[vtk_mfem[j]];
10858  }
10859  }
10860  os << '\n';
10861  }
10862  }
10863 
10864  os << "CELL_TYPES " << NumOfElements << '\n';
10865  for (int i = 0; i < NumOfElements; i++)
10866  {
10867  int vtk_cell_type = 5;
10869  if (order == 1) { vtk_cell_type = VTKGeometry::Map[geom]; }
10870  else if (order == 2) { vtk_cell_type = VTKGeometry::QuadraticMap[geom]; }
10871  os << vtk_cell_type << '\n';
10872  }
10873 
10874  // write attributes
10875  os << "CELL_DATA " << NumOfElements << '\n'
10876  << "SCALARS material int\n"
10877  << "LOOKUP_TABLE default\n";
10878  for (int i = 0; i < NumOfElements; i++)
10879  {
10880  os << elements[i]->GetAttribute() << '\n';
10881  }
10882  os.flush();
10883 }
10884 
10885 void Mesh::PrintVTU(std::string fname,
10886  VTKFormat format,
10887  bool high_order_output,
10888  int compression_level,
10889  bool bdr)
10890 {
10891  int ref = (high_order_output && Nodes)
10892  ? Nodes->FESpace()->GetMaxElementOrder() : 1;
10893 
10894  fname = fname + ".vtu";
10895  std::fstream os(fname.c_str(),std::ios::out);
10896  os << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"";
10897  if (compression_level != 0)
10898  {
10899  os << " compressor=\"vtkZLibDataCompressor\"";
10900  }
10901  os << " byte_order=\"" << VTKByteOrder() << "\">\n";
10902  os << "<UnstructuredGrid>\n";
10903  PrintVTU(os, ref, format, high_order_output, compression_level, bdr);
10904  os << "</Piece>\n"; // need to close the piece open in the PrintVTU method
10905  os << "</UnstructuredGrid>\n";
10906  os << "</VTKFile>" << std::endl;
10907 
10908  os.close();
10909 }
10910 
10911 void Mesh::PrintBdrVTU(std::string fname,
10912  VTKFormat format,
10913  bool high_order_output,
10914  int compression_level)
10915 {
10916  PrintVTU(fname, format, high_order_output, compression_level, true);
10917 }
10918 
10919 void Mesh::PrintVTU(std::ostream &os, int ref, VTKFormat format,
10920  bool high_order_output, int compression_level,
10921  bool bdr_elements)
10922 {
10923  RefinedGeometry *RefG;
10924  DenseMatrix pmat;
10925 
10926  const char *fmt_str = (format == VTKFormat::ASCII) ? "ascii" : "binary";
10927  const char *type_str = (format != VTKFormat::BINARY32) ? "Float64" : "Float32";
10928  std::vector<char> buf;
10929 
10930  auto get_geom = [&](int i)
10931  {
10932  if (bdr_elements) { return GetBdrElementBaseGeometry(i); }
10933  else { return GetElementBaseGeometry(i); }
10934  };
10935 
10936  int ne = bdr_elements ? GetNBE() : GetNE();
10937  // count the number of points and cells
10938  int np = 0, nc_ref = 0;
10939  for (int i = 0; i < ne; i++)
10940  {
10941  Geometry::Type geom = get_geom(i);
10942  int nv = Geometries.GetVertices(geom)->GetNPoints();
10943  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10944  np += RefG->RefPts.GetNPoints();
10945  nc_ref += RefG->RefGeoms.Size() / nv;
10946  }
10947 
10948  os << "<Piece NumberOfPoints=\"" << np << "\" NumberOfCells=\""
10949  << (high_order_output ? ne : nc_ref) << "\">\n";
10950 
10951  // print out the points
10952  os << "<Points>\n";
10953  os << "<DataArray type=\"" << type_str
10954  << "\" NumberOfComponents=\"3\" format=\"" << fmt_str << "\">\n";
10955  for (int i = 0; i < ne; i++)
10956  {
10957  RefG = GlobGeometryRefiner.Refine(get_geom(i), ref, 1);
10958 
10959  if (bdr_elements)
10960  {
10961  GetBdrElementTransformation(i)->Transform(RefG->RefPts, pmat);
10962  }
10963  else
10964  {
10965  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
10966  }
10967 
10968  for (int j = 0; j < pmat.Width(); j++)
10969  {
10970  WriteBinaryOrASCII(os, buf, pmat(0,j), " ", format);
10971  if (pmat.Height() > 1)
10972  {
10973  WriteBinaryOrASCII(os, buf, pmat(1,j), " ", format);
10974  }
10975  else
10976  {
10977  WriteBinaryOrASCII(os, buf, 0.0, " ", format);
10978  }
10979  if (pmat.Height() > 2)
10980  {
10981  WriteBinaryOrASCII(os, buf, pmat(2,j), "", format);
10982  }
10983  else
10984  {
10985  WriteBinaryOrASCII(os, buf, 0.0, "", format);
10986  }
10987  if (format == VTKFormat::ASCII) { os << '\n'; }
10988  }
10989  }
10990  if (format != VTKFormat::ASCII)
10991  {
10992  WriteBase64WithSizeAndClear(os, buf, compression_level);
10993  }
10994  os << "</DataArray>" << std::endl;
10995  os << "</Points>" << std::endl;
10996 
10997  os << "<Cells>" << std::endl;
10998  os << "<DataArray type=\"Int32\" Name=\"connectivity\" format=\""
10999  << fmt_str << "\">" << std::endl;
11000  // connectivity
11001  std::vector<int> offset;
11002 
11003  np = 0;
11004  if (high_order_output)
11005  {
11006  Array<int> local_connectivity;
11007  for (int iel = 0; iel < ne; iel++)
11008  {
11009  Geometry::Type geom = get_geom(iel);
11010  CreateVTKElementConnectivity(local_connectivity, geom, ref);
11011  int nnodes = local_connectivity.Size();
11012  for (int i=0; i<nnodes; ++i)
11013  {
11014  WriteBinaryOrASCII(os, buf, np+local_connectivity[i], " ",
11015  format);
11016  }
11017  if (format == VTKFormat::ASCII) { os << '\n'; }
11018  np += nnodes;
11019  offset.push_back(np);
11020  }
11021  }
11022  else
11023  {
11024  int coff = 0;
11025  for (int i = 0; i < ne; i++)
11026  {
11027  Geometry::Type geom = get_geom(i);
11028  int nv = Geometries.GetVertices(geom)->GetNPoints();
11029  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11030  Array<int> &RG = RefG->RefGeoms;
11031  for (int j = 0; j < RG.Size(); )
11032  {
11033  coff = coff+nv;
11034  offset.push_back(coff);
11035  const int *p = VTKGeometry::VertexPermutation[geom];
11036  for (int k = 0; k < nv; k++, j++)
11037  {
11038  WriteBinaryOrASCII(os, buf, np + RG[p ? p[j] : j], " ",
11039  format);
11040  }
11041  if (format == VTKFormat::ASCII) { os << '\n'; }
11042  }
11043  np += RefG->RefPts.GetNPoints();
11044  }
11045  }
11046  if (format != VTKFormat::ASCII)
11047  {
11048  WriteBase64WithSizeAndClear(os, buf, compression_level);
11049  }
11050  os << "</DataArray>" << std::endl;
11051 
11052  os << "<DataArray type=\"Int32\" Name=\"offsets\" format=\""
11053  << fmt_str << "\">" << std::endl;
11054  // offsets
11055  for (size_t ii=0; ii<offset.size(); ii++)
11056  {
11057  WriteBinaryOrASCII(os, buf, offset[ii], "\n", format);
11058  }
11059  if (format != VTKFormat::ASCII)
11060  {
11061  WriteBase64WithSizeAndClear(os, buf, compression_level);
11062  }
11063  os << "</DataArray>" << std::endl;
11064  os << "<DataArray type=\"UInt8\" Name=\"types\" format=\""
11065  << fmt_str << "\">" << std::endl;
11066  // cell types
11067  const int *vtk_geom_map =
11068  high_order_output ? VTKGeometry::HighOrderMap : VTKGeometry::Map;
11069  for (int i = 0; i < ne; i++)
11070  {
11071  Geometry::Type geom = get_geom(i);
11072  uint8_t vtk_cell_type = 5;
11073 
11074  vtk_cell_type = vtk_geom_map[geom];
11075 
11076  if (high_order_output)
11077  {
11078  WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
11079  }
11080  else
11081  {
11082  int nv = Geometries.GetVertices(geom)->GetNPoints();
11083  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11084  Array<int> &RG = RefG->RefGeoms;
11085  for (int j = 0; j < RG.Size(); j += nv)
11086  {
11087  WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
11088  }
11089  }
11090  }
11091  if (format != VTKFormat::ASCII)
11092  {
11093  WriteBase64WithSizeAndClear(os, buf, compression_level);
11094  }
11095  os << "</DataArray>" << std::endl;
11096  os << "</Cells>" << std::endl;
11097 
11098  os << "<CellData Scalars=\"attribute\">" << std::endl;
11099  os << "<DataArray type=\"Int32\" Name=\"attribute\" format=\""
11100  << fmt_str << "\">" << std::endl;
11101  for (int i = 0; i < ne; i++)
11102  {
11103  int attr = bdr_elements ? GetBdrAttribute(i) : GetAttribute(i);
11104  if (high_order_output)
11105  {
11106  WriteBinaryOrASCII(os, buf, attr, "\n", format);
11107  }
11108  else
11109  {
11110  Geometry::Type geom = get_geom(i);
11111  int nv = Geometries.GetVertices(geom)->GetNPoints();
11112  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11113  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
11114  {
11115  WriteBinaryOrASCII(os, buf, attr, "\n", format);
11116  }
11117  }
11118  }
11119  if (format != VTKFormat::ASCII)
11120  {
11121  WriteBase64WithSizeAndClear(os, buf, compression_level);
11122  }
11123  os << "</DataArray>" << std::endl;
11124  os << "</CellData>" << std::endl;
11125 }
11126 
11127 
11128 void Mesh::PrintVTK(std::ostream &os, int ref, int field_data)
11129 {
11130  int np, nc, size;
11131  RefinedGeometry *RefG;
11132  DenseMatrix pmat;
11133 
11134  os <<
11135  "# vtk DataFile Version 3.0\n"
11136  "Generated by MFEM\n"
11137  "ASCII\n"
11138  "DATASET UNSTRUCTURED_GRID\n";
11139 
11140  // additional dataset information
11141  if (field_data)
11142  {
11143  os << "FIELD FieldData 1\n"
11144  << "MaterialIds " << 1 << " " << attributes.Size() << " int\n";
11145  for (int i = 0; i < attributes.Size(); i++)
11146  {
11147  os << ' ' << attributes[i];
11148  }
11149  os << '\n';
11150  }
11151 
11152  // count the points, cells, size
11153  np = nc = size = 0;
11154  for (int i = 0; i < GetNE(); i++)
11155  {
11157  int nv = Geometries.GetVertices(geom)->GetNPoints();
11158  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11159  np += RefG->RefPts.GetNPoints();
11160  nc += RefG->RefGeoms.Size() / nv;
11161  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
11162  }
11163  os << "POINTS " << np << " double\n";
11164  // write the points
11165  for (int i = 0; i < GetNE(); i++)
11166  {
11167  RefG = GlobGeometryRefiner.Refine(
11168  GetElementBaseGeometry(i), ref, 1);
11169 
11170  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
11171 
11172  for (int j = 0; j < pmat.Width(); j++)
11173  {
11174  os << pmat(0, j) << ' ';
11175  if (pmat.Height() > 1)
11176  {
11177  os << pmat(1, j) << ' ';
11178  if (pmat.Height() > 2)
11179  {
11180  os << pmat(2, j);
11181  }
11182  else
11183  {
11184  os << 0.0;
11185  }
11186  }
11187  else
11188  {
11189  os << 0.0 << ' ' << 0.0;
11190  }
11191  os << '\n';
11192  }
11193  }
11194 
11195  // write the cells
11196  os << "CELLS " << nc << ' ' << size << '\n';
11197  np = 0;
11198  for (int i = 0; i < GetNE(); i++)
11199  {
11201  int nv = Geometries.GetVertices(geom)->GetNPoints();
11202  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11203  Array<int> &RG = RefG->RefGeoms;
11204 
11205  for (int j = 0; j < RG.Size(); )
11206  {
11207  os << nv;
11208  for (int k = 0; k < nv; k++, j++)
11209  {
11210  os << ' ' << np + RG[j];
11211  }
11212  os << '\n';
11213  }
11214  np += RefG->RefPts.GetNPoints();
11215  }
11216  os << "CELL_TYPES " << nc << '\n';
11217  for (int i = 0; i < GetNE(); i++)
11218  {
11220  int nv = Geometries.GetVertices(geom)->GetNPoints();
11221  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11222  Array<int> &RG = RefG->RefGeoms;
11223  int vtk_cell_type = VTKGeometry::Map[geom];
11224 
11225  for (int j = 0; j < RG.Size(); j += nv)
11226  {
11227  os << vtk_cell_type << '\n';
11228  }
11229  }
11230  // write attributes (materials)
11231  os << "CELL_DATA " << nc << '\n'
11232  << "SCALARS material int\n"
11233  << "LOOKUP_TABLE default\n";
11234  for (int i = 0; i < GetNE(); i++)
11235  {
11237  int nv = Geometries.GetVertices(geom)->GetNPoints();
11238  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11239  int attr = GetAttribute(i);
11240  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
11241  {
11242  os << attr << '\n';
11243  }
11244  }
11245 
11246  if (Dim > 1)
11247  {
11248  Array<int> coloring;
11249  srand((unsigned)time(0));
11250  double a = double(rand()) / (double(RAND_MAX) + 1.);
11251  int el0 = (int)floor(a * GetNE());
11252  GetElementColoring(coloring, el0);
11253  os << "SCALARS element_coloring int\n"
11254  << "LOOKUP_TABLE default\n";
11255  for (int i = 0; i < GetNE(); i++)
11256  {
11258  int nv = Geometries.GetVertices(geom)->GetNPoints();
11259  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11260  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
11261  {
11262  os << coloring[i] + 1 << '\n';
11263  }
11264  }
11265  }
11266 
11267  // prepare to write data
11268  os << "POINT_DATA " << np << '\n' << flush;
11269 }
11270 
11271 void Mesh::GetElementColoring(Array<int> &colors, int el0)
11272 {
11273  int delete_el_to_el = (el_to_el) ? (0) : (1);
11274  const Table &el_el = ElementToElementTable();
11275  int num_el = GetNE(), stack_p, stack_top_p, max_num_col;
11276  Array<int> el_stack(num_el);
11277 
11278  const int *i_el_el = el_el.GetI();
11279  const int *j_el_el = el_el.GetJ();
11280 
11281  colors.SetSize(num_el);
11282  colors = -2;
11283  max_num_col = 1;
11284  stack_p = stack_top_p = 0;
11285  for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el)
11286  {
11287  if (colors[el] != -2)
11288  {
11289  continue;
11290  }
11291 
11292  colors[el] = -1;
11293  el_stack[stack_top_p++] = el;
11294 
11295  for ( ; stack_p < stack_top_p; stack_p++)
11296  {
11297  int i = el_stack[stack_p];
11298  int num_nb = i_el_el[i+1] - i_el_el[i];
11299  if (max_num_col < num_nb + 1)
11300  {
11301  max_num_col = num_nb + 1;
11302  }
11303  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
11304  {
11305  int k = j_el_el[j];
11306  if (colors[k] == -2)
11307  {
11308  colors[k] = -1;
11309  el_stack[stack_top_p++] = k;
11310  }
11311  }
11312  }
11313  }
11314 
11315  Array<int> col_marker(max_num_col);
11316 
11317  for (stack_p = 0; stack_p < stack_top_p; stack_p++)
11318  {
11319  int i = el_stack[stack_p], col;
11320  col_marker = 0;
11321  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
11322  {
11323  col = colors[j_el_el[j]];
11324  if (col != -1)
11325  {
11326  col_marker[col] = 1;
11327  }
11328  }
11329 
11330  for (col = 0; col < max_num_col; col++)
11331  if (col_marker[col] == 0)
11332  {
11333  break;
11334  }
11335 
11336  colors[i] = col;
11337  }
11338 
11339  if (delete_el_to_el)
11340  {
11341  delete el_to_el;
11342  el_to_el = NULL;
11343  }
11344 }
11345 
11346 void Mesh::PrintWithPartitioning(int *partitioning, std::ostream &os,
11347  int elem_attr) const
11348 {
11349  if (Dim != 3 && Dim != 2) { return; }
11350 
11351  int i, j, k, l, nv, nbe, *v;
11352 
11353  os << "MFEM mesh v1.0\n";
11354 
11355  // optional
11356  os <<
11357  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
11358  "# POINT = 0\n"
11359  "# SEGMENT = 1\n"
11360  "# TRIANGLE = 2\n"
11361  "# SQUARE = 3\n"
11362  "# TETRAHEDRON = 4\n"
11363  "# CUBE = 5\n"
11364  "# PRISM = 6\n"
11365  "#\n";
11366 
11367  os << "\ndimension\n" << Dim
11368  << "\n\nelements\n" << NumOfElements << '\n';
11369  for (i = 0; i < NumOfElements; i++)
11370  {
11371  os << int((elem_attr) ? partitioning[i]+1 : elements[i]->GetAttribute())
11372  << ' ' << elements[i]->GetGeometryType();
11373  nv = elements[i]->GetNVertices();
11374  v = elements[i]->GetVertices();
11375  for (j = 0; j < nv; j++)
11376  {
11377  os << ' ' << v[j];
11378  }
11379  os << '\n';
11380  }
11381  nbe = 0;
11382  for (i = 0; i < faces_info.Size(); i++)
11383  {
11384  if ((l = faces_info[i].Elem2No) >= 0)
11385  {
11386  k = partitioning[faces_info[i].Elem1No];
11387  l = partitioning[l];
11388  if (k != l)
11389  {
11390  nbe++;
11391  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
11392  {
11393  nbe++;
11394  }
11395  }
11396  }
11397  else
11398  {
11399  nbe++;
11400  }
11401  }
11402  os << "\nboundary\n" << nbe << '\n';
11403  for (i = 0; i < faces_info.Size(); i++)
11404  {
11405  if ((l = faces_info[i].Elem2No) >= 0)
11406  {
11407  k = partitioning[faces_info[i].Elem1No];
11408  l = partitioning[l];
11409  if (k != l)
11410  {
11411  nv = faces[i]->GetNVertices();
11412  v = faces[i]->GetVertices();
11413  os << k+1 << ' ' << faces[i]->GetGeometryType();
11414  for (j = 0; j < nv; j++)
11415  {
11416  os << ' ' << v[j];
11417  }
11418  os << '\n';
11419  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
11420  {
11421  os << l+1 << ' ' << faces[i]->GetGeometryType();
11422  for (j = nv-1; j >= 0; j--)
11423  {
11424  os << ' ' << v[j];
11425  }
11426  os << '\n';
11427  }
11428  }
11429  }
11430  else
11431  {
11432  k = partitioning[faces_info[i].Elem1No];
11433  nv = faces[i]->GetNVertices();
11434  v = faces[i]->GetVertices();
11435  os << k+1 << ' ' << faces[i]->GetGeometryType();
11436  for (j = 0; j < nv; j++)
11437  {
11438  os << ' ' << v[j];
11439  }
11440  os << '\n';
11441  }
11442  }
11443  os << "\nvertices\n" << NumOfVertices << '\n';
11444  if (Nodes == NULL)
11445  {
11446  os << spaceDim << '\n';
11447  for (i = 0; i < NumOfVertices; i++)
11448  {
11449  os << vertices[i](0);
11450  for (j = 1; j < spaceDim; j++)
11451  {
11452  os << ' ' << vertices[i](j);
11453  }
11454  os << '\n';
11455  }
11456  os.flush();
11457  }
11458  else
11459  {
11460  os << "\nnodes\n";
11461  Nodes->Save(os);
11462  }
11463 }
11464 
11466  std::ostream &os,
11467  int interior_faces)
11468 {
11469  MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported\n");
11470  if (Dim != 3 && Dim != 2) { return; }
11471 
11472  int *vcount = new int[NumOfVertices];
11473  for (int i = 0; i < NumOfVertices; i++)
11474  {
11475  vcount[i] = 0;
11476  }
11477  for (int i = 0; i < NumOfElements; i++)
11478  {
11479  int nv = elements[i]->GetNVertices();
11480  const int *ind = elements[i]->GetVertices();
11481  for (int j = 0; j < nv; j++)
11482  {
11483  vcount[ind[j]]++;
11484  }
11485  }
11486 
11487  int *voff = new int[NumOfVertices+1];
11488  voff[0] = 0;
11489  for (int i = 1; i <= NumOfVertices; i++)
11490  {
11491  voff[i] = vcount[i-1] + voff[i-1];
11492  }
11493 
11494  int **vown = new int*[NumOfVertices];
11495  for (int i = 0; i < NumOfVertices; i++)
11496  {
11497  vown[i] = new int[vcount[i]];
11498  }
11499 
11500  // 2D
11501  if (Dim == 2)
11502  {
11503  Table edge_el;
11504  Transpose(ElementToEdgeTable(), edge_el);
11505 
11506  // Fake printing of the elements.
11507  for (int i = 0; i < NumOfElements; i++)
11508  {
11509  int nv = elements[i]->GetNVertices();
11510  const int *ind = elements[i]->GetVertices();
11511  for (int j = 0; j < nv; j++)
11512  {
11513  vcount[ind[j]]--;
11514  vown[ind[j]][vcount[ind[j]]] = i;
11515  }
11516  }
11517 
11518  for (int i = 0; i < NumOfVertices; i++)
11519  {
11520  vcount[i] = voff[i+1] - voff[i];
11521  }
11522 
11523  int nbe = 0;
11524  for (int i = 0; i < edge_el.Size(); i++)
11525  {
11526  const int *el = edge_el.GetRow(i);
11527  if (edge_el.RowSize(i) > 1)
11528  {
11529  int k = partitioning[el[0]];
11530  int l = partitioning[el[1]];
11531  if (interior_faces || k != l)
11532  {
11533  nbe += 2;
11534  }
11535  }
11536  else
11537  {
11538  nbe++;
11539  }
11540  }
11541 
11542  // Print the type of the mesh and the boundary elements.
11543  os << "areamesh2\n\n" << nbe << '\n';
11544 
11545  for (int i = 0; i < edge_el.Size(); i++)
11546  {
11547  const int *el = edge_el.GetRow(i);
11548  if (edge_el.RowSize(i) > 1)
11549  {
11550  int k = partitioning[el[0]];
11551  int l = partitioning[el[1]];
11552  if (interior_faces || k != l)
11553  {
11554  Array<int> ev;
11555  GetEdgeVertices(i,ev);
11556  os << k+1; // attribute
11557  for (int j = 0; j < 2; j++)
11558  for (int s = 0; s < vcount[ev[j]]; s++)
11559  if (vown[ev[j]][s] == el[0])
11560  {
11561  os << ' ' << voff[ev[j]]+s+1;
11562  }
11563  os << '\n';
11564  os << l+1; // attribute
11565  for (int j = 1; j >= 0; j--)
11566  for (int s = 0; s < vcount[ev[j]]; s++)
11567  if (vown[ev[j]][s] == el[1])
11568  {
11569  os << ' ' << voff[ev[j]]+s+1;
11570  }
11571  os << '\n';
11572  }
11573  }
11574  else
11575  {
11576  int k = partitioning[el[0]];
11577  Array<int> ev;
11578  GetEdgeVertices(i,ev);
11579  os << k+1; // attribute
11580  for (int j = 0; j < 2; j++)
11581  for (int s = 0; s < vcount[ev[j]]; s++)
11582  if (vown[ev[j]][s] == el[0])
11583  {
11584  os << ' ' << voff[ev[j]]+s+1;
11585  }
11586  os << '\n';
11587  }
11588  }
11589 
11590  // Print the elements.
11591  os << NumOfElements << '\n';
11592  for (int i = 0; i < NumOfElements; i++)
11593  {
11594  int nv = elements[i]->GetNVertices();
11595  const int *ind = elements[i]->GetVertices();
11596  os << partitioning[i]+1 << ' '; // use subdomain number as attribute
11597  os << nv << ' ';
11598  for (int j = 0; j < nv; j++)
11599  {
11600  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11601  vown[ind[j]][vcount[ind[j]]] = i;
11602  }
11603  os << '\n';
11604  }
11605 
11606  for (int i = 0; i < NumOfVertices; i++)
11607  {
11608  vcount[i] = voff[i+1] - voff[i];
11609  }
11610 
11611  // Print the vertices.
11612  os << voff[NumOfVertices] << '\n';
11613  for (int i = 0; i < NumOfVertices; i++)
11614  for (int k = 0; k < vcount[i]; k++)
11615  {
11616  for (int j = 0; j < Dim; j++)
11617  {
11618  os << vertices[i](j) << ' ';
11619  }
11620  os << '\n';
11621  }
11622  }
11623  // Dim is 3
11624  else if (meshgen == 1)
11625  {
11626  os << "NETGEN_Neutral_Format\n";
11627  // print the vertices
11628  os << voff[NumOfVertices] << '\n';
11629  for (int i = 0; i < NumOfVertices; i++)
11630  for (int k = 0; k < vcount[i]; k++)
11631  {
11632  for (int j = 0; j < Dim; j++)
11633  {
11634  os << ' ' << vertices[i](j);
11635  }
11636  os << '\n';
11637  }
11638 
11639  // print the elements
11640  os << NumOfElements << '\n';
11641  for (int i = 0; i < NumOfElements; i++)
11642  {
11643  int nv = elements[i]->GetNVertices();
11644  const int *ind = elements[i]->GetVertices();
11645  os << partitioning[i]+1; // use subdomain number as attribute
11646  for (int j = 0; j < nv; j++)
11647  {
11648  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11649  vown[ind[j]][vcount[ind[j]]] = i;
11650  }
11651  os << '\n';
11652  }
11653 
11654  for (int i = 0; i < NumOfVertices; i++)
11655  {
11656  vcount[i] = voff[i+1] - voff[i];
11657  }
11658 
11659  // print the boundary information.
11660  int nbe = 0;
11661  for (int i = 0; i < NumOfFaces; i++)
11662  {
11663  int l = faces_info[i].Elem2No;
11664  if (l >= 0)
11665  {
11666  int k = partitioning[faces_info[i].Elem1No];
11667  l = partitioning[l];
11668  if (interior_faces || k != l)
11669  {
11670  nbe += 2;
11671  }
11672  }
11673  else
11674  {
11675  nbe++;
11676  }
11677  }
11678 
11679  os << nbe << '\n';
11680  for (int i = 0; i < NumOfFaces; i++)
11681  {
11682  int l = faces_info[i].Elem2No;
11683  if (l >= 0)
11684  {
11685  int k = partitioning[faces_info[i].Elem1No];
11686  l = partitioning[l];
11687  if (interior_faces || k != l)
11688  {
11689  int nv = faces[i]->GetNVertices();
11690  const int *ind = faces[i]->GetVertices();
11691  os << k+1; // attribute
11692  for (int j = 0; j < nv; j++)
11693  for (int s = 0; s < vcount[ind[j]]; s++)
11694  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11695  {
11696  os << ' ' << voff[ind[j]]+s+1;
11697  }
11698  os << '\n';
11699  os << l+1; // attribute
11700  for (int j = nv-1; j >= 0; j--)
11701  for (int s = 0; s < vcount[ind[j]]; s++)
11702  if (vown[ind[j]][s] == faces_info[i].Elem2No)
11703  {
11704  os << ' ' << voff[ind[j]]+s+1;
11705  }
11706  os << '\n';
11707  }
11708  }
11709  else
11710  {
11711  int k = partitioning[faces_info[i].Elem1No];
11712  int nv = faces[i]->GetNVertices();
11713  const int *ind = faces[i]->GetVertices();
11714  os << k+1; // attribute
11715  for (int j = 0; j < nv; j++)
11716  for (int s = 0; s < vcount[ind[j]]; s++)
11717  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11718  {
11719  os << ' ' << voff[ind[j]]+s+1;
11720  }
11721  os << '\n';
11722  }
11723  }
11724  }
11725  // Dim is 3
11726  else if (meshgen == 2) // TrueGrid
11727  {
11728  // count the number of the boundary elements.
11729  int nbe = 0;
11730  for (int i = 0; i < NumOfFaces; i++)
11731  {
11732  int l = faces_info[i].Elem2No;
11733  if (l >= 0)
11734  {
11735  int k = partitioning[faces_info[i].Elem1No];
11736  l = partitioning[l];
11737  if (interior_faces || k != l)
11738  {
11739  nbe += 2;
11740  }
11741  }
11742  else
11743  {
11744  nbe++;
11745  }
11746  }
11747 
11748  os << "TrueGrid\n"
11749  << "1 " << voff[NumOfVertices] << " " << NumOfElements
11750  << " 0 0 0 0 0 0 0\n"
11751  << "0 0 0 1 0 0 0 0 0 0 0\n"
11752  << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
11753  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
11754  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
11755 
11756  for (int i = 0; i < NumOfVertices; i++)
11757  for (int k = 0; k < vcount[i]; k++)
11758  os << voff[i]+k << " 0.0 " << vertices[i](0) << ' '
11759  << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n";
11760 
11761  for (int i = 0; i < NumOfElements; i++)
11762  {
11763  int nv = elements[i]->GetNVertices();
11764  const int *ind = elements[i]->GetVertices();
11765  os << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute
11766  for (int j = 0; j < nv; j++)
11767  {
11768  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11769  vown[ind[j]][vcount[ind[j]]] = i;
11770  }
11771  os << '\n';
11772  }
11773 
11774  for (int i = 0; i < NumOfVertices; i++)
11775  {
11776  vcount[i] = voff[i+1] - voff[i];
11777  }
11778 
11779  // boundary elements
11780  for (int i = 0; i < NumOfFaces; i++)
11781  {
11782  int l = faces_info[i].Elem2No;
11783  if (l >= 0)
11784  {
11785  int k = partitioning[faces_info[i].Elem1No];
11786  l = partitioning[l];
11787  if (interior_faces || k != l)
11788  {
11789  int nv = faces[i]->GetNVertices();
11790  const int *ind = faces[i]->GetVertices();
11791  os << k+1; // attribute
11792  for (int j = 0; j < nv; j++)
11793  for (int s = 0; s < vcount[ind[j]]; s++)
11794  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11795  {
11796  os << ' ' << voff[ind[j]]+s+1;
11797  }
11798  os << " 1.0 1.0 1.0 1.0\n";
11799  os << l+1; // attribute
11800  for (int j = nv-1; j >= 0; j--)
11801  for (int s = 0; s < vcount[ind[j]]; s++)
11802  if (vown[ind[j]][s] == faces_info[i].Elem2No)
11803  {
11804  os << ' ' << voff[ind[j]]+s+1;
11805  }
11806  os << " 1.0 1.0 1.0 1.0\n";
11807  }
11808  }
11809  else
11810  {
11811  int k = partitioning[faces_info[i].Elem1No];
11812  int nv = faces[i]->GetNVertices();
11813  const int *ind = faces[i]->GetVertices();
11814  os << k+1; // attribute
11815  for (int j = 0; j < nv; j++)
11816  for (int s = 0; s < vcount[ind[j]]; s++)
11817  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11818  {
11819  os << ' ' << voff[ind[j]]+s+1;
11820  }
11821  os << " 1.0 1.0 1.0 1.0\n";
11822  }
11823  }
11824  }
11825 
11826  os << flush;
11827 
11828  for (int i = 0; i < NumOfVertices; i++)
11829  {
11830  delete [] vown[i];
11831  }
11832 
11833  delete [] vcount;
11834  delete [] voff;
11835  delete [] vown;
11836 }
11837 
11838 void Mesh::PrintSurfaces(const Table & Aface_face, std::ostream &os) const
11839 {
11840  int i, j;
11841 
11842  if (NURBSext)
11843  {
11844  mfem_error("Mesh::PrintSurfaces"
11845  " NURBS mesh is not supported!");
11846  return;
11847  }
11848 
11849  os << "MFEM mesh v1.0\n";
11850 
11851  // optional
11852  os <<
11853  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
11854  "# POINT = 0\n"
11855  "# SEGMENT = 1\n"
11856  "# TRIANGLE = 2\n"
11857  "# SQUARE = 3\n"
11858  "# TETRAHEDRON = 4\n"
11859  "# CUBE = 5\n"
11860  "# PRISM = 6\n"
11861  "#\n";
11862 
11863  os << "\ndimension\n" << Dim
11864  << "\n\nelements\n" << NumOfElements << '\n';
11865  for (i = 0; i < NumOfElements; i++)
11866  {
11867  PrintElement(elements[i], os);
11868  }
11869 
11870  os << "\nboundary\n" << Aface_face.Size_of_connections() << '\n';
11871  const int * const i_AF_f = Aface_face.GetI();
11872  const int * const j_AF_f = Aface_face.GetJ();
11873 
11874  for (int iAF=0; iAF < Aface_face.Size(); ++iAF)
11875  for (const int * iface = j_AF_f + i_AF_f[iAF];
11876  iface < j_AF_f + i_AF_f[iAF+1];
11877  ++iface)
11878  {
11879  os << iAF+1 << ' ';
11880  PrintElementWithoutAttr(faces[*iface],os);
11881  }
11882 
11883  os << "\nvertices\n" << NumOfVertices << '\n';
11884  if (Nodes == NULL)
11885  {
11886  os << spaceDim << '\n';
11887  for (i = 0; i < NumOfVertices; i++)
11888  {
11889  os << vertices[i](0);
11890  for (j = 1; j < spaceDim; j++)
11891  {
11892  os << ' ' << vertices[i](j);
11893  }
11894  os << '\n';
11895  }
11896  os.flush();
11897  }
11898  else
11899  {
11900  os << "\nnodes\n";
11901  Nodes->Save(os);
11902  }
11903 }
11904 
11905 void Mesh::ScaleSubdomains(double sf)
11906 {
11907  int i,j,k;
11908  Array<int> vert;
11909  DenseMatrix pointmat;
11910  int na = attributes.Size();
11911  double *cg = new double[na*spaceDim];
11912  int *nbea = new int[na];
11913 
11914  int *vn = new int[NumOfVertices];
11915  for (i = 0; i < NumOfVertices; i++)
11916  {
11917  vn[i] = 0;
11918  }
11919  for (i = 0; i < na; i++)
11920  {
11921  for (j = 0; j < spaceDim; j++)
11922  {
11923  cg[i*spaceDim+j] = 0.0;
11924  }
11925  nbea[i] = 0;
11926  }
11927 
11928  for (i = 0; i < NumOfElements; i++)
11929  {
11930  GetElementVertices(i, vert);
11931  for (k = 0; k < vert.Size(); k++)
11932  {
11933  vn[vert[k]] = 1;
11934  }
11935  }
11936 
11937  for (i = 0; i < NumOfElements; i++)
11938  {
11939  int bea = GetAttribute(i)-1;
11940  GetPointMatrix(i, pointmat);
11941  GetElementVertices(i, vert);
11942 
11943  for (k = 0; k < vert.Size(); k++)
11944  if (vn[vert[k]] == 1)
11945  {
11946  nbea[bea]++;
11947  for (j = 0; j < spaceDim; j++)
11948  {
11949  cg[bea*spaceDim+j] += pointmat(j,k);
11950  }
11951  vn[vert[k]] = 2;
11952  }
11953  }
11954 
11955  for (i = 0; i < NumOfElements; i++)
11956  {
11957  int bea = GetAttribute(i)-1;
11958  GetElementVertices (i, vert);
11959 
11960  for (k = 0; k < vert.Size(); k++)
11961  if (vn[vert[k]])
11962  {
11963  for (j = 0; j < spaceDim; j++)
11964  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
11965  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
11966  vn[vert[k]] = 0;
11967  }
11968  }
11969 
11970  delete [] cg;
11971  delete [] nbea;
11972  delete [] vn;
11973 }
11974 
11975 void Mesh::ScaleElements(double sf)
11976 {
11977  int i,j,k;
11978  Array<int> vert;
11979  DenseMatrix pointmat;
11980  int na = NumOfElements;
11981  double *cg = new double[na*spaceDim];
11982  int *nbea = new int[na];
11983 
11984  int *vn = new int[NumOfVertices];
11985  for (i = 0; i < NumOfVertices; i++)
11986  {
11987  vn[i] = 0;
11988  }
11989  for (i = 0; i < na; i++)
11990  {
11991  for (j = 0; j < spaceDim; j++)
11992  {
11993  cg[i*spaceDim+j] = 0.0;
11994  }
11995  nbea[i] = 0;
11996  }
11997 
11998  for (i = 0; i < NumOfElements; i++)
11999  {
12000  GetElementVertices(i, vert);
12001  for (k = 0; k < vert.Size(); k++)
12002  {
12003  vn[vert[k]] = 1;
12004  }
12005  }
12006 
12007  for (i = 0; i < NumOfElements; i++)
12008  {
12009  int bea = i;
12010  GetPointMatrix(i, pointmat);
12011  GetElementVertices(i, vert);
12012 
12013  for (k = 0; k < vert.Size(); k++)
12014  if (vn[vert[k]] == 1)
12015  {
12016  nbea[bea]++;
12017  for (j = 0; j < spaceDim; j++)
12018  {
12019  cg[bea*spaceDim+j] += pointmat(j,k);
12020  }
12021  vn[vert[k]] = 2;
12022  }
12023  }
12024 
12025  for (i = 0; i < NumOfElements; i++)
12026  {
12027  int bea = i;
12028  GetElementVertices(i, vert);
12029 
12030  for (k = 0; k < vert.Size(); k++)
12031  if (vn[vert[k]])
12032  {
12033  for (j = 0; j < spaceDim; j++)
12034  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
12035  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
12036  vn[vert[k]] = 0;
12037  }
12038  }
12039 
12040  delete [] cg;
12041  delete [] nbea;
12042  delete [] vn;
12043 }
12044 
12045 void Mesh::Transform(void (*f)(const Vector&, Vector&))
12046 {
12047  // TODO: support for different new spaceDim.
12048  if (Nodes == NULL)
12049  {
12050  Vector vold(spaceDim), vnew(NULL, spaceDim);
12051  for (int i = 0; i < vertices.Size(); i++)
12052  {
12053  for (int j = 0; j < spaceDim; j++)
12054  {
12055  vold(j) = vertices[i](j);
12056  }
12057  vnew.SetData(vertices[i]());
12058  (*f)(vold, vnew);
12059  }
12060  }
12061  else
12062  {
12063  GridFunction xnew(Nodes->FESpace());
12065  xnew.ProjectCoefficient(f_pert);
12066  *Nodes = xnew;
12067  }
12068  NodesUpdated();
12069 }
12070 
12072 {
12073  MFEM_VERIFY(spaceDim == deformation.GetVDim(),
12074  "incompatible vector dimensions");
12075  if (Nodes == NULL)
12076  {
12077  LinearFECollection fec;
12078  FiniteElementSpace fes(this, &fec, spaceDim, Ordering::byVDIM);
12079  GridFunction xnew(&fes);
12080  xnew.ProjectCoefficient(deformation);
12081  for (int i = 0; i < NumOfVertices; i++)
12082  for (int d = 0; d < spaceDim; d++)
12083  {
12084  vertices[i](d) = xnew(d + spaceDim*i);
12085  }
12086  }
12087  else
12088  {
12089  GridFunction xnew(Nodes->FESpace());
12090  xnew.ProjectCoefficient(deformation);
12091  *Nodes = xnew;
12092  }
12093  NodesUpdated();
12094 }
12095 
12097 {
12098  if (NURBSext || ncmesh) { return; }
12099 
12100  Array<int> v2v(GetNV());
12101  v2v = -1;
12102  for (int i = 0; i < GetNE(); i++)
12103  {
12104  Element *el = GetElement(i);
12105  int nv = el->GetNVertices();
12106  int *v = el->GetVertices();
12107  for (int j = 0; j < nv; j++)
12108  {
12109  v2v[v[j]] = 0;
12110  }
12111  }
12112  for (int i = 0; i < GetNBE(); i++)
12113  {
12114  Element *el = GetBdrElement(i);
12115  int *v = el->GetVertices();
12116  int nv = el->GetNVertices();
12117  for (int j = 0; j < nv; j++)
12118  {
12119  v2v[v[j]] = 0;
12120  }
12121  }
12122  int num_vert = 0;
12123  for (int i = 0; i < v2v.Size(); i++)
12124  {
12125  if (v2v[i] == 0)
12126  {
12127  vertices[num_vert] = vertices[i];
12128  v2v[i] = num_vert++;
12129  }
12130  }
12131 
12132  if (num_vert == v2v.Size()) { return; }
12133 
12134  Vector nodes_by_element;
12135  Array<int> vdofs;
12136  if (Nodes)
12137  {
12138  int s = 0;
12139  for (int i = 0; i < GetNE(); i++)
12140  {
12141  Nodes->FESpace()->GetElementVDofs(i, vdofs);
12142  s += vdofs.Size();
12143  }
12144  nodes_by_element.SetSize(s);
12145  s = 0;
12146  for (int i = 0; i < GetNE(); i++)
12147  {
12148  Nodes->FESpace()->GetElementVDofs(i, vdofs);
12149  Nodes->GetSubVector(vdofs, &nodes_by_element(s));
12150  s += vdofs.Size();
12151  }
12152  }
12153  vertices.SetSize(num_vert);
12154  NumOfVertices = num_vert;
12155  for (int i = 0; i < GetNE(); i++)
12156  {
12157  Element *el = GetElement(i);
12158  int *v = el->GetVertices();
12159  int nv = el->GetNVertices();
12160  for (int j = 0; j < nv; j++)
12161  {
12162  v[j] = v2v[v[j]];
12163  }
12164  }
12165  for (int i = 0; i < GetNBE(); i++)
12166  {
12167  Element *el = GetBdrElement(i);
12168  int *v = el->GetVertices();
12169  int nv = el->GetNVertices();
12170  for (int j = 0; j < nv; j++)
12171  {
12172  v[j] = v2v[v[j]];
12173  }
12174  }
12175  DeleteTables();
12176  if (Dim > 1)
12177  {
12178  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
12179  el_to_edge = new Table;
12181  }
12182  if (Dim > 2)
12183  {
12184  // generate el_to_face, be_to_face
12186  }
12187  // Update faces and faces_info
12188  GenerateFaces();
12189  if (Nodes)
12190  {
12191  Nodes->FESpace()->Update();
12192  Nodes->Update();
12193  int s = 0;
12194  for (int i = 0; i < GetNE(); i++)
12195  {
12196  Nodes->FESpace()->GetElementVDofs(i, vdofs);
12197  Nodes->SetSubVector(vdofs, &nodes_by_element(s));
12198  s += vdofs.Size();
12199  }
12200  }
12201 }
12202 
12204 {
12205  if (NURBSext || ncmesh) { return; }
12206 
12207  int num_bdr_elem = 0;
12208  int new_bel_to_edge_nnz = 0;
12209  for (int i = 0; i < GetNBE(); i++)
12210  {
12212  {
12213  FreeElement(boundary[i]);
12214  }
12215  else
12216  {
12217  num_bdr_elem++;
12218  if (Dim == 3)
12219  {
12220  new_bel_to_edge_nnz += bel_to_edge->RowSize(i);
12221  }
12222  }
12223  }
12224 
12225  if (num_bdr_elem == GetNBE()) { return; }
12226 
12227  Array<Element *> new_boundary(num_bdr_elem);
12228  Array<int> new_be_to_edge, new_be_to_face;
12229  Table *new_bel_to_edge = NULL;
12230  new_boundary.SetSize(0);
12231  if (Dim == 2)
12232  {
12233  new_be_to_edge.Reserve(num_bdr_elem);
12234  }
12235  else if (Dim == 3)
12236  {
12237  new_be_to_face.Reserve(num_bdr_elem);
12238  new_bel_to_edge = new Table;
12239  new_bel_to_edge->SetDims(num_bdr_elem, new_bel_to_edge_nnz);
12240  }
12241  for (int i = 0; i < GetNBE(); i++)
12242  {
12244  {
12245  new_boundary.Append(boundary[i]);
12246  if (Dim == 2)
12247  {
12248  new_be_to_edge.Append(be_to_edge[i]);
12249  }
12250  else if (Dim == 3)
12251  {
12252  int row = new_be_to_face.Size();
12253  new_be_to_face.Append(be_to_face[i]);
12254  int *e = bel_to_edge->GetRow(i);
12255  int ne = bel_to_edge->RowSize(i);
12256  int *new_e = new_bel_to_edge->GetRow(row);
12257  for (int j = 0; j < ne; j++)
12258  {
12259  new_e[j] = e[j];
12260  }
12261  new_bel_to_edge->GetI()[row+1] = new_bel_to_edge->GetI()[row] + ne;
12262  }
12263  }
12264  }
12265 
12266  NumOfBdrElements = new_boundary.Size();
12267  mfem::Swap(boundary, new_boundary);
12268 
12269  if (Dim == 2)
12270  {
12271  mfem::Swap(be_to_edge, new_be_to_edge);
12272  }
12273  else if (Dim == 3)
12274  {
12275  mfem::Swap(be_to_face, new_be_to_face);
12276  delete bel_to_edge;
12277  bel_to_edge = new_bel_to_edge;
12278  }
12279 
12280  Array<int> attribs(num_bdr_elem);
12281  for (int i = 0; i < attribs.Size(); i++)
12282  {
12283  attribs[i] = GetBdrAttribute(i);
12284  }
12285  attribs.Sort();
12286  attribs.Unique();
12288  attribs.Copy(bdr_attributes);
12289 }
12290 
12292 {
12293 #ifdef MFEM_USE_MEMALLOC
12294  if (E)
12295  {
12296  if (E->GetType() == Element::TETRAHEDRON)
12297  {
12298  TetMemory.Free((Tetrahedron*) E);
12299  }
12300  else
12301  {
12302  delete E;
12303  }
12304  }
12305 #else
12306  delete E;
12307 #endif
12308 }
12309 
12310 std::ostream &operator<<(std::ostream &os, const Mesh &mesh)
12311 {
12312  mesh.Print(os);
12313  return os;
12314 }
12315 
12316 int Mesh::FindPoints(DenseMatrix &point_mat, Array<int>& elem_ids,
12317  Array<IntegrationPoint>& ips, bool warn,
12318  InverseElementTransformation *inv_trans)
12319 {
12320  const int npts = point_mat.Width();
12321  if (!npts) { return 0; }
12322  MFEM_VERIFY(point_mat.Height() == spaceDim,"Invalid points matrix");
12323  elem_ids.SetSize(npts);
12324  ips.SetSize(npts);
12325  elem_ids = -1;
12326  if (!GetNE()) { return 0; }
12327 
12328  double *data = point_mat.GetData();
12329  InverseElementTransformation *inv_tr = inv_trans;
12330  inv_tr = inv_tr ? inv_tr : new InverseElementTransformation;
12331 
12332  // For each point in 'point_mat', find the element whose center is closest.
12333  Vector min_dist(npts);
12334  Array<int> e_idx(npts);
12335  min_dist = std::numeric_limits<double>::max();
12336  e_idx = -1;
12337 
12338  Vector pt(spaceDim);
12339  for (int i = 0; i < GetNE(); i++)
12340  {
12341  GetElementTransformation(i)->Transform(
12343  for (int k = 0; k < npts; k++)
12344  {
12345  double dist = pt.DistanceTo(data+k*spaceDim);
12346  if (dist < min_dist(k))
12347  {
12348  min_dist(k) = dist;
12349  e_idx[k] = i;
12350  }
12351  }
12352  }
12353 
12354  // Checks if the points lie in the closest element
12355  int pts_found = 0;
12356  pt.NewDataAndSize(NULL, spaceDim);
12357  for (int k = 0; k < npts; k++)
12358  {
12359  pt.SetData(data+k*spaceDim);
12360  inv_tr->SetTransformation(*GetElementTransformation(e_idx[k]));
12361  int res = inv_tr->Transform(pt, ips[k]);
12363  {
12364  elem_ids[k] = e_idx[k];
12365  pts_found++;
12366  }
12367  }
12368  if (pts_found != npts)
12369  {
12370  Array<int> elvertices;
12371  Table *vtoel = GetVertexToElementTable();
12372  for (int k = 0; k < npts; k++)
12373  {
12374  if (elem_ids[k] != -1) { continue; }
12375  // Try all vertex-neighbors of element e_idx[k]
12376  pt.SetData(data+k*spaceDim);
12377  GetElementVertices(e_idx[k], elvertices);
12378  for (int v = 0; v < elvertices.Size(); v++)
12379  {
12380  int vv = elvertices[v];
12381  int ne = vtoel->RowSize(vv);
12382  const int* els = vtoel->GetRow(vv);
12383  for (int e = 0; e < ne; e++)
12384  {
12385  if (els[e] == e_idx[k]) { continue; }
12386  inv_tr->SetTransformation(*GetElementTransformation(els[e]));
12387  int res = inv_tr->Transform(pt, ips[k]);
12389  {
12390  elem_ids[k] = els[e];
12391  pts_found++;
12392  goto next_point;
12393  }
12394  }
12395  }
12396  // Try neighbors for non-conforming meshes
12397  if (ncmesh)
12398  {
12399  Array<int> neigh;
12400  int le = ncmesh->leaf_elements[e_idx[k]];
12401  ncmesh->FindNeighbors(le,neigh);
12402  for (int e = 0; e < neigh.Size(); e++)
12403  {
12404  int nn = neigh[e];
12405  if (ncmesh->IsGhost(ncmesh->elements[nn])) { continue; }
12406  int el = ncmesh->elements[nn].index;
12408  int res = inv_tr->Transform(pt, ips[k]);
12410  {
12411  elem_ids[k] = el;
12412  pts_found++;
12413  goto next_point;
12414  }
12415  }
12416  }
12417  next_point: ;
12418  }
12419  delete vtoel;
12420  }
12421  if (inv_trans == NULL) { delete inv_tr; }
12422 
12423  if (warn && pts_found != npts)
12424  {
12425  MFEM_WARNING((npts-pts_found) << " points were not found");
12426  }
12427  return pts_found;
12428 }
12429 
12431  double &volume,
12432  Vector &aspr,
12433  Vector &skew,
12434  Vector &ori) const
12435 {
12436  J.HostRead();
12437  aspr.HostWrite();
12438  skew.HostWrite();
12439  ori.HostWrite();
12440  MFEM_VERIFY(Dim == 2 || Dim == 3, "Only 2D/3D meshes supported right now.");
12441  MFEM_VERIFY(Dim == spaceDim, "Surface meshes not currently supported.");
12442  if (Dim == 2)
12443  {
12444  aspr.SetSize(1);
12445  skew.SetSize(1);
12446  ori.SetSize(1);
12447  Vector col1, col2;
12448  J.GetColumn(0, col1);
12449  J.GetColumn(1, col2);
12450 
12451  // Area/Volume
12452  volume = J.Det();
12453 
12454  // Aspect-ratio
12455  aspr(0) = col2.Norml2()/col1.Norml2();
12456 
12457  // Skewness
12458  skew(0) = std::atan2(J.Det(), col1 * col2);
12459 
12460  // Orientation
12461  ori(0) = std::atan2(J(1,0), J(0,0));
12462  }
12463  else if (Dim == 3)
12464  {
12465  aspr.SetSize(4);
12466  skew.SetSize(3);
12467  ori.SetSize(4);
12468  Vector col1, col2, col3;
12469  J.GetColumn(0, col1);
12470  J.GetColumn(1, col2);
12471  J.GetColumn(2, col3);
12472  double len1 = col1.Norml2(),
12473  len2 = col2.Norml2(),
12474  len3 = col3.Norml2();
12475 
12476  Vector col1unit = col1,
12477  col2unit = col2,
12478  col3unit = col3;
12479  col1unit *= 1.0/len1;
12480  col2unit *= 1.0/len2;
12481  col3unit *= 1.0/len3;
12482 
12483  // Area/Volume
12484  volume = J.Det();
12485 
12486  // Aspect-ratio - non-dimensional
12487  aspr(0) = len1/std::sqrt(len2*len3),
12488  aspr(1) = len2/std::sqrt(len1*len3);
12489 
12490  // Aspect-ratio - dimensional - needed for TMOP
12491  aspr(2) = std::sqrt(len1/(len2*len3)),
12492  aspr(3) = std::sqrt(len2/(len1*len3));
12493 
12494  // Skewness
12495  Vector crosscol12, crosscol13;
12496  col1.cross3D(col2, crosscol12);
12497  col1.cross3D(col3, crosscol13);
12498  skew(0) = std::acos(col1unit*col2unit);
12499  skew(1) = std::acos(col1unit*col3unit);
12500  skew(2) = std::atan(len1*volume/(crosscol12*crosscol13));
12501 
12502  // Orientation
12503  // First we define the rotation matrix
12504  DenseMatrix rot(Dim);
12505  // First column
12506  for (int d=0; d<Dim; d++) { rot(d, 0) = col1unit(d); }
12507  // Second column
12508  Vector rot2 = col2unit;
12509  Vector rot1 = col1unit;
12510  rot1 *= col1unit*col2unit;
12511  rot2 -= rot1;
12512  col1unit.cross3D(col2unit, rot1);
12513  rot2 /= rot1.Norml2();
12514  for (int d=0; d < Dim; d++) { rot(d, 1) = rot2(d); }
12515  // Third column
12516  rot1 /= rot1.Norml2();
12517  for (int d=0; d < Dim; d++) { rot(d, 2) = rot1(d); }
12518  double delta = sqrt(pow(rot(2,1)-rot(1,2), 2.0) +
12519  pow(rot(0,2)-rot(2,0), 2.0) +
12520  pow(rot(1,0)-rot(0,1), 2.0));
12521  ori = 0.0;
12522  if (delta == 0.0) // Matrix is symmetric. Check if it is Identity.
12523  {
12524  DenseMatrix Iden(Dim);
12525  for (int d = 0; d < Dim; d++) { Iden(d, d) = 1.0; };
12526  Iden -= rot;
12527  if (Iden.FNorm2() != 0)
12528  {
12529  // TODO: Handling of these cases.
12530  rot.Print();
12531  MFEM_ABORT("Invalid rotation matrix. Contact TMOP Developers.");
12532  }
12533  }
12534  else
12535  {
12536  ori(0) = (1./delta)*(rot(2,1)-rot(1,2));
12537  ori(1) = (1./delta)*(rot(0,2)-rot(2,0));
12538  ori(2) = (1./delta)*(rot(1,0)-rot(0,1));
12539  ori(3) = std::acos(0.5*(rot.Trace()-1.0));
12540  }
12541  }
12542 }
12543 
12544 
12546  int flags, MemoryType d_mt)
12547 {
12548  this->mesh = mesh;
12549  IntRule = &ir;
12550  computed_factors = flags;
12551 
12552  MFEM_ASSERT(mesh->GetNumGeometries(mesh->Dimension()) <= 1,
12553  "mixed meshes are not supported!");
12554  MFEM_ASSERT(mesh->GetNodes(), "meshes without nodes are not supported!");
12555 
12556  Compute(*mesh->GetNodes(), d_mt);
12557 }
12558 
12560  const IntegrationRule &ir,
12561  int flags, MemoryType d_mt)
12562 {
12563  this->mesh = nodes.FESpace()->GetMesh();
12564  IntRule = &ir;
12565  computed_factors = flags;
12566 
12567  Compute(nodes, d_mt);
12568 }
12569 
12570 void GeometricFactors::Compute(const GridFunction &nodes,
12571  MemoryType d_mt)
12572 {
12573 
12574  const FiniteElementSpace *fespace = nodes.FESpace();
12575  const FiniteElement *fe = fespace->GetFE(0);
12576  const int dim = fe->GetDim();
12577  const int vdim = fespace->GetVDim();
12578  const int NE = fespace->GetNE();
12579  const int ND = fe->GetDof();
12580  const int NQ = IntRule->GetNPoints();
12581 
12582  unsigned eval_flags = 0;
12583  MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
12586  {
12587  X.SetSize(vdim*NQ*NE, my_d_mt); // NQ x SDIM x NE
12588  eval_flags |= QuadratureInterpolator::VALUES;
12589  }
12591  {
12592  J.SetSize(dim*vdim*NQ*NE, my_d_mt); // NQ x SDIM x DIM x NE
12594  }
12596  {
12597  detJ.SetSize(NQ*NE, my_d_mt); // NQ x NE
12599  }
12600 
12601  const QuadratureInterpolator *qi = fespace->GetQuadratureInterpolator(*IntRule);
12602  // All X, J, and detJ use this layout:
12604 
12605  const bool use_tensor_products = UsesTensorBasis(*fespace);
12606 
12607  qi->DisableTensorProducts(!use_tensor_products);
12608  const ElementDofOrdering e_ordering = use_tensor_products ?
12611  const Operator *elem_restr = fespace->GetElementRestriction(e_ordering);
12612 
12613  if (elem_restr) // Always true as of 2021-04-27
12614  {
12615  Vector Enodes(vdim*ND*NE, my_d_mt);
12616  elem_restr->Mult(nodes, Enodes);
12617  qi->Mult(Enodes, eval_flags, X, J, detJ);
12618  }
12619  else
12620  {
12621  qi->Mult(nodes, eval_flags, X, J, detJ);
12622  }
12623 }
12624 
12626  const IntegrationRule &ir,
12627  int flags, FaceType type,
12628  MemoryType d_mt)
12629  : type(type)
12630 {
12631  this->mesh = mesh;
12632  IntRule = &ir;
12633  computed_factors = flags;
12634 
12635  const GridFunction *nodes = mesh->GetNodes();
12636  const FiniteElementSpace *fespace = nodes->FESpace();
12637  const int vdim = fespace->GetVDim();
12638  const int NF = fespace->GetNFbyType(type);
12639  const int NQ = ir.GetNPoints();
12640 
12641  const FaceRestriction *face_restr = fespace->GetFaceRestriction(
12643  type,
12645 
12646 
12647  MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
12649 
12650  Vector Fnodes(face_restr->Height(), my_d_mt);
12651  face_restr->Mult(*nodes, Fnodes);
12652 
12653  unsigned eval_flags = 0;
12654 
12656  {
12657  X.SetSize(vdim*NQ*NF, my_d_mt);
12658  eval_flags |= FaceQuadratureInterpolator::VALUES;
12659  }
12660  if (flags & FaceGeometricFactors::JACOBIANS)
12661  {
12662  J.SetSize(vdim*vdim*NQ*NF, my_d_mt);
12664  }
12666  {
12667  detJ.SetSize(NQ*NF, my_d_mt);
12669  }
12670  if (flags & FaceGeometricFactors::NORMALS)
12671  {
12672  normal.SetSize(vdim*NQ*NF, my_d_mt);
12674  }
12675 
12676  const FaceQuadratureInterpolator *qi =
12677  fespace->GetFaceQuadratureInterpolator(ir, type);
12678  // All face data vectors assume layout byNODES.
12680  const bool use_tensor_products = UsesTensorBasis(*fespace);
12681  qi->DisableTensorProducts(!use_tensor_products);
12682 
12683  qi->Mult(Fnodes, eval_flags, X, J, detJ, normal);
12684 }
12685 
12687  const double s_)
12688  : VectorCoefficient(dim), n(n_), s(s_), tip(p, dim-1)
12689 {
12690 }
12691 
12693  const IntegrationPoint &ip)
12694 {
12695  V.SetSize(vdim);
12696  T.Transform(ip, tip);
12697  V(0) = p[0];
12698  if (vdim == 2)
12699  {
12700  V(1) = s * ((ip.y + layer) / n);
12701  }
12702  else
12703  {
12704  V(1) = p[1];
12705  V(2) = s * ((ip.z + layer) / n);
12706  }
12707 }
12708 
12709 
12710 Mesh *Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
12711 {
12712  if (mesh->Dimension() != 1)
12713  {
12714  mfem::err << "Extrude1D : Not a 1D mesh!" << endl;
12715  mfem_error();
12716  }
12717 
12718  int nvy = (closed) ? (ny) : (ny + 1);
12719  int nvt = mesh->GetNV() * nvy;
12720 
12721  Mesh *mesh2d;
12722 
12723  if (closed)
12724  {
12725  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny, mesh->GetNBE()*ny);
12726  }
12727  else
12728  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny,
12729  mesh->GetNBE()*ny+2*mesh->GetNE());
12730 
12731  // vertices
12732  double vc[2];
12733  for (int i = 0; i < mesh->GetNV(); i++)
12734  {
12735  vc[0] = mesh->GetVertex(i)[0];
12736  for (int j = 0; j < nvy; j++)
12737  {
12738  vc[1] = sy * (double(j) / ny);
12739  mesh2d->AddVertex(vc);
12740  }
12741  }
12742  // elements
12743  Array<int> vert;
12744  for (int i = 0; i < mesh->GetNE(); i++)
12745  {
12746  const Element *elem = mesh->GetElement(i);
12747  elem->GetVertices(vert);
12748  const int attr = elem->GetAttribute();
12749  for (int j = 0; j < ny; j++)
12750  {
12751  int qv[4];
12752  qv[0] = vert[0] * nvy + j;
12753  qv[1] = vert[1] * nvy + j;
12754  qv[2] = vert[1] * nvy + (j + 1) % nvy;
12755  qv[3] = vert[0] * nvy + (j + 1) % nvy;
12756 
12757  mesh2d->AddQuad(qv, attr);
12758  }
12759  }
12760  // 2D boundary from the 1D boundary
12761  for (int i = 0; i < mesh->GetNBE(); i++)
12762  {
12763  const Element *elem = mesh->GetBdrElement(i);
12764  elem->GetVertices(vert);
12765  const int attr = elem->GetAttribute();
12766  for (int j = 0; j < ny; j++)
12767  {
12768  int sv[2];
12769  sv[0] = vert[0] * nvy + j;
12770  sv[1] = vert[0] * nvy + (j + 1) % nvy;
12771 
12772  if (attr%2)
12773  {
12774  Swap<int>(sv[0], sv[1]);
12775  }
12776 
12777  mesh2d->AddBdrSegment(sv, attr);
12778  }
12779  }
12780 
12781  if (!closed)
12782  {
12783  // 2D boundary from the 1D elements (bottom + top)
12784  int nba = (mesh->bdr_attributes.Size() > 0 ?
12785  mesh->bdr_attributes.Max() : 0);
12786  for (int i = 0; i < mesh->GetNE(); i++)
12787  {
12788  const Element *elem = mesh->GetElement(i);
12789  elem->GetVertices(vert);
12790  const int attr = nba + elem->GetAttribute();
12791  int sv[2];
12792  sv[0] = vert[0] * nvy;
12793  sv[1] = vert[1] * nvy;
12794 
12795  mesh2d->AddBdrSegment(sv, attr);
12796 
12797  sv[0] = vert[1] * nvy + ny;
12798  sv[1] = vert[0] * nvy + ny;
12799 
12800  mesh2d->AddBdrSegment(sv, attr);
12801  }
12802  }
12803 
12804  mesh2d->FinalizeQuadMesh(1, 0, false);
12805 
12806  GridFunction *nodes = mesh->GetNodes();
12807  if (nodes)
12808  {
12809  // duplicate the fec of the 1D mesh so that it can be deleted safely
12810  // along with its nodes, fes and fec
12811  FiniteElementCollection *fec2d = NULL;
12812  FiniteElementSpace *fes2d;
12813  const char *name = nodes->FESpace()->FEColl()->Name();
12814  string cname = name;
12815  if (cname == "Linear")
12816  {
12817  fec2d = new LinearFECollection;
12818  }
12819  else if (cname == "Quadratic")
12820  {
12821  fec2d = new QuadraticFECollection;
12822  }
12823  else if (cname == "Cubic")
12824  {
12825  fec2d = new CubicFECollection;
12826  }
12827  else if (!strncmp(name, "H1_", 3))
12828  {
12829  fec2d = new H1_FECollection(atoi(name + 7), 2);
12830  }
12831  else if (!strncmp(name, "L2_T", 4))
12832  {
12833  fec2d = new L2_FECollection(atoi(name + 10), 2, atoi(name + 4));
12834  }
12835  else if (!strncmp(name, "L2_", 3))
12836  {
12837  fec2d = new L2_FECollection(atoi(name + 7), 2);
12838  }
12839  else
12840  {
12841  delete mesh2d;
12842  mfem::err << "Extrude1D : The mesh uses unknown FE collection : "
12843  << cname << endl;
12844  mfem_error();
12845  }
12846  fes2d = new FiniteElementSpace(mesh2d, fec2d, 2);
12847  mesh2d->SetNodalFESpace(fes2d);
12848  GridFunction *nodes2d = mesh2d->GetNodes();
12849  nodes2d->MakeOwner(fec2d);
12850 
12851  NodeExtrudeCoefficient ecoeff(2, ny, sy);
12852  Vector lnodes;
12853  Array<int> vdofs2d;
12854  for (int i = 0; i < mesh->GetNE(); i++)
12855  {
12857  for (int j = ny-1; j >= 0; j--)
12858  {
12859  fes2d->GetElementVDofs(i*ny+j, vdofs2d);
12860  lnodes.SetSize(vdofs2d.Size());
12861  ecoeff.SetLayer(j);
12862  fes2d->GetFE(i*ny+j)->Project(ecoeff, T, lnodes);
12863  nodes2d->SetSubVector(vdofs2d, lnodes);
12864  }
12865  }
12866  }
12867  return mesh2d;
12868 }
12869 
12870 Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz)
12871 {
12872  if (mesh->Dimension() != 2)
12873  {
12874  mfem::err << "Extrude2D : Not a 2D mesh!" << endl;
12875  mfem_error();
12876  }
12877 
12878  int nvz = nz + 1;
12879  int nvt = mesh->GetNV() * nvz;
12880 
12881  Mesh *mesh3d = new Mesh(3, nvt, mesh->GetNE()*nz,
12882  mesh->GetNBE()*nz+2*mesh->GetNE());
12883 
12884  bool wdgMesh = false;
12885  bool hexMesh = false;
12886 
12887  // vertices
12888  double vc[3];
12889  for (int i = 0; i < mesh->GetNV(); i++)
12890  {
12891  vc[0] = mesh->GetVertex(i)[0];
12892  vc[1] = mesh->GetVertex(i)[1];
12893  for (int j = 0; j < nvz; j++)
12894  {
12895  vc[2] = sz * (double(j) / nz);
12896  mesh3d->AddVertex(vc);
12897  }
12898  }
12899  // elements
12900  Array<int> vert;
12901  for (int i = 0; i < mesh->GetNE(); i++)
12902  {
12903  const Element *elem = mesh->GetElement(i);
12904  elem->GetVertices(vert);
12905  const int attr = elem->GetAttribute();
12906  Geometry::Type geom = elem->GetGeometryType();
12907  switch (geom)
12908  {
12909  case Geometry::TRIANGLE:
12910  wdgMesh = true;
12911  for (int j = 0; j < nz; j++)
12912  {
12913  int pv[6];
12914  pv[0] = vert[0] * nvz + j;
12915  pv[1] = vert[1] * nvz + j;
12916  pv[2] = vert[2] * nvz + j;
12917  pv[3] = vert[0] * nvz + (j + 1) % nvz;
12918  pv[4] = vert[1] * nvz + (j + 1) % nvz;
12919  pv[5] = vert[2] * nvz + (j + 1) % nvz;
12920 
12921  mesh3d->AddWedge(pv, attr);
12922  }
12923  break;
12924  case Geometry::SQUARE:
12925  hexMesh = true;
12926  for (int j = 0; j < nz; j++)
12927  {
12928  int hv[8];
12929  hv[0] = vert[0] * nvz + j;
12930  hv[1] = vert[1] * nvz + j;
12931  hv[2] = vert[2] * nvz + j;
12932  hv[3] = vert[3] * nvz + j;
12933  hv[4] = vert[0] * nvz + (j + 1) % nvz;
12934  hv[5] = vert[1] * nvz + (j + 1) % nvz;
12935  hv[6] = vert[2] * nvz + (j + 1) % nvz;
12936  hv[7] = vert[3] * nvz + (j + 1) % nvz;
12937 
12938  mesh3d->AddHex(hv, attr);
12939  }
12940  break;
12941  default:
12942  mfem::err << "Extrude2D : Invalid 2D element type \'"
12943  << geom << "\'" << endl;
12944  mfem_error();
12945  break;
12946  }
12947  }
12948  // 3D boundary from the 2D boundary
12949  for (int i = 0; i < mesh->GetNBE(); i++)
12950  {
12951  const Element *elem = mesh->GetBdrElement(i);
12952  elem->GetVertices(vert);
12953  const int attr = elem->GetAttribute();
12954  for (int j = 0; j < nz; j++)
12955  {
12956  int qv[4];
12957  qv[0] = vert[0] * nvz + j;
12958  qv[1] = vert[1] * nvz + j;
12959  qv[2] = vert[1] * nvz + (j + 1) % nvz;
12960  qv[3] = vert[0] * nvz + (j + 1) % nvz;
12961 
12962  mesh3d->AddBdrQuad(qv, attr);
12963  }
12964  }
12965 
12966  // 3D boundary from the 2D elements (bottom + top)
12967  int nba = (mesh->bdr_attributes.Size() > 0 ?
12968  mesh->bdr_attributes.Max() : 0);
12969  for (int i = 0; i < mesh->GetNE(); i++)
12970  {
12971  const Element *elem = mesh->GetElement(i);
12972  elem->GetVertices(vert);
12973  const int attr = nba + elem->GetAttribute();
12974  Geometry::Type geom = elem->GetGeometryType();
12975  switch (geom)
12976  {
12977  case Geometry::TRIANGLE:
12978  {
12979  int tv[3];
12980  tv[0] = vert[0] * nvz;
12981  tv[1] = vert[2] * nvz;
12982  tv[2] = vert[1] * nvz;
12983 
12984  mesh3d->AddBdrTriangle(tv, attr);
12985 
12986  tv[0] = vert[0] * nvz + nz;
12987  tv[1] = vert[1] * nvz + nz;
12988  tv[2] = vert[2] * nvz + nz;
12989 
12990  mesh3d->AddBdrTriangle(tv, attr);
12991  }
12992  break;
12993  case Geometry::SQUARE:
12994  {
12995  int qv[4];
12996  qv[0] = vert[0] * nvz;
12997  qv[1] = vert[3] * nvz;
12998  qv[2] = vert[2] * nvz;
12999  qv[3] = vert[1] * nvz;
13000 
13001  mesh3d->AddBdrQuad(qv, attr);
13002 
13003  qv[0] = vert[0] * nvz + nz;
13004  qv[1] = vert[1] * nvz + nz;
13005  qv[2] = vert[2] * nvz + nz;
13006  qv[3] = vert[3] * nvz + nz;
13007 
13008  mesh3d->AddBdrQuad(qv, attr);
13009  }
13010  break;
13011  default:
13012  mfem::err << "Extrude2D : Invalid 2D element type \'"
13013  << geom << "\'" << endl;
13014  mfem_error();
13015  break;
13016  }
13017  }
13018 
13019  if ( hexMesh && wdgMesh )
13020  {
13021  mesh3d->FinalizeMesh(0, false);
13022  }
13023  else if ( hexMesh )
13024  {
13025  mesh3d->FinalizeHexMesh(1, 0, false);
13026  }
13027  else if ( wdgMesh )
13028  {
13029  mesh3d->FinalizeWedgeMesh(1, 0, false);
13030  }
13031 
13032  GridFunction *nodes = mesh->GetNodes();
13033  if (nodes)
13034  {
13035  // duplicate the fec of the 2D mesh so that it can be deleted safely
13036  // along with its nodes, fes and fec
13037  FiniteElementCollection *fec3d = NULL;
13038  FiniteElementSpace *fes3d;
13039  const char *name = nodes->FESpace()->FEColl()->Name();
13040  string cname = name;
13041  if (cname == "Linear")
13042  {
13043  fec3d = new LinearFECollection;
13044  }
13045  else if (cname == "Quadratic")
13046  {
13047  fec3d = new QuadraticFECollection;
13048  }
13049  else if (cname == "Cubic")
13050  {
13051  fec3d = new CubicFECollection;
13052  }
13053  else if (!strncmp(name, "H1_", 3))
13054  {
13055  fec3d = new H1_FECollection(atoi(name + 7), 3);
13056  }
13057  else if (!strncmp(name, "L2_T", 4))
13058  {
13059  fec3d = new L2_FECollection(atoi(name + 10), 3, atoi(name + 4));
13060  }
13061  else if (!strncmp(name, "L2_", 3))
13062  {
13063  fec3d = new L2_FECollection(atoi(name + 7), 3);
13064  }
13065  else
13066  {
13067  delete mesh3d;
13068  mfem::err << "Extrude3D : The mesh uses unknown FE collection : "
13069  << cname << endl;
13070  mfem_error();
13071  }
13072  fes3d = new FiniteElementSpace(mesh3d, fec3d, 3);
13073  mesh3d->SetNodalFESpace(fes3d);
13074  GridFunction *nodes3d = mesh3d->GetNodes();
13075  nodes3d->MakeOwner(fec3d);
13076 
13077  NodeExtrudeCoefficient ecoeff(3, nz, sz);
13078  Vector lnodes;
13079  Array<int> vdofs3d;
13080  for (int i = 0; i < mesh->GetNE(); i++)
13081  {
13083  for (int j = nz-1; j >= 0; j--)
13084  {
13085  fes3d->GetElementVDofs(i*nz+j, vdofs3d);
13086  lnodes.SetSize(vdofs3d.Size());
13087  ecoeff.SetLayer(j);
13088  fes3d->GetFE(i*nz+j)->Project(ecoeff, T, lnodes);
13089  nodes3d->SetSubVector(vdofs3d, lnodes);
13090  }
13091  }
13092  }
13093  return mesh3d;
13094 }
13095 
13096 #ifdef MFEM_DEBUG
13097 void Mesh::DebugDump(std::ostream &os) const
13098 {
13099  // dump vertices and edges (NCMesh "nodes")
13100  os << NumOfVertices + NumOfEdges << "\n";
13101  for (int i = 0; i < NumOfVertices; i++)
13102  {
13103  const double *v = GetVertex(i);
13104  os << i << " " << v[0] << " " << v[1] << " " << v[2]
13105  << " 0 0 " << i << " -1 0\n";
13106  }
13107 
13108  Array<int> ev;
13109  for (int i = 0; i < NumOfEdges; i++)
13110  {
13111  GetEdgeVertices(i, ev);
13112  double mid[3] = {0, 0, 0};
13113  for (int j = 0; j < 2; j++)
13114  {
13115  for (int k = 0; k < spaceDim; k++)
13116  {
13117  mid[k] += GetVertex(ev[j])[k];
13118  }
13119  }
13120  os << NumOfVertices+i << " "
13121  << mid[0]/2 << " " << mid[1]/2 << " " << mid[2]/2 << " "
13122  << ev[0] << " " << ev[1] << " -1 " << i << " 0\n";
13123  }
13124 
13125  // dump elements
13126  os << NumOfElements << "\n";
13127  for (int i = 0; i < NumOfElements; i++)
13128  {
13129  const Element* e = elements[i];
13130  os << e->GetNVertices() << " ";
13131  for (int j = 0; j < e->GetNVertices(); j++)
13132  {
13133  os << e->GetVertices()[j] << " ";
13134  }
13135  os << e->GetAttribute() << " 0 " << i << "\n";
13136  }
13137 
13138  // dump faces
13139  os << "0\n";
13140 }
13141 #endif
13142 
13143 }
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:4951
Abstract class for all finite elements.
Definition: fe_base.hpp:233
const IntegrationRule * IntRule
Definition: mesh.hpp:2241
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
Definition: array.cpp:85
void Loader(std::istream &input, int generate_edges=0, std::string parse_tag="")
Definition: mesh.cpp:4026
Mesh * Make3D(int nsteps, double rstep, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:370
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the interior of the specified edge.
Definition: fespace.cpp:3130
Table * GetEdgeVertexTable() const
Definition: mesh.cpp:6419
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:605
void SetCoordsFromPatches(Vector &Nodes)
Definition: nurbs.cpp:3634
void Print(std::ostream &out) const
I/O: Print the mesh in "MFEM NC mesh v1.0" format.
Definition: ncmesh.cpp:5634
BiLinear2DFiniteElement QuadrilateralFE
static const int vtk_quadratic_hex[27]
Definition: mesh.hpp:251
int * CartesianPartitioning(int nxyz[])
Definition: mesh.cpp:7383
void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:253
int Push(int i, int j)
Definition: table.cpp:219
int * GetJ()
Definition: table.hpp:114
Arc::Index insert_arc(Node::Index i, Node::Index j, Float w=1, Float b=1)
Definition: gecko.cpp:679
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:96
const FiniteElementSpace * GetNodalFESpace() const
Definition: mesh.cpp:5630
void Init(int ind1, int ind2, int ind3, int ind4, int attr=1, int ref_flag=0)
Initialize the vertex indices and the attribute of a Tetrahedron.
Definition: tetrahedron.cpp:43
void NewDataAndSize(double *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition: vector.hpp:160
void ScaleElements(double sf)
Definition: mesh.cpp:11975
static const int HighOrderMap[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to arbitrary-order Lagrange VTK geometries.
Definition: vtk.hpp:82
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Definition: mesh.cpp:6298
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T...
Definition: array.hpp:259
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition: array.hpp:295
void ReadVTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo)
void UseExternalData(double *ext_data, int i, int j, int k)
Definition: densemat.hpp:1157
void FreeElement(Element *E)
Definition: mesh.cpp:12291
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:3402
int AddQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1694
int CheckElementOrientation(bool fix_it=true)
Check (and optionally attempt to fix) the orientation of the elements.
Definition: mesh.cpp:5712
void SetVertices(const Vector &vert_coord)
Definition: mesh.cpp:8242
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:980
static const int vtk_quadratic_tet[10]
Definition: mesh.hpp:248
void Make2D(int nx, int ny, Element::Type type, double sx, double sy, bool generate_edges, bool sfc_ordering)
Definition: mesh.cpp:3398
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:2271
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:78
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:2215
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition: globals.hpp:71
virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip)
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
Definition: mesh.cpp:12692
static Mesh MakeSimplicial(const Mesh &orig_mesh)
Definition: mesh.cpp:4622
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:8559
Linear1DFiniteElement SegmentFE
Definition: segment.cpp:49
int GetNV() const
Definition: nurbs.hpp:418
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:81
void METIS_PartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
class LinearPyramidFiniteElement PyramidFE
Definition: fe.cpp:44
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:1242
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:6588
static const int NumGeom
Definition: geom.hpp:42
static int ComposeQuadOrientations(int ori_a_b, int ori_b_c)
Definition: mesh.cpp:5999
const Table & ElementToFaceTable() const
Definition: mesh.cpp:6825
Array< Slave > slaves
Definition: ncmesh.hpp:231
Array< Element * > boundary
Definition: mesh.hpp:91
int Dimension() const
Dimension of the reference space used within the elements.
Definition: mesh.hpp:1020
int * GeneratePartitioning(int nparts, int part_method=1)
Definition: mesh.cpp:7427
CoarseFineTransformations CoarseFineTr
Definition: mesh.hpp:240
int own_nodes
Definition: mesh.hpp:246
virtual void LimitNCLevel(int max_nc_level)
Definition: ncmesh.cpp:5437
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:5668
void MoveVertices(const Vector &displacements)
Definition: mesh.cpp:8222
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:517
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:1054
static Mesh LoadFromFile(const std::string &filename, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition: mesh.cpp:3755
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: tetrahedron.hpp:82
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:457
static FiniteElement * GetTransformationFEforElementType(Element::Type)
Return FiniteElement for reference element of the specified type.
Definition: mesh.cpp:334
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:12625
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:3783
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
Definition: mesh.cpp:8329
int Dimension() const
Return the dimension of the NCMesh.
Definition: ncmesh.hpp:144
int NumOfEdges
Definition: mesh.hpp:70
virtual int Transform(const Vector &pt, IntegrationPoint &ip)
Given a point, pt, in physical space, find its reference coordinates, ip.
Definition: eltrans.cpp:336
void UniformRefinement()
Definition: nurbs.cpp:3774
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:227
virtual void UniformRefinement2D()
Refine a mixed 2D mesh uniformly.
Definition: mesh.hpp:400
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Swap the internal node GridFunction pointer and ownership flag members with the given ones...
Definition: mesh.cpp:8351
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:475
Element::Type GetBdrElementType(int i) const
Returns the type of boundary element i.
Definition: mesh.cpp:6649
void DisableTensorProducts(bool disable=true) const
Disable the use of tensor product evaluations, for tensor-product elements, e.g. quads and hexes...
static int InvertTriOrientation(int ori)
Definition: mesh.cpp:5945
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition: mesh.hpp:1249
void ReadNetgen2DMesh(std::istream &input, int &curved)
void ShiftRight(int &a, int &b, int &c)
Definition: mesh.hpp:2312
void SetDims(int rows, int nnz)
Definition: table.cpp:140
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:226
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:72
int Push(int a, int b)
Definition: table.hpp:267
virtual DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element &#39;bel&#39;. The returned indices are offsets in...
Definition: fespace.cpp:2878
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:6725
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:93
int GetAttribute() const
Return element&#39;s attribute.
Definition: element.hpp:55
static Mesh MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
Create a refined (by any factor) version of orig_mesh.
Definition: mesh.cpp:3793
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
virtual const FaceRestriction * GetFaceRestriction(ElementDofOrdering f_ordering, FaceType, L2FaceValues mul=L2FaceValues::DoubleValued) const
Return an Operator that converts L-vectors to E-vectors on each face.
Definition: fespace.cpp:1335
T * GetData()
Returns the data.
Definition: array.hpp:115
long GetSequence() const
Definition: mesh.hpp:1982
unsigned int uint
Definition: gecko.hpp:204
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:2277
double Det() const
Definition: densemat.cpp:487
bool Nonconforming() const
Definition: mesh.hpp:1969
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:274
int Size() const
Returns the size of the vector.
Definition: vector.hpp:197
static const int Edges[NumEdges][2]
Definition: geom.hpp:270
int Push(int r, int c, int f)
Check to see if this entry is in the table and add it to the table if it is not there. Returns the number assigned to the table entry.
Definition: stable3d.cpp:64
void DeleteTables()
Definition: mesh.hpp:295
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition: array.cpp:68
Piecewise-(bi/tri)linear continuous finite elements.
Definition: fe_coll.hpp:707
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
virtual double * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:465
const NURBSExtension * GetNURBSext() const
Definition: fespace.hpp:557
GridFunction * Nodes
Definition: mesh.hpp:245
int NumOfElements
Definition: mesh.hpp:69
double * Data() const
Returns the matrix data array.
Definition: densemat.hpp:111
void GetBdrElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of boundary element i.
Definition: mesh.hpp:1297
int Dimension() const
Definition: nurbs.hpp:405
Mesh * Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
Extrude a 1D mesh.
Definition: mesh.cpp:12710
int idxtype
Definition: mesh.cpp:44
void Transform(void(*f)(const Vector &, Vector &))
Definition: mesh.cpp:12045
bool IsSlaveFace(const FaceInfo &fi) const
Definition: mesh.cpp:1058
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition: fespace.hpp:706
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:524
void GetElementJacobian(int i, DenseMatrix &J, const IntegrationPoint *ip=NULL)
Definition: mesh.cpp:60
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:8364
int GetNE() const
Definition: nurbs.hpp:420
static int GetQuadrature1D(int b_type)
Get the corresponding Quadrature1D constant, when that makes sense; otherwise return Quadrature1D::In...
Definition: fe_base.hpp:61
void FinalizeWedgeMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a wedge Mesh.
Definition: mesh.cpp:2873
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: triangle.cpp:188
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
Definition: densemat.cpp:1267
virtual void SetVertices(const int *ind)
Set the indices the element according to the input.
Definition: element.cpp:17
virtual void Save(const std::string &fname, int precision=16) const
Definition: mesh.cpp:10705
void GetBdrElementTopo(Array< Element *> &boundary) const
Definition: nurbs.cpp:3045
void GetElementData(const Array< Element *> &elem_array, int geom, Array< int > &elem_vtx, Array< int > &attr) const
Definition: mesh.cpp:9756
void order(Functional *functional, uint iterations=1, uint window=2, uint period=2, uint seed=0, Progress *progress=0)
Definition: gecko.cpp:1232
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:1092
const Element * GetElement(int i) const
Return pointer to the i&#39;th element object.
Definition: mesh.hpp:1143
double kappa
Definition: ex24.cpp:54
TriLinear3DFiniteElement HexahedronFE
Definition: hexahedron.cpp:52
Evaluate the derivatives at quadrature points.
bool IsGhost(const Element &el) const
Return true if the Element el is a ghost element.
Definition: ncmesh.hpp:605
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition: mesh.hpp:2183
NodeExtrudeCoefficient(const int dim, const int n_, const double s_)
Definition: mesh.cpp:12686
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec and fes.
Definition: gridfunc.hpp:122
Data type for vertex.
Definition: vertex.hpp:22
void GetElementLocalToGlobal(Array< int > &lelem_elem)
Definition: nurbs.cpp:3569
void SetMeshGen()
Determine the mesh generator bitmask meshgen, see MeshGenerator().
Definition: mesh.cpp:3973
STL namespace.
void KnotInsert(Array< KnotVector *> &kv)
Definition: nurbs.cpp:3782
virtual void Transform(const IntegrationPoint &, Vector &)
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Definition: eltrans.cpp:492
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:579
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition: mesh.cpp:5951
Data type quadrilateral element.
void ReadNetgen3DMesh(std::istream &input)
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
Definition: fespace.hpp:1306
double Weight() const
Definition: densemat.cpp:544
Data arrays will be written in ASCII format.
The inverse transformation of a given ElementTransformation.
Definition: eltrans.hpp:185
void Print(std::ostream &out) const
Definition: nurbs.cpp:1908
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:3559
void ReadInlineMesh(std::istream &input, bool generate_edges=false)
virtual int OrderJ() const =0
Return the order of the elements of the Jacobian of the transformation.
void RemoveInternalBoundaries()
Definition: mesh.cpp:12203
void GetVertexDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the specified vertices.
Definition: fespace.cpp:3099
Mesh * Extrude2D(Mesh *mesh, const int nz, const double sz)
Extrude a 2D mesh.
Definition: mesh.cpp:12870
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: triangle.hpp:62
void Print(const Mesh &mesh, const adios2stream::mode print_mode=mode::sync)
int RowSize(int i) const
Definition: table.hpp:108
Data type Wedge element.
Definition: wedge.hpp:22
void SetEmpty()
Definition: mesh.cpp:1481
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
double Trace() const
Trace of a square matrix.
Definition: densemat.cpp:463
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:4985
void FinalizeHexMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a hexahedral Mesh.
Definition: mesh.cpp:2908
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:6654
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:1089
friend class NURBSExtension
Definition: mesh.hpp:59
Geometry Geometries
Definition: fe.cpp:49
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:355
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:147
Operation last_operation
Definition: mesh.hpp:289
void ReadCubit(const char *filename, int &curved, int &read_gf)
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
Definition: text.hpp:31
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition: vector.cpp:317
void DeleteAll()
Delete the whole array.
Definition: array.hpp:854
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:2841
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition: mesh.cpp:6274
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:104
int master
master number (in Mesh numbering)
Definition: ncmesh.hpp:216
void InitRefinementTransforms()
Definition: mesh.cpp:10322
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:8400
Array< NCFaceInfo > nc_faces_info
Definition: mesh.hpp:218
Element * ReadElement(std::istream &)
Definition: mesh.cpp:3955
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:480
void OnMeshUpdated(Mesh *mesh)
Definition: ncmesh.cpp:2540
Element * NewElement(int geom)
Definition: mesh.cpp:3901
Table * el_to_face
Definition: mesh.hpp:221
void SetTransformation(ElementTransformation &Trans)
Set a new forward ElementTransformation, Trans.
Definition: eltrans.hpp:292
void SetVerticesFromNodes(const GridFunction *nodes)
Helper to set vertex coordinates given a high-order curvature function.
Definition: mesh.cpp:5654
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition: fespace.cpp:1302
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition: fespace.hpp:753
Structure for storing face geometric factors: coordinates, Jacobians, determinants of the Jacobians...
Definition: mesh.hpp:2237
ElementTransformation * GetBdrElementTransformation(int i)
Definition: mesh.cpp:438
std::function< double(const Vector &)> f(double mass_coeff)
Definition: lor_mms.hpp:30
void GetElementTopo(Array< Element *> &elements) const
Definition: nurbs.cpp:2916
virtual void UpdateMeshPointer(Mesh *new_mesh)
Definition: fespace.cpp:3507
void DebugDump(std::ostream &out) const
Output an NCMesh-compatible debug dump.
Definition: mesh.cpp:13097
int AddBdrTriangle(int v1, int v2, int v3, int attr=1)
Definition: mesh.cpp:1857
Mesh * Make2D(int nsteps, double rstep, double phi, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:49
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Given a coefficient and a transformation, compute its projection (approximation) in the local finite ...
Definition: fe_base.cpp:126
void GetMeshComponents(Mesh &mesh) const
Fill Mesh::{vertices,elements,boundary} for the current finest level.
Definition: ncmesh.cpp:2435
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:1083
void MakeRefined_(Mesh &orig_mesh, const Array< int > ref_factors, int ref_type)
Internal function used in Mesh::MakeRefined.
Definition: mesh.cpp:4393
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe_base.hpp:320
int GetAttribute(int i) const
Return the attribute of element i.
Definition: mesh.hpp:1190
friend class NCMesh
Definition: mesh.hpp:58
Piecewise-(bi)cubic continuous finite elements.
Definition: fe_coll.hpp:787
Data type hexahedron element.
Definition: hexahedron.hpp:22
static int GetTetOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition: mesh.cpp:6030
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:256
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:6622
int AddVertex(double x, double y=0.0, double z=0.0)
Definition: mesh.cpp:1626
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition: eltrans.hpp:401
void GetBdrElementFace(int i, int *f, int *o) const
Return the index and the orientation of the face of bdr element i. (3D)
Definition: mesh.cpp:6565
uint Index
Definition: gecko.hpp:595
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:2224
FaceType
Definition: mesh.hpp:45
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: segment.cpp:40
Data type Pyramid element.
Definition: pyramid.hpp:22
static const int Edges[NumEdges][2]
Definition: geom.hpp:168
void MoveNodes(const Vector &displacements)
Definition: mesh.cpp:8290
double DistanceTo(const double *p) const
Compute the Euclidean distance to another vector.
Definition: vector.hpp:669
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:6514
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:1773
The point is inside the element.
Definition: eltrans.hpp:224
double * GetData() const
Returns the matrix data array.
Definition: densemat.hpp:115
void UpdateNURBS()
Definition: mesh.cpp:5221
int GetMaxElementOrder() const
Return the maximum polynomial order.
Definition: fespace.hpp:573
Geometry::Type GetGeometryType() const
Definition: element.hpp:52
Symmetric 3D Table stored as an array of rows each of which has a stack of column, floor, number nodes. The number of the node is assigned by counting the nodes from zero as they are pushed into the table. Diagonals of any kind are not allowed so the row, column and floor must all be different for each node. Only one node is stored for all 6 symmetric entries that are indexable by unique triplets of row, column, and floor.
Definition: stable3d.hpp:34
void GetVertices(Vector &vert_coord) const
Definition: mesh.cpp:8231
const Table & GetDerefinementTable()
Definition: ncmesh.cpp:1937
double UserTime()
Return the number of user seconds elapsed since the stopwatch was started.
Definition: tic_toc.cpp:434
void PrintVTK(std::ostream &os)
Definition: mesh.cpp:10719
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:7884
void Make3D(int nx, int ny, int nz, Element::Type type, double sx, double sy, double sz, bool sfc_ordering)
Definition: mesh.cpp:3117
unsigned matrix
Definition: ncmesh.hpp:58
void AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
Definition: mesh.cpp:6875
virtual void SetAttributes()
Determine the sets of unique attribute values in domain and boundary elements.
Definition: mesh.cpp:1572
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:759
void SetType(const int t)
Set the Quadrature1D type of points to use for subdivision.
Definition: geom.hpp:338
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition: mesh.cpp:9888
void GetNode(int i, double *coord) const
Definition: mesh.cpp:8251
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: triangle.hpp:61
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:723
IntegrationPointTransformation Loc1
Definition: eltrans.hpp:524
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:2230
const double * HostRead() const
Shortcut for mfem::Read(GetMemory(), TotalSize(), false).
Definition: densemat.hpp:470
int FindCoarseElement(int i)
Definition: mesh.cpp:10334
int SpaceDimension() const
Return the space dimension of the NCMesh.
Definition: ncmesh.hpp:146
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:214
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:154
virtual void Derefine(const Array< int > &derefs)
Definition: ncmesh.cpp:1981
double b
Definition: lissajous.cpp:42
void CreateRefinementFlag(int refinement_edges[2], int type, int flag=0)
Definition: tetrahedron.cpp:71
void FindNeighbors(int elem, Array< int > &neighbors, const Array< int > *search_set=NULL)
Definition: ncmesh.cpp:3739
virtual void PrintXG(std::ostream &os=mfem::out) const
Print the mesh to the given stream using Netgen/Truegrid format.
Definition: mesh.cpp:10407
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:10232
static const int Map[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to linear VTK geometries.
Definition: vtk.hpp:78
void AddQuadFaceElement(int lf, int gf, int el, int v0, int v1, int v2, int v3)
Definition: mesh.cpp:6940
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:7827
Timing object.
Definition: tic_toc.hpp:35
void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
void KnotInsert(Array< KnotVector *> &kv)
Definition: mesh.cpp:5147
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:5282
void ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:7192
void Reset()
Force the reevaluation of the Jacobian in the next call.
Definition: eltrans.hpp:89
virtual void Print(std::ostream &out=mfem::out, int width_=4) const
Prints matrix to stream out.
Definition: densemat.cpp:2221
bool Conforming() const
Definition: mesh.hpp:1968
A pair of objects.
Definition: sort_pairs.hpp:23
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Definition: mesh.cpp:5635
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:6382
double delta
Definition: lissajous.cpp:43
Type
Constants for the classes derived from Element.
Definition: element.hpp:41
void InitTables()
Definition: mesh.cpp:1474
void Get(double *p, const int dim) const
Definition: intrules.hpp:57
void CheckDisplacements(const Vector &displacements, double &tmax)
Definition: mesh.cpp:8145
This structure stores the low level information necessary to interpret the configuration of elements ...
Definition: mesh.hpp:153
NURBSExtension * StealNURBSext()
Definition: fespace.cpp:2281
Array< DenseMatrix * > point_matrices[Geometry::NumGeom]
List of unique point matrices for each slave geometry.
Definition: ncmesh.hpp:234
void Mult(const Vector &e_vec, unsigned eval_flags, Vector &q_val, Vector &q_der, Vector &q_det, Vector &q_nor) const
Interpolate the E-vector e_vec to quadrature points.
PointFiniteElement PointFE
Definition: point.cpp:30
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:1125
VTKFormat
Data array format for VTK and VTU files.
Definition: vtk.hpp:98
virtual const char * Name() const
Definition: fe_coll.hpp:80
int mesh_geoms
Definition: mesh.hpp:78
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:159
int AddBdrSegment(int v1, int v2, int attr=1)
Definition: mesh.cpp:1843
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition: mesh.hpp:1293
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:1399
int AddElement(Element *elem)
Definition: mesh.cpp:1829
void ReadLineMesh(std::istream &input)
Array< Embedding > embeddings
Fine element positions in their parents.
Definition: ncmesh.hpp:73
virtual void Load(std::istream &input, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition: mesh.hpp:666
void GetGeometricParametersFromJacobian(const DenseMatrix &J, double &volume, Vector &aspr, Vector &skew, Vector &ori) const
Computes geometric parameters associated with a Jacobian matrix in 2D/3D. These parameters are (1) Ar...
Definition: mesh.cpp:12430
const CoarseFineTransformations & GetRefinementTransforms()
Definition: ncmesh.cpp:4572
void SetLayer(const int l)
Definition: mesh.hpp:2296
Table * GetFaceToElementTable() const
Definition: mesh.cpp:6480
Array< int > FindFaceNeighbors(const int elem) const
Returns the sorted, unique indices of elements sharing a face with element elem, including elem...
Definition: mesh.cpp:6537
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:6750
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition: array.hpp:292
void SetKnotsFromPatches()
Definition: nurbs.cpp:3642
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:9912
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:6320
Data type triangle element.
Definition: triangle.hpp:23
void MarkCoarseLevel()
Definition: ncmesh.cpp:4524
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Definition: triangle.cpp:45
void ResetLazyData()
Definition: mesh.cpp:1561
IntegrationRule RefPts
Definition: geom.hpp:314
signed char local
local number within &#39;element&#39;
Definition: ncmesh.hpp:191
void GetColumn(int c, Vector &col) const
Definition: densemat.cpp:1330
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
Definition: densemat.hpp:1148
double Float
Definition: gecko.hpp:208
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
Definition: array.hpp:251
double FNorm2() const
Compute the square of the Frobenius norm of the matrix.
Definition: densemat.hpp:269
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:1456
virtual void SetNodalFESpace(FiniteElementSpace *nfes)
Definition: mesh.cpp:5577
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: tetrahedron.hpp:81
Vector normal
Normals at all quadrature points.
Definition: mesh.hpp:2284
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
Definition: ncmesh.hpp:121
static const int Edges[NumEdges][2]
Definition: geom.hpp:222
void SetData(double *d)
Definition: vector.hpp:147
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:691
bool IsOfFaceType(FaceType type) const
Return true if the face is of the same type as type.
Definition: mesh.hpp:1712
struct mfem::Mesh::FaceInformation::@13 element[2]
virtual MFEM_DEPRECATED void ReorientTetMesh()
Definition: mesh.cpp:7321
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:187
prob_type prob
Definition: ex25.cpp:154
int NumOfBdrElements
Definition: mesh.hpp:69
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:736
Table * el_to_edge
Definition: mesh.hpp:220
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:311
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the interior of the specified face.
Definition: fespace.cpp:3142
static const int QuadraticMap[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to legacy quadratic VTK geometries/.
Definition: vtk.hpp:80
A class that performs interpolation from a face E-vector to quadrature point values and/or derivative...
void GetNodalValues(int i, Array< double > &nval, int vdim=1) const
Returns the values in the vertices of i&#39;th element for dimension vdim.
Definition: gridfunc.cpp:395
void ReadMFEMMesh(std::istream &input, int version, int &curved)
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:9266
MPI_Comm GetComm() const
Definition: pmesh.hpp:351
void Start()
Start the stopwatch. The elapsed time is not cleared.
Definition: tic_toc.cpp:408
Table * GetFaceEdgeTable() const
Definition: mesh.cpp:6391
void FindPartitioningComponents(Table &elem_elem, const Array< int > &partitioning, Array< int > &component, Array< int > &num_comp)
Definition: mesh.cpp:7756
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:206
void MakeTopologyOnly()
Definition: ncmesh.hpp:413
List of mesh geometries stored as Array<Geometry::Type>.
Definition: mesh.hpp:1273
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:702
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:10919
This structure is used as a human readable output format that decipheres the information contained in...
Definition: mesh.hpp:1664
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i&#39;th element. The returned indices are offsets into an ...
Definition: fespace.cpp:281
int CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition: mesh.cpp:6163
Geometry::Type GetElementGeometry(int i) const
Definition: mesh.hpp:1228
int GetMyRank() const
Definition: pmesh.hpp:353
GeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, MemoryType d_mt=MemoryType::DEFAULT)
Definition: mesh.cpp:12545
void PrintElementsWithPartitioning(int *partitioning, std::ostream &out, int interior_faces=0)
Definition: mesh.cpp:11465
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition: mesh.hpp:1196
static const int Edges[NumEdges][2]
Definition: geom.hpp:198
void AddPointFaceElement(int lf, int gf, int el)
Used in GenerateFaces()
Definition: mesh.cpp:6843
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:3576
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:555
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:638
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:275
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:9508
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:2938
const Table & ElementToEdgeTable() const
Definition: mesh.cpp:6834
static int CheckClosed(int type)
If the Quadrature1D type is not closed return Invalid; otherwise return type.
Definition: intrules.cpp:911
Table * el_to_el
Definition: mesh.hpp:222
int GetDim() const
Returns the reference space dimension for the finite element.
Definition: fe_base.hpp:311
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:219
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition: mesh.cpp:12096
static void PrintElement(const Element *, std::ostream &)
Definition: mesh.cpp:3967
virtual void NURBSUniformRefinement()
Refine NURBS mesh.
Definition: mesh.cpp:5191
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int attr=1)
Definition: mesh.cpp:1757
const IntegrationRule * IntRule
Definition: mesh.hpp:2192
MemoryType
Memory types supported by MFEM.
Definition: mem_manager.hpp:31
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:2262
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition: mesh.cpp:2945
void AddAColumnInRow(int r)
Definition: table.hpp:77
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition: mesh.hpp:1853
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:687
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
Definition: mesh.cpp:2501
int AddBdrQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1871
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:7964
Array< Vertex > vertices
Definition: mesh.hpp:90
void PrintTopo(std::ostream &out, const Array< int > &e_to_k) const
Definition: mesh.cpp:10663
int Push4(int r, int c, int f, int t)
Check to see if this entry is in the table and add it to the table if it is not there. The entry is addressed by the three smallest values of (r,c,f,t). Returns the number assigned to the table entry.
Definition: stable3d.cpp:140
void JacToPerfJac(int GeomType, const DenseMatrix &J, DenseMatrix &PJ) const
Definition: geom.cpp:867
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, double sx=1.0, double sy=1.0, bool sfc_ordering=true)
Definition: mesh.cpp:3773
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Definition: mesh.cpp:1603
void ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo, const std::string &xml_prefix="")
Helper struct for defining a connectivity table, see Table::MakeFromList.
Definition: table.hpp:27
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe_base.hpp:323
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:66
void RefineAtVertex(const Vertex &vert, double eps=0.0, int nonconforming=-1)
Refine elements sharing the specified vertex. Uses GeneralRefinement.
Definition: mesh.cpp:9931
MFEM_EXPORT class Linear3DFiniteElement TetrahedronFE
Definition: fe.cpp:36
A class to initialize the size of a Tensor.
Definition: dtensor.hpp:54
static Mesh MakeCartesian1D(int n, double sx=1.0)
Definition: mesh.cpp:3765
virtual DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element &#39;elem&#39;. The returned indices are offsets into an ldo...
Definition: fespace.cpp:2731
Array< Element * > elements
Definition: mesh.hpp:85
const Table & ElementToElementTable()
Definition: mesh.cpp:6789
void SetRelaxedHpConformity(bool relaxed=true)
Definition: fespace.hpp:1288
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition: gridfunc.cpp:164
void ShiftUpI()
Definition: table.cpp:115
MFEM_EXPORT Linear2DFiniteElement TriangleFE
Definition: fe.cpp:32
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition: mesh.hpp:1023
int meshgen
Definition: mesh.hpp:77
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:252
const CoarseFineTransformations & GetRefinementTransforms()
Definition: mesh.cpp:10344
void RefineNURBSFromFile(std::string ref_file)
Definition: mesh.cpp:5110
bool RefineByError(const Array< double > &elem_error, double threshold, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:9957
Table * bel_to_edge
Definition: mesh.hpp:224
void GetGeometries(int dim, Array< Geometry::Type > &el_geoms) const
Return all element geometries of the given dimension present in the mesh.
Definition: mesh.cpp:6285
Evaluate the values at quadrature points.
Geometry::Type GetBdrElementGeometry(int i) const
Definition: mesh.hpp:1233
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:1086
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
Definition: mesh.cpp:6352
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
double a
Definition: lissajous.cpp:41
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:277
int nbInteriorFaces
Definition: mesh.hpp:75
void PrintBdrVTU(std::string fname, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0)
Definition: mesh.cpp:10911
Array< int > be_to_edge
Definition: mesh.hpp:223
static const int Edges[NumEdges][2]
Definition: geom.hpp:292
Class for integration point with weight.
Definition: intrules.hpp:31
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition: mesh.cpp:6644
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition: fespace.cpp:1370
Element * ReadElementWithoutAttr(std::istream &)
Definition: mesh.cpp:3925
void Swap(Mesh &other, bool non_geometry)
Definition: mesh.cpp:9699
int VectorDim() const
Definition: gridfunc.cpp:323
int GetElementOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:178
A standard isoparametric element transformation.
Definition: eltrans.hpp:361
static const int vtk_quadratic_wedge[18]
Definition: mesh.hpp:250
virtual long long ReduceInt(int value) const
Utility function: sum integers from all processors (Allreduce).
Definition: mesh.hpp:2160
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: mesh.cpp:355
static const int DimStart[MaxDim+2]
Definition: geom.hpp:48
virtual int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type, does not count master nonconforming face...
Definition: mesh.cpp:5684
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
MFEM_EXPORT class LinearWedgeFiniteElement WedgeFE
Definition: fe.cpp:40
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:721
Table * face_edge
Definition: mesh.hpp:231
void FinalizeQuadMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a quadrilateral Mesh.
Definition: mesh.cpp:1988
Array< int > leaf_elements
finest elements, in Mesh ordering (+ ghosts)
Definition: ncmesh.hpp:540
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
Definition: mesh.cpp:3042
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:700
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:209
bool DerefineByError(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
Definition: mesh.cpp:9626
Array< Master > masters
Definition: ncmesh.hpp:230
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition: fespace.hpp:74
const char * VTKByteOrder()
Determine the byte order and return either "BigEndian" or "LittleEndian".
Definition: vtk.cpp:602
void MakeJ()
Definition: table.cpp:91
void DegreeElevate(int rel_degree, int degree=16)
Definition: mesh.cpp:5204
int dim
Definition: ex24.cpp:53
Table * edge_vertex
Definition: mesh.hpp:232
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition: eltrans.hpp:381
long sequence
Definition: mesh.hpp:83
signed char geom
Geometry::Type (faces only) (char to save RAM)
Definition: ncmesh.hpp:192
void FindTMax(Vector &c, Vector &x, double &tmax, const double factor, const int Dim)
Definition: mesh.cpp:8111
IsoparametricTransformation Transf
Definition: eltrans.hpp:464
int index(int i, int j, int nx, int ny)
Definition: life.cpp:235
int NumberOfEntries() const
Definition: table.hpp:266
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:864
ElementTransformation * Elem1
Definition: eltrans.hpp:522
constexpr int dimension
This example only works in 3D. Kernels for 2D are not implemented.
Definition: hooke.cpp:45
static const int Edges[NumEdges][2]
Definition: geom.hpp:248
const Mesh * mesh
Definition: mesh.hpp:2191
Float cost() const
Definition: gecko.cpp:857
void MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
Definition: mesh.cpp:4629
Lexicographic ordering for tensor-product FiniteElements.
Array< FaceInfo > faces_info
Definition: mesh.hpp:217
double infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition: vector.hpp:44
virtual int GetNVertices() const =0
int GetNKV() const
Definition: nurbs.hpp:415
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:2415
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:235
static int InvertQuadOrientation(int ori)
Definition: mesh.cpp:6024
double Norml2() const
Returns the l2 norm of the vector.
Definition: vector.cpp:835
STable3D * GetFacesTable()
Definition: mesh.cpp:7129
Piecewise-(bi)quadratic continuous finite elements.
Definition: fe_coll.hpp:735
int Size_of_connections() const
Definition: table.hpp:98
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
Definition: sparsemat.hpp:711
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition: mesh.hpp:278
virtual void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level)
Definition: ncmesh.cpp:1952
virtual void UniformRefinement3D()
Refine a mixed 3D mesh uniformly.
Definition: mesh.hpp:410
int AddBdrElement(Element *elem)
Definition: mesh.cpp:1836
int Size() const
Return the logical size of the array.
Definition: array.hpp:141
RefCoord t[3]
NQPT x VDIM x NE (values) / NQPT x VDIM x DIM x NE (grads)
static void PrintElementWithoutAttr(const Element *, std::ostream &)
Definition: mesh.cpp:3943
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr=1)
Definition: mesh.cpp:1729
BlockArray< Element > elements
Definition: ncmesh.hpp:511
FaceInformation GetFaceInformation(int f) const
Definition: mesh.cpp:1138
virtual bool NonconformingDerefinement(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
NC version of GeneralDerefinement.
Definition: mesh.cpp:9578
int Dim
Definition: mesh.hpp:66
void Clear()
Clear the contents of the Mesh.
Definition: mesh.hpp:678
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:45
const int * GetDofMap(Geometry::Type GeomType) const
Get the Cartesian to local H1 dof map.
Definition: fe_coll.cpp:2007
ElementConformity conformity
Definition: mesh.hpp:1671
double AggregateError(const Array< double > &elem_error, const int *fine, int nfine, int op)
Derefinement helper.
Definition: mesh.cpp:9558
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:12316
int DofToVDof(int dof, int vd, int ndofs=-1) const
Compute a single vdof corresponding to the index dof and the vector index vd.
Definition: fespace.cpp:251
Mesh & operator=(Mesh &&mesh)
Move assignment operator.
Definition: mesh.cpp:3749
Evaluate the derivatives at quadrature points.
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:1095
Vector data type.
Definition: vector.hpp:58
Data type point element.
Definition: point.hpp:22
void ReadTrueGridMesh(std::istream &input)
virtual void Print(std::ostream &os=mfem::out) const
Definition: mesh.hpp:2011
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition: fespace.hpp:1274
static void GetElementArrayEdgeTable(const Array< Element *> &elem_array, const DSTable &v_to_v, Table &el_to_edge)
Definition: mesh.cpp:6703
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition: eltrans.hpp:404
bool IsNonconformingCoarse() const
Return true if the face is a nonconforming coarse face.
Definition: mesh.hpp:1743
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition: mesh.cpp:5862
void SetNode(int i, const double *coord)
Definition: mesh.cpp:8270
Table * face_to_elem
Definition: mesh.hpp:230
int SizeK() const
Definition: densemat.hpp:1144
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:609
void PrintSurfaces(const Table &Aface_face, std::ostream &out) const
Print set of disjoint surfaces:
Definition: mesh.cpp:11838
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:259
void XYZ_VectorFunction(const Vector &p, Vector &v)
Definition: mesh.cpp:5540
void GenerateFaces()
Definition: mesh.cpp:6967
void GetElementColoring(Array< int > &colors, int el0=0)
Definition: mesh.cpp:11271
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:8302
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:3835
int GetNumFacesWithGhost() const
Return the number of faces (3D), edges (2D) or vertices (1D) including ghost faces.
Definition: mesh.cpp:5679
int spaceDim
Definition: mesh.hpp:67
Defines the coarse-fine transformations of all fine elements.
Definition: ncmesh.hpp:70
RefCoord s[3]
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
void Printer(std::ostream &out=mfem::out, std::string section_delimiter="") const
Definition: mesh.cpp:10571
const std::string filename
Definition: zstr.hpp:811
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Definition: ncmesh.hpp:260
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the interior of the specified element.
Definition: fespace.cpp:3109
MemAlloc< Tetrahedron, 1024 > TetMemory
Definition: mesh.hpp:255
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag)
Definition: tetrahedron.cpp:55
Node::Index insert_node(Float length=1)
Definition: gecko.cpp:657
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
Definition: mesh.cpp:2567
void SetNodes(const Vector &node_coord)
Updates the vertex/node locations. Invokes NodesUpdated().
Definition: mesh.cpp:8314
const Element * GetBdrElement(int i) const
Return pointer to the i&#39;th boundary element object.
Definition: mesh.hpp:1158
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
friend class ParNCMesh
Definition: mesh.hpp:56
void SetNodalGridFunction(GridFunction *nodes, bool make_owner=false)
Definition: mesh.cpp:5624
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition: mesh.hpp:1976
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:75
void ScaleSubdomains(double sf)
Definition: mesh.cpp:11905
std::ostream & operator<<(std::ostream &os, const Mesh &mesh)
Definition: mesh.cpp:12310
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:3696
Array< int > be_to_face
Definition: mesh.hpp:225
void DegreeElevate(int rel_degree, int degree=16)
Definition: nurbs.cpp:3758
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
Definition: mesh.cpp:9655
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:9986
int GetNBE() const
Definition: nurbs.hpp:422
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition: fe_base.hpp:389
virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const =0
Evaluate the gradients of all shape functions of a scalar finite element in reference space at the gi...
uint rank(Node::Index i) const
Definition: gecko.hpp:672
int index
Mesh number.
Definition: ncmesh.hpp:189
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:9820
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:1096
ElementLocation location
Definition: mesh.hpp:1670
Class for parallel meshes.
Definition: pmesh.hpp:32
Geometry::Type GetBdrElementBaseGeometry(int i) const
Definition: mesh.hpp:1245
Abstract data type element.
Definition: element.hpp:28
void AddTriangleFaceElement(int lf, int gf, int el, int v0, int v1, int v2)
Definition: mesh.cpp:6912
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
void cross3D(const Vector &vin, Vector &vout) const
Definition: vector.cpp:542
Data type line segment element.
Definition: segment.hpp:22
Array< GeometricFactors * > geom_factors
Optional geometric factors.
Definition: mesh.hpp:279
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition: fespace.hpp:730
int NumberOfRows() const
Definition: table.hpp:265
void BdrBisection(int i, const HashTable< Hashed2 > &)
Bisect a boundary triangle: boundary element with index i is bisected.
Definition: mesh.cpp:10195
static int ComposeTriOrientations(int ori_a_b, int ori_b_c)
Definition: mesh.cpp:5922
MPI_Comm GetGlobalMPI_Comm()
Get MFEM&#39;s "global" MPI communicator.
Definition: globals.cpp:62
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Compute the full set of vdofs corresponding to each entry in dofs.
Definition: fespace.cpp:215
int NumberOfElements()
Return the number of elements added to the table.
Definition: stable3d.hpp:70
void GenerateNCFaceInfo()
Definition: mesh.cpp:7068
Array< int > RefGeoms
Definition: geom.hpp:315
friend class Tetrahedron
Definition: mesh.hpp:254
virtual Type GetType() const =0
Returns element&#39;s type.
double GetLength(int i, int j) const
Return the length of the segment from node i to node j.
Definition: mesh.cpp:6688
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition: mesh.hpp:273
const T & AsConst(const T &a)
Utility function similar to std::as_const in c++17.
Definition: array.hpp:350
class Mesh * mesh
The Mesh object containing the element.
Definition: eltrans.hpp:84
Table * GetVertexToElementTable()
The returned Table should be deleted by the caller.
Definition: mesh.cpp:6445
void EnsureNodes()
Make sure that the mesh has valid nodes, i.e. its geometry is described by a vector finite element gr...
Definition: mesh.cpp:5583
void ConvertToPatches(const Vector &Nodes)
Definition: nurbs.cpp:3623
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:11346
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:184
const DenseMatrix * point_matrix
Definition: mesh.hpp:1679
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
Definition: triangle.cpp:126
void UpdateNodes()
Update the nodes of a curved mesh after the topological part of a Mesh::Operation, such as refinement, has been performed.
Definition: mesh.cpp:8385
Defines the position of a fine element within a coarse element.
Definition: ncmesh.hpp:49
void GetBdrPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:6672
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:6600
int idx_t
Definition: mesh.cpp:43
virtual void Refine(const Array< Refinement > &refinements)
Definition: ncmesh.cpp:1620
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:361
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition: fe_coll.hpp:327
Evaluate the values at quadrature points.
double f(const Vector &p)
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:296
void NodesUpdated()
This function should be called after the mesh node coordinates have been updated externally, e.g. by modifying the internal nodal GridFunction returned by GetNodes().
Definition: mesh.hpp:1835
Class used to extrude the nodes of a mesh.
Definition: mesh.hpp:2288
int NumOfFaces
Definition: mesh.hpp:70