MFEM  v4.4.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
mesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 // Implementation of data type mesh
13 
14 #include "mesh_headers.hpp"
15 #include "../fem/fem.hpp"
16 #include "../general/sort_pairs.hpp"
17 #include "../general/binaryio.hpp"
18 #include "../general/text.hpp"
19 #include "../general/device.hpp"
20 #include "../general/tic_toc.hpp"
21 #include "../general/gecko.hpp"
22 #include "../fem/quadinterpolator.hpp"
23 
24 #include <iostream>
25 #include <sstream>
26 #include <fstream>
27 #include <limits>
28 #include <cmath>
29 #include <cstring>
30 #include <ctime>
31 #include <functional>
32 #include <map>
33 #include <set>
34 
35 // Include the METIS header, if using version 5. If using METIS 4, the needed
36 // declarations are inlined below, i.e. no header is needed.
37 #if defined(MFEM_USE_METIS) && defined(MFEM_USE_METIS_5)
38 #include "metis.h"
39 #endif
40 
41 // METIS 4 prototypes
42 #if defined(MFEM_USE_METIS) && !defined(MFEM_USE_METIS_5)
43 typedef int idx_t;
44 typedef int idxtype;
45 extern "C" {
47  int*, int*, int*, int*, int*, idxtype*);
49  int*, int*, int*, int*, int*, idxtype*);
51  int*, int*, int*, int*, int*, idxtype*);
52 }
53 #endif
54 
55 using namespace std;
56 
57 namespace mfem
58 {
59 
60 void Mesh::GetElementJacobian(int i, DenseMatrix &J)
61 {
62  Geometry::Type geom = GetElementBaseGeometry(i);
63  ElementTransformation *eltransf = GetElementTransformation(i);
64  eltransf->SetIntPoint(&Geometries.GetCenter(geom));
65  Geometries.JacToPerfJac(geom, eltransf->Jacobian(), J);
66 }
67 
68 void Mesh::GetElementCenter(int i, Vector &center)
69 {
70  center.SetSize(spaceDim);
71  int geom = GetElementBaseGeometry(i);
72  ElementTransformation *eltransf = GetElementTransformation(i);
73  eltransf->Transform(Geometries.GetCenter(geom), center);
74 }
75 
76 double Mesh::GetElementSize(ElementTransformation *T, int type)
77 {
78  DenseMatrix J(spaceDim, Dim);
79 
80  Geometry::Type geom = T->GetGeometryType();
81  T->SetIntPoint(&Geometries.GetCenter(geom));
82  Geometries.JacToPerfJac(geom, T->Jacobian(), J);
83 
84  if (type == 0)
85  {
86  return pow(fabs(J.Weight()), 1./Dim);
87  }
88  else if (type == 1)
89  {
90  return J.CalcSingularvalue(Dim-1); // h_min
91  }
92  else
93  {
94  return J.CalcSingularvalue(0); // h_max
95  }
96 }
97 
98 double Mesh::GetElementSize(int i, int type)
99 {
100  return GetElementSize(GetElementTransformation(i), type);
101 }
102 
103 double Mesh::GetElementSize(int i, const Vector &dir)
104 {
105  DenseMatrix J(spaceDim, Dim);
106  Vector d_hat(Dim);
107  GetElementJacobian(i, J);
108  J.MultTranspose(dir, d_hat);
109  return sqrt((d_hat * d_hat) / (dir * dir));
110 }
111 
112 double Mesh::GetElementVolume(int i)
113 {
114  ElementTransformation *et = GetElementTransformation(i);
115  const IntegrationRule &ir = IntRules.Get(GetElementBaseGeometry(i),
116  et->OrderJ());
117  double volume = 0.0;
118  for (int j = 0; j < ir.GetNPoints(); j++)
119  {
120  const IntegrationPoint &ip = ir.IntPoint(j);
121  et->SetIntPoint(&ip);
122  volume += ip.weight * et->Weight();
123  }
124 
125  return volume;
126 }
127 
128 // Similar to VisualizationSceneSolution3d::FindNewBox in GLVis
129 void Mesh::GetBoundingBox(Vector &min, Vector &max, int ref)
130 {
131  min.SetSize(spaceDim);
132  max.SetSize(spaceDim);
133 
134  for (int d = 0; d < spaceDim; d++)
135  {
136  min(d) = infinity();
137  max(d) = -infinity();
138  }
139 
140  if (Nodes == NULL)
141  {
142  double *coord;
143  for (int i = 0; i < NumOfVertices; i++)
144  {
145  coord = GetVertex(i);
146  for (int d = 0; d < spaceDim; d++)
147  {
148  if (coord[d] < min(d)) { min(d) = coord[d]; }
149  if (coord[d] > max(d)) { max(d) = coord[d]; }
150  }
151  }
152  }
153  else
154  {
155  const bool use_boundary = false; // make this a parameter?
156  int ne = use_boundary ? GetNBE() : GetNE();
157  int fn, fo;
158  DenseMatrix pointmat;
159  RefinedGeometry *RefG;
160  IntegrationRule eir;
163 
164  for (int i = 0; i < ne; i++)
165  {
166  if (use_boundary)
167  {
168  GetBdrElementFace(i, &fn, &fo);
169  RefG = GlobGeometryRefiner.Refine(GetFaceBaseGeometry(fn), ref);
170  Tr = GetFaceElementTransformations(fn, 5);
171  eir.SetSize(RefG->RefPts.GetNPoints());
172  Tr->Loc1.Transform(RefG->RefPts, eir);
173  Tr->Elem1->Transform(eir, pointmat);
174  }
175  else
176  {
177  T = GetElementTransformation(i);
178  RefG = GlobGeometryRefiner.Refine(GetElementBaseGeometry(i), ref);
179  T->Transform(RefG->RefPts, pointmat);
180  }
181  for (int j = 0; j < pointmat.Width(); j++)
182  {
183  for (int d = 0; d < pointmat.Height(); d++)
184  {
185  if (pointmat(d,j) < min(d)) { min(d) = pointmat(d,j); }
186  if (pointmat(d,j) > max(d)) { max(d) = pointmat(d,j); }
187  }
188  }
189  }
190  }
191 }
192 
193 void Mesh::GetCharacteristics(double &h_min, double &h_max,
194  double &kappa_min, double &kappa_max,
195  Vector *Vh, Vector *Vk)
196 {
197  int i, dim, sdim;
198  DenseMatrix J;
199  double h, kappa;
200 
201  dim = Dimension();
202  sdim = SpaceDimension();
203 
204  if (Vh) { Vh->SetSize(NumOfElements); }
205  if (Vk) { Vk->SetSize(NumOfElements); }
206 
207  h_min = kappa_min = infinity();
208  h_max = kappa_max = -h_min;
209  if (dim == 0) { if (Vh) { *Vh = 1.0; } if (Vk) {*Vk = 1.0; } return; }
210  J.SetSize(sdim, dim);
211  for (i = 0; i < NumOfElements; i++)
212  {
213  GetElementJacobian(i, J);
214  h = pow(fabs(J.Weight()), 1.0/double(dim));
215  kappa = (dim == sdim) ?
216  J.CalcSingularvalue(0) / J.CalcSingularvalue(dim-1) : -1.0;
217  if (Vh) { (*Vh)(i) = h; }
218  if (Vk) { (*Vk)(i) = kappa; }
219 
220  if (h < h_min) { h_min = h; }
221  if (h > h_max) { h_max = h; }
222  if (kappa < kappa_min) { kappa_min = kappa; }
223  if (kappa > kappa_max) { kappa_max = kappa; }
224  }
225 }
226 
227 // static method
228 void Mesh::PrintElementsByGeometry(int dim,
229  const Array<int> &num_elems_by_geom,
230  std::ostream &os)
231 {
232  for (int g = Geometry::DimStart[dim], first = 1;
233  g < Geometry::DimStart[dim+1]; g++)
234  {
235  if (!num_elems_by_geom[g]) { continue; }
236  if (!first) { os << " + "; }
237  else { first = 0; }
238  os << num_elems_by_geom[g] << ' ' << Geometry::Name[g] << "(s)";
239  }
240 }
241 
242 void Mesh::PrintCharacteristics(Vector *Vh, Vector *Vk, std::ostream &os)
243 {
244  double h_min, h_max, kappa_min, kappa_max;
245 
246  os << "Mesh Characteristics:";
247 
248  this->GetCharacteristics(h_min, h_max, kappa_min, kappa_max, Vh, Vk);
249 
250  Array<int> num_elems_by_geom(Geometry::NumGeom);
251  num_elems_by_geom = 0;
252  for (int i = 0; i < GetNE(); i++)
253  {
254  num_elems_by_geom[GetElementBaseGeometry(i)]++;
255  }
256 
257  os << '\n'
258  << "Dimension : " << Dimension() << '\n'
259  << "Space dimension : " << SpaceDimension();
260  if (Dim == 0)
261  {
262  os << '\n'
263  << "Number of vertices : " << GetNV() << '\n'
264  << "Number of elements : " << GetNE() << '\n'
265  << "Number of bdr elem : " << GetNBE() << '\n';
266  }
267  else if (Dim == 1)
268  {
269  os << '\n'
270  << "Number of vertices : " << GetNV() << '\n'
271  << "Number of elements : " << GetNE() << '\n'
272  << "Number of bdr elem : " << GetNBE() << '\n'
273  << "h_min : " << h_min << '\n'
274  << "h_max : " << h_max << '\n';
275  }
276  else if (Dim == 2)
277  {
278  os << '\n'
279  << "Number of vertices : " << GetNV() << '\n'
280  << "Number of edges : " << GetNEdges() << '\n'
281  << "Number of elements : " << GetNE() << " -- ";
282  PrintElementsByGeometry(2, num_elems_by_geom, os);
283  os << '\n'
284  << "Number of bdr elem : " << GetNBE() << '\n'
285  << "Euler Number : " << EulerNumber2D() << '\n'
286  << "h_min : " << h_min << '\n'
287  << "h_max : " << h_max << '\n'
288  << "kappa_min : " << kappa_min << '\n'
289  << "kappa_max : " << kappa_max << '\n';
290  }
291  else
292  {
293  Array<int> num_bdr_elems_by_geom(Geometry::NumGeom);
294  num_bdr_elems_by_geom = 0;
295  for (int i = 0; i < GetNBE(); i++)
296  {
297  num_bdr_elems_by_geom[GetBdrElementBaseGeometry(i)]++;
298  }
299  Array<int> num_faces_by_geom(Geometry::NumGeom);
300  num_faces_by_geom = 0;
301  for (int i = 0; i < GetNFaces(); i++)
302  {
303  num_faces_by_geom[GetFaceBaseGeometry(i)]++;
304  }
305 
306  os << '\n'
307  << "Number of vertices : " << GetNV() << '\n'
308  << "Number of edges : " << GetNEdges() << '\n'
309  << "Number of faces : " << GetNFaces() << " -- ";
310  PrintElementsByGeometry(Dim-1, num_faces_by_geom, os);
311  os << '\n'
312  << "Number of elements : " << GetNE() << " -- ";
313  PrintElementsByGeometry(Dim, num_elems_by_geom, os);
314  os << '\n'
315  << "Number of bdr elem : " << GetNBE() << " -- ";
316  PrintElementsByGeometry(Dim-1, num_bdr_elems_by_geom, os);
317  os << '\n'
318  << "Euler Number : " << EulerNumber() << '\n'
319  << "h_min : " << h_min << '\n'
320  << "h_max : " << h_max << '\n'
321  << "kappa_min : " << kappa_min << '\n'
322  << "kappa_max : " << kappa_max << '\n';
323  }
324  os << '\n' << std::flush;
325 }
326 
327 FiniteElement *Mesh::GetTransformationFEforElementType(Element::Type ElemType)
328 {
329  switch (ElemType)
330  {
331  case Element::POINT : return &PointFE;
332  case Element::SEGMENT : return &SegmentFE;
333  case Element::TRIANGLE : return &TriangleFE;
334  case Element::QUADRILATERAL : return &QuadrilateralFE;
335  case Element::TETRAHEDRON : return &TetrahedronFE;
336  case Element::HEXAHEDRON : return &HexahedronFE;
337  case Element::WEDGE : return &WedgeFE;
338  case Element::PYRAMID : return &PyramidFE;
339  default:
340  MFEM_ABORT("Unknown element type \"" << ElemType << "\"");
341  break;
342  }
343  MFEM_ABORT("Unknown element type");
344  return NULL;
345 }
346 
347 
348 void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr)
349 {
350  ElTr->Attribute = GetAttribute(i);
351  ElTr->ElementNo = i;
352  ElTr->ElementType = ElementTransformation::ELEMENT;
353  ElTr->mesh = this;
354  ElTr->Reset();
355  if (Nodes == NULL)
356  {
357  GetPointMatrix(i, ElTr->GetPointMat());
358  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
359  }
360  else
361  {
362  DenseMatrix &pm = ElTr->GetPointMat();
363  Array<int> vdofs;
364  Nodes->FESpace()->GetElementVDofs(i, vdofs);
365  Nodes->HostRead();
366  const GridFunction &nodes = *Nodes;
367  int n = vdofs.Size()/spaceDim;
368  pm.SetSize(spaceDim, n);
369  for (int k = 0; k < spaceDim; k++)
370  {
371  for (int j = 0; j < n; j++)
372  {
373  pm(k,j) = nodes(vdofs[n*k+j]);
374  }
375  }
376  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
377  }
378 }
379 
380 void Mesh::GetElementTransformation(int i, const Vector &nodes,
382 {
383  ElTr->Attribute = GetAttribute(i);
384  ElTr->ElementNo = i;
385  ElTr->ElementType = ElementTransformation::ELEMENT;
386  ElTr->mesh = this;
387  DenseMatrix &pm = ElTr->GetPointMat();
388  ElTr->Reset();
389  nodes.HostRead();
390  if (Nodes == NULL)
391  {
392  MFEM_ASSERT(nodes.Size() == spaceDim*GetNV(), "");
393  int nv = elements[i]->GetNVertices();
394  const int *v = elements[i]->GetVertices();
395  int n = vertices.Size();
396  pm.SetSize(spaceDim, nv);
397  for (int k = 0; k < spaceDim; k++)
398  {
399  for (int j = 0; j < nv; j++)
400  {
401  pm(k, j) = nodes(k*n+v[j]);
402  }
403  }
404  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
405  }
406  else
407  {
408  MFEM_ASSERT(nodes.Size() == Nodes->Size(), "");
409  Array<int> vdofs;
410  Nodes->FESpace()->GetElementVDofs(i, vdofs);
411  int n = vdofs.Size()/spaceDim;
412  pm.SetSize(spaceDim, n);
413  for (int k = 0; k < spaceDim; k++)
414  {
415  for (int j = 0; j < n; j++)
416  {
417  pm(k,j) = nodes(vdofs[n*k+j]);
418  }
419  }
420  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
421  }
422 }
423 
424 ElementTransformation *Mesh::GetElementTransformation(int i)
425 {
426  GetElementTransformation(i, &Transformation);
427 
428  return &Transformation;
429 }
430 
431 ElementTransformation *Mesh::GetBdrElementTransformation(int i)
432 {
433  GetBdrElementTransformation(i, &BdrTransformation);
434  return &BdrTransformation;
435 }
436 
437 void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr)
438 {
439  ElTr->Attribute = GetBdrAttribute(i);
440  ElTr->ElementNo = i; // boundary element number
441  ElTr->ElementType = ElementTransformation::BDR_ELEMENT;
442  ElTr->mesh = this;
443  DenseMatrix &pm = ElTr->GetPointMat();
444  ElTr->Reset();
445  if (Nodes == NULL)
446  {
447  GetBdrPointMatrix(i, pm);
448  ElTr->SetFE(GetTransformationFEforElementType(GetBdrElementType(i)));
449  }
450  else
451  {
452  const FiniteElement *bdr_el = Nodes->FESpace()->GetBE(i);
453  Nodes->HostRead();
454  const GridFunction &nodes = *Nodes;
455  if (bdr_el)
456  {
457  Array<int> vdofs;
458  Nodes->FESpace()->GetBdrElementVDofs(i, vdofs);
459  int n = vdofs.Size()/spaceDim;
460  pm.SetSize(spaceDim, n);
461  for (int k = 0; k < spaceDim; k++)
462  {
463  for (int j = 0; j < n; j++)
464  {
465  pm(k,j) = nodes(vdofs[n*k+j]);
466  }
467  }
468  ElTr->SetFE(bdr_el);
469  }
470  else // L2 Nodes (e.g., periodic mesh)
471  {
472  int elem_id, face_info;
473  GetBdrElementAdjacentElement(i, elem_id, face_info);
474 
475  GetLocalFaceTransformation(GetBdrElementType(i),
476  GetElementType(elem_id),
477  FaceElemTr.Loc1.Transf, face_info);
478  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
479 
480  Geometry::Type face_geom = GetBdrElementBaseGeometry(i);
481  const FiniteElement *face_el =
482  Nodes->FESpace()->GetTraceElement(elem_id, face_geom);
483  MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
484  "Mesh requires nodal Finite Element.");
485  IntegrationRule eir(face_el->GetDof());
486  FaceElemTr.Loc1.Transf.ElementNo = elem_id;
487  FaceElemTr.Loc1.Transf.mesh = this;
488  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
489  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
490  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
491 
492  ElTr->SetFE(face_el);
493  }
494  }
495 }
496 
497 void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr)
498 {
499  FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute();
500  FTr->ElementNo = FaceNo;
501  FTr->ElementType = ElementTransformation::FACE;
502  FTr->mesh = this;
503  DenseMatrix &pm = FTr->GetPointMat();
504  FTr->Reset();
505  if (Nodes == NULL)
506  {
507  const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
508  const int nv = (Dim == 1) ? 1 : faces[FaceNo]->GetNVertices();
509  pm.SetSize(spaceDim, nv);
510  for (int i = 0; i < spaceDim; i++)
511  {
512  for (int j = 0; j < nv; j++)
513  {
514  pm(i, j) = vertices[v[j]](i);
515  }
516  }
517  FTr->SetFE(GetTransformationFEforElementType(GetFaceElementType(FaceNo)));
518  }
519  else // curved mesh
520  {
521  const FiniteElement *face_el = Nodes->FESpace()->GetFaceElement(FaceNo);
522  Nodes->HostRead();
523  const GridFunction &nodes = *Nodes;
524  if (face_el)
525  {
526  Array<int> vdofs;
527  Nodes->FESpace()->GetFaceVDofs(FaceNo, vdofs);
528  int n = vdofs.Size()/spaceDim;
529  pm.SetSize(spaceDim, n);
530  for (int i = 0; i < spaceDim; i++)
531  {
532  for (int j = 0; j < n; j++)
533  {
534  pm(i, j) = nodes(vdofs[n*i+j]);
535  }
536  }
537  FTr->SetFE(face_el);
538  }
539  else // L2 Nodes (e.g., periodic mesh), go through the volume of Elem1
540  {
541  FaceInfo &face_info = faces_info[FaceNo];
542 
543  Geometry::Type face_geom = GetFaceGeometryType(FaceNo);
544  Element::Type face_type = GetFaceElementType(FaceNo);
545 
546  GetLocalFaceTransformation(face_type,
547  GetElementType(face_info.Elem1No),
548  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
549  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
550 
551  face_el = Nodes->FESpace()->GetTraceElement(face_info.Elem1No,
552  face_geom);
553  MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
554  "Mesh requires nodal Finite Element.");
555 
556  IntegrationRule eir(face_el->GetDof());
557  FaceElemTr.Loc1.Transf.ElementNo = face_info.Elem1No;
558  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
559  FaceElemTr.Loc1.Transf.mesh = this;
560  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
561  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
562 
563  FTr->SetFE(face_el);
564  }
565  }
566 }
567 
568 ElementTransformation *Mesh::GetFaceTransformation(int FaceNo)
569 {
570  GetFaceTransformation(FaceNo, &FaceTransformation);
571  return &FaceTransformation;
572 }
573 
574 void Mesh::GetEdgeTransformation(int EdgeNo, IsoparametricTransformation *EdTr)
575 {
576  if (Dim == 2)
577  {
578  GetFaceTransformation(EdgeNo, EdTr);
579  return;
580  }
581  if (Dim == 1)
582  {
583  mfem_error("Mesh::GetEdgeTransformation not defined in 1D \n");
584  }
585 
586  EdTr->Attribute = 1;
587  EdTr->ElementNo = EdgeNo;
588  EdTr->ElementType = ElementTransformation::EDGE;
589  EdTr->mesh = this;
590  DenseMatrix &pm = EdTr->GetPointMat();
591  EdTr->Reset();
592  if (Nodes == NULL)
593  {
594  Array<int> v;
595  GetEdgeVertices(EdgeNo, v);
596  const int nv = 2;
597  pm.SetSize(spaceDim, nv);
598  for (int i = 0; i < spaceDim; i++)
599  {
600  for (int j = 0; j < nv; j++)
601  {
602  pm(i, j) = vertices[v[j]](i);
603  }
604  }
605  EdTr->SetFE(GetTransformationFEforElementType(Element::SEGMENT));
606  }
607  else
608  {
609  const FiniteElement *edge_el = Nodes->FESpace()->GetEdgeElement(EdgeNo);
610  Nodes->HostRead();
611  const GridFunction &nodes = *Nodes;
612  if (edge_el)
613  {
614  Array<int> vdofs;
615  Nodes->FESpace()->GetEdgeVDofs(EdgeNo, vdofs);
616  int n = vdofs.Size()/spaceDim;
617  pm.SetSize(spaceDim, n);
618  for (int i = 0; i < spaceDim; i++)
619  {
620  for (int j = 0; j < n; j++)
621  {
622  pm(i, j) = nodes(vdofs[n*i+j]);
623  }
624  }
625  EdTr->SetFE(edge_el);
626  }
627  else
628  {
629  MFEM_ABORT("Not implemented.");
630  }
631  }
632 }
633 
634 ElementTransformation *Mesh::GetEdgeTransformation(int EdgeNo)
635 {
636  GetEdgeTransformation(EdgeNo, &EdgeTransformation);
637  return &EdgeTransformation;
638 }
639 
640 
641 void Mesh::GetLocalPtToSegTransformation(
642  IsoparametricTransformation &Transf, int i)
643 {
644  const IntegrationRule *SegVert;
645  DenseMatrix &locpm = Transf.GetPointMat();
646  Transf.Reset();
647 
648  Transf.SetFE(&PointFE);
649  SegVert = Geometries.GetVertices(Geometry::SEGMENT);
650  locpm.SetSize(1, 1);
651  locpm(0, 0) = SegVert->IntPoint(i/64).x;
652  // (i/64) is the local face no. in the segment
653  // (i%64) is the orientation of the point (not used)
654 }
655 
656 void Mesh::GetLocalSegToTriTransformation(
657  IsoparametricTransformation &Transf, int i)
658 {
659  const int *tv, *so;
660  const IntegrationRule *TriVert;
661  DenseMatrix &locpm = Transf.GetPointMat();
662  Transf.Reset();
663 
664  Transf.SetFE(&SegmentFE);
665  tv = tri_t::Edges[i/64]; // (i/64) is the local face no. in the triangle
666  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
667  TriVert = Geometries.GetVertices(Geometry::TRIANGLE);
668  locpm.SetSize(2, 2);
669  for (int j = 0; j < 2; j++)
670  {
671  locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x;
672  locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y;
673  }
674 }
675 
676 void Mesh::GetLocalSegToQuadTransformation(
677  IsoparametricTransformation &Transf, int i)
678 {
679  const int *qv, *so;
680  const IntegrationRule *QuadVert;
681  DenseMatrix &locpm = Transf.GetPointMat();
682  Transf.Reset();
683 
684  Transf.SetFE(&SegmentFE);
685  qv = quad_t::Edges[i/64]; // (i/64) is the local face no. in the quad
686  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
687  QuadVert = Geometries.GetVertices(Geometry::SQUARE);
688  locpm.SetSize(2, 2);
689  for (int j = 0; j < 2; j++)
690  {
691  locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x;
692  locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y;
693  }
694 }
695 
696 void Mesh::GetLocalTriToTetTransformation(
697  IsoparametricTransformation &Transf, int i)
698 {
699  DenseMatrix &locpm = Transf.GetPointMat();
700  Transf.Reset();
701 
702  Transf.SetFE(&TriangleFE);
703  // (i/64) is the local face no. in the tet
704  const int *tv = tet_t::FaceVert[i/64];
705  // (i%64) is the orientation of the tetrahedron face
706  // w.r.t. the face element
707  const int *to = tri_t::Orient[i%64];
708  const IntegrationRule *TetVert =
709  Geometries.GetVertices(Geometry::TETRAHEDRON);
710  locpm.SetSize(3, 3);
711  for (int j = 0; j < 3; j++)
712  {
713  const IntegrationPoint &vert = TetVert->IntPoint(tv[to[j]]);
714  locpm(0, j) = vert.x;
715  locpm(1, j) = vert.y;
716  locpm(2, j) = vert.z;
717  }
718 }
719 
720 void Mesh::GetLocalTriToWdgTransformation(
721  IsoparametricTransformation &Transf, int i)
722 {
723  DenseMatrix &locpm = Transf.GetPointMat();
724  Transf.Reset();
725 
726  Transf.SetFE(&TriangleFE);
727  // (i/64) is the local face no. in the pri
728  MFEM_VERIFY(i < 128, "Local face index " << i/64
729  << " is not a triangular face of a wedge.");
730  const int *pv = pri_t::FaceVert[i/64];
731  // (i%64) is the orientation of the wedge face
732  // w.r.t. the face element
733  const int *to = tri_t::Orient[i%64];
734  const IntegrationRule *PriVert =
735  Geometries.GetVertices(Geometry::PRISM);
736  locpm.SetSize(3, 3);
737  for (int j = 0; j < 3; j++)
738  {
739  const IntegrationPoint &vert = PriVert->IntPoint(pv[to[j]]);
740  locpm(0, j) = vert.x;
741  locpm(1, j) = vert.y;
742  locpm(2, j) = vert.z;
743  }
744 }
745 
746 void Mesh::GetLocalTriToPyrTransformation(
747  IsoparametricTransformation &Transf, int i)
748 {
749  DenseMatrix &locpm = Transf.GetPointMat();
750 
751  Transf.SetFE(&TriangleFE);
752  // (i/64) is the local face no. in the pyr
753  MFEM_VERIFY(i >= 64, "Local face index " << i/64
754  << " is not a triangular face of a pyramid.");
755  const int *pv = pyr_t::FaceVert[i/64];
756  // (i%64) is the orientation of the pyramid face
757  // w.r.t. the face element
758  const int *to = tri_t::Orient[i%64];
759  const IntegrationRule *PyrVert =
760  Geometries.GetVertices(Geometry::PYRAMID);
761  locpm.SetSize(3, 3);
762  for (int j = 0; j < 3; j++)
763  {
764  const IntegrationPoint &vert = PyrVert->IntPoint(pv[to[j]]);
765  locpm(0, j) = vert.x;
766  locpm(1, j) = vert.y;
767  locpm(2, j) = vert.z;
768  }
769 }
770 
771 void Mesh::GetLocalQuadToHexTransformation(
772  IsoparametricTransformation &Transf, int i)
773 {
774  DenseMatrix &locpm = Transf.GetPointMat();
775  Transf.Reset();
776 
777  Transf.SetFE(&QuadrilateralFE);
778  // (i/64) is the local face no. in the hex
779  const int *hv = hex_t::FaceVert[i/64];
780  // (i%64) is the orientation of the quad
781  const int *qo = quad_t::Orient[i%64];
782  const IntegrationRule *HexVert = Geometries.GetVertices(Geometry::CUBE);
783  locpm.SetSize(3, 4);
784  for (int j = 0; j < 4; j++)
785  {
786  const IntegrationPoint &vert = HexVert->IntPoint(hv[qo[j]]);
787  locpm(0, j) = vert.x;
788  locpm(1, j) = vert.y;
789  locpm(2, j) = vert.z;
790  }
791 }
792 
793 void Mesh::GetLocalQuadToWdgTransformation(
794  IsoparametricTransformation &Transf, int i)
795 {
796  DenseMatrix &locpm = Transf.GetPointMat();
797  Transf.Reset();
798 
799  Transf.SetFE(&QuadrilateralFE);
800  // (i/64) is the local face no. in the pri
801  MFEM_VERIFY(i >= 128, "Local face index " << i/64
802  << " is not a quadrilateral face of a wedge.");
803  const int *pv = pri_t::FaceVert[i/64];
804  // (i%64) is the orientation of the quad
805  const int *qo = quad_t::Orient[i%64];
806  const IntegrationRule *PriVert = Geometries.GetVertices(Geometry::PRISM);
807  locpm.SetSize(3, 4);
808  for (int j = 0; j < 4; j++)
809  {
810  const IntegrationPoint &vert = PriVert->IntPoint(pv[qo[j]]);
811  locpm(0, j) = vert.x;
812  locpm(1, j) = vert.y;
813  locpm(2, j) = vert.z;
814  }
815 }
816 
817 void Mesh::GetLocalQuadToPyrTransformation(
818  IsoparametricTransformation &Transf, int i)
819 {
820  DenseMatrix &locpm = Transf.GetPointMat();
821 
822  Transf.SetFE(&QuadrilateralFE);
823  // (i/64) is the local face no. in the pyr
824  MFEM_VERIFY(i < 64, "Local face index " << i/64
825  << " is not a quadrilateral face of a pyramid.");
826  const int *pv = pyr_t::FaceVert[i/64];
827  // (i%64) is the orientation of the quad
828  const int *qo = quad_t::Orient[i%64];
829  const IntegrationRule *PyrVert = Geometries.GetVertices(Geometry::PYRAMID);
830  locpm.SetSize(3, 4);
831  for (int j = 0; j < 4; j++)
832  {
833  const IntegrationPoint &vert = PyrVert->IntPoint(pv[qo[j]]);
834  locpm(0, j) = vert.x;
835  locpm(1, j) = vert.y;
836  locpm(2, j) = vert.z;
837  }
838 }
839 
840 const GeometricFactors* Mesh::GetGeometricFactors(const IntegrationRule& ir,
841  const int flags,
842  MemoryType d_mt)
843 {
844  for (int i = 0; i < geom_factors.Size(); i++)
845  {
846  GeometricFactors *gf = geom_factors[i];
847  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags)
848  {
849  return gf;
850  }
851  }
852 
853  this->EnsureNodes();
854 
855  GeometricFactors *gf = new GeometricFactors(this, ir, flags, d_mt);
856  geom_factors.Append(gf);
857  return gf;
858 }
859 
860 const FaceGeometricFactors* Mesh::GetFaceGeometricFactors(
861  const IntegrationRule& ir,
862  const int flags, FaceType type)
863 {
864  for (int i = 0; i < face_geom_factors.Size(); i++)
865  {
866  FaceGeometricFactors *gf = face_geom_factors[i];
867  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags &&
868  gf->type==type)
869  {
870  return gf;
871  }
872  }
873 
874  this->EnsureNodes();
875 
876  FaceGeometricFactors *gf = new FaceGeometricFactors(this, ir, flags, type);
877  face_geom_factors.Append(gf);
878  return gf;
879 }
880 
881 void Mesh::DeleteGeometricFactors()
882 {
883  for (int i = 0; i < geom_factors.Size(); i++)
884  {
885  delete geom_factors[i];
886  }
887  geom_factors.SetSize(0);
888  for (int i = 0; i < face_geom_factors.Size(); i++)
889  {
890  delete face_geom_factors[i];
891  }
892  face_geom_factors.SetSize(0);
893 }
894 
895 void Mesh::GetLocalFaceTransformation(
896  int face_type, int elem_type, IsoparametricTransformation &Transf, int info)
897 {
898  switch (face_type)
899  {
900  case Element::POINT:
901  GetLocalPtToSegTransformation(Transf, info);
902  break;
903 
904  case Element::SEGMENT:
905  if (elem_type == Element::TRIANGLE)
906  {
907  GetLocalSegToTriTransformation(Transf, info);
908  }
909  else
910  {
911  MFEM_ASSERT(elem_type == Element::QUADRILATERAL, "");
912  GetLocalSegToQuadTransformation(Transf, info);
913  }
914  break;
915 
916  case Element::TRIANGLE:
917  if (elem_type == Element::TETRAHEDRON)
918  {
919  GetLocalTriToTetTransformation(Transf, info);
920  }
921  else if (elem_type == Element::WEDGE)
922  {
923  GetLocalTriToWdgTransformation(Transf, info);
924  }
925  else if (elem_type == Element::PYRAMID)
926  {
927  GetLocalTriToPyrTransformation(Transf, info);
928  }
929  else
930  {
931  MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
932  "face type " << face_type
933  << " and element type " << elem_type << "\n");
934  }
935  break;
936 
937  case Element::QUADRILATERAL:
938  if (elem_type == Element::HEXAHEDRON)
939  {
940  GetLocalQuadToHexTransformation(Transf, info);
941  }
942  else if (elem_type == Element::WEDGE)
943  {
944  GetLocalQuadToWdgTransformation(Transf, info);
945  }
946  else if (elem_type == Element::PYRAMID)
947  {
948  GetLocalQuadToPyrTransformation(Transf, info);
949  }
950  else
951  {
952  MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
953  "face type " << face_type
954  << " and element type " << elem_type << "\n");
955  }
956  break;
957  }
958 }
959 
960 FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo,
961  int mask)
962 {
963  FaceInfo &face_info = faces_info[FaceNo];
964 
965  int cmask = 0;
966  FaceElemTr.SetConfigurationMask(cmask);
967  FaceElemTr.Elem1 = NULL;
968  FaceElemTr.Elem2 = NULL;
969 
970  // setup the transformation for the first element
971  FaceElemTr.Elem1No = face_info.Elem1No;
972  if (mask & FaceElementTransformations::HAVE_ELEM1)
973  {
974  GetElementTransformation(FaceElemTr.Elem1No, &Transformation);
975  FaceElemTr.Elem1 = &Transformation;
976  cmask |= 1;
977  }
978 
979  // setup the transformation for the second element
980  // return NULL in the Elem2 field if there's no second element, i.e.
981  // the face is on the "boundary"
982  FaceElemTr.Elem2No = face_info.Elem2No;
983  if ((mask & FaceElementTransformations::HAVE_ELEM2) &&
984  FaceElemTr.Elem2No >= 0)
985  {
986 #ifdef MFEM_DEBUG
987  if (NURBSext && (mask & FaceElementTransformations::HAVE_ELEM1))
988  { MFEM_ABORT("NURBS mesh not supported!"); }
989 #endif
990  GetElementTransformation(FaceElemTr.Elem2No, &Transformation2);
991  FaceElemTr.Elem2 = &Transformation2;
992  cmask |= 2;
993  }
994 
995  // setup the face transformation
996  if (mask & FaceElementTransformations::HAVE_FACE)
997  {
998  GetFaceTransformation(FaceNo, &FaceElemTr);
999  cmask |= 16;
1000  }
1001  else
1002  {
1003  FaceElemTr.SetGeometryType(GetFaceGeometryType(FaceNo));
1004  }
1005 
1006  // setup Loc1 & Loc2
1007  int face_type = GetFaceElementType(FaceNo);
1008  if (mask & FaceElementTransformations::HAVE_LOC1)
1009  {
1010  int elem_type = GetElementType(face_info.Elem1No);
1011  GetLocalFaceTransformation(face_type, elem_type,
1012  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
1013  cmask |= 4;
1014  }
1015  if ((mask & FaceElementTransformations::HAVE_LOC2) &&
1016  FaceElemTr.Elem2No >= 0)
1017  {
1018  int elem_type = GetElementType(face_info.Elem2No);
1019  GetLocalFaceTransformation(face_type, elem_type,
1020  FaceElemTr.Loc2.Transf, face_info.Elem2Inf);
1021 
1022  // NC meshes: prepend slave edge/face transformation to Loc2
1023  if (Nonconforming() && IsSlaveFace(face_info))
1024  {
1025  ApplyLocalSlaveTransformation(FaceElemTr, face_info, false);
1026  }
1027  cmask |= 8;
1028  }
1029 
1030  FaceElemTr.SetConfigurationMask(cmask);
1031 
1032  // This check can be useful for internal debugging, however it will fail on
1033  // periodic boundary faces, so we keep it disabled in general.
1034 #if 0
1035 #ifdef MFEM_DEBUG
1036  double dist = FaceElemTr.CheckConsistency();
1037  if (dist >= 1e-12)
1038  {
1039  mfem::out << "\nInternal error: face id = " << FaceNo
1040  << ", dist = " << dist << '\n';
1041  FaceElemTr.CheckConsistency(1); // print coordinates
1042  MFEM_ABORT("internal error");
1043  }
1044 #endif
1045 #endif
1046 
1047  return &FaceElemTr;
1048 }
1049 
1050 bool Mesh::IsSlaveFace(const FaceInfo &fi) const
1051 {
1052  return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
1053 }
1054 
1055 void Mesh::ApplyLocalSlaveTransformation(FaceElementTransformations &FT,
1056  const FaceInfo &fi, bool is_ghost)
1057 {
1058 #ifdef MFEM_THREAD_SAFE
1059  DenseMatrix composition;
1060 #else
1061  static DenseMatrix composition;
1062 #endif
1063  MFEM_ASSERT(fi.NCFace >= 0, "");
1064  MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error");
1065  if (!is_ghost)
1066  {
1067  // side 1 -> child side, side 2 -> parent side
1069  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1070  // In 2D, we need to flip the point matrix since it is aligned with the
1071  // parent side.
1072  if (Dim == 2)
1073  {
1074  // swap points (columns) 0 and 1
1075  std::swap(composition(0,0), composition(0,1));
1076  std::swap(composition(1,0), composition(1,1));
1077  }
1078  LT.SetPointMat(composition);
1079  }
1080  else // is_ghost == true
1081  {
1082  // side 1 -> parent side, side 2 -> child side
1084  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1085  // In 2D, there is no need to flip the point matrix since it is already
1086  // aligned with the parent side, see also ParNCMesh::GetFaceNeighbors.
1087  // In 3D the point matrix was flipped during construction in
1088  // ParNCMesh::GetFaceNeighbors and due to that it is already aligned with
1089  // the parent side.
1090  LT.SetPointMat(composition);
1091  }
1092 }
1093 
1094 FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
1095 {
1097  int fn = GetBdrFace(BdrElemNo);
1098 
1099  // Check if the face is interior, shared, or nonconforming.
1100  if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
1101  {
1102  return NULL;
1103  }
1104  tr = GetFaceElementTransformations(fn, 21);
1105  tr->Attribute = boundary[BdrElemNo]->GetAttribute();
1106  tr->ElementNo = BdrElemNo;
1107  tr->ElementType = ElementTransformation::BDR_FACE;
1108  tr->mesh = this;
1109  return tr;
1110 }
1111 
1112 int Mesh::GetBdrFace(int BdrElemNo) const
1113 {
1114  int fn;
1115  if (Dim == 3)
1116  {
1117  fn = be_to_face[BdrElemNo];
1118  }
1119  else if (Dim == 2)
1120  {
1121  fn = be_to_edge[BdrElemNo];
1122  }
1123  else
1124  {
1125  fn = boundary[BdrElemNo]->GetVertices()[0];
1126  }
1127  return fn;
1128 }
1129 
1130 Mesh::FaceInformation Mesh::GetFaceInformation(int f) const
1131 {
1132  FaceInformation face;
1133  int e1, e2;
1134  int inf1, inf2;
1135  int ncface;
1136  GetFaceElements(f, &e1, &e2);
1137  GetFaceInfos(f, &inf1, &inf2, &ncface);
1138  face.element[0].index = e1;
1139  face.element[0].location = ElementLocation::Local;
1140  face.element[0].orientation = inf1%64;
1141  face.element[0].local_face_id = inf1/64;
1142  face.element[1].local_face_id = inf2/64;
1143  face.ncface = ncface;
1144  face.point_matrix = nullptr;
1145  // The following figures out face.location, face.conformity,
1146  // face.element[1].index, and face.element[1].orientation.
1147  if (f < GetNumFaces()) // Non-ghost face
1148  {
1149  if (e2>=0)
1150  {
1151  if (ncface==-1)
1152  {
1153  face.tag = FaceInfoTag::LocalConforming;
1154  face.topology = FaceTopology::Conforming;
1155  face.element[1].location = ElementLocation::Local;
1156  face.element[0].conformity = ElementConformity::Coincident;
1157  face.element[1].conformity = ElementConformity::Coincident;
1158  face.element[1].index = e2;
1159  face.element[1].orientation = inf2%64;
1160  }
1161  else // ncface >= 0
1162  {
1163  face.tag = FaceInfoTag::LocalSlaveNonconforming;
1164  face.topology = FaceTopology::Nonconforming;
1165  face.element[1].location = ElementLocation::Local;
1166  face.element[0].conformity = ElementConformity::Coincident;
1167  face.element[1].conformity = ElementConformity::Superset;
1168  face.element[1].index = e2;
1169  MFEM_ASSERT(inf2%64==0, "unexpected slave face orientation.");
1170  face.element[1].orientation = inf2%64;
1171  face.point_matrix = nc_faces_info[ncface].PointMatrix;
1172  }
1173  }
1174  else // e2<0
1175  {
1176  if (ncface==-1)
1177  {
1178  if (inf2<0)
1179  {
1180  face.tag = FaceInfoTag::Boundary;
1181  face.topology = FaceTopology::Boundary;
1182  face.element[1].location = ElementLocation::NA;
1183  face.element[0].conformity = ElementConformity::Coincident;
1184  face.element[1].conformity = ElementConformity::NA;
1185  face.element[1].index = -1;
1186  face.element[1].orientation = -1;
1187  }
1188  else // inf2 >= 0
1189  {
1190  face.tag = FaceInfoTag::SharedConforming;
1191  face.topology = FaceTopology::Conforming;
1192  face.element[0].conformity = ElementConformity::Coincident;
1193  face.element[1].conformity = ElementConformity::Coincident;
1194  face.element[1].location = ElementLocation::FaceNbr;
1195  face.element[1].index = -1 - e2;
1196  face.element[1].orientation = inf2%64;
1197  }
1198  }
1199  else // ncface >= 0
1200  {
1201  if (inf2 < 0)
1202  {
1203  face.tag = FaceInfoTag::MasterNonconforming;
1204  face.topology = FaceTopology::Nonconforming;
1205  face.element[1].location = ElementLocation::NA;
1206  face.element[0].conformity = ElementConformity::Coincident;
1207  face.element[1].conformity = ElementConformity::Subset;
1208  face.element[1].index = -1;
1209  face.element[1].orientation = -1;
1210  }
1211  else
1212  {
1213  face.tag = FaceInfoTag::SharedSlaveNonconforming;
1214  face.topology = FaceTopology::Nonconforming;
1215  face.element[1].location = ElementLocation::FaceNbr;
1216  face.element[0].conformity = ElementConformity::Coincident;
1217  face.element[1].conformity = ElementConformity::Superset;
1218  face.element[1].index = -1 - e2;
1219  face.element[1].orientation = inf2%64;
1220  }
1221  face.point_matrix = nc_faces_info[ncface].PointMatrix;
1222  }
1223  }
1224  }
1225  else // Ghost face
1226  {
1227  if (e1==-1)
1228  {
1229  face.tag = FaceInfoTag::GhostMaster;
1230  face.topology = FaceTopology::NA;
1231  face.element[1].location = ElementLocation::NA;
1232  face.element[0].conformity = ElementConformity::NA;
1233  face.element[1].conformity = ElementConformity::NA;
1234  face.element[1].index = -1;
1235  face.element[1].orientation = -1;
1236  }
1237  else
1238  {
1239  face.tag = FaceInfoTag::GhostSlave;
1240  face.topology = FaceTopology::Nonconforming;
1241  face.element[1].location = ElementLocation::FaceNbr;
1242  face.element[0].conformity = ElementConformity::Superset;
1243  face.element[1].conformity = ElementConformity::Coincident;
1244  face.element[1].index = -1 - e2;
1245  face.element[1].orientation = inf2%64;
1246  face.point_matrix = nc_faces_info[ncface].PointMatrix;
1247  }
1248  }
1249  return face;
1250 }
1251 
1252 Mesh::FaceInformation::operator Mesh::FaceInfo() const
1253 {
1254  FaceInfo res {-1, -1, -1, -1, -1};
1255  switch (tag)
1256  {
1257  case FaceInfoTag::LocalConforming:
1258  res.Elem1No = element[0].index;
1259  res.Elem2No = element[1].index;
1260  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1261  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1262  res.NCFace = ncface;
1263  break;
1264  case FaceInfoTag::LocalSlaveNonconforming:
1265  res.Elem1No = element[0].index;
1266  res.Elem2No = element[1].index;
1267  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1268  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1269  res.NCFace = ncface;
1270  break;
1271  case FaceInfoTag::Boundary:
1272  res.Elem1No = element[0].index;
1273  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1274  break;
1275  case FaceInfoTag::SharedConforming:
1276  res.Elem1No = element[0].index;
1277  res.Elem2No = -1 - element[1].index;
1278  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1279  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1280  break;
1281  case FaceInfoTag::MasterNonconforming:
1282  res.Elem1No = element[0].index;
1283  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1284  break;
1285  case FaceInfoTag::SharedSlaveNonconforming:
1286  res.Elem1No = element[0].index;
1287  res.Elem2No = -1 - element[1].index;
1288  res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1289  res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1290  break;
1291  case FaceInfoTag::GhostMaster:
1292  break;
1293  case FaceInfoTag::GhostSlave:
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  }
1300  return res;
1301 }
1302 
1303 std::ostream& operator<<(std::ostream& os, const Mesh::FaceInformation& info)
1304 {
1305  os << "face topology=";
1306  switch (info.topology)
1307  {
1308  case Mesh::FaceTopology::Boundary:
1309  os << "Boundary";
1310  break;
1311  case Mesh::FaceTopology::Conforming:
1312  os << "Conforming";
1313  break;
1314  case Mesh::FaceTopology::Nonconforming:
1315  os << "Non-conforming";
1316  break;
1317  case Mesh::FaceTopology::NA:
1318  os << "NA";
1319  break;
1320  }
1321  os << "element[0].location=";
1322  switch (info.element[0].location)
1323  {
1324  case Mesh::ElementLocation::Local:
1325  os << "Local";
1326  break;
1327  case Mesh::ElementLocation::FaceNbr:
1328  os << "FaceNbr";
1329  break;
1330  case Mesh::ElementLocation::NA:
1331  os << "NA";
1332  break;
1333  }
1334  os << std::endl;
1335  os << "element[1].location=";
1336  switch (info.element[1].location)
1337  {
1338  case Mesh::ElementLocation::Local:
1339  os << "Local";
1340  break;
1341  case Mesh::ElementLocation::FaceNbr:
1342  os << "FaceNbr";
1343  break;
1344  case Mesh::ElementLocation::NA:
1345  os << "NA";
1346  break;
1347  }
1348  os << std::endl;
1349  os << "element[0].conformity=";
1350  switch (info.element[0].conformity)
1351  {
1352  case Mesh::ElementConformity::Coincident:
1353  os << "Coincident";
1354  break;
1355  case Mesh::ElementConformity::Superset:
1356  os << "Superset";
1357  break;
1358  case Mesh::ElementConformity::Subset:
1359  os << "Subset";
1360  break;
1361  case Mesh::ElementConformity::NA:
1362  os << "NA";
1363  break;
1364  }
1365  os << std::endl;
1366  os << "element[1].conformity=";
1367  switch (info.element[1].conformity)
1368  {
1369  case Mesh::ElementConformity::Coincident:
1370  os << "Coincident";
1371  break;
1372  case Mesh::ElementConformity::Superset:
1373  os << "Superset";
1374  break;
1375  case Mesh::ElementConformity::Subset:
1376  os << "Subset";
1377  break;
1378  case Mesh::ElementConformity::NA:
1379  os << "NA";
1380  break;
1381  }
1382  os << std::endl;
1383  os << "element[0].index=" << info.element[0].index << std::endl
1384  << "element[1].index=" << info.element[1].index << std::endl
1385  << "element[0].local_face_id=" << info.element[0].local_face_id << std::endl
1386  << "element[1].local_face_id=" << info.element[1].local_face_id << std::endl
1387  << "element[0].orientation=" << info.element[0].orientation << std::endl
1388  << "element[1].orientation=" << info.element[1].orientation << std::endl
1389  << "ncface=" << info.ncface << std::endl;
1390  return os;
1391 }
1392 
1393 void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2) const
1394 {
1395  *Elem1 = faces_info[Face].Elem1No;
1396  *Elem2 = faces_info[Face].Elem2No;
1397 }
1398 
1399 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const
1400 {
1401  *Inf1 = faces_info[Face].Elem1Inf;
1402  *Inf2 = faces_info[Face].Elem2Inf;
1403 }
1404 
1405 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2, int *NCFace) const
1406 {
1407  *Inf1 = faces_info[Face].Elem1Inf;
1408  *Inf2 = faces_info[Face].Elem2Inf;
1409  *NCFace = faces_info[Face].NCFace;
1410 }
1411 
1412 Geometry::Type Mesh::GetFaceGeometryType(int Face) const
1413 {
1414  switch (Dim)
1415  {
1416  case 1: return Geometry::POINT;
1417  case 2: return Geometry::SEGMENT;
1418  case 3:
1419  if (Face < NumOfFaces) // local (non-ghost) face
1420  {
1421  return faces[Face]->GetGeometryType();
1422  }
1423  // ghost face
1424  const int nc_face_id = faces_info[Face].NCFace;
1425  MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported");
1426  return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType();
1427  }
1428  return Geometry::INVALID;
1429 }
1430 
1431 Element::Type Mesh::GetFaceElementType(int Face) const
1432 {
1433  return (Dim == 1) ? Element::POINT : faces[Face]->GetType();
1434 }
1435 
1436 void Mesh::Init()
1437 {
1438  // in order of declaration:
1439  Dim = spaceDim = 0;
1440  NumOfVertices = -1;
1441  NumOfElements = NumOfBdrElements = 0;
1442  NumOfEdges = NumOfFaces = 0;
1443  nbInteriorFaces = -1;
1444  nbBoundaryFaces = -1;
1445  meshgen = mesh_geoms = 0;
1446  sequence = 0;
1447  Nodes = NULL;
1448  own_nodes = 1;
1449  NURBSext = NULL;
1450  ncmesh = NULL;
1451  last_operation = Mesh::NONE;
1452 }
1453 
1454 void Mesh::InitTables()
1455 {
1456  el_to_edge =
1457  el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
1458 }
1459 
1460 void Mesh::SetEmpty()
1461 {
1462  Init();
1463  InitTables();
1464 }
1465 
1466 void Mesh::DestroyTables()
1467 {
1468  delete el_to_edge;
1469  delete el_to_face;
1470  delete el_to_el;
1471  DeleteGeometricFactors();
1472 
1473  if (Dim == 3)
1474  {
1475  delete bel_to_edge;
1476  }
1477 
1478  delete face_edge;
1479  delete edge_vertex;
1480 }
1481 
1482 void Mesh::DestroyPointers()
1483 {
1484  if (own_nodes) { delete Nodes; }
1485 
1486  delete ncmesh;
1487 
1488  delete NURBSext;
1489 
1490  for (int i = 0; i < NumOfElements; i++)
1491  {
1492  FreeElement(elements[i]);
1493  }
1494 
1495  for (int i = 0; i < NumOfBdrElements; i++)
1496  {
1497  FreeElement(boundary[i]);
1498  }
1499 
1500  for (int i = 0; i < faces.Size(); i++)
1501  {
1502  FreeElement(faces[i]);
1503  }
1504 
1505  DestroyTables();
1506 }
1507 
1508 void Mesh::Destroy()
1509 {
1510  DestroyPointers();
1511 
1512  elements.DeleteAll();
1513  vertices.DeleteAll();
1514  boundary.DeleteAll();
1515  faces.DeleteAll();
1516  faces_info.DeleteAll();
1517  nc_faces_info.DeleteAll();
1518  be_to_edge.DeleteAll();
1519  be_to_face.DeleteAll();
1520 
1521  // TODO:
1522  // IsoparametricTransformations
1523  // Transformation, Transformation2, BdrTransformation, FaceTransformation,
1524  // EdgeTransformation;
1525  // FaceElementTransformations FaceElemTr;
1526 
1527  CoarseFineTr.Clear();
1528 
1529 #ifdef MFEM_USE_MEMALLOC
1530  TetMemory.Clear();
1531 #endif
1532 
1533  attributes.DeleteAll();
1534  bdr_attributes.DeleteAll();
1535 }
1536 
1537 void Mesh::ResetLazyData()
1538 {
1539  delete el_to_el; el_to_el = NULL;
1540  delete face_edge; face_edge = NULL;
1541  delete edge_vertex; edge_vertex = NULL;
1542  DeleteGeometricFactors();
1543  nbInteriorFaces = -1;
1544  nbBoundaryFaces = -1;
1545 }
1546 
1547 void Mesh::SetAttributes()
1548 {
1549  Array<int> attribs;
1550 
1551  attribs.SetSize(GetNBE());
1552  for (int i = 0; i < attribs.Size(); i++)
1553  {
1554  attribs[i] = GetBdrAttribute(i);
1555  }
1556  attribs.Sort();
1557  attribs.Unique();
1558  attribs.Copy(bdr_attributes);
1559  if (bdr_attributes.Size() > 0 && bdr_attributes[0] <= 0)
1560  {
1561  MFEM_WARNING("Non-positive attributes on the boundary!");
1562  }
1563 
1564  attribs.SetSize(GetNE());
1565  for (int i = 0; i < attribs.Size(); i++)
1566  {
1567  attribs[i] = GetAttribute(i);
1568  }
1569  attribs.Sort();
1570  attribs.Unique();
1571  attribs.Copy(attributes);
1572  if (attributes.Size() > 0 && attributes[0] <= 0)
1573  {
1574  MFEM_WARNING("Non-positive attributes in the domain!");
1575  }
1576 }
1577 
1578 void Mesh::InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
1579 {
1580  SetEmpty();
1581 
1582  Dim = Dim_;
1583  spaceDim = spaceDim_;
1584 
1585  NumOfVertices = 0;
1586  vertices.SetSize(NVert); // just allocate space for vertices
1587 
1588  NumOfElements = 0;
1589  elements.SetSize(NElem); // just allocate space for Element *
1590 
1591  NumOfBdrElements = 0;
1592  boundary.SetSize(NBdrElem); // just allocate space for Element *
1593 }
1594 
1595 template<typename T>
1596 static void CheckEnlarge(Array<T> &array, int size)
1597 {
1598  if (size >= array.Size()) { array.SetSize(size + 1); }
1599 }
1600 
1601 int Mesh::AddVertex(double x, double y, double z)
1602 {
1603  CheckEnlarge(vertices, NumOfVertices);
1604  double *v = vertices[NumOfVertices]();
1605  v[0] = x;
1606  v[1] = y;
1607  v[2] = z;
1608  return NumOfVertices++;
1609 }
1610 
1611 int Mesh::AddVertex(const double *coords)
1612 {
1613  CheckEnlarge(vertices, NumOfVertices);
1614  vertices[NumOfVertices].SetCoords(spaceDim, coords);
1615  return NumOfVertices++;
1616 }
1617 
1618 void Mesh::AddVertexParents(int i, int p1, int p2)
1619 {
1620  tmp_vertex_parents.Append(Triple<int, int, int>(i, p1, p2));
1621 
1622  // if vertex coordinates are defined, make sure the hanging vertex has the
1623  // correct position
1624  if (i < vertices.Size())
1625  {
1626  double *vi = vertices[i](), *vp1 = vertices[p1](), *vp2 = vertices[p2]();
1627  for (int j = 0; j < 3; j++)
1628  {
1629  vi[j] = (vp1[j] + vp2[j]) * 0.5;
1630  }
1631  }
1632 }
1633 
1634 int Mesh::AddSegment(int v1, int v2, int attr)
1635 {
1636  CheckEnlarge(elements, NumOfElements);
1637  elements[NumOfElements] = new Segment(v1, v2, attr);
1638  return NumOfElements++;
1639 }
1640 
1641 int Mesh::AddSegment(const int *vi, int attr)
1642 {
1643  CheckEnlarge(elements, NumOfElements);
1644  elements[NumOfElements] = new Segment(vi, attr);
1645  return NumOfElements++;
1646 }
1647 
1648 int Mesh::AddTriangle(int v1, int v2, int v3, int attr)
1649 {
1650  CheckEnlarge(elements, NumOfElements);
1651  elements[NumOfElements] = new Triangle(v1, v2, v3, attr);
1652  return NumOfElements++;
1653 }
1654 
1655 int Mesh::AddTriangle(const int *vi, int attr)
1656 {
1657  CheckEnlarge(elements, NumOfElements);
1658  elements[NumOfElements] = new Triangle(vi, attr);
1659  return NumOfElements++;
1660 }
1661 
1662 int Mesh::AddQuad(int v1, int v2, int v3, int v4, int attr)
1663 {
1664  CheckEnlarge(elements, NumOfElements);
1665  elements[NumOfElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1666  return NumOfElements++;
1667 }
1668 
1669 int Mesh::AddQuad(const int *vi, int attr)
1670 {
1671  CheckEnlarge(elements, NumOfElements);
1672  elements[NumOfElements] = new Quadrilateral(vi, attr);
1673  return NumOfElements++;
1674 }
1675 
1676 int Mesh::AddTet(int v1, int v2, int v3, int v4, int attr)
1677 {
1678  int vi[4] = {v1, v2, v3, v4};
1679  return AddTet(vi, attr);
1680 }
1681 
1682 int Mesh::AddTet(const int *vi, int attr)
1683 {
1684  CheckEnlarge(elements, NumOfElements);
1685 #ifdef MFEM_USE_MEMALLOC
1686  Tetrahedron *tet;
1687  tet = TetMemory.Alloc();
1688  tet->SetVertices(vi);
1689  tet->SetAttribute(attr);
1690  elements[NumOfElements] = tet;
1691 #else
1692  elements[NumOfElements] = new Tetrahedron(vi, attr);
1693 #endif
1694  return NumOfElements++;
1695 }
1696 
1697 int Mesh::AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr)
1698 {
1699  CheckEnlarge(elements, NumOfElements);
1700  elements[NumOfElements] = new Wedge(v1, v2, v3, v4, v5, v6, attr);
1701  return NumOfElements++;
1702 }
1703 
1704 int Mesh::AddWedge(const int *vi, int attr)
1705 {
1706  CheckEnlarge(elements, NumOfElements);
1707  elements[NumOfElements] = new Wedge(vi, attr);
1708  return NumOfElements++;
1709 }
1710 
1711 int Mesh::AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr)
1712 {
1713  CheckEnlarge(elements, NumOfElements);
1714  elements[NumOfElements] = new Pyramid(v1, v2, v3, v4, v5, attr);
1715  return NumOfElements++;
1716 }
1717 
1718 int Mesh::AddPyramid(const int *vi, int attr)
1719 {
1720  CheckEnlarge(elements, NumOfElements);
1721  elements[NumOfElements] = new Pyramid(vi, attr);
1722  return NumOfElements++;
1723 }
1724 
1725 int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
1726  int attr)
1727 {
1728  CheckEnlarge(elements, NumOfElements);
1729  elements[NumOfElements] =
1730  new Hexahedron(v1, v2, v3, v4, v5, v6, v7, v8, attr);
1731  return NumOfElements++;
1732 }
1733 
1734 int Mesh::AddHex(const int *vi, int attr)
1735 {
1736  CheckEnlarge(elements, NumOfElements);
1737  elements[NumOfElements] = new Hexahedron(vi, attr);
1738  return NumOfElements++;
1739 }
1740 
1741 void Mesh::AddHexAsTets(const int *vi, int attr)
1742 {
1743  static const int hex_to_tet[6][4] =
1744  {
1745  { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
1746  { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
1747  };
1748  int ti[4];
1749 
1750  for (int i = 0; i < 6; i++)
1751  {
1752  for (int j = 0; j < 4; j++)
1753  {
1754  ti[j] = vi[hex_to_tet[i][j]];
1755  }
1756  AddTet(ti, attr);
1757  }
1758 }
1759 
1760 void Mesh::AddHexAsWedges(const int *vi, int attr)
1761 {
1762  static const int hex_to_wdg[2][6] =
1763  {
1764  { 0, 1, 2, 4, 5, 6 }, { 0, 2, 3, 4, 6, 7 }
1765  };
1766  int ti[6];
1767 
1768  for (int i = 0; i < 2; i++)
1769  {
1770  for (int j = 0; j < 6; j++)
1771  {
1772  ti[j] = vi[hex_to_wdg[i][j]];
1773  }
1774  AddWedge(ti, attr);
1775  }
1776 }
1777 
1778 void Mesh::AddHexAsPyramids(const int *vi, int attr)
1779 {
1780  static const int hex_to_pyr[6][5] =
1781  {
1782  { 0, 1, 2, 3, 8 }, { 0, 4, 5, 1, 8 }, { 1, 5, 6, 2, 8 },
1783  { 2, 6, 7, 3, 8 }, { 3, 7, 4, 0, 8 }, { 7, 6, 5, 4, 8 }
1784  };
1785  int ti[5];
1786 
1787  for (int i = 0; i < 6; i++)
1788  {
1789  for (int j = 0; j < 5; j++)
1790  {
1791  ti[j] = vi[hex_to_pyr[i][j]];
1792  }
1793  AddPyramid(ti, attr);
1794  }
1795 }
1796 
1797 int Mesh::AddElement(Element *elem)
1798 {
1799  CheckEnlarge(elements, NumOfElements);
1800  elements[NumOfElements] = elem;
1801  return NumOfElements++;
1802 }
1803 
1804 int Mesh::AddBdrElement(Element *elem)
1805 {
1806  CheckEnlarge(boundary, NumOfBdrElements);
1807  boundary[NumOfBdrElements] = elem;
1808  return NumOfBdrElements++;
1809 }
1810 
1811 int Mesh::AddBdrSegment(int v1, int v2, int attr)
1812 {
1813  CheckEnlarge(boundary, NumOfBdrElements);
1814  boundary[NumOfBdrElements] = new Segment(v1, v2, attr);
1815  return NumOfBdrElements++;
1816 }
1817 
1818 int Mesh::AddBdrSegment(const int *vi, int attr)
1819 {
1820  CheckEnlarge(boundary, NumOfBdrElements);
1821  boundary[NumOfBdrElements] = new Segment(vi, attr);
1822  return NumOfBdrElements++;
1823 }
1824 
1825 int Mesh::AddBdrTriangle(int v1, int v2, int v3, int attr)
1826 {
1827  CheckEnlarge(boundary, NumOfBdrElements);
1828  boundary[NumOfBdrElements] = new Triangle(v1, v2, v3, attr);
1829  return NumOfBdrElements++;
1830 }
1831 
1832 int Mesh::AddBdrTriangle(const int *vi, int attr)
1833 {
1834  CheckEnlarge(boundary, NumOfBdrElements);
1835  boundary[NumOfBdrElements] = new Triangle(vi, attr);
1836  return NumOfBdrElements++;
1837 }
1838 
1839 int Mesh::AddBdrQuad(int v1, int v2, int v3, int v4, int attr)
1840 {
1841  CheckEnlarge(boundary, NumOfBdrElements);
1842  boundary[NumOfBdrElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1843  return NumOfBdrElements++;
1844 }
1845 
1846 int Mesh::AddBdrQuad(const int *vi, int attr)
1847 {
1848  CheckEnlarge(boundary, NumOfBdrElements);
1849  boundary[NumOfBdrElements] = new Quadrilateral(vi, attr);
1850  return NumOfBdrElements++;
1851 }
1852 
1853 void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
1854 {
1855  static const int quad_to_tri[2][3] = { { 0, 1, 2 }, { 0, 2, 3 } };
1856  int ti[3];
1857 
1858  for (int i = 0; i < 2; i++)
1859  {
1860  for (int j = 0; j < 3; j++)
1861  {
1862  ti[j] = vi[quad_to_tri[i][j]];
1863  }
1864  AddBdrTriangle(ti, attr);
1865  }
1866 }
1867 
1868 int Mesh::AddBdrPoint(int v, int attr)
1869 {
1870  CheckEnlarge(boundary, NumOfBdrElements);
1871  boundary[NumOfBdrElements] = new Point(&v, attr);
1872  return NumOfBdrElements++;
1873 }
1874 
1875 void Mesh::GenerateBoundaryElements()
1876 {
1877  int i, j;
1878  Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
1879 
1880  // GenerateFaces();
1881 
1882  for (i = 0; i < boundary.Size(); i++)
1883  {
1884  FreeElement(boundary[i]);
1885  }
1886 
1887  if (Dim == 3)
1888  {
1889  delete bel_to_edge;
1890  bel_to_edge = NULL;
1891  }
1892 
1893  // count the 'NumOfBdrElements'
1894  NumOfBdrElements = 0;
1895  for (i = 0; i < faces_info.Size(); i++)
1896  {
1897  if (faces_info[i].Elem2No < 0) { NumOfBdrElements++; }
1898  }
1899 
1900  boundary.SetSize(NumOfBdrElements);
1901  be2face.SetSize(NumOfBdrElements);
1902  for (j = i = 0; i < faces_info.Size(); i++)
1903  {
1904  if (faces_info[i].Elem2No < 0)
1905  {
1906  boundary[j] = faces[i]->Duplicate(this);
1907  be2face[j++] = i;
1908  }
1909  }
1910  // In 3D, 'bel_to_edge' is destroyed but it's not updated.
1911 }
1912 
1913 void Mesh::FinalizeCheck()
1914 {
1915  MFEM_VERIFY(vertices.Size() == NumOfVertices ||
1916  vertices.Size() == 0,
1917  "incorrect number of vertices: preallocated: " << vertices.Size()
1918  << ", actually added: " << NumOfVertices);
1919  MFEM_VERIFY(elements.Size() == NumOfElements,
1920  "incorrect number of elements: preallocated: " << elements.Size()
1921  << ", actually added: " << NumOfElements);
1922  MFEM_VERIFY(boundary.Size() == NumOfBdrElements,
1923  "incorrect number of boundary elements: preallocated: "
1924  << boundary.Size() << ", actually added: " << NumOfBdrElements);
1925 }
1926 
1927 void Mesh::FinalizeTriMesh(int generate_edges, int refine, bool fix_orientation)
1928 {
1929  FinalizeCheck();
1930  CheckElementOrientation(fix_orientation);
1931 
1932  if (refine)
1933  {
1934  MarkTriMeshForRefinement();
1935  }
1936 
1937  if (generate_edges)
1938  {
1939  el_to_edge = new Table;
1940  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1941  GenerateFaces();
1942  CheckBdrElementOrientation();
1943  }
1944  else
1945  {
1946  NumOfEdges = 0;
1947  }
1948 
1949  NumOfFaces = 0;
1950 
1951  SetAttributes();
1952 
1953  SetMeshGen();
1954 }
1955 
1956 void Mesh::FinalizeQuadMesh(int generate_edges, int refine,
1957  bool fix_orientation)
1958 {
1959  FinalizeCheck();
1960  if (fix_orientation)
1961  {
1962  CheckElementOrientation(fix_orientation);
1963  }
1964 
1965  if (generate_edges)
1966  {
1967  el_to_edge = new Table;
1968  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1969  GenerateFaces();
1970  CheckBdrElementOrientation();
1971  }
1972  else
1973  {
1974  NumOfEdges = 0;
1975  }
1976 
1977  NumOfFaces = 0;
1978 
1979  SetAttributes();
1980 
1981  SetMeshGen();
1982 }
1983 
1984 
1985 class GeckoProgress : public Gecko::Progress
1986 {
1987  double limit;
1988  mutable StopWatch sw;
1989 public:
1990  GeckoProgress(double limit) : limit(limit) { sw.Start(); }
1991  virtual bool quit() const { return limit > 0 && sw.UserTime() > limit; }
1992 };
1993 
1994 class GeckoVerboseProgress : public GeckoProgress
1995 {
1996  using Float = Gecko::Float;
1997  using Graph = Gecko::Graph;
1998  using uint = Gecko::uint;
1999 public:
2000  GeckoVerboseProgress(double limit) : GeckoProgress(limit) {}
2001 
2002  virtual void beginorder(const Graph* graph, Float cost) const
2003  { mfem::out << "Begin Gecko ordering, cost = " << cost << std::endl; }
2004  virtual void endorder(const Graph* graph, Float cost) const
2005  { mfem::out << "End ordering, cost = " << cost << std::endl; }
2006 
2007  virtual void beginiter(const Graph* graph,
2008  uint iter, uint maxiter, uint window) const
2009  {
2010  mfem::out << "Iteration " << iter << "/" << maxiter << ", window "
2011  << window << std::flush;
2012  }
2013  virtual void enditer(const Graph* graph, Float mincost, Float cost) const
2014  { mfem::out << ", cost = " << cost << endl; }
2015 };
2016 
2017 
2018 double Mesh::GetGeckoElementOrdering(Array<int> &ordering,
2019  int iterations, int window,
2020  int period, int seed, bool verbose,
2021  double time_limit)
2022 {
2023  Gecko::Graph graph;
2024  Gecko::FunctionalGeometric functional; // edge product cost
2025 
2026  GeckoProgress progress(time_limit);
2027  GeckoVerboseProgress vprogress(time_limit);
2028 
2029  // insert elements as nodes in the graph
2030  for (int elemid = 0; elemid < GetNE(); ++elemid)
2031  {
2032  graph.insert_node();
2033  }
2034 
2035  // insert graph edges for element neighbors
2036  // NOTE: indices in Gecko are 1 based hence the +1 on insertion
2037  const Table &my_el_to_el = ElementToElementTable();
2038  for (int elemid = 0; elemid < GetNE(); ++elemid)
2039  {
2040  const int *neighid = my_el_to_el.GetRow(elemid);
2041  for (int i = 0; i < my_el_to_el.RowSize(elemid); ++i)
2042  {
2043  graph.insert_arc(elemid + 1, neighid[i] + 1);
2044  }
2045  }
2046 
2047  // get the ordering from Gecko and copy it into the Array<int>
2048  graph.order(&functional, iterations, window, period, seed,
2049  verbose ? &vprogress : &progress);
2050 
2051  ordering.SetSize(GetNE());
2052  Gecko::Node::Index NE = GetNE();
2053  for (Gecko::Node::Index gnodeid = 1; gnodeid <= NE; ++gnodeid)
2054  {
2055  ordering[gnodeid - 1] = graph.rank(gnodeid);
2056  }
2057 
2058  return graph.cost();
2059 }
2060 
2061 
2062 struct HilbertCmp
2063 {
2064  int coord;
2065  bool dir;
2066  const Array<double> &points;
2067  double mid;
2068 
2069  HilbertCmp(int coord, bool dir, const Array<double> &points, double mid)
2070  : coord(coord), dir(dir), points(points), mid(mid) {}
2071 
2072  bool operator()(int i) const
2073  {
2074  return (points[3*i + coord] < mid) != dir;
2075  }
2076 };
2077 
2078 static void HilbertSort2D(int coord1, // major coordinate to sort points by
2079  bool dir1, // sort coord1 ascending/descending?
2080  bool dir2, // sort coord2 ascending/descending?
2081  const Array<double> &points, int *beg, int *end,
2082  double xmin, double ymin, double xmax, double ymax)
2083 {
2084  if (end - beg <= 1) { return; }
2085 
2086  double xmid = (xmin + xmax)*0.5;
2087  double ymid = (ymin + ymax)*0.5;
2088 
2089  int coord2 = (coord1 + 1) % 2; // the 'other' coordinate
2090 
2091  // sort (partition) points into four quadrants
2092  int *p0 = beg, *p4 = end;
2093  int *p2 = std::partition(p0, p4, HilbertCmp(coord1, dir1, points, xmid));
2094  int *p1 = std::partition(p0, p2, HilbertCmp(coord2, dir2, points, ymid));
2095  int *p3 = std::partition(p2, p4, HilbertCmp(coord2, !dir2, points, ymid));
2096 
2097  if (p1 != p4)
2098  {
2099  HilbertSort2D(coord2, dir2, dir1, points, p0, p1,
2100  ymin, xmin, ymid, xmid);
2101  }
2102  if (p1 != p0 || p2 != p4)
2103  {
2104  HilbertSort2D(coord1, dir1, dir2, points, p1, p2,
2105  xmin, ymid, xmid, ymax);
2106  }
2107  if (p2 != p0 || p3 != p4)
2108  {
2109  HilbertSort2D(coord1, dir1, dir2, points, p2, p3,
2110  xmid, ymid, xmax, ymax);
2111  }
2112  if (p3 != p0)
2113  {
2114  HilbertSort2D(coord2, !dir2, !dir1, points, p3, p4,
2115  ymid, xmax, ymin, xmid);
2116  }
2117 }
2118 
2119 static void HilbertSort3D(int coord1, bool dir1, bool dir2, bool dir3,
2120  const Array<double> &points, int *beg, int *end,
2121  double xmin, double ymin, double zmin,
2122  double xmax, double ymax, double zmax)
2123 {
2124  if (end - beg <= 1) { return; }
2125 
2126  double xmid = (xmin + xmax)*0.5;
2127  double ymid = (ymin + ymax)*0.5;
2128  double zmid = (zmin + zmax)*0.5;
2129 
2130  int coord2 = (coord1 + 1) % 3;
2131  int coord3 = (coord1 + 2) % 3;
2132 
2133  // sort (partition) points into eight octants
2134  int *p0 = beg, *p8 = end;
2135  int *p4 = std::partition(p0, p8, HilbertCmp(coord1, dir1, points, xmid));
2136  int *p2 = std::partition(p0, p4, HilbertCmp(coord2, dir2, points, ymid));
2137  int *p6 = std::partition(p4, p8, HilbertCmp(coord2, !dir2, points, ymid));
2138  int *p1 = std::partition(p0, p2, HilbertCmp(coord3, dir3, points, zmid));
2139  int *p3 = std::partition(p2, p4, HilbertCmp(coord3, !dir3, points, zmid));
2140  int *p5 = std::partition(p4, p6, HilbertCmp(coord3, dir3, points, zmid));
2141  int *p7 = std::partition(p6, p8, HilbertCmp(coord3, !dir3, points, zmid));
2142 
2143  if (p1 != p8)
2144  {
2145  HilbertSort3D(coord3, dir3, dir1, dir2, points, p0, p1,
2146  zmin, xmin, ymin, zmid, xmid, ymid);
2147  }
2148  if (p1 != p0 || p2 != p8)
2149  {
2150  HilbertSort3D(coord2, dir2, dir3, dir1, points, p1, p2,
2151  ymin, zmid, xmin, ymid, zmax, xmid);
2152  }
2153  if (p2 != p0 || p3 != p8)
2154  {
2155  HilbertSort3D(coord2, dir2, dir3, dir1, points, p2, p3,
2156  ymid, zmid, xmin, ymax, zmax, xmid);
2157  }
2158  if (p3 != p0 || p4 != p8)
2159  {
2160  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p3, p4,
2161  xmin, ymax, zmid, xmid, ymid, zmin);
2162  }
2163  if (p4 != p0 || p5 != p8)
2164  {
2165  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p4, p5,
2166  xmid, ymax, zmid, xmax, ymid, zmin);
2167  }
2168  if (p5 != p0 || p6 != p8)
2169  {
2170  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p5, p6,
2171  ymax, zmid, xmax, ymid, zmax, xmid);
2172  }
2173  if (p6 != p0 || p7 != p8)
2174  {
2175  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p6, p7,
2176  ymid, zmid, xmax, ymin, zmax, xmid);
2177  }
2178  if (p7 != p0)
2179  {
2180  HilbertSort3D(coord3, !dir3, !dir1, dir2, points, p7, p8,
2181  zmid, xmax, ymin, zmin, xmid, ymid);
2182  }
2183 }
2184 
2185 void Mesh::GetHilbertElementOrdering(Array<int> &ordering)
2186 {
2187  MFEM_VERIFY(spaceDim <= 3, "");
2188 
2189  Vector min, max, center;
2190  GetBoundingBox(min, max);
2191 
2192  Array<int> indices(GetNE());
2193  Array<double> points(3*GetNE());
2194 
2195  if (spaceDim < 3) { points = 0.0; }
2196 
2197  // calculate element centers
2198  for (int i = 0; i < GetNE(); i++)
2199  {
2200  GetElementCenter(i, center);
2201  for (int j = 0; j < spaceDim; j++)
2202  {
2203  points[3*i + j] = center(j);
2204  }
2205  indices[i] = i;
2206  }
2207 
2208  if (spaceDim == 1)
2209  {
2210  indices.Sort([&](int a, int b)
2211  { return points[3*a] < points[3*b]; });
2212  }
2213  else if (spaceDim == 2)
2214  {
2215  // recursively partition the points in 2D
2216  HilbertSort2D(0, false, false,
2217  points, indices.begin(), indices.end(),
2218  min(0), min(1), max(0), max(1));
2219  }
2220  else
2221  {
2222  // recursively partition the points in 3D
2223  HilbertSort3D(0, false, false, false,
2224  points, indices.begin(), indices.end(),
2225  min(0), min(1), min(2), max(0), max(1), max(2));
2226  }
2227 
2228  // return ordering in the format required by ReorderElements
2229  ordering.SetSize(GetNE());
2230  for (int i = 0; i < GetNE(); i++)
2231  {
2232  ordering[indices[i]] = i;
2233  }
2234 }
2235 
2236 
2237 void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
2238 {
2239  if (NURBSext)
2240  {
2241  MFEM_WARNING("element reordering of NURBS meshes is not supported.");
2242  return;
2243  }
2244  if (ncmesh)
2245  {
2246  MFEM_WARNING("element reordering of non-conforming meshes is not"
2247  " supported.");
2248  return;
2249  }
2250  MFEM_VERIFY(ordering.Size() == GetNE(), "invalid reordering array.")
2251 
2252  // Data members that need to be updated:
2253 
2254  // - elements - reorder of the pointers and the vertex ids if reordering
2255  // the vertices
2256  // - vertices - if reordering the vertices
2257  // - boundary - update the vertex ids, if reordering the vertices
2258  // - faces - regenerate
2259  // - faces_info - regenerate
2260 
2261  // Deleted by DeleteTables():
2262  // - el_to_edge - rebuild in 2D and 3D only
2263  // - el_to_face - rebuild in 3D only
2264  // - bel_to_edge - rebuild in 3D only
2265  // - el_to_el - no need to rebuild
2266  // - face_edge - no need to rebuild
2267  // - edge_vertex - no need to rebuild
2268  // - geom_factors - no need to rebuild
2269 
2270  // - be_to_edge - 2D only
2271  // - be_to_face - 3D only
2272 
2273  // - Nodes
2274 
2275  // Save the locations of the Nodes so we can rebuild them later
2276  Array<Vector*> old_elem_node_vals;
2277  FiniteElementSpace *nodes_fes = NULL;
2278  if (Nodes)
2279  {
2280  old_elem_node_vals.SetSize(GetNE());
2281  nodes_fes = Nodes->FESpace();
2282  Array<int> old_dofs;
2283  Vector vals;
2284  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2285  {
2286  nodes_fes->GetElementVDofs(old_elid, old_dofs);
2287  Nodes->GetSubVector(old_dofs, vals);
2288  old_elem_node_vals[old_elid] = new Vector(vals);
2289  }
2290  }
2291 
2292  // Get the newly ordered elements
2293  Array<Element *> new_elements(GetNE());
2294  for (int old_elid = 0; old_elid < ordering.Size(); ++old_elid)
2295  {
2296  int new_elid = ordering[old_elid];
2297  new_elements[new_elid] = elements[old_elid];
2298  }
2299  mfem::Swap(elements, new_elements);
2300  new_elements.DeleteAll();
2301 
2302  if (reorder_vertices)
2303  {
2304  // Get the new vertex ordering permutation vectors and fill the new
2305  // vertices
2306  Array<int> vertex_ordering(GetNV());
2307  vertex_ordering = -1;
2308  Array<Vertex> new_vertices(GetNV());
2309  int new_vertex_ind = 0;
2310  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2311  {
2312  int *elem_vert = elements[new_elid]->GetVertices();
2313  int nv = elements[new_elid]->GetNVertices();
2314  for (int vi = 0; vi < nv; ++vi)
2315  {
2316  int old_vertex_ind = elem_vert[vi];
2317  if (vertex_ordering[old_vertex_ind] == -1)
2318  {
2319  vertex_ordering[old_vertex_ind] = new_vertex_ind;
2320  new_vertices[new_vertex_ind] = vertices[old_vertex_ind];
2321  new_vertex_ind++;
2322  }
2323  }
2324  }
2325  mfem::Swap(vertices, new_vertices);
2326  new_vertices.DeleteAll();
2327 
2328  // Replace the vertex ids in the elements with the reordered vertex
2329  // numbers
2330  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2331  {
2332  int *elem_vert = elements[new_elid]->GetVertices();
2333  int nv = elements[new_elid]->GetNVertices();
2334  for (int vi = 0; vi < nv; ++vi)
2335  {
2336  elem_vert[vi] = vertex_ordering[elem_vert[vi]];
2337  }
2338  }
2339 
2340  // Replace the vertex ids in the boundary with reordered vertex numbers
2341  for (int belid = 0; belid < GetNBE(); ++belid)
2342  {
2343  int *be_vert = boundary[belid]->GetVertices();
2344  int nv = boundary[belid]->GetNVertices();
2345  for (int vi = 0; vi < nv; ++vi)
2346  {
2347  be_vert[vi] = vertex_ordering[be_vert[vi]];
2348  }
2349  }
2350  }
2351 
2352  // Destroy tables that need to be rebuild
2353  DeleteTables();
2354 
2355  if (Dim > 1)
2356  {
2357  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
2358  el_to_edge = new Table;
2359  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2360  }
2361  if (Dim > 2)
2362  {
2363  // generate el_to_face, be_to_face
2364  GetElementToFaceTable();
2365  }
2366  // Update faces and faces_info
2367  GenerateFaces();
2368 
2369  // Build the nodes from the saved locations if they were around before
2370  if (Nodes)
2371  {
2372  // To force FE space update, we need to increase 'sequence':
2373  sequence++;
2374  last_operation = Mesh::NONE;
2375  nodes_fes->Update(false); // want_transform = false
2376  Nodes->Update(); // just needed to update Nodes->sequence
2377  Array<int> new_dofs;
2378  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2379  {
2380  int new_elid = ordering[old_elid];
2381  nodes_fes->GetElementVDofs(new_elid, new_dofs);
2382  Nodes->SetSubVector(new_dofs, *(old_elem_node_vals[old_elid]));
2383  delete old_elem_node_vals[old_elid];
2384  }
2385  }
2386 }
2387 
2388 
2389 void Mesh::MarkForRefinement()
2390 {
2391  if (meshgen & 1)
2392  {
2393  if (Dim == 2)
2394  {
2395  MarkTriMeshForRefinement();
2396  }
2397  else if (Dim == 3)
2398  {
2399  DSTable v_to_v(NumOfVertices);
2400  GetVertexToVertexTable(v_to_v);
2401  MarkTetMeshForRefinement(v_to_v);
2402  }
2403  }
2404 }
2405 
2406 void Mesh::MarkTriMeshForRefinement()
2407 {
2408  // Mark the longest triangle edge by rotating the indeces so that
2409  // vertex 0 - vertex 1 is the longest edge in the triangle.
2410  DenseMatrix pmat;
2411  for (int i = 0; i < NumOfElements; i++)
2412  {
2413  if (elements[i]->GetType() == Element::TRIANGLE)
2414  {
2415  GetPointMatrix(i, pmat);
2416  static_cast<Triangle*>(elements[i])->MarkEdge(pmat);
2417  }
2418  }
2419 }
2420 
2421 void Mesh::GetEdgeOrdering(DSTable &v_to_v, Array<int> &order)
2422 {
2423  NumOfEdges = v_to_v.NumberOfEntries();
2424  order.SetSize(NumOfEdges);
2425  Array<Pair<double, int> > length_idx(NumOfEdges);
2426 
2427  for (int i = 0; i < NumOfVertices; i++)
2428  {
2429  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
2430  {
2431  int j = it.Index();
2432  length_idx[j].one = GetLength(i, it.Column());
2433  length_idx[j].two = j;
2434  }
2435  }
2436 
2437  // Sort by increasing edge-length.
2438  length_idx.Sort();
2439 
2440  for (int i = 0; i < NumOfEdges; i++)
2441  {
2442  order[length_idx[i].two] = i;
2443  }
2444 }
2445 
2446 void Mesh::MarkTetMeshForRefinement(DSTable &v_to_v)
2447 {
2448  // Mark the longest tetrahedral edge by rotating the indices so that
2449  // vertex 0 - vertex 1 is the longest edge in the element.
2450  Array<int> order;
2451  GetEdgeOrdering(v_to_v, order);
2452 
2453  for (int i = 0; i < NumOfElements; i++)
2454  {
2455  if (elements[i]->GetType() == Element::TETRAHEDRON)
2456  {
2457  elements[i]->MarkEdge(v_to_v, order);
2458  }
2459  }
2460  for (int i = 0; i < NumOfBdrElements; i++)
2461  {
2462  if (boundary[i]->GetType() == Element::TRIANGLE)
2463  {
2464  boundary[i]->MarkEdge(v_to_v, order);
2465  }
2466  }
2467 }
2468 
2469 void Mesh::PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
2470 {
2471  if (*old_v_to_v && *old_elem_vert)
2472  {
2473  return;
2474  }
2475 
2476  FiniteElementSpace *fes = Nodes->FESpace();
2477 
2478  if (*old_v_to_v == NULL)
2479  {
2480  bool need_v_to_v = false;
2481  Array<int> dofs;
2482  for (int i = 0; i < GetNEdges(); i++)
2483  {
2484  // Since edge indices may change, we need to permute edge interior dofs
2485  // any time an edge index changes and there is at least one dof on that
2486  // edge.
2487  fes->GetEdgeInteriorDofs(i, dofs);
2488  if (dofs.Size() > 0)
2489  {
2490  need_v_to_v = true;
2491  break;
2492  }
2493  }
2494  if (need_v_to_v)
2495  {
2496  *old_v_to_v = new DSTable(NumOfVertices);
2497  GetVertexToVertexTable(*(*old_v_to_v));
2498  }
2499  }
2500  if (*old_elem_vert == NULL)
2501  {
2502  bool need_elem_vert = false;
2503  Array<int> dofs;
2504  for (int i = 0; i < GetNE(); i++)
2505  {
2506  // Since element indices do not change, we need to permute element
2507  // interior dofs only when there are at least 2 interior dofs in an
2508  // element (assuming the nodal dofs are non-directional).
2509  fes->GetElementInteriorDofs(i, dofs);
2510  if (dofs.Size() > 1)
2511  {
2512  need_elem_vert = true;
2513  break;
2514  }
2515  }
2516  if (need_elem_vert)
2517  {
2518  *old_elem_vert = new Table;
2519  (*old_elem_vert)->MakeI(GetNE());
2520  for (int i = 0; i < GetNE(); i++)
2521  {
2522  (*old_elem_vert)->AddColumnsInRow(i, elements[i]->GetNVertices());
2523  }
2524  (*old_elem_vert)->MakeJ();
2525  for (int i = 0; i < GetNE(); i++)
2526  {
2527  (*old_elem_vert)->AddConnections(i, elements[i]->GetVertices(),
2528  elements[i]->GetNVertices());
2529  }
2530  (*old_elem_vert)->ShiftUpI();
2531  }
2532  }
2533 }
2534 
2535 void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
2536 {
2537  FiniteElementSpace *fes = Nodes->FESpace();
2538  const FiniteElementCollection *fec = fes->FEColl();
2539  Array<int> old_dofs, new_dofs;
2540 
2541  // assuming that all edges have the same number of dofs
2542  if (NumOfEdges) { fes->GetEdgeInteriorDofs(0, old_dofs); }
2543  const int num_edge_dofs = old_dofs.Size();
2544 
2545  // Save the original nodes
2546  const Vector onodes = *Nodes;
2547 
2548  // vertex dofs do not need to be moved
2549  fes->GetVertexDofs(0, old_dofs);
2550  int offset = NumOfVertices * old_dofs.Size();
2551 
2552  // edge dofs:
2553  // edge enumeration may be different but edge orientation is the same
2554  if (num_edge_dofs > 0)
2555  {
2556  DSTable new_v_to_v(NumOfVertices);
2557  GetVertexToVertexTable(new_v_to_v);
2558 
2559  for (int i = 0; i < NumOfVertices; i++)
2560  {
2561  for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it)
2562  {
2563  const int old_i = (*old_v_to_v)(i, it.Column());
2564  const int new_i = it.Index();
2565  if (new_i == old_i) { continue; }
2566 
2567  old_dofs.SetSize(num_edge_dofs);
2568  new_dofs.SetSize(num_edge_dofs);
2569  for (int j = 0; j < num_edge_dofs; j++)
2570  {
2571  old_dofs[j] = offset + old_i * num_edge_dofs + j;
2572  new_dofs[j] = offset + new_i * num_edge_dofs + j;
2573  }
2574  fes->DofsToVDofs(old_dofs);
2575  fes->DofsToVDofs(new_dofs);
2576  for (int j = 0; j < old_dofs.Size(); j++)
2577  {
2578  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2579  }
2580  }
2581  }
2582  offset += NumOfEdges * num_edge_dofs;
2583  }
2584 
2585  // face dofs:
2586  // both enumeration and orientation of the faces may be different
2587  if (fes->GetNFDofs() > 0)
2588  {
2589  // generate the old face-vertex table using the unmodified 'faces'
2590  Table old_face_vertex;
2591  old_face_vertex.MakeI(NumOfFaces);
2592  for (int i = 0; i < NumOfFaces; i++)
2593  {
2594  old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices());
2595  }
2596  old_face_vertex.MakeJ();
2597  for (int i = 0; i < NumOfFaces; i++)
2598  old_face_vertex.AddConnections(i, faces[i]->GetVertices(),
2599  faces[i]->GetNVertices());
2600  old_face_vertex.ShiftUpI();
2601 
2602  // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info'
2603  STable3D *faces_tbl = GetElementToFaceTable(1);
2604  GenerateFaces();
2605 
2606  // compute the new face dof offsets
2607  Array<int> new_fdofs(NumOfFaces+1);
2608  new_fdofs[0] = 0;
2609  for (int i = 0; i < NumOfFaces; i++) // i = old face index
2610  {
2611  const int *old_v = old_face_vertex.GetRow(i);
2612  int new_i; // new face index
2613  switch (old_face_vertex.RowSize(i))
2614  {
2615  case 3:
2616  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2617  break;
2618  case 4:
2619  default:
2620  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2621  break;
2622  }
2623  fes->GetFaceInteriorDofs(i, old_dofs);
2624  new_fdofs[new_i+1] = old_dofs.Size();
2625  }
2626  new_fdofs.PartialSum();
2627 
2628  // loop over the old face numbers
2629  for (int i = 0; i < NumOfFaces; i++)
2630  {
2631  const int *old_v = old_face_vertex.GetRow(i), *new_v;
2632  const int *dof_ord;
2633  int new_i, new_or;
2634  switch (old_face_vertex.RowSize(i))
2635  {
2636  case 3:
2637  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2638  new_v = faces[new_i]->GetVertices();
2639  new_or = GetTriOrientation(old_v, new_v);
2640  dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, new_or);
2641  break;
2642  case 4:
2643  default:
2644  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2645  new_v = faces[new_i]->GetVertices();
2646  new_or = GetQuadOrientation(old_v, new_v);
2647  dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, new_or);
2648  break;
2649  }
2650 
2651  fes->GetFaceInteriorDofs(i, old_dofs);
2652  new_dofs.SetSize(old_dofs.Size());
2653  for (int j = 0; j < old_dofs.Size(); j++)
2654  {
2655  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2656  const int old_j = dof_ord[j];
2657  new_dofs[old_j] = offset + new_fdofs[new_i] + j;
2658  }
2659  fes->DofsToVDofs(old_dofs);
2660  fes->DofsToVDofs(new_dofs);
2661  for (int j = 0; j < old_dofs.Size(); j++)
2662  {
2663  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2664  }
2665  }
2666 
2667  offset += fes->GetNFDofs();
2668  delete faces_tbl;
2669  }
2670 
2671  // element dofs:
2672  // element orientation may be different
2673  if (old_elem_vert) // have elements with 2 or more dofs
2674  {
2675  // matters when the 'fec' is
2676  // (this code is executed only for triangles/tets)
2677  // - Pk on triangles, k >= 4
2678  // - Qk on quads, k >= 3
2679  // - Pk on tets, k >= 5
2680  // - Qk on hexes, k >= 3
2681  // - DG spaces
2682  // - ...
2683 
2684  // loop over all elements
2685  for (int i = 0; i < GetNE(); i++)
2686  {
2687  const int *old_v = old_elem_vert->GetRow(i);
2688  const int *new_v = elements[i]->GetVertices();
2689  const int *dof_ord;
2690  int new_or;
2691  const Geometry::Type geom = elements[i]->GetGeometryType();
2692  switch (geom)
2693  {
2694  case Geometry::SEGMENT:
2695  new_or = (old_v[0] == new_v[0]) ? +1 : -1;
2696  break;
2697  case Geometry::TRIANGLE:
2698  new_or = GetTriOrientation(old_v, new_v);
2699  break;
2700  case Geometry::SQUARE:
2701  new_or = GetQuadOrientation(old_v, new_v);
2702  break;
2703  case Geometry::TETRAHEDRON:
2704  new_or = GetTetOrientation(old_v, new_v);
2705  break;
2706  default:
2707  new_or = 0;
2708  MFEM_ABORT(Geometry::Name[geom] << " elements (" << fec->Name()
2709  << " FE collection) are not supported yet!");
2710  break;
2711  }
2712  dof_ord = fec->DofOrderForOrientation(geom, new_or);
2713  MFEM_VERIFY(dof_ord != NULL,
2714  "FE collection '" << fec->Name()
2715  << "' does not define reordering for "
2716  << Geometry::Name[geom] << " elements!");
2717  fes->GetElementInteriorDofs(i, old_dofs);
2718  new_dofs.SetSize(old_dofs.Size());
2719  for (int j = 0; j < new_dofs.Size(); j++)
2720  {
2721  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2722  const int old_j = dof_ord[j];
2723  new_dofs[old_j] = offset + j;
2724  }
2725  offset += new_dofs.Size();
2726  fes->DofsToVDofs(old_dofs);
2727  fes->DofsToVDofs(new_dofs);
2728  for (int j = 0; j < old_dofs.Size(); j++)
2729  {
2730  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2731  }
2732  }
2733  }
2734 
2735  // Update Tables, faces, etc
2736  if (Dim > 2)
2737  {
2738  if (fes->GetNFDofs() == 0)
2739  {
2740  // needed for FE spaces that have face dofs, even if
2741  // the 'Nodes' do not have face dofs.
2742  GetElementToFaceTable();
2743  GenerateFaces();
2744  }
2745  CheckBdrElementOrientation();
2746  }
2747  if (el_to_edge)
2748  {
2749  // update 'el_to_edge', 'be_to_edge' (2D), 'bel_to_edge' (3D)
2750  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2751  if (Dim == 2)
2752  {
2753  // update 'faces' and 'faces_info'
2754  GenerateFaces();
2755  CheckBdrElementOrientation();
2756  }
2757  }
2758  // To force FE space update, we need to increase 'sequence':
2759  sequence++;
2760  last_operation = Mesh::NONE;
2761  fes->Update(false); // want_transform = false
2762  Nodes->Update(); // just needed to update Nodes->sequence
2763 }
2764 
2765 void Mesh::FinalizeTetMesh(int generate_edges, int refine, bool fix_orientation)
2766 {
2767  FinalizeCheck();
2768  CheckElementOrientation(fix_orientation);
2769 
2770  if (NumOfBdrElements == 0)
2771  {
2772  GetElementToFaceTable();
2773  GenerateFaces();
2774  GenerateBoundaryElements();
2775  }
2776 
2777  if (refine)
2778  {
2779  DSTable v_to_v(NumOfVertices);
2780  GetVertexToVertexTable(v_to_v);
2781  MarkTetMeshForRefinement(v_to_v);
2782  }
2783 
2784  GetElementToFaceTable();
2785  GenerateFaces();
2786 
2787  CheckBdrElementOrientation();
2788 
2789  if (generate_edges == 1)
2790  {
2791  el_to_edge = new Table;
2792  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2793  }
2794  else
2795  {
2796  el_to_edge = NULL; // Not really necessary -- InitTables was called
2797  bel_to_edge = NULL;
2798  NumOfEdges = 0;
2799  }
2800 
2801  SetAttributes();
2802 
2803  SetMeshGen();
2804 }
2805 
2806 void Mesh::FinalizeWedgeMesh(int generate_edges, int refine,
2807  bool fix_orientation)
2808 {
2809  FinalizeCheck();
2810  CheckElementOrientation(fix_orientation);
2811 
2812  if (NumOfBdrElements == 0)
2813  {
2814  GetElementToFaceTable();
2815  GenerateFaces();
2816  GenerateBoundaryElements();
2817  }
2818 
2819  GetElementToFaceTable();
2820  GenerateFaces();
2821 
2822  CheckBdrElementOrientation();
2823 
2824  if (generate_edges == 1)
2825  {
2826  el_to_edge = new Table;
2827  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2828  }
2829  else
2830  {
2831  el_to_edge = NULL; // Not really necessary -- InitTables was called
2832  bel_to_edge = NULL;
2833  NumOfEdges = 0;
2834  }
2835 
2836  SetAttributes();
2837 
2838  SetMeshGen();
2839 }
2840 
2841 void Mesh::FinalizeHexMesh(int generate_edges, int refine, bool fix_orientation)
2842 {
2843  FinalizeCheck();
2844  CheckElementOrientation(fix_orientation);
2845 
2846  GetElementToFaceTable();
2847  GenerateFaces();
2848 
2849  if (NumOfBdrElements == 0)
2850  {
2851  GenerateBoundaryElements();
2852  }
2853 
2854  CheckBdrElementOrientation();
2855 
2856  if (generate_edges)
2857  {
2858  el_to_edge = new Table;
2859  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2860  }
2861  else
2862  {
2863  NumOfEdges = 0;
2864  }
2865 
2866  SetAttributes();
2867 
2868  SetMeshGen();
2869 }
2870 
2871 void Mesh::FinalizeMesh(int refine, bool fix_orientation)
2872 {
2873  FinalizeTopology();
2874 
2875  Finalize(refine, fix_orientation);
2876 }
2877 
2878 void Mesh::FinalizeTopology(bool generate_bdr)
2879 {
2880  // Requirements: the following should be defined:
2881  // 1) Dim
2882  // 2) NumOfElements, elements
2883  // 3) NumOfBdrElements, boundary
2884  // 4) NumOfVertices
2885  // Optional:
2886  // 2) ncmesh may be defined
2887  // 3) el_to_edge may be allocated (it will be re-computed)
2888 
2889  FinalizeCheck();
2890  bool generate_edges = true;
2891 
2892  if (spaceDim == 0) { spaceDim = Dim; }
2893  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
2894 
2895  // if the user defined any hanging nodes (see AddVertexParent),
2896  // we're initializing a non-conforming mesh
2897  if (tmp_vertex_parents.Size())
2898  {
2899  MFEM_VERIFY(ncmesh == NULL, "");
2900  ncmesh = new NCMesh(this);
2901 
2902  // we need to recreate the Mesh because NCMesh reorders the vertices
2903  // (see NCMesh::UpdateVertices())
2904  InitFromNCMesh(*ncmesh);
2905  ncmesh->OnMeshUpdated(this);
2906  GenerateNCFaceInfo();
2907 
2908  SetAttributes();
2909 
2910  tmp_vertex_parents.DeleteAll();
2911  return;
2912  }
2913 
2914  // set the mesh type: 'meshgen', ...
2915  SetMeshGen();
2916 
2917  // generate the faces
2918  if (Dim > 2)
2919  {
2920  GetElementToFaceTable();
2921  GenerateFaces();
2922  if (NumOfBdrElements == 0 && generate_bdr)
2923  {
2924  GenerateBoundaryElements();
2925  GetElementToFaceTable(); // update be_to_face
2926  }
2927  }
2928  else
2929  {
2930  NumOfFaces = 0;
2931  }
2932 
2933  // generate edges if requested
2934  if (Dim > 1 && generate_edges)
2935  {
2936  // el_to_edge may already be allocated (P2 VTK meshes)
2937  if (!el_to_edge) { el_to_edge = new Table; }
2938  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2939  if (Dim == 2)
2940  {
2941  GenerateFaces(); // 'Faces' in 2D refers to the edges
2942  if (NumOfBdrElements == 0 && generate_bdr)
2943  {
2944  GenerateBoundaryElements();
2945  }
2946  }
2947  }
2948  else
2949  {
2950  NumOfEdges = 0;
2951  }
2952 
2953  if (Dim == 1)
2954  {
2955  GenerateFaces();
2956  }
2957 
2958  if (ncmesh)
2959  {
2960  // tell NCMesh the numbering of edges/faces
2961  ncmesh->OnMeshUpdated(this);
2962 
2963  // update faces_info with NC relations
2964  GenerateNCFaceInfo();
2965  }
2966 
2967  // generate the arrays 'attributes' and 'bdr_attributes'
2968  SetAttributes();
2969 }
2970 
2971 void Mesh::Finalize(bool refine, bool fix_orientation)
2972 {
2973  if (NURBSext || ncmesh)
2974  {
2975  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
2976  MFEM_ASSERT(CheckBdrElementOrientation() == 0, "");
2977  return;
2978  }
2979 
2980  // Requirements:
2981  // 1) FinalizeTopology() or equivalent was called
2982  // 2) if (Nodes == NULL), vertices must be defined
2983  // 3) if (Nodes != NULL), Nodes must be defined
2984 
2985  const bool check_orientation = true; // for regular elements, not boundary
2986  const bool curved = (Nodes != NULL);
2987  const bool may_change_topology =
2988  ( refine && (Dim > 1 && (meshgen & 1)) ) ||
2989  ( check_orientation && fix_orientation &&
2990  (Dim == 2 || (Dim == 3 && (meshgen & 1))) );
2991 
2992  DSTable *old_v_to_v = NULL;
2993  Table *old_elem_vert = NULL;
2994 
2995  if (curved && may_change_topology)
2996  {
2997  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
2998  }
2999 
3000  if (check_orientation)
3001  {
3002  // check and optionally fix element orientation
3003  CheckElementOrientation(fix_orientation);
3004  }
3005  if (refine)
3006  {
3007  MarkForRefinement(); // may change topology!
3008  }
3009 
3010  if (may_change_topology)
3011  {
3012  if (curved)
3013  {
3014  DoNodeReorder(old_v_to_v, old_elem_vert); // updates the mesh topology
3015  delete old_elem_vert;
3016  delete old_v_to_v;
3017  }
3018  else
3019  {
3020  FinalizeTopology(); // Re-computes some data unnecessarily.
3021  }
3022 
3023  // TODO: maybe introduce Mesh::NODE_REORDER operation and FESpace::
3024  // NodeReorderMatrix and do Nodes->Update() instead of DoNodeReorder?
3025  }
3026 
3027  // check and fix boundary element orientation
3028  CheckBdrElementOrientation();
3029 
3030 #ifdef MFEM_DEBUG
3031  // For non-orientable surfaces/manifolds, the check below will fail, so we
3032  // only perform it when Dim == spaceDim.
3033  if (Dim >= 2 && Dim == spaceDim)
3034  {
3035  const int num_faces = GetNumFaces();
3036  for (int i = 0; i < num_faces; i++)
3037  {
3038  MFEM_VERIFY(faces_info[i].Elem2No < 0 ||
3039  faces_info[i].Elem2Inf%2 != 0, "Invalid mesh topology."
3040  " Interior face with incompatible orientations.");
3041  }
3042  }
3043 #endif
3044 }
3045 
3046 void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
3047  double sx, double sy, double sz, bool sfc_ordering)
3048 {
3049  int x, y, z;
3050 
3051  int NVert, NElem, NBdrElem;
3052 
3053  NVert = (nx+1) * (ny+1) * (nz+1);
3054  NElem = nx * ny * nz;
3055  NBdrElem = 2*(nx*ny+nx*nz+ny*nz);
3056  if (type == Element::TETRAHEDRON)
3057  {
3058  NElem *= 6;
3059  NBdrElem *= 2;
3060  }
3061  else if (type == Element::WEDGE)
3062  {
3063  NElem *= 2;
3064  NBdrElem += 2*nx*ny;
3065  }
3066  else if (type == Element::PYRAMID)
3067  {
3068  NElem *= 6;
3069  NVert += nx * ny * nz;
3070  }
3071 
3072  InitMesh(3, 3, NVert, NElem, NBdrElem);
3073 
3074  double coord[3];
3075  int ind[9];
3076 
3077  // Sets vertices and the corresponding coordinates
3078  for (z = 0; z <= nz; z++)
3079  {
3080  coord[2] = ((double) z / nz) * sz;
3081  for (y = 0; y <= ny; y++)
3082  {
3083  coord[1] = ((double) y / ny) * sy;
3084  for (x = 0; x <= nx; x++)
3085  {
3086  coord[0] = ((double) x / nx) * sx;
3087  AddVertex(coord);
3088  }
3089  }
3090  }
3091  if (type == Element::PYRAMID)
3092  {
3093  for (z = 0; z < nz; z++)
3094  {
3095  coord[2] = (((double) z + 0.5) / nz) * sz;
3096  for (y = 0; y < ny; y++)
3097  {
3098  coord[1] = (((double) y + 0.5 ) / ny) * sy;
3099  for (x = 0; x < nx; x++)
3100  {
3101  coord[0] = (((double) x + 0.5 ) / nx) * sx;
3102  AddVertex(coord);
3103  }
3104  }
3105  }
3106  }
3107 
3108 #define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
3109 #define VTXP(XC, YC, ZC) ((nx+1)*(ny+1)*(nz+1)+(XC)+((YC)+(ZC)*ny)*nx)
3110 
3111  // Sets elements and the corresponding indices of vertices
3112  if (sfc_ordering && type == Element::HEXAHEDRON)
3113  {
3114  Array<int> sfc;
3115  NCMesh::GridSfcOrdering3D(nx, ny, nz, sfc);
3116  MFEM_VERIFY(sfc.Size() == 3*nx*ny*nz, "");
3117 
3118  for (int k = 0; k < nx*ny*nz; k++)
3119  {
3120  x = sfc[3*k + 0];
3121  y = sfc[3*k + 1];
3122  z = sfc[3*k + 2];
3123 
3124  // *INDENT-OFF*
3125  ind[0] = VTX(x , y , z );
3126  ind[1] = VTX(x+1, y , z );
3127  ind[2] = VTX(x+1, y+1, z );
3128  ind[3] = VTX(x , y+1, z );
3129  ind[4] = VTX(x , y , z+1);
3130  ind[5] = VTX(x+1, y , z+1);
3131  ind[6] = VTX(x+1, y+1, z+1);
3132  ind[7] = VTX(x , y+1, z+1);
3133  // *INDENT-ON*
3134 
3135  AddHex(ind, 1);
3136  }
3137  }
3138  else
3139  {
3140  for (z = 0; z < nz; z++)
3141  {
3142  for (y = 0; y < ny; y++)
3143  {
3144  for (x = 0; x < nx; x++)
3145  {
3146  // *INDENT-OFF*
3147  ind[0] = VTX(x , y , z );
3148  ind[1] = VTX(x+1, y , z );
3149  ind[2] = VTX(x+1, y+1, z );
3150  ind[3] = VTX(x , y+1, z );
3151  ind[4] = VTX(x , y , z+1);
3152  ind[5] = VTX(x+1, y , z+1);
3153  ind[6] = VTX(x+1, y+1, z+1);
3154  ind[7] = VTX( x, y+1, z+1);
3155  // *INDENT-ON*
3156  if (type == Element::TETRAHEDRON)
3157  {
3158  AddHexAsTets(ind, 1);
3159  }
3160  else if (type == Element::WEDGE)
3161  {
3162  AddHexAsWedges(ind, 1);
3163  }
3164  else if (type == Element::PYRAMID)
3165  {
3166  ind[8] = VTXP(x, y, z);
3167  AddHexAsPyramids(ind, 1);
3168  }
3169  else
3170  {
3171  AddHex(ind, 1);
3172  }
3173  }
3174  }
3175  }
3176  }
3177 
3178  // Sets boundary elements and the corresponding indices of vertices
3179  // bottom, bdr. attribute 1
3180  for (y = 0; y < ny; y++)
3181  {
3182  for (x = 0; x < nx; x++)
3183  {
3184  // *INDENT-OFF*
3185  ind[0] = VTX(x , y , 0);
3186  ind[1] = VTX(x , y+1, 0);
3187  ind[2] = VTX(x+1, y+1, 0);
3188  ind[3] = VTX(x+1, y , 0);
3189  // *INDENT-ON*
3190  if (type == Element::TETRAHEDRON)
3191  {
3192  AddBdrQuadAsTriangles(ind, 1);
3193  }
3194  else if (type == Element::WEDGE)
3195  {
3196  AddBdrQuadAsTriangles(ind, 1);
3197  }
3198  else
3199  {
3200  AddBdrQuad(ind, 1);
3201  }
3202  }
3203  }
3204  // top, bdr. attribute 6
3205  for (y = 0; y < ny; y++)
3206  {
3207  for (x = 0; x < nx; x++)
3208  {
3209  // *INDENT-OFF*
3210  ind[0] = VTX(x , y , nz);
3211  ind[1] = VTX(x+1, y , nz);
3212  ind[2] = VTX(x+1, y+1, nz);
3213  ind[3] = VTX(x , y+1, nz);
3214  // *INDENT-ON*
3215  if (type == Element::TETRAHEDRON)
3216  {
3217  AddBdrQuadAsTriangles(ind, 6);
3218  }
3219  else if (type == Element::WEDGE)
3220  {
3221  AddBdrQuadAsTriangles(ind, 6);
3222  }
3223  else
3224  {
3225  AddBdrQuad(ind, 6);
3226  }
3227  }
3228  }
3229  // left, bdr. attribute 5
3230  for (z = 0; z < nz; z++)
3231  {
3232  for (y = 0; y < ny; y++)
3233  {
3234  // *INDENT-OFF*
3235  ind[0] = VTX(0 , y , z );
3236  ind[1] = VTX(0 , y , z+1);
3237  ind[2] = VTX(0 , y+1, z+1);
3238  ind[3] = VTX(0 , y+1, z );
3239  // *INDENT-ON*
3240  if (type == Element::TETRAHEDRON)
3241  {
3242  AddBdrQuadAsTriangles(ind, 5);
3243  }
3244  else
3245  {
3246  AddBdrQuad(ind, 5);
3247  }
3248  }
3249  }
3250  // right, bdr. attribute 3
3251  for (z = 0; z < nz; z++)
3252  {
3253  for (y = 0; y < ny; y++)
3254  {
3255  // *INDENT-OFF*
3256  ind[0] = VTX(nx, y , z );
3257  ind[1] = VTX(nx, y+1, z );
3258  ind[2] = VTX(nx, y+1, z+1);
3259  ind[3] = VTX(nx, y , z+1);
3260  // *INDENT-ON*
3261  if (type == Element::TETRAHEDRON)
3262  {
3263  AddBdrQuadAsTriangles(ind, 3);
3264  }
3265  else
3266  {
3267  AddBdrQuad(ind, 3);
3268  }
3269  }
3270  }
3271  // front, bdr. attribute 2
3272  for (x = 0; x < nx; x++)
3273  {
3274  for (z = 0; z < nz; z++)
3275  {
3276  // *INDENT-OFF*
3277  ind[0] = VTX(x , 0, z );
3278  ind[1] = VTX(x+1, 0, z );
3279  ind[2] = VTX(x+1, 0, z+1);
3280  ind[3] = VTX(x , 0, z+1);
3281  // *INDENT-ON*
3282  if (type == Element::TETRAHEDRON)
3283  {
3284  AddBdrQuadAsTriangles(ind, 2);
3285  }
3286  else
3287  {
3288  AddBdrQuad(ind, 2);
3289  }
3290  }
3291  }
3292  // back, bdr. attribute 4
3293  for (x = 0; x < nx; x++)
3294  {
3295  for (z = 0; z < nz; z++)
3296  {
3297  // *INDENT-OFF*
3298  ind[0] = VTX(x , ny, z );
3299  ind[1] = VTX(x , ny, z+1);
3300  ind[2] = VTX(x+1, ny, z+1);
3301  ind[3] = VTX(x+1, ny, z );
3302  // *INDENT-ON*
3303  if (type == Element::TETRAHEDRON)
3304  {
3305  AddBdrQuadAsTriangles(ind, 4);
3306  }
3307  else
3308  {
3309  AddBdrQuad(ind, 4);
3310  }
3311  }
3312  }
3313 
3314 #undef VTX
3315 
3316 #if 0
3317  ofstream test_stream("debug.mesh");
3318  Print(test_stream);
3319  test_stream.close();
3320 #endif
3321 
3322  FinalizeTopology();
3323 
3324  // Finalize(...) can be called after this method, if needed
3325 }
3326 
3327 void Mesh::Make2D(int nx, int ny, Element::Type type,
3328  double sx, double sy,
3329  bool generate_edges, bool sfc_ordering)
3330 {
3331  int i, j, k;
3332 
3333  SetEmpty();
3334 
3335  Dim = spaceDim = 2;
3336 
3337  // Creates quadrilateral mesh
3338  if (type == Element::QUADRILATERAL)
3339  {
3340  NumOfVertices = (nx+1) * (ny+1);
3341  NumOfElements = nx * ny;
3342  NumOfBdrElements = 2 * nx + 2 * ny;
3343 
3344  vertices.SetSize(NumOfVertices);
3345  elements.SetSize(NumOfElements);
3346  boundary.SetSize(NumOfBdrElements);
3347 
3348  double cx, cy;
3349  int ind[4];
3350 
3351  // Sets vertices and the corresponding coordinates
3352  k = 0;
3353  for (j = 0; j < ny+1; j++)
3354  {
3355  cy = ((double) j / ny) * sy;
3356  for (i = 0; i < nx+1; i++)
3357  {
3358  cx = ((double) i / nx) * sx;
3359  vertices[k](0) = cx;
3360  vertices[k](1) = cy;
3361  k++;
3362  }
3363  }
3364 
3365  // Sets elements and the corresponding indices of vertices
3366  if (sfc_ordering)
3367  {
3368  Array<int> sfc;
3369  NCMesh::GridSfcOrdering2D(nx, ny, sfc);
3370  MFEM_VERIFY(sfc.Size() == 2*nx*ny, "");
3371 
3372  for (k = 0; k < nx*ny; k++)
3373  {
3374  i = sfc[2*k + 0];
3375  j = sfc[2*k + 1];
3376  ind[0] = i + j*(nx+1);
3377  ind[1] = i + 1 +j*(nx+1);
3378  ind[2] = i + 1 + (j+1)*(nx+1);
3379  ind[3] = i + (j+1)*(nx+1);
3380  elements[k] = new Quadrilateral(ind);
3381  }
3382  }
3383  else
3384  {
3385  k = 0;
3386  for (j = 0; j < ny; j++)
3387  {
3388  for (i = 0; i < nx; i++)
3389  {
3390  ind[0] = i + j*(nx+1);
3391  ind[1] = i + 1 +j*(nx+1);
3392  ind[2] = i + 1 + (j+1)*(nx+1);
3393  ind[3] = i + (j+1)*(nx+1);
3394  elements[k] = new Quadrilateral(ind);
3395  k++;
3396  }
3397  }
3398  }
3399 
3400  // Sets boundary elements and the corresponding indices of vertices
3401  int m = (nx+1)*ny;
3402  for (i = 0; i < nx; i++)
3403  {
3404  boundary[i] = new Segment(i, i+1, 1);
3405  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3406  }
3407  m = nx+1;
3408  for (j = 0; j < ny; j++)
3409  {
3410  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3411  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3412  }
3413  }
3414  // Creates triangular mesh
3415  else if (type == Element::TRIANGLE)
3416  {
3417  NumOfVertices = (nx+1) * (ny+1);
3418  NumOfElements = 2 * nx * ny;
3419  NumOfBdrElements = 2 * nx + 2 * ny;
3420 
3421  vertices.SetSize(NumOfVertices);
3422  elements.SetSize(NumOfElements);
3423  boundary.SetSize(NumOfBdrElements);
3424 
3425  double cx, cy;
3426  int ind[3];
3427 
3428  // Sets vertices and the corresponding coordinates
3429  k = 0;
3430  for (j = 0; j < ny+1; j++)
3431  {
3432  cy = ((double) j / ny) * sy;
3433  for (i = 0; i < nx+1; i++)
3434  {
3435  cx = ((double) i / nx) * sx;
3436  vertices[k](0) = cx;
3437  vertices[k](1) = cy;
3438  k++;
3439  }
3440  }
3441 
3442  // Sets the elements and the corresponding indices of vertices
3443  k = 0;
3444  for (j = 0; j < ny; j++)
3445  {
3446  for (i = 0; i < nx; i++)
3447  {
3448  ind[0] = i + j*(nx+1);
3449  ind[1] = i + 1 + (j+1)*(nx+1);
3450  ind[2] = i + (j+1)*(nx+1);
3451  elements[k] = new Triangle(ind);
3452  k++;
3453  ind[1] = i + 1 + j*(nx+1);
3454  ind[2] = i + 1 + (j+1)*(nx+1);
3455  elements[k] = new Triangle(ind);
3456  k++;
3457  }
3458  }
3459 
3460  // Sets boundary elements and the corresponding indices of vertices
3461  int m = (nx+1)*ny;
3462  for (i = 0; i < nx; i++)
3463  {
3464  boundary[i] = new Segment(i, i+1, 1);
3465  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3466  }
3467  m = nx+1;
3468  for (j = 0; j < ny; j++)
3469  {
3470  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3471  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3472  }
3473 
3474  // MarkTriMeshForRefinement(); // done in Finalize(...)
3475  }
3476  else
3477  {
3478  MFEM_ABORT("Unsupported element type.");
3479  }
3480 
3481  SetMeshGen();
3482  CheckElementOrientation();
3483 
3484  if (generate_edges == 1)
3485  {
3486  el_to_edge = new Table;
3487  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3488  GenerateFaces();
3489  CheckBdrElementOrientation();
3490  }
3491  else
3492  {
3493  NumOfEdges = 0;
3494  }
3495 
3496  NumOfFaces = 0;
3497 
3498  attributes.Append(1);
3499  bdr_attributes.Append(1); bdr_attributes.Append(2);
3500  bdr_attributes.Append(3); bdr_attributes.Append(4);
3501 
3502  // Finalize(...) can be called after this method, if needed
3503 }
3504 
3505 void Mesh::Make1D(int n, double sx)
3506 {
3507  int j, ind[1];
3508 
3509  SetEmpty();
3510 
3511  Dim = 1;
3512  spaceDim = 1;
3513 
3514  NumOfVertices = n + 1;
3515  NumOfElements = n;
3516  NumOfBdrElements = 2;
3517  vertices.SetSize(NumOfVertices);
3518  elements.SetSize(NumOfElements);
3519  boundary.SetSize(NumOfBdrElements);
3520 
3521  // Sets vertices and the corresponding coordinates
3522  for (j = 0; j < n+1; j++)
3523  {
3524  vertices[j](0) = ((double) j / n) * sx;
3525  }
3526 
3527  // Sets elements and the corresponding indices of vertices
3528  for (j = 0; j < n; j++)
3529  {
3530  elements[j] = new Segment(j, j+1, 1);
3531  }
3532 
3533  // Sets the boundary elements
3534  ind[0] = 0;
3535  boundary[0] = new Point(ind, 1);
3536  ind[0] = n;
3537  boundary[1] = new Point(ind, 2);
3538 
3539  NumOfEdges = 0;
3540  NumOfFaces = 0;
3541 
3542  SetMeshGen();
3543  GenerateFaces();
3544 
3545  attributes.Append(1);
3546  bdr_attributes.Append(1); bdr_attributes.Append(2);
3547 }
3548 
3549 Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
3550 {
3551  Dim = mesh.Dim;
3552  spaceDim = mesh.spaceDim;
3553 
3554  NumOfVertices = mesh.NumOfVertices;
3555  NumOfElements = mesh.NumOfElements;
3556  NumOfBdrElements = mesh.NumOfBdrElements;
3557  NumOfEdges = mesh.NumOfEdges;
3558  NumOfFaces = mesh.NumOfFaces;
3559  nbInteriorFaces = mesh.nbInteriorFaces;
3560  nbBoundaryFaces = mesh.nbBoundaryFaces;
3561 
3562  meshgen = mesh.meshgen;
3563  mesh_geoms = mesh.mesh_geoms;
3564 
3565  // Create the new Mesh instance without a record of its refinement history
3566  sequence = 0;
3567  last_operation = Mesh::NONE;
3568 
3569  // Duplicate the elements
3570  elements.SetSize(NumOfElements);
3571  for (int i = 0; i < NumOfElements; i++)
3572  {
3573  elements[i] = mesh.elements[i]->Duplicate(this);
3574  }
3575 
3576  // Copy the vertices
3577  mesh.vertices.Copy(vertices);
3578 
3579  // Duplicate the boundary
3580  boundary.SetSize(NumOfBdrElements);
3581  for (int i = 0; i < NumOfBdrElements; i++)
3582  {
3583  boundary[i] = mesh.boundary[i]->Duplicate(this);
3584  }
3585 
3586  // Copy the element-to-face Table, el_to_face
3587  el_to_face = (mesh.el_to_face) ? new Table(*mesh.el_to_face) : NULL;
3588 
3589  // Copy the boundary-to-face Array, be_to_face.
3590  mesh.be_to_face.Copy(be_to_face);
3591 
3592  // Copy the element-to-edge Table, el_to_edge
3593  el_to_edge = (mesh.el_to_edge) ? new Table(*mesh.el_to_edge) : NULL;
3594 
3595  // Copy the boundary-to-edge Table, bel_to_edge (3D)
3596  bel_to_edge = (mesh.bel_to_edge) ? new Table(*mesh.bel_to_edge) : NULL;
3597 
3598  // Copy the boundary-to-edge Array, be_to_edge (2D)
3599  mesh.be_to_edge.Copy(be_to_edge);
3600 
3601  // Duplicate the faces and faces_info.
3602  faces.SetSize(mesh.faces.Size());
3603  for (int i = 0; i < faces.Size(); i++)
3604  {
3605  Element *face = mesh.faces[i]; // in 1D the faces are NULL
3606  faces[i] = (face) ? face->Duplicate(this) : NULL;
3607  }
3608  mesh.faces_info.Copy(faces_info);
3609  mesh.nc_faces_info.Copy(nc_faces_info);
3610 
3611  // Do NOT copy the element-to-element Table, el_to_el
3612  el_to_el = NULL;
3613 
3614  // Do NOT copy the face-to-edge Table, face_edge
3615  face_edge = NULL;
3616 
3617  // Copy the edge-to-vertex Table, edge_vertex
3618  edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
3619 
3620  // Copy the attributes and bdr_attributes
3621  mesh.attributes.Copy(attributes);
3622  mesh.bdr_attributes.Copy(bdr_attributes);
3623 
3624  // Deep copy the NURBSExtension.
3625 #ifdef MFEM_USE_MPI
3626  ParNURBSExtension *pNURBSext =
3627  dynamic_cast<ParNURBSExtension *>(mesh.NURBSext);
3628  if (pNURBSext)
3629  {
3630  NURBSext = new ParNURBSExtension(*pNURBSext);
3631  }
3632  else
3633 #endif
3634  {
3635  NURBSext = mesh.NURBSext ? new NURBSExtension(*mesh.NURBSext) : NULL;
3636  }
3637 
3638  // Deep copy the NCMesh.
3639 #ifdef MFEM_USE_MPI
3640  if (dynamic_cast<const ParMesh*>(&mesh))
3641  {
3642  ncmesh = NULL; // skip; will be done in ParMesh copy ctor
3643  }
3644  else
3645 #endif
3646  {
3647  ncmesh = mesh.ncmesh ? new NCMesh(*mesh.ncmesh) : NULL;
3648  }
3649 
3650  // Duplicate the Nodes, including the FiniteElementCollection and the
3651  // FiniteElementSpace
3652  if (mesh.Nodes && copy_nodes)
3653  {
3654  FiniteElementSpace *fes = mesh.Nodes->FESpace();
3655  const FiniteElementCollection *fec = fes->FEColl();
3656  FiniteElementCollection *fec_copy =
3657  FiniteElementCollection::New(fec->Name());
3658  FiniteElementSpace *fes_copy =
3659  new FiniteElementSpace(*fes, this, fec_copy);
3660  Nodes = new GridFunction(fes_copy);
3661  Nodes->MakeOwner(fec_copy);
3662  *Nodes = *mesh.Nodes;
3663  own_nodes = 1;
3664  }
3665  else
3666  {
3667  Nodes = mesh.Nodes;
3668  own_nodes = 0;
3669  }
3670 }
3671 
3672 Mesh::Mesh(Mesh &&mesh) : Mesh()
3673 {
3674  Swap(mesh, true);
3675 }
3676 
3678 {
3679  Swap(mesh, true);
3680  return *this;
3681 }
3682 
3683 Mesh Mesh::LoadFromFile(const char *filename, int generate_edges, int refine,
3684  bool fix_orientation)
3685 {
3686  Mesh mesh;
3687  named_ifgzstream imesh(filename);
3688  if (!imesh) { MFEM_ABORT("Mesh file not found: " << filename << '\n'); }
3689  else { mesh.Load(imesh, generate_edges, refine, fix_orientation); }
3690  return mesh;
3691 }
3692 
3693 Mesh Mesh::MakeCartesian1D(int n, double sx)
3694 {
3695  Mesh mesh;
3696  mesh.Make1D(n, sx);
3697  // mesh.Finalize(); not needed in this case
3698  return mesh;
3699 }
3700 
3702  int nx, int ny, Element::Type type, bool generate_edges,
3703  double sx, double sy, bool sfc_ordering)
3704 {
3705  Mesh mesh;
3706  mesh.Make2D(nx, ny, type, sx, sy, generate_edges, sfc_ordering);
3707  mesh.Finalize(true); // refine = true
3708  return mesh;
3709 }
3710 
3712  int nx, int ny, int nz, Element::Type type,
3713  double sx, double sy, double sz, bool sfc_ordering)
3714 {
3715  Mesh mesh;
3716  mesh.Make3D(nx, ny, nz, type, sx, sy, sz, sfc_ordering);
3717  mesh.Finalize(true); // refine = true
3718  return mesh;
3719 }
3720 
3721 Mesh Mesh::MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
3722 {
3723  Mesh mesh;
3724  Array<int> ref_factors(orig_mesh.GetNE());
3725  ref_factors = ref_factor;
3726  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3727  return mesh;
3728 }
3729 
3730 Mesh Mesh::MakeRefined(Mesh &orig_mesh, const Array<int> &ref_factors,
3731  int ref_type)
3732 {
3733  Mesh mesh;
3734  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3735  return mesh;
3736 }
3737 
3738 Mesh::Mesh(const char *filename, int generate_edges, int refine,
3739  bool fix_orientation)
3740 {
3741  // Initialization as in the default constructor
3742  SetEmpty();
3743 
3744  named_ifgzstream imesh(filename);
3745  if (!imesh)
3746  {
3747  // Abort with an error message.
3748  MFEM_ABORT("Mesh file not found: " << filename << '\n');
3749  }
3750  else
3751  {
3752  Load(imesh, generate_edges, refine, fix_orientation);
3753  }
3754 }
3755 
3756 Mesh::Mesh(std::istream &input, int generate_edges, int refine,
3757  bool fix_orientation)
3758 {
3759  SetEmpty();
3760  Load(input, generate_edges, refine, fix_orientation);
3761 }
3762 
3763 void Mesh::ChangeVertexDataOwnership(double *vertex_data, int len_vertex_data,
3764  bool zerocopy)
3765 {
3766  // A dimension of 3 is now required since we use mfem::Vertex objects as PODs
3767  // and these object have a hardcoded double[3] entry
3768  MFEM_VERIFY(len_vertex_data >= NumOfVertices * 3,
3769  "Not enough vertices in external array : "
3770  "len_vertex_data = "<< len_vertex_data << ", "
3771  "NumOfVertices * 3 = " << NumOfVertices * 3);
3772  // Allow multiple calls to this method with the same vertex_data
3773  if (vertex_data == (double *)(vertices.GetData()))
3774  {
3775  MFEM_ASSERT(!vertices.OwnsData(), "invalid ownership");
3776  return;
3777  }
3778  if (!zerocopy)
3779  {
3780  memcpy(vertex_data, vertices.GetData(),
3781  NumOfVertices * 3 * sizeof(double));
3782  }
3783  // Vertex is POD double[3]
3784  vertices.MakeRef(reinterpret_cast<Vertex*>(vertex_data), NumOfVertices);
3785 }
3786 
3787 Mesh::Mesh(double *vertices_, int num_vertices,
3788  int *element_indices, Geometry::Type element_type,
3789  int *element_attributes, int num_elements,
3790  int *boundary_indices, Geometry::Type boundary_type,
3791  int *boundary_attributes, int num_boundary_elements,
3792  int dimension, int space_dimension)
3793 {
3794  if (space_dimension == -1)
3795  {
3796  space_dimension = dimension;
3797  }
3798 
3799  InitMesh(dimension, space_dimension, /*num_vertices*/ 0, num_elements,
3800  num_boundary_elements);
3801 
3802  int element_index_stride = Geometry::NumVerts[element_type];
3803  int boundary_index_stride = num_boundary_elements > 0 ?
3804  Geometry::NumVerts[boundary_type] : 0;
3805 
3806  // assuming Vertex is POD
3807  vertices.MakeRef(reinterpret_cast<Vertex*>(vertices_), num_vertices);
3808  NumOfVertices = num_vertices;
3809 
3810  for (int i = 0; i < num_elements; i++)
3811  {
3812  elements[i] = NewElement(element_type);
3813  elements[i]->SetVertices(element_indices + i * element_index_stride);
3814  elements[i]->SetAttribute(element_attributes[i]);
3815  }
3816  NumOfElements = num_elements;
3817 
3818  for (int i = 0; i < num_boundary_elements; i++)
3819  {
3820  boundary[i] = NewElement(boundary_type);
3821  boundary[i]->SetVertices(boundary_indices + i * boundary_index_stride);
3822  boundary[i]->SetAttribute(boundary_attributes[i]);
3823  }
3824  NumOfBdrElements = num_boundary_elements;
3825 
3826  FinalizeTopology();
3827 }
3828 
3830 {
3831  switch (geom)
3832  {
3833  case Geometry::POINT: return (new Point);
3834  case Geometry::SEGMENT: return (new Segment);
3835  case Geometry::TRIANGLE: return (new Triangle);
3836  case Geometry::SQUARE: return (new Quadrilateral);
3837  case Geometry::TETRAHEDRON:
3838 #ifdef MFEM_USE_MEMALLOC
3839  return TetMemory.Alloc();
3840 #else
3841  return (new Tetrahedron);
3842 #endif
3843  case Geometry::CUBE: return (new Hexahedron);
3844  case Geometry::PRISM: return (new Wedge);
3845  case Geometry::PYRAMID: return (new Pyramid);
3846  default:
3847  MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
3848  }
3849 
3850  return NULL;
3851 }
3852 
3854 {
3855  int geom, nv, *v;
3856  Element *el;
3857 
3858  input >> geom;
3859  el = NewElement(geom);
3860  MFEM_VERIFY(el, "Unsupported element type: " << geom);
3861  nv = el->GetNVertices();
3862  v = el->GetVertices();
3863  for (int i = 0; i < nv; i++)
3864  {
3865  input >> v[i];
3866  }
3867 
3868  return el;
3869 }
3870 
3871 void Mesh::PrintElementWithoutAttr(const Element *el, std::ostream &os)
3872 {
3873  os << el->GetGeometryType();
3874  const int nv = el->GetNVertices();
3875  const int *v = el->GetVertices();
3876  for (int j = 0; j < nv; j++)
3877  {
3878  os << ' ' << v[j];
3879  }
3880  os << '\n';
3881 }
3882 
3883 Element *Mesh::ReadElement(std::istream &input)
3884 {
3885  int attr;
3886  Element *el;
3887 
3888  input >> attr;
3889  el = ReadElementWithoutAttr(input);
3890  el->SetAttribute(attr);
3891 
3892  return el;
3893 }
3894 
3895 void Mesh::PrintElement(const Element *el, std::ostream &os)
3896 {
3897  os << el->GetAttribute() << ' ';
3898  PrintElementWithoutAttr(el, os);
3899 }
3900 
3902 {
3903  meshgen = mesh_geoms = 0;
3904  for (int i = 0; i < NumOfElements; i++)
3905  {
3906  const Element::Type type = GetElement(i)->GetType();
3907  switch (type)
3908  {
3909  case Element::TETRAHEDRON:
3911  case Element::TRIANGLE:
3912  mesh_geoms |= (1 << Geometry::TRIANGLE);
3913  case Element::SEGMENT:
3914  mesh_geoms |= (1 << Geometry::SEGMENT);
3915  case Element::POINT:
3916  mesh_geoms |= (1 << Geometry::POINT);
3917  meshgen |= 1;
3918  break;
3919 
3920  case Element::HEXAHEDRON:
3921  mesh_geoms |= (1 << Geometry::CUBE);
3923  mesh_geoms |= (1 << Geometry::SQUARE);
3924  mesh_geoms |= (1 << Geometry::SEGMENT);
3925  mesh_geoms |= (1 << Geometry::POINT);
3926  meshgen |= 2;
3927  break;
3928 
3929  case Element::WEDGE:
3930  mesh_geoms |= (1 << Geometry::PRISM);
3931  mesh_geoms |= (1 << Geometry::SQUARE);
3932  mesh_geoms |= (1 << Geometry::TRIANGLE);
3933  mesh_geoms |= (1 << Geometry::SEGMENT);
3934  mesh_geoms |= (1 << Geometry::POINT);
3935  meshgen |= 4;
3936  break;
3937 
3938  case Element::PYRAMID:
3939  mesh_geoms |= (1 << Geometry::PYRAMID);
3940  mesh_geoms |= (1 << Geometry::SQUARE);
3941  mesh_geoms |= (1 << Geometry::TRIANGLE);
3942  mesh_geoms |= (1 << Geometry::SEGMENT);
3943  mesh_geoms |= (1 << Geometry::POINT);
3944  meshgen |= 8;
3945  break;
3946 
3947  default:
3948  MFEM_ABORT("invalid element type: " << type);
3949  break;
3950  }
3951  }
3952 }
3953 
3954 void Mesh::Loader(std::istream &input, int generate_edges,
3955  std::string parse_tag)
3956 {
3957  int curved = 0, read_gf = 1;
3958  bool finalize_topo = true;
3959 
3960  if (!input)
3961  {
3962  MFEM_ABORT("Input stream is not open");
3963  }
3964 
3965  Clear();
3966 
3967  string mesh_type;
3968  input >> ws;
3969  getline(input, mesh_type);
3970  filter_dos(mesh_type);
3971 
3972  // MFEM's conforming mesh formats
3973  int mfem_version = 0;
3974  if (mesh_type == "MFEM mesh v1.0") { mfem_version = 10; } // serial
3975  else if (mesh_type == "MFEM mesh v1.2") { mfem_version = 12; } // parallel
3976 
3977  // MFEM nonconforming mesh format
3978  // (NOTE: previous v1.1 is now under this branch for backward compatibility)
3979  int mfem_nc_version = 0;
3980  if (mesh_type == "MFEM NC mesh v1.0") { mfem_nc_version = 10; }
3981  else if (mesh_type == "MFEM mesh v1.1") { mfem_nc_version = 1 /*legacy*/; }
3982 
3983  if (mfem_version)
3984  {
3985  // Formats mfem_v12 and newer have a tag indicating the end of the mesh
3986  // section in the stream. A user provided parse tag can also be provided
3987  // via the arguments. For example, if this is called from parallel mesh
3988  // object, it can indicate to read until parallel mesh section begins.
3989  if (mfem_version == 12 && parse_tag.empty())
3990  {
3991  parse_tag = "mfem_mesh_end";
3992  }
3993  ReadMFEMMesh(input, mfem_version, curved);
3994  }
3995  else if (mfem_nc_version)
3996  {
3997  MFEM_ASSERT(ncmesh == NULL, "internal error");
3998  int is_nc = 1;
3999 
4000 #ifdef MFEM_USE_MPI
4001  ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
4002  if (pmesh)
4003  {
4004  MFEM_VERIFY(mfem_nc_version >= 10,
4005  "Legacy nonconforming format (MFEM mesh v1.1) cannot be "
4006  "used to load a parallel nonconforming mesh, sorry.");
4007 
4008  ncmesh = new ParNCMesh(pmesh->GetComm(),
4009  input, mfem_nc_version, curved, is_nc);
4010  }
4011  else
4012 #endif
4013  {
4014  ncmesh = new NCMesh(input, mfem_nc_version, curved, is_nc);
4015  }
4017 
4018  if (!is_nc)
4019  {
4020  // special case for backward compatibility with MFEM <=4.2:
4021  // if the "vertex_parents" section is missing in the v1.1 format,
4022  // the mesh is treated as conforming
4023  delete ncmesh;
4024  ncmesh = NULL;
4025  }
4026  }
4027  else if (mesh_type == "linemesh") // 1D mesh
4028  {
4029  ReadLineMesh(input);
4030  }
4031  else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2")
4032  {
4033  if (mesh_type == "curved_areamesh2")
4034  {
4035  curved = 1;
4036  }
4037  ReadNetgen2DMesh(input, curved);
4038  }
4039  else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format")
4040  {
4041  ReadNetgen3DMesh(input);
4042  }
4043  else if (mesh_type == "TrueGrid")
4044  {
4045  ReadTrueGridMesh(input);
4046  }
4047  else if (mesh_type.rfind("# vtk DataFile Version") == 0)
4048  {
4049  int major_vtk_version = mesh_type[mesh_type.length()-3] - '0';
4050  // int minor_vtk_version = mesh_type[mesh_type.length()-1] - '0';
4051  MFEM_VERIFY(major_vtk_version >= 2 && major_vtk_version <= 4,
4052  "Unsupported VTK format");
4053  ReadVTKMesh(input, curved, read_gf, finalize_topo);
4054  }
4055  else if (mesh_type.rfind("<VTKFile ") == 0 || mesh_type.rfind("<?xml") == 0)
4056  {
4057  ReadXML_VTKMesh(input, curved, read_gf, finalize_topo, mesh_type);
4058  }
4059  else if (mesh_type == "MFEM NURBS mesh v1.0")
4060  {
4061  ReadNURBSMesh(input, curved, read_gf);
4062  }
4063  else if (mesh_type == "MFEM INLINE mesh v1.0")
4064  {
4065  ReadInlineMesh(input, generate_edges);
4066  return; // done with inline mesh construction
4067  }
4068  else if (mesh_type == "$MeshFormat") // Gmsh
4069  {
4070  ReadGmshMesh(input, curved, read_gf);
4071  }
4072  else if
4073  ((mesh_type.size() > 2 &&
4074  mesh_type[0] == 'C' && mesh_type[1] == 'D' && mesh_type[2] == 'F') ||
4075  (mesh_type.size() > 3 &&
4076  mesh_type[1] == 'H' && mesh_type[2] == 'D' && mesh_type[3] == 'F'))
4077  {
4078  named_ifgzstream *mesh_input = dynamic_cast<named_ifgzstream *>(&input);
4079  if (mesh_input)
4080  {
4081 #ifdef MFEM_USE_NETCDF
4082  ReadCubit(mesh_input->filename.c_str(), curved, read_gf);
4083 #else
4084  MFEM_ABORT("NetCDF support requires configuration with"
4085  " MFEM_USE_NETCDF=YES");
4086  return;
4087 #endif
4088  }
4089  else
4090  {
4091  MFEM_ABORT("Can not determine Cubit mesh filename!"
4092  " Use mfem::named_ifgzstream for input.");
4093  return;
4094  }
4095  }
4096  else
4097  {
4098  MFEM_ABORT("Unknown input mesh format: " << mesh_type);
4099  return;
4100  }
4101 
4102  // at this point the following should be defined:
4103  // 1) Dim
4104  // 2) NumOfElements, elements
4105  // 3) NumOfBdrElements, boundary
4106  // 4) NumOfVertices, with allocated space in vertices
4107  // 5) curved
4108  // 5a) if curved == 0, vertices must be defined
4109  // 5b) if curved != 0 and read_gf != 0,
4110  // 'input' must point to a GridFunction
4111  // 5c) if curved != 0 and read_gf == 0,
4112  // vertices and Nodes must be defined
4113  // optional:
4114  // 1) el_to_edge may be allocated (as in the case of P2 VTK meshes)
4115  // 2) ncmesh may be allocated
4116 
4117  // FinalizeTopology() will:
4118  // - assume that generate_edges is true
4119  // - assume that refine is false
4120  // - does not check the orientation of regular and boundary elements
4121  if (finalize_topo)
4122  {
4123  // don't generate any boundary elements, especially in parallel
4124  bool generate_bdr = false;
4125 
4126  FinalizeTopology(generate_bdr);
4127  }
4128 
4129  if (curved && read_gf)
4130  {
4131  Nodes = new GridFunction(this, input);
4132 
4133  own_nodes = 1;
4134  spaceDim = Nodes->VectorDim();
4135  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
4136 
4137  // Set vertex coordinates from the 'Nodes'
4139  }
4140 
4141  // If a parse tag was supplied, keep reading the stream until the tag is
4142  // encountered.
4143  if (mfem_version == 12)
4144  {
4145  string line;
4146  do
4147  {
4148  skip_comment_lines(input, '#');
4149  MFEM_VERIFY(input.good(), "Required mesh-end tag not found");
4150  getline(input, line);
4151  filter_dos(line);
4152  // mfem v1.2 may not have parse_tag in it, e.g. if trying to read a
4153  // serial mfem v1.2 mesh as parallel with "mfem_serial_mesh_end" as
4154  // parse_tag. That's why, regardless of parse_tag, we stop reading if
4155  // we find "mfem_mesh_end" which is required by mfem v1.2 format.
4156  if (line == "mfem_mesh_end") { break; }
4157  }
4158  while (line != parse_tag);
4159  }
4160  else if (mfem_nc_version >= 10)
4161  {
4162  string ident;
4163  skip_comment_lines(input, '#');
4164  input >> ident;
4165  MFEM_VERIFY(ident == "mfem_mesh_end",
4166  "invalid mesh: end of file tag not found");
4167  }
4168 
4169  // Finalize(...) should be called after this, if needed.
4170 }
4171 
4172 Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
4173 {
4174  int i, j, ie, ib, iv, *v, nv;
4175  Element *el;
4176  Mesh *m;
4177 
4178  SetEmpty();
4179 
4180  Dim = mesh_array[0]->Dimension();
4181  spaceDim = mesh_array[0]->SpaceDimension();
4182 
4183  if (mesh_array[0]->NURBSext)
4184  {
4185  // assuming the pieces form a partition of a NURBS mesh
4186  NURBSext = new NURBSExtension(mesh_array, num_pieces);
4187 
4190 
4192 
4193  // NumOfBdrElements = NURBSext->GetNBE();
4194  // NURBSext->GetBdrElementTopo(boundary);
4195 
4196  Array<int> lvert_vert, lelem_elem;
4197 
4198  // Here, for visualization purposes, we copy the boundary elements from
4199  // the individual pieces which include the interior boundaries. This
4200  // creates 'boundary' array that is different from the one generated by
4201  // the NURBSExtension which, in particular, makes the boundary-dof table
4202  // invalid. This, in turn, causes GetBdrElementTransformation to not
4203  // function properly.
4204  NumOfBdrElements = 0;
4205  for (i = 0; i < num_pieces; i++)
4206  {
4207  NumOfBdrElements += mesh_array[i]->GetNBE();
4208  }
4209  boundary.SetSize(NumOfBdrElements);
4210  vertices.SetSize(NumOfVertices);
4211  ib = 0;
4212  for (i = 0; i < num_pieces; i++)
4213  {
4214  m = mesh_array[i];
4215  m->NURBSext->GetVertexLocalToGlobal(lvert_vert);
4216  m->NURBSext->GetElementLocalToGlobal(lelem_elem);
4217  // copy the element attributes
4218  for (j = 0; j < m->GetNE(); j++)
4219  {
4220  elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j));
4221  }
4222  // copy the boundary
4223  for (j = 0; j < m->GetNBE(); j++)
4224  {
4225  el = m->GetBdrElement(j)->Duplicate(this);
4226  v = el->GetVertices();
4227  nv = el->GetNVertices();
4228  for (int k = 0; k < nv; k++)
4229  {
4230  v[k] = lvert_vert[v[k]];
4231  }
4232  boundary[ib++] = el;
4233  }
4234  // copy the vertices
4235  for (j = 0; j < m->GetNV(); j++)
4236  {
4237  vertices[lvert_vert[j]].SetCoords(m->SpaceDimension(),
4238  m->GetVertex(j));
4239  }
4240  }
4241  }
4242  else // not a NURBS mesh
4243  {
4244  NumOfElements = 0;
4245  NumOfBdrElements = 0;
4246  NumOfVertices = 0;
4247  for (i = 0; i < num_pieces; i++)
4248  {
4249  m = mesh_array[i];
4250  NumOfElements += m->GetNE();
4251  NumOfBdrElements += m->GetNBE();
4252  NumOfVertices += m->GetNV();
4253  }
4254  elements.SetSize(NumOfElements);
4255  boundary.SetSize(NumOfBdrElements);
4256  vertices.SetSize(NumOfVertices);
4257  ie = ib = iv = 0;
4258  for (i = 0; i < num_pieces; i++)
4259  {
4260  m = mesh_array[i];
4261  // copy the elements
4262  for (j = 0; j < m->GetNE(); j++)
4263  {
4264  el = m->GetElement(j)->Duplicate(this);
4265  v = el->GetVertices();
4266  nv = el->GetNVertices();
4267  for (int k = 0; k < nv; k++)
4268  {
4269  v[k] += iv;
4270  }
4271  elements[ie++] = el;
4272  }
4273  // copy the boundary elements
4274  for (j = 0; j < m->GetNBE(); j++)
4275  {
4276  el = m->GetBdrElement(j)->Duplicate(this);
4277  v = el->GetVertices();
4278  nv = el->GetNVertices();
4279  for (int k = 0; k < nv; k++)
4280  {
4281  v[k] += iv;
4282  }
4283  boundary[ib++] = el;
4284  }
4285  // copy the vertices
4286  for (j = 0; j < m->GetNV(); j++)
4287  {
4288  vertices[iv++].SetCoords(m->SpaceDimension(), m->GetVertex(j));
4289  }
4290  }
4291  }
4292 
4293  FinalizeTopology();
4294 
4295  // copy the nodes (curvilinear meshes)
4296  GridFunction *g = mesh_array[0]->GetNodes();
4297  if (g)
4298  {
4299  Array<GridFunction *> gf_array(num_pieces);
4300  for (i = 0; i < num_pieces; i++)
4301  {
4302  gf_array[i] = mesh_array[i]->GetNodes();
4303  }
4304  Nodes = new GridFunction(this, gf_array, num_pieces);
4305  own_nodes = 1;
4306  }
4307 
4308 #ifdef MFEM_DEBUG
4309  CheckElementOrientation(false);
4311 #endif
4312 }
4313 
4314 Mesh::Mesh(Mesh *orig_mesh, int ref_factor, int ref_type)
4315 {
4316  Array<int> ref_factors(orig_mesh->GetNE());
4317  ref_factors = ref_factor;
4318  MakeRefined_(*orig_mesh, ref_factors, ref_type);
4319 }
4320 
4321 void Mesh::MakeRefined_(Mesh &orig_mesh, const Array<int> ref_factors,
4322  int ref_type)
4323 {
4324  SetEmpty();
4325  Dim = orig_mesh.Dimension();
4326  spaceDim = orig_mesh.SpaceDimension();
4327 
4328  int orig_ne = orig_mesh.GetNE();
4329  MFEM_VERIFY(ref_factors.Size() == orig_ne && orig_ne > 0,
4330  "Number of refinement factors must equal number of elements")
4331  MFEM_VERIFY(ref_factors.Min() >= 1, "Refinement factor must be >= 1");
4332  const int q_type = BasisType::GetQuadrature1D(ref_type);
4333  MFEM_VERIFY(Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid,
4334  "Invalid refinement type. Must use closed basis type.");
4335 
4336  int min_ref = ref_factors.Min();
4337  int max_ref = ref_factors.Max();
4338 
4339  bool var_order = (min_ref != max_ref);
4340 
4341  // variable order space can only be constructed over an NC mesh
4342  if (var_order) { orig_mesh.EnsureNCMesh(true); }
4343 
4344  // Construct a scalar H1 FE space of order ref_factor and use its dofs as
4345  // the indices of the new, refined vertices.
4346  H1_FECollection rfec(min_ref, Dim, ref_type);
4347  FiniteElementSpace rfes(&orig_mesh, &rfec);
4348 
4349  if (var_order)
4350  {
4351  rfes.SetRelaxedHpConformity(false);
4352  for (int i = 0; i < orig_ne; i++)
4353  {
4354  rfes.SetElementOrder(i, ref_factors[i]);
4355  }
4356  rfes.Update(false);
4357  }
4358 
4359  // Set the number of vertices, set the actual coordinates later
4360  NumOfVertices = rfes.GetNDofs();
4361  vertices.SetSize(NumOfVertices);
4362 
4363  Array<int> rdofs;
4364  DenseMatrix phys_pts;
4365 
4366  GeometryRefiner refiner;
4367  refiner.SetType(q_type);
4368 
4369  // Add refined elements and set vertex coordinates
4370  for (int el = 0; el < orig_ne; el++)
4371  {
4372  Geometry::Type geom = orig_mesh.GetElementGeometry(el);
4373  int attrib = orig_mesh.GetAttribute(el);
4374  int nvert = Geometry::NumVerts[geom];
4375  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el]);
4376 
4377  rfes.GetElementDofs(el, rdofs);
4378  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4379  const FiniteElement *rfe = rfes.GetFE(el);
4380  orig_mesh.GetElementTransformation(el)->Transform(rfe->GetNodes(),
4381  phys_pts);
4382  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[el]);
4383  for (int i = 0; i < phys_pts.Width(); i++)
4384  {
4385  vertices[rdofs[i]].SetCoords(spaceDim, phys_pts.GetColumn(i));
4386  }
4387  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4388  {
4389  Element *elem = NewElement(geom);
4390  elem->SetAttribute(attrib);
4391  int *v = elem->GetVertices();
4392  for (int k = 0; k < nvert; k++)
4393  {
4394  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4395  v[k] = rdofs[c2h_map[cid]];
4396  }
4397  AddElement(elem);
4398  }
4399  }
4400 
4401  if (Dim > 2)
4402  {
4403  GetElementToFaceTable(false);
4404  GenerateFaces();
4405  }
4406 
4407  // Add refined boundary elements
4408  for (int el = 0; el < orig_mesh.GetNBE(); el++)
4409  {
4410  int i, info;
4411  orig_mesh.GetBdrElementAdjacentElement(el, i, info);
4412  Geometry::Type geom = orig_mesh.GetBdrElementBaseGeometry(el);
4413  int attrib = orig_mesh.GetBdrAttribute(el);
4414  int nvert = Geometry::NumVerts[geom];
4415  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[i]);
4416 
4417  rfes.GetBdrElementDofs(el, rdofs);
4418  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4419  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[i]);
4420  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4421  {
4422  Element *elem = NewElement(geom);
4423  elem->SetAttribute(attrib);
4424  int *v = elem->GetVertices();
4425  for (int k = 0; k < nvert; k++)
4426  {
4427  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4428  v[k] = rdofs[c2h_map[cid]];
4429  }
4430  AddBdrElement(elem);
4431  }
4432  }
4433  FinalizeTopology(false);
4434  sequence = orig_mesh.GetSequence() + 1;
4436 
4437  // Set up the nodes of the new mesh (if the original mesh has nodes). The new
4438  // mesh is always straight-sided (i.e. degree 1 finite element space), but
4439  // the nodes are required for e.g. periodic meshes.
4440  if (orig_mesh.GetNodes())
4441  {
4442  bool discont = orig_mesh.GetNodalFESpace()->IsDGSpace();
4443  Ordering::Type dof_ordering = orig_mesh.GetNodalFESpace()->GetOrdering();
4444  Mesh::SetCurvature(1, discont, spaceDim, dof_ordering);
4445  FiniteElementSpace *nodal_fes = Nodes->FESpace();
4446  const FiniteElementCollection *nodal_fec = nodal_fes->FEColl();
4447  H1_FECollection vertex_fec(1, Dim);
4448  Array<int> dofs;
4449  int el_counter = 0;
4450  for (int iel = 0; iel < orig_ne; iel++)
4451  {
4452  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(iel);
4453  int nvert = Geometry::NumVerts[geom];
4454  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[iel]);
4455  rfes.GetElementDofs(iel, rdofs);
4456  const FiniteElement *rfe = rfes.GetFE(iel);
4457  orig_mesh.GetElementTransformation(iel)->Transform(rfe->GetNodes(),
4458  phys_pts);
4459  const int *node_map = NULL;
4460  const H1_FECollection *h1_fec =
4461  dynamic_cast<const H1_FECollection *>(nodal_fec);
4462  if (h1_fec != NULL) { node_map = h1_fec->GetDofMap(geom); }
4463  const int *vertex_map = vertex_fec.GetDofMap(geom);
4464  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[iel]);
4465  for (int jel = 0; jel < RG.RefGeoms.Size()/nvert; jel++)
4466  {
4467  nodal_fes->GetElementVDofs(el_counter++, dofs);
4468  for (int iv_lex=0; iv_lex<nvert; ++iv_lex)
4469  {
4470  // convert from lexicographic to vertex index
4471  int iv = vertex_map[iv_lex];
4472  // index of vertex of current element in phys_pts matrix
4473  int pt_idx = c2h_map[RG.RefGeoms[iv+nvert*jel]];
4474  // index of current vertex into DOF array
4475  int node_idx = node_map ? node_map[iv_lex] : iv_lex;
4476  for (int d=0; d<spaceDim; ++d)
4477  {
4478  (*Nodes)[dofs[node_idx + d*nvert]] = phys_pts(d,pt_idx);
4479  }
4480  }
4481  }
4482  }
4483  }
4484 
4485  // Setup the data for the coarse-fine refinement transformations
4486  CoarseFineTr.embeddings.SetSize(GetNE());
4487  // First, compute total number of point matrices that we need per geometry
4488  // and the offsets into that array
4489  using GeomRef = std::pair<Geometry::Type, int>;
4490  std::map<GeomRef, int> point_matrices_offsets;
4491  int n_point_matrices[Geometry::NumGeom] = {}; // initialize to zero
4492  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4493  {
4494  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4495  // Have we seen this pair of (goemetry, refinement level) before?
4496  GeomRef id(geom, ref_factors[el_coarse]);
4497  if (point_matrices_offsets.find(id) == point_matrices_offsets.end())
4498  {
4499  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el_coarse]);
4500  int nvert = Geometry::NumVerts[geom];
4501  int nref_el = RG.RefGeoms.Size()/nvert;
4502  // If not, then store the offset and add to the size required
4503  point_matrices_offsets[id] = n_point_matrices[geom];
4504  n_point_matrices[geom] += nref_el;
4505  }
4506  }
4507 
4508  // Set up the sizes
4509  for (int geom = 0; geom < Geometry::NumGeom; ++geom)
4510  {
4511  int nmatrices = n_point_matrices[geom];
4512  int nvert = Geometry::NumVerts[geom];
4513  CoarseFineTr.point_matrices[geom].SetSize(Dim, nvert, nmatrices);
4514  }
4515 
4516  // Compute the point matrices and embeddings
4517  int el_fine = 0;
4518  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4519  {
4520  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4521  int ref = ref_factors[el_coarse];
4522  int offset = point_matrices_offsets[GeomRef(geom, ref)];
4523  int nvert = Geometry::NumVerts[geom];
4524  RefinedGeometry &RG = *refiner.Refine(geom, ref);
4525  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4526  {
4527  DenseMatrix &Pj = CoarseFineTr.point_matrices[geom](offset + j);
4528  for (int k = 0; k < nvert; k++)
4529  {
4530  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4531  const IntegrationPoint &ip = RG.RefPts[cid];
4532  ip.Get(Pj.GetColumn(k), Dim);
4533  }
4534 
4535  Embedding &emb = CoarseFineTr.embeddings[el_fine];
4536  emb.parent = el_coarse;
4537  emb.matrix = offset + j;
4538  ++el_fine;
4539  }
4540  }
4541 
4542  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4543 
4544  // The check below is disabled because is fails for parallel meshes with
4545  // interior "boundary" element that, when such "boundary" element is between
4546  // two elements on different processors.
4547  // MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4548 }
4549 
4550 Mesh Mesh::MakeSimplicial(const Mesh &orig_mesh)
4551 {
4552  Mesh mesh;
4553  mesh.MakeSimplicial_(orig_mesh, NULL);
4554  return mesh;
4555 }
4556 
4557 void Mesh::MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
4558 {
4559  MFEM_VERIFY(const_cast<Mesh&>(orig_mesh).CheckElementOrientation(false) == 0,
4560  "Mesh::MakeSimplicial requires a properly oriented input mesh");
4561  MFEM_VERIFY(orig_mesh.Conforming(),
4562  "Mesh::MakeSimplicial does not support non-conforming meshes.")
4563 
4564  int dim = orig_mesh.Dimension();
4565  int sdim = orig_mesh.SpaceDimension();
4566 
4567  if (dim == 1)
4568  {
4569  Mesh copy(orig_mesh);
4570  Swap(copy, true);
4571  return;
4572  }
4573 
4574  int nv = orig_mesh.GetNV();
4575  int ne = orig_mesh.GetNE();
4576  int nbe = orig_mesh.GetNBE();
4577 
4578  static int num_subdivisions[Geometry::NUM_GEOMETRIES];
4579  num_subdivisions[Geometry::POINT] = 1;
4580  num_subdivisions[Geometry::SEGMENT] = 1;
4581  num_subdivisions[Geometry::TRIANGLE] = 1;
4582  num_subdivisions[Geometry::TETRAHEDRON] = 1;
4583  num_subdivisions[Geometry::SQUARE] = 2;
4584  num_subdivisions[Geometry::PRISM] = 3;
4585  num_subdivisions[Geometry::CUBE] = 6;
4586  // NOTE: some hexes may be subdivided into only 5 tets, so this is an
4587  // estimate only. The actual number of created tets may be less, so the
4588  // elements array will need to be shrunk after mesh creation.
4589  int new_ne = 0, new_nbe = 0;
4590  for (int i=0; i<ne; ++i)
4591  {
4592  new_ne += num_subdivisions[orig_mesh.GetElementBaseGeometry(i)];
4593  }
4594  for (int i=0; i<nbe; ++i)
4595  {
4596  new_nbe += num_subdivisions[orig_mesh.GetBdrElementBaseGeometry(i)];
4597  }
4598 
4599  InitMesh(dim, sdim, nv, new_ne, new_nbe);
4600 
4601  // Vertices of the new mesh are same as the original mesh
4602  NumOfVertices = nv;
4603  for (int i=0; i<nv; ++i)
4604  {
4605  vertices[i].SetCoords(dim, orig_mesh.vertices[i]());
4606  }
4607 
4608  // We need a global vertex numbering to identify which diagonals to split
4609  // (quad faces are split using the diagonal originating from the smallest
4610  // global vertex number). Use the supplied global numbering, if it is
4611  // non-NULL, otherwise use the local numbering.
4612  Array<int> vglobal_id;
4613  if (vglobal == NULL)
4614  {
4615  vglobal_id.SetSize(nv);
4616  for (int i=0; i<nv; ++i) { vglobal_id[i] = i; }
4617  vglobal = vglobal_id.GetData();
4618  }
4619 
4620  constexpr int nv_tri = 3, nv_quad = 4, nv_tet = 4, nv_prism = 6, nv_hex = 8;
4621  constexpr int quad_ntris = 2, prism_ntets = 3;
4622  static const int quad_trimap[2][nv_tri*quad_ntris] =
4623  {
4624  {
4625  0, 0,
4626  1, 2,
4627  2, 3
4628  },{
4629  0, 1,
4630  1, 2,
4631  3, 3
4632  }
4633  };
4634  static const int prism_rot[nv_prism*nv_prism] =
4635  {
4636  0, 1, 2, 3, 4, 5,
4637  1, 2, 0, 4, 5, 3,
4638  2, 0, 1, 5, 3, 4,
4639  3, 5, 4, 0, 2, 1,
4640  4, 3, 5, 1, 0, 2,
4641  5, 4, 3, 2, 1, 0
4642  };
4643  static const int prism_f[nv_quad] = {1, 2, 5, 4};
4644  static const int prism_tetmaps[2][nv_prism*prism_ntets] =
4645  {
4646  {
4647  0, 0, 0,
4648  1, 1, 4,
4649  2, 5, 5,
4650  5, 4, 3
4651  },{
4652  0, 0, 0,
4653  1, 4, 4,
4654  2, 2, 5,
4655  4, 5, 3
4656  }
4657  };
4658  static const int hex_rot[nv_hex*nv_hex] =
4659  {
4660  0, 1, 2, 3, 4, 5, 6, 7,
4661  1, 0, 4, 5, 2, 3, 7, 6,
4662  2, 1, 5, 6, 3, 0, 4, 7,
4663  3, 0, 1, 2, 7, 4, 5, 6,
4664  4, 0, 3, 7, 5, 1, 2, 6,
4665  5, 1, 0, 4, 6, 2, 3, 7,
4666  6, 2, 1, 5, 7, 3, 0, 4,
4667  7, 3, 2, 6, 4, 0, 1, 5
4668  };
4669  static const int hex_f0[nv_quad] = {1, 2, 6, 5};
4670  static const int hex_f1[nv_quad] = {2, 3, 7, 6};
4671  static const int hex_f2[nv_quad] = {4, 5, 6, 7};
4672  static const int num_rot[8] = {0, 1, 2, 0, 0, 2, 1, 0};
4673  static const int hex_tetmap0[nv_tet*5] =
4674  {
4675  0, 0, 0, 0, 2,
4676  1, 2, 2, 5, 7,
4677  2, 7, 3, 7, 5,
4678  5, 5, 7, 4, 6
4679  };
4680  static const int hex_tetmap1[nv_tet*6] =
4681  {
4682  0, 0, 1, 0, 0, 1,
4683  5, 1, 6, 7, 7, 7,
4684  7, 7, 7, 2, 1, 6,
4685  4, 5, 5, 3, 2, 2
4686  };
4687  static const int hex_tetmap2[nv_tet*6] =
4688  {
4689  0, 0, 0, 0, 0, 0,
4690  4, 3, 7, 1, 3, 6,
4691  5, 7, 4, 2, 6, 5,
4692  6, 6, 6, 5, 2, 2
4693  };
4694  static const int hex_tetmap3[nv_tet*6] =
4695  {
4696  0, 0, 0, 0, 1, 1,
4697  2, 3, 7, 5, 5, 6,
4698  3, 7, 4, 6, 6, 2,
4699  6, 6, 6, 4, 0, 0
4700  };
4701  static const int *hex_tetmaps[4] =
4702  {
4703  hex_tetmap0, hex_tetmap1, hex_tetmap2, hex_tetmap3
4704  };
4705 
4706  auto find_min = [](const int*a, int n) { return std::min_element(a,a+n)-a; };
4707 
4708  for (int i=0; i<ne; ++i)
4709  {
4710  const int *v = orig_mesh.elements[i]->GetVertices();
4711  const int attrib = orig_mesh.GetAttribute(i);
4712  const Geometry::Type orig_geom = orig_mesh.GetElementBaseGeometry(i);
4713 
4714  if (num_subdivisions[orig_geom] == 1)
4715  {
4716  // (num_subdivisions[orig_geom] == 1) implies that the element does
4717  // not need to be further split (it is either a segment, triangle,
4718  // or tetrahedron), and so it is left unchanged.
4719  Element *e = NewElement(orig_geom);
4720  e->SetAttribute(attrib);
4721  e->SetVertices(v);
4722  AddElement(e);
4723  }
4724  else if (orig_geom == Geometry::SQUARE)
4725  {
4726  for (int itri=0; itri<quad_ntris; ++itri)
4727  {
4729  e->SetAttribute(attrib);
4730  int *v2 = e->GetVertices();
4731  for (int iv=0; iv<nv_tri; ++iv)
4732  {
4733  v2[iv] = v[quad_trimap[0][itri + iv*quad_ntris]];
4734  }
4735  AddElement(e);
4736  }
4737  }
4738  else if (orig_geom == Geometry::PRISM)
4739  {
4740  int vg[nv_prism];
4741  for (int iv=0; iv<nv_prism; ++iv) { vg[iv] = vglobal[v[iv]]; }
4742  // Rotate the vertices of the prism so that the smallest vertex index
4743  // is in the first place
4744  int irot = find_min(vg, nv_prism);
4745  for (int iv=0; iv<nv_prism; ++iv)
4746  {
4747  int jv = prism_rot[iv + irot*nv_prism];
4748  vg[iv] = v[jv];
4749  }
4750  // Two cases according to which diagonal splits third quad face
4751  int q[nv_quad];
4752  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[prism_f[iv]]]; }
4753  int j = find_min(q, nv_quad);
4754  const int *tetmap = (j == 0 || j == 2) ? prism_tetmaps[0] : prism_tetmaps[1];
4755  for (int itet=0; itet<prism_ntets; ++itet)
4756  {
4758  e->SetAttribute(attrib);
4759  int *v2 = e->GetVertices();
4760  for (int iv=0; iv<nv_tet; ++iv)
4761  {
4762  v2[iv] = vg[tetmap[itet + iv*prism_ntets]];
4763  }
4764  AddElement(e);
4765  }
4766  }
4767  else if (orig_geom == Geometry::CUBE)
4768  {
4769  int vg[nv_hex];
4770  for (int iv=0; iv<nv_hex; ++iv) { vg[iv] = vglobal[v[iv]]; }
4771 
4772  // Rotate the vertices of the hex so that the smallest vertex index is
4773  // in the first place
4774  int irot = find_min(vg, nv_hex);
4775  for (int iv=0; iv<nv_hex; ++iv)
4776  {
4777  int jv = hex_rot[iv + irot*nv_hex];
4778  vg[iv] = v[jv];
4779  }
4780 
4781  int q[nv_quad];
4782  // Bitmask is three binary digits, each digit is 1 if the diagonal of
4783  // the corresponding face goes through the 7th vertex, and 0 if not.
4784  int bitmask = 0;
4785  int j;
4786  // First quad face
4787  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f0[iv]]]; }
4788  j = find_min(q, nv_quad);
4789  if (j == 0 || j == 2) { bitmask += 4; }
4790  // Second quad face
4791  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f1[iv]]]; }
4792  j = find_min(q, nv_quad);
4793  if (j == 1 || j == 3) { bitmask += 2; }
4794  // Third quad face
4795  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f2[iv]]]; }
4796  j = find_min(q, nv_quad);
4797  if (j == 0 || j == 2) { bitmask += 1; }
4798 
4799  // Apply rotations
4800  int nrot = num_rot[bitmask];
4801  for (int k=0; k<nrot; ++k)
4802  {
4803  int vtemp;
4804  vtemp = vg[1];
4805  vg[1] = vg[4];
4806  vg[4] = vg[3];
4807  vg[3] = vtemp;
4808  vtemp = vg[5];
4809  vg[5] = vg[7];
4810  vg[7] = vg[2];
4811  vg[2] = vtemp;
4812  }
4813 
4814  // Sum up nonzero bits in bitmask
4815  int ndiags = ((bitmask&4) >> 2) + ((bitmask&2) >> 1) + (bitmask&1);
4816  int ntets = (ndiags == 0) ? 5 : 6;
4817  const int *tetmap = hex_tetmaps[ndiags];
4818  for (int itet=0; itet<ntets; ++itet)
4819  {
4821  e->SetAttribute(attrib);
4822  int *v2 = e->GetVertices();
4823  for (int iv=0; iv<nv_tet; ++iv)
4824  {
4825  v2[iv] = vg[tetmap[itet + iv*ntets]];
4826  }
4827  AddElement(e);
4828  }
4829  }
4830  }
4831  // In 3D, shrink the element array because some hexes have only 5 tets
4832  if (dim == 3) { elements.SetSize(NumOfElements); }
4833 
4834  for (int i=0; i<nbe; ++i)
4835  {
4836  const int *v = orig_mesh.boundary[i]->GetVertices();
4837  const int attrib = orig_mesh.GetBdrAttribute(i);
4838  const Geometry::Type orig_geom = orig_mesh.GetBdrElementBaseGeometry(i);
4839  if (num_subdivisions[orig_geom] == 1)
4840  {
4841  Element *be = NewElement(orig_geom);
4842  be->SetAttribute(attrib);
4843  be->SetVertices(v);
4844  AddBdrElement(be);
4845  }
4846  else if (orig_geom == Geometry::SQUARE)
4847  {
4848  int vg[nv_quad];
4849  for (int iv=0; iv<nv_quad; ++iv) { vg[iv] = vglobal[v[iv]]; }
4850  // Split quad according the smallest (global) vertex
4851  int iv_min = find_min(vg, nv_quad);
4852  int isplit = (iv_min == 0 || iv_min == 2) ? 0 : 1;
4853  for (int itri=0; itri<quad_ntris; ++itri)
4854  {
4856  be->SetAttribute(attrib);
4857  int *v2 = be->GetVertices();
4858  for (int iv=0; iv<nv_tri; ++iv)
4859  {
4860  v2[iv] = v[quad_trimap[isplit][itri + iv*quad_ntris]];
4861  }
4862  AddBdrElement(be);
4863  }
4864  }
4865  else
4866  {
4867  MFEM_ABORT("Unreachable");
4868  }
4869  }
4870 
4871  FinalizeTopology(false);
4872  sequence = orig_mesh.GetSequence();
4873  last_operation = orig_mesh.last_operation;
4874 
4875  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4876  MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4877 }
4878 
4879 Mesh Mesh::MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v)
4880 {
4881  Mesh periodic_mesh(orig_mesh, true); // Make a copy of the original mesh
4882  const FiniteElementSpace *nodal_fes = orig_mesh.GetNodalFESpace();
4883  int nodal_order = nodal_fes ? nodal_fes->GetMaxElementOrder() : 1;
4884  periodic_mesh.SetCurvature(nodal_order, true);
4885 
4886  // renumber element vertices
4887  for (int i = 0; i < periodic_mesh.GetNE(); i++)
4888  {
4889  Element *el = periodic_mesh.GetElement(i);
4890  int *v = el->GetVertices();
4891  int nv = el->GetNVertices();
4892  for (int j = 0; j < nv; j++)
4893  {
4894  v[j] = v2v[v[j]];
4895  }
4896  }
4897  // renumber boundary element vertices
4898  for (int i = 0; i < periodic_mesh.GetNBE(); i++)
4899  {
4900  Element *el = periodic_mesh.GetBdrElement(i);
4901  int *v = el->GetVertices();
4902  int nv = el->GetNVertices();
4903  for (int j = 0; j < nv; j++)
4904  {
4905  v[j] = v2v[v[j]];
4906  }
4907  }
4908 
4909  periodic_mesh.RemoveUnusedVertices();
4910  return periodic_mesh;
4911 }
4912 
4914  const std::vector<Vector> &translations, double tol) const
4915 {
4916  int sdim = SpaceDimension();
4917 
4918  Vector coord(sdim), at(sdim), dx(sdim);
4919  Vector xMax(sdim), xMin(sdim), xDiff(sdim);
4920  xMax = xMin = xDiff = 0.0;
4921 
4922  // Get a list of all vertices on the boundary
4923  set<int> bdr_v;
4924  for (int be = 0; be < GetNBE(); be++)
4925  {
4926  Array<int> dofs;
4927  GetBdrElementVertices(be,dofs);
4928 
4929  for (int i = 0; i < dofs.Size(); i++)
4930  {
4931  bdr_v.insert(dofs[i]);
4932 
4933  coord = GetVertex(dofs[i]);
4934  for (int j = 0; j < sdim; j++)
4935  {
4936  xMax[j] = max(xMax[j], coord[j]);
4937  xMin[j] = min(xMin[j], coord[j]);
4938  }
4939  }
4940  }
4941  add(xMax, -1.0, xMin, xDiff);
4942  double dia = xDiff.Norml2(); // compute mesh diameter
4943 
4944  // We now identify coincident vertices. Several originally distinct vertices
4945  // may become coincident under the periodic mapping. One of these vertices
4946  // will be identified as the "primary" vertex, and all other coincident
4947  // vertices will be considered as "replicas".
4948 
4949  // replica2primary[v] is the index of the primary vertex of replica `v`
4950  map<int, int> replica2primary;
4951  // primary2replicas[v] is a set of indices of replicas of primary vertex `v`
4952  map<int, set<int>> primary2replicas;
4953 
4954  // We begin with the assumption that all vertices are primary, and that there
4955  // are no replicas.
4956  for (int v : bdr_v) { primary2replicas[v]; }
4957 
4958  // Make `r` and all of `r`'s replicas be replicas of `p`. Delete `r` from the
4959  // list of primary vertices.
4960  auto make_replica = [&replica2primary, &primary2replicas](int r, int p)
4961  {
4962  if (r == p) { return; }
4963  primary2replicas[p].insert(r);
4964  replica2primary[r] = p;
4965  for (int s : primary2replicas[r])
4966  {
4967  primary2replicas[p].insert(s);
4968  replica2primary[s] = p;
4969  }
4970  primary2replicas.erase(r);
4971  };
4972 
4973  for (unsigned int i = 0; i < translations.size(); i++)
4974  {
4975  for (int vi : bdr_v)
4976  {
4977  coord = GetVertex(vi);
4978  add(coord, translations[i], at);
4979 
4980  for (int vj : bdr_v)
4981  {
4982  coord = GetVertex(vj);
4983  add(at, -1.0, coord, dx);
4984  if (dx.Norml2() > dia*tol) { continue; }
4985 
4986  // The two vertices vi and vj are coincident.
4987 
4988  // Are vertices `vi` and `vj` already primary?
4989  bool pi = primary2replicas.find(vi) != primary2replicas.end();
4990  bool pj = primary2replicas.find(vj) != primary2replicas.end();
4991 
4992  if (pi && pj)
4993  {
4994  // Both vertices are currently primary
4995  // Demote `vj` to be a replica of `vi`
4996  make_replica(vj, vi);
4997  }
4998  else if (pi && !pj)
4999  {
5000  // `vi` is primary and `vj` is a replica
5001  int owner_of_vj = replica2primary[vj];
5002  // Make `vi` and its replicas be replicas of `vj`'s owner
5003  make_replica(vi, owner_of_vj);
5004  }
5005  else if (!pi && pj)
5006  {
5007  // `vi` is currently a replica and `vj` is currently primary
5008  // Make `vj` and its replicas be replicas of `vi`'s owner
5009  int owner_of_vi = replica2primary[vi];
5010  make_replica(vj, owner_of_vi);
5011  }
5012  else
5013  {
5014  // Both vertices are currently replicas
5015  // Make `vj`'s owner and all of its owner's replicas be replicas
5016  // of `vi`'s owner
5017  int owner_of_vi = replica2primary[vi];
5018  int owner_of_vj = replica2primary[vj];
5019  make_replica(owner_of_vj, owner_of_vi);
5020  }
5021  break;
5022  }
5023  }
5024  }
5025 
5026  std::vector<int> v2v(GetNV());
5027  for (size_t i = 0; i < v2v.size(); i++)
5028  {
5029  v2v[i] = i;
5030  }
5031  for (auto &&r2p : replica2primary)
5032  {
5033  v2v[r2p.first] = r2p.second;
5034  }
5035  return v2v;
5036 }
5037 
5039 {
5040  if (NURBSext == NULL)
5041  {
5042  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5043  }
5044 
5045  if (kv.Size() != NURBSext->GetNKV())
5046  {
5047  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5048  }
5049 
5051 
5052  NURBSext->KnotInsert(kv);
5053 
5054  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5055  sequence++;
5056 
5057  UpdateNURBS();
5058 }
5059 
5061 {
5062  if (NURBSext == NULL)
5063  {
5064  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5065  }
5066 
5067  if (kv.Size() != NURBSext->GetNKV())
5068  {
5069  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5070  }
5071 
5073 
5074  NURBSext->KnotInsert(kv);
5075 
5076  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5077  sequence++;
5078 
5079  UpdateNURBS();
5080 }
5081 
5083 {
5084  // do not check for NURBSext since this method is protected
5086 
5088 
5089  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5090  sequence++;
5091 
5092  UpdateNURBS();
5093 }
5094 
5095 void Mesh::DegreeElevate(int rel_degree, int degree)
5096 {
5097  if (NURBSext == NULL)
5098  {
5099  mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!");
5100  }
5101 
5103 
5104  NURBSext->DegreeElevate(rel_degree, degree);
5105 
5106  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5107  sequence++;
5108 
5109  UpdateNURBS();
5110 }
5111 
5113 {
5114  ResetLazyData();
5115 
5117 
5118  Dim = NURBSext->Dimension();
5119  spaceDim = Dim;
5120 
5121  if (NumOfElements != NURBSext->GetNE())
5122  {
5123  for (int i = 0; i < elements.Size(); i++)
5124  {
5125  FreeElement(elements[i]);
5126  }
5129  }
5130 
5131  if (NumOfBdrElements != NURBSext->GetNBE())
5132  {
5133  for (int i = 0; i < boundary.Size(); i++)
5134  {
5135  FreeElement(boundary[i]);
5136  }
5139  }
5140 
5141  Nodes->FESpace()->Update();
5142  Nodes->Update();
5144 
5145  if (NumOfVertices != NURBSext->GetNV())
5146  {
5148  vertices.SetSize(NumOfVertices);
5149  int vd = Nodes->VectorDim();
5150  for (int i = 0; i < vd; i++)
5151  {
5152  Vector vert_val;
5153  Nodes->GetNodalValues(vert_val, i+1);
5154  for (int j = 0; j < NumOfVertices; j++)
5155  {
5156  vertices[j](i) = vert_val(j);
5157  }
5158  }
5159  }
5160 
5161  if (el_to_edge)
5162  {
5164  if (Dim == 2)
5165  {
5166  GenerateFaces();
5167  }
5168  }
5169 
5170  if (el_to_face)
5171  {
5173  GenerateFaces();
5174  }
5175 }
5176 
5177 void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot)
5178 {
5179  SetEmpty();
5180 
5181  // Read MFEM NURBS mesh v1.0 format
5182  string ident;
5183 
5184  skip_comment_lines(input, '#');
5185 
5186  input >> ident; // 'dimension'
5187  input >> Dim;
5188  spaceDim = Dim;
5189 
5190  skip_comment_lines(input, '#');
5191 
5192  input >> ident; // 'elements'
5193  input >> NumOfElements;
5194  elements.SetSize(NumOfElements);
5195  for (int j = 0; j < NumOfElements; j++)
5196  {
5197  elements[j] = ReadElement(input);
5198  }
5199 
5200  skip_comment_lines(input, '#');
5201 
5202  input >> ident; // 'boundary'
5203  input >> NumOfBdrElements;
5204  boundary.SetSize(NumOfBdrElements);
5205  for (int j = 0; j < NumOfBdrElements; j++)
5206  {
5207  boundary[j] = ReadElement(input);
5208  }
5209 
5210  skip_comment_lines(input, '#');
5211 
5212  input >> ident; // 'edges'
5213  input >> NumOfEdges;
5214  edge_vertex = new Table(NumOfEdges, 2);
5215  edge_to_knot.SetSize(NumOfEdges);
5216  for (int j = 0; j < NumOfEdges; j++)
5217  {
5218  int *v = edge_vertex->GetRow(j);
5219  input >> edge_to_knot[j] >> v[0] >> v[1];
5220  if (v[0] > v[1])
5221  {
5222  edge_to_knot[j] = -1 - edge_to_knot[j];
5223  }
5224  }
5225 
5226  skip_comment_lines(input, '#');
5227 
5228  input >> ident; // 'vertices'
5229  input >> NumOfVertices;
5230  vertices.SetSize(0);
5231 
5232  FinalizeTopology();
5233  CheckBdrElementOrientation(); // check and fix boundary element orientation
5234 }
5235 
5237 {
5238  if (p.Size() >= v.Size())
5239  {
5240  for (int d = 0; d < v.Size(); d++)
5241  {
5242  v(d) = p(d);
5243  }
5244  }
5245  else
5246  {
5247  int d;
5248  for (d = 0; d < p.Size(); d++)
5249  {
5250  v(d) = p(d);
5251  }
5252  for ( ; d < v.Size(); d++)
5253  {
5254  v(d) = 0.0;
5255  }
5256  }
5257 }
5258 
5259 void Mesh::GetNodes(GridFunction &nodes) const
5260 {
5261  if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
5262  {
5263  const int newSpaceDim = nodes.FESpace()->GetVDim();
5265  nodes.ProjectCoefficient(xyz);
5266  }
5267  else
5268  {
5269  nodes = *Nodes;
5270  }
5271 }
5272 
5274 {
5275  GridFunction *nodes = new GridFunction(nfes);
5276  SetNodalGridFunction(nodes, true);
5277 }
5278 
5280 {
5281  if (Nodes)
5282  {
5284  if (dynamic_cast<const H1_FECollection*>(fec)
5285  || dynamic_cast<const L2_FECollection*>(fec))
5286  {
5287  return;
5288  }
5289  else // Mesh using a legacy FE_Collection
5290  {
5291  const int order = GetNodalFESpace()->GetElementOrder(0);
5292  SetCurvature(order, false, -1, Ordering::byVDIM);
5293  }
5294  }
5295  else // First order H1 mesh
5296  {
5297  SetCurvature(1, false, -1, Ordering::byVDIM);
5298  }
5299 }
5300 
5301 void Mesh::SetNodalGridFunction(GridFunction *nodes, bool make_owner)
5302 {
5303  GetNodes(*nodes);
5304  NewNodes(*nodes, make_owner);
5305 }
5306 
5308 {
5309  return ((Nodes) ? Nodes->FESpace() : NULL);
5310 }
5311 
5312 void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
5313 {
5314  space_dim = (space_dim == -1) ? spaceDim : space_dim;
5316  if (discont)
5317  {
5318  const int type = 1; // Gauss-Lobatto points
5319  nfec = new L2_FECollection(order, Dim, type);
5320  }
5321  else
5322  {
5323  nfec = new H1_FECollection(order, Dim);
5324  }
5325  FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
5326  ordering);
5327  SetNodalFESpace(nfes);
5328  Nodes->MakeOwner(nfec);
5329 }
5330 
5332 {
5333  MFEM_ASSERT(nodes != NULL, "");
5334  for (int i = 0; i < spaceDim; i++)
5335  {
5336  Vector vert_val;
5337  nodes->GetNodalValues(vert_val, i+1);
5338  for (int j = 0; j < NumOfVertices; j++)
5339  {
5340  vertices[j](i) = vert_val(j);
5341  }
5342  }
5343 }
5344 
5346 {
5347  switch (Dim)
5348  {
5349  case 1: return GetNV();
5350  case 2: return GetNEdges();
5351  case 3: return GetNFaces();
5352  }
5353  return 0;
5354 }
5355 
5357 {
5358  return faces_info.Size();
5359 }
5360 
5362 {
5363  const bool isInt = type==FaceType::Interior;
5364  int &nf = isInt ? nbInteriorFaces : nbBoundaryFaces;
5365  if (nf<0)
5366  {
5367  nf = 0;
5368  for (int f = 0; f < GetNumFacesWithGhost(); ++f)
5369  {
5371  if ( face.IsOfFaceType(type) )
5372  {
5373  if (face.IsNonconformingCoarse())
5374  {
5375  // We don't count nonconforming coarse faces.
5376  continue;
5377  }
5378  nf++;
5379  }
5380  }
5381  }
5382  return nf;
5383 }
5384 
5385 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5386 static const char *fixed_or_not[] = { "fixed", "NOT FIXED" };
5387 #endif
5388 
5390 {
5391  int i, j, k, wo = 0, fo = 0;
5392  double *v[4];
5393 
5394  if (Dim == 2 && spaceDim == 2)
5395  {
5396  DenseMatrix J(2, 2);
5397 
5398  for (i = 0; i < NumOfElements; i++)
5399  {
5400  int *vi = elements[i]->GetVertices();
5401  if (Nodes == NULL)
5402  {
5403  for (j = 0; j < 3; j++)
5404  {
5405  v[j] = vertices[vi[j]]();
5406  }
5407  for (j = 0; j < 2; j++)
5408  for (k = 0; k < 2; k++)
5409  {
5410  J(j, k) = v[j+1][k] - v[0][k];
5411  }
5412  }
5413  else
5414  {
5415  // only check the Jacobian at the center of the element
5416  GetElementJacobian(i, J);
5417  }
5418  if (J.Det() < 0.0)
5419  {
5420  if (fix_it)
5421  {
5422  switch (GetElementType(i))
5423  {
5424  case Element::TRIANGLE:
5425  mfem::Swap(vi[0], vi[1]);
5426  break;
5428  mfem::Swap(vi[1], vi[3]);
5429  break;
5430  default:
5431  MFEM_ABORT("Invalid 2D element type \""
5432  << GetElementType(i) << "\"");
5433  break;
5434  }
5435  fo++;
5436  }
5437  wo++;
5438  }
5439  }
5440  }
5441 
5442  if (Dim == 3)
5443  {
5444  DenseMatrix J(3, 3);
5445 
5446  for (i = 0; i < NumOfElements; i++)
5447  {
5448  int *vi = elements[i]->GetVertices();
5449  switch (GetElementType(i))
5450  {
5451  case Element::TETRAHEDRON:
5452  if (Nodes == NULL)
5453  {
5454  for (j = 0; j < 4; j++)
5455  {
5456  v[j] = vertices[vi[j]]();
5457  }
5458  for (j = 0; j < 3; j++)
5459  for (k = 0; k < 3; k++)
5460  {
5461  J(j, k) = v[j+1][k] - v[0][k];
5462  }
5463  }
5464  else
5465  {
5466  // only check the Jacobian at the center of the element
5467  GetElementJacobian(i, J);
5468  }
5469  if (J.Det() < 0.0)
5470  {
5471  wo++;
5472  if (fix_it)
5473  {
5474  mfem::Swap(vi[0], vi[1]);
5475  fo++;
5476  }
5477  }
5478  break;
5479 
5480  case Element::WEDGE:
5481  // only check the Jacobian at the center of the element
5482  GetElementJacobian(i, J);
5483  if (J.Det() < 0.0)
5484  {
5485  wo++;
5486  if (fix_it)
5487  {
5488  // how?
5489  }
5490  }
5491  break;
5492 
5493  case Element::PYRAMID:
5494  // only check the Jacobian at the center of the element
5495  GetElementJacobian(i, J);
5496  if (J.Det() < 0.0)
5497  {
5498  wo++;
5499  if (fix_it)
5500  {
5501  // how?
5502  }
5503  }
5504  break;
5505 
5506  case Element::HEXAHEDRON:
5507  // only check the Jacobian at the center of the element
5508  GetElementJacobian(i, J);
5509  if (J.Det() < 0.0)
5510  {
5511  wo++;
5512  if (fix_it)
5513  {
5514  // how?
5515  }
5516  }
5517  break;
5518 
5519  default:
5520  MFEM_ABORT("Invalid 3D element type \""
5521  << GetElementType(i) << "\"");
5522  break;
5523  }
5524  }
5525  }
5526 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5527  if (wo > 0)
5528  {
5529  mfem::out << "Elements with wrong orientation: " << wo << " / "
5530  << NumOfElements << " (" << fixed_or_not[(wo == fo) ? 0 : 1]
5531  << ")" << endl;
5532  }
5533 #endif
5534  return wo;
5535 }
5536 
5537 int Mesh::GetTriOrientation(const int *base, const int *test)
5538 {
5539  // Static method.
5540  // This function computes the index 'j' of the permutation that transforms
5541  // test into base: test[tri_orientation[j][i]]=base[i].
5542  // tri_orientation = Geometry::Constants<Geometry::TRIANGLE>::Orient
5543  int orient;
5544 
5545  if (test[0] == base[0])
5546  if (test[1] == base[1])
5547  {
5548  orient = 0; // (0, 1, 2)
5549  }
5550  else
5551  {
5552  orient = 5; // (0, 2, 1)
5553  }
5554  else if (test[0] == base[1])
5555  if (test[1] == base[0])
5556  {
5557  orient = 1; // (1, 0, 2)
5558  }
5559  else
5560  {
5561  orient = 2; // (1, 2, 0)
5562  }
5563  else // test[0] == base[2]
5564  if (test[1] == base[0])
5565  {
5566  orient = 4; // (2, 0, 1)
5567  }
5568  else
5569  {
5570  orient = 3; // (2, 1, 0)
5571  }
5572 
5573 #ifdef MFEM_DEBUG
5574  const int *aor = tri_t::Orient[orient];
5575  for (int j = 0; j < 3; j++)
5576  if (test[aor[j]] != base[j])
5577  {
5578  mfem_error("Mesh::GetTriOrientation(...)");
5579  }
5580 #endif
5581 
5582  return orient;
5583 }
5584 
5585 int Mesh::GetQuadOrientation(const int *base, const int *test)
5586 {
5587  int i;
5588 
5589  for (i = 0; i < 4; i++)
5590  if (test[i] == base[0])
5591  {
5592  break;
5593  }
5594 
5595 #ifdef MFEM_DEBUG
5596  int orient;
5597  if (test[(i+1)%4] == base[1])
5598  {
5599  orient = 2*i;
5600  }
5601  else
5602  {
5603  orient = 2*i+1;
5604  }
5605  const int *aor = quad_t::Orient[orient];
5606  for (int j = 0; j < 4; j++)
5607  if (test[aor[j]] != base[j])
5608  {
5609  mfem::err << "Mesh::GetQuadOrientation(...)" << endl;
5610  mfem::err << " base = [";
5611  for (int k = 0; k < 4; k++)
5612  {
5613  mfem::err << " " << base[k];
5614  }
5615  mfem::err << " ]\n test = [";
5616  for (int k = 0; k < 4; k++)
5617  {
5618  mfem::err << " " << test[k];
5619  }
5620  mfem::err << " ]" << endl;
5621  mfem_error();
5622  }
5623 #endif
5624 
5625  if (test[(i+1)%4] == base[1])
5626  {
5627  return 2*i;
5628  }
5629 
5630  return 2*i+1;
5631 }
5632 
5633 int Mesh::GetTetOrientation(const int *base, const int *test)
5634 {
5635  // Static method.
5636  // This function computes the index 'j' of the permutation that transforms
5637  // test into base: test[tet_orientation[j][i]]=base[i].
5638  // tet_orientation = Geometry::Constants<Geometry::TETRAHEDRON>::Orient
5639  int orient;
5640 
5641  if (test[0] == base[0])
5642  if (test[1] == base[1])
5643  if (test[2] == base[2])
5644  {
5645  orient = 0; // (0, 1, 2, 3)
5646  }
5647  else
5648  {
5649  orient = 1; // (0, 1, 3, 2)
5650  }
5651  else if (test[2] == base[1])
5652  if (test[3] == base[2])
5653  {
5654  orient = 2; // (0, 2, 3, 1)
5655  }
5656  else
5657  {
5658  orient = 3; // (0, 2, 1, 3)
5659  }
5660  else // test[3] == base[1]
5661  if (test[1] == base[2])
5662  {
5663  orient = 4; // (0, 3, 1, 2)
5664  }
5665  else
5666  {
5667  orient = 5; // (0, 3, 2, 1)
5668  }
5669  else if (test[1] == base[0])
5670  if (test[2] == base[1])
5671  if (test[0] == base[2])
5672  {
5673  orient = 6; // (1, 2, 0, 3)
5674  }
5675  else
5676  {
5677  orient = 7; // (1, 2, 3, 0)
5678  }
5679  else if (test[3] == base[1])
5680  if (test[2] == base[2])
5681  {
5682  orient = 8; // (1, 3, 2, 0)
5683  }
5684  else
5685  {
5686  orient = 9; // (1, 3, 0, 2)
5687  }
5688  else // test[0] == base[1]
5689  if (test[3] == base[2])
5690  {
5691  orient = 10; // (1, 0, 3, 2)
5692  }
5693  else
5694  {
5695  orient = 11; // (1, 0, 2, 3)
5696  }
5697  else if (test[2] == base[0])
5698  if (test[3] == base[1])
5699  if (test[0] == base[2])
5700  {
5701  orient = 12; // (2, 3, 0, 1)
5702  }
5703  else
5704  {
5705  orient = 13; // (2, 3, 1, 0)
5706  }
5707  else if (test[0] == base[1])
5708  if (test[1] == base[2])
5709  {
5710  orient = 14; // (2, 0, 1, 3)
5711  }
5712  else
5713  {
5714  orient = 15; // (2, 0, 3, 1)
5715  }
5716  else // test[1] == base[1]
5717  if (test[3] == base[2])
5718  {
5719  orient = 16; // (2, 1, 3, 0)
5720  }
5721  else
5722  {
5723  orient = 17; // (2, 1, 0, 3)
5724  }
5725  else // (test[3] == base[0])
5726  if (test[0] == base[1])
5727  if (test[2] == base[2])
5728  {
5729  orient = 18; // (3, 0, 2, 1)
5730  }
5731  else
5732  {
5733  orient = 19; // (3, 0, 1, 2)
5734  }
5735  else if (test[1] == base[1])
5736  if (test[0] == base[2])
5737  {
5738  orient = 20; // (3, 1, 0, 2)
5739  }
5740  else
5741  {
5742  orient = 21; // (3, 1, 2, 0)
5743  }
5744  else // test[2] == base[1]
5745  if (test[1] == base[2])
5746  {
5747  orient = 22; // (3, 2, 1, 0)
5748  }
5749  else
5750  {
5751  orient = 23; // (3, 2, 0, 1)
5752  }
5753 
5754 #ifdef MFEM_DEBUG
5755  const int *aor = tet_t::Orient[orient];
5756  for (int j = 0; j < 4; j++)
5757  if (test[aor[j]] != base[j])
5758  {
5759  mfem_error("Mesh::GetTetOrientation(...)");
5760  }
5761 #endif
5762 
5763  return orient;
5764 }
5765 
5767 {
5768  int wo = 0; // count wrong orientations
5769 
5770  if (Dim == 2)
5771  {
5772  if (el_to_edge == NULL) // edges were not generated
5773  {
5774  el_to_edge = new Table;
5776  GenerateFaces(); // 'Faces' in 2D refers to the edges
5777  }
5778  for (int i = 0; i < NumOfBdrElements; i++)
5779  {
5780  if (faces_info[be_to_edge[i]].Elem2No < 0) // boundary face
5781  {
5782  int *bv = boundary[i]->GetVertices();
5783  int *fv = faces[be_to_edge[i]]->GetVertices();
5784  if (bv[0] != fv[0])
5785  {
5786  if (fix_it)
5787  {
5788  mfem::Swap<int>(bv[0], bv[1]);
5789  }
5790  wo++;
5791  }
5792  }
5793  }
5794  }
5795 
5796  if (Dim == 3)
5797  {
5798  for (int i = 0; i < NumOfBdrElements; i++)
5799  {
5800  const int fi = be_to_face[i];
5801 
5802  if (faces_info[fi].Elem2No >= 0) { continue; }
5803 
5804  // boundary face
5805  int *bv = boundary[i]->GetVertices();
5806  // Make sure the 'faces' are generated:
5807  MFEM_ASSERT(fi < faces.Size(), "internal error");
5808  const int *fv = faces[fi]->GetVertices();
5809  int orientation; // orientation of the bdr. elem. w.r.t. the
5810  // corresponding face element (that's the base)
5811  const Element::Type bdr_type = GetBdrElementType(i);
5812  switch (bdr_type)
5813  {
5814  case Element::TRIANGLE:
5815  {
5816  orientation = GetTriOrientation(fv, bv);
5817  break;
5818  }
5820  {
5821  orientation = GetQuadOrientation(fv, bv);
5822  break;
5823  }
5824  default:
5825  MFEM_ABORT("Invalid 2D boundary element type \""
5826  << bdr_type << "\"");
5827  orientation = 0; // suppress a warning
5828  break;
5829  }
5830 
5831  if (orientation % 2 == 0) { continue; }
5832  wo++;
5833  if (!fix_it) { continue; }
5834 
5835  switch (bdr_type)
5836  {
5837  case Element::TRIANGLE:
5838  {
5839  // swap vertices 0 and 1 so that we don't change the marked edge:
5840  // (0,1,2) -> (1,0,2)
5841  mfem::Swap<int>(bv[0], bv[1]);
5842  if (bel_to_edge)
5843  {
5844  int *be = bel_to_edge->GetRow(i);
5845  mfem::Swap<int>(be[1], be[2]);
5846  }
5847  break;
5848  }
5850  {
5851  mfem::Swap<int>(bv[0], bv[2]);
5852  if (bel_to_edge)
5853  {
5854  int *be = bel_to_edge->GetRow(i);
5855  mfem::Swap<int>(be[0], be[1]);
5856  mfem::Swap<int>(be[2], be[3]);
5857  }
5858  break;
5859  }
5860  default: // unreachable
5861  break;
5862  }
5863  }
5864  }
5865  // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5866 #ifdef MFEM_DEBUG
5867  if (wo > 0)
5868  {
5869  mfem::out << "Boundary elements with wrong orientation: " << wo << " / "
5870  << NumOfBdrElements << " (" << fixed_or_not[fix_it ? 0 : 1]
5871  << ")" << endl;
5872  }
5873 #endif
5874  return wo;
5875 }
5876 
5878 {
5879  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
5880  int num_geoms = 0;
5881  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
5882  {
5883  if (HasGeometry(Geometry::Type(g))) { num_geoms++; }
5884  }
5885  return num_geoms;
5886 }
5887 
5889 {
5890  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
5891  el_geoms.SetSize(0);
5892  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
5893  {
5894  if (HasGeometry(Geometry::Type(g)))
5895  {
5896  el_geoms.Append(Geometry::Type(g));
5897  }
5898  }
5899 }
5900 
5901 void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const
5902 {
5903  if (el_to_edge)
5904  {
5905  el_to_edge->GetRow(i, edges);
5906  }
5907  else
5908  {
5909  mfem_error("Mesh::GetElementEdges(...) element to edge table "
5910  "is not generated.");
5911  }
5912 
5913  const int *v = elements[i]->GetVertices();
5914  const int ne = elements[i]->GetNEdges();
5915  cor.SetSize(ne);
5916  for (int j = 0; j < ne; j++)
5917  {
5918  const int *e = elements[i]->GetEdgeVertices(j);
5919  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5920  }
5921 }
5922 
5923 void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const
5924 {
5925  if (Dim == 2)
5926  {
5927  edges.SetSize(1);
5928  cor.SetSize(1);
5929  edges[0] = be_to_edge[i];
5930  const int *v = boundary[i]->GetVertices();
5931  cor[0] = (v[0] < v[1]) ? (1) : (-1);
5932  }
5933  else if (Dim == 3)
5934  {
5935  if (bel_to_edge)
5936  {
5937  bel_to_edge->GetRow(i, edges);
5938  }
5939  else
5940  {
5941  mfem_error("Mesh::GetBdrElementEdges(...)");
5942  }
5943 
5944  const int *v = boundary[i]->GetVertices();
5945  const int ne = boundary[i]->GetNEdges();
5946  cor.SetSize(ne);
5947  for (int j = 0; j < ne; j++)
5948  {
5949  const int *e = boundary[i]->GetEdgeVertices(j);
5950  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5951  }
5952  }
5953 }
5954 
5955 void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const
5956 {
5957  if (Dim == 2)
5958  {
5959  edges.SetSize(1);
5960  edges[0] = i;
5961  o.SetSize(1);
5962  const int *v = faces[i]->GetVertices();
5963  o[0] = (v[0] < v[1]) ? (1) : (-1);
5964  }
5965 
5966  if (Dim != 3)
5967  {
5968  return;
5969  }
5970 
5971  GetFaceEdgeTable(); // generate face_edge Table (if not generated)
5972 
5973  face_edge->GetRow(i, edges);
5974 
5975  const int *v = faces[i]->GetVertices();
5976  const int ne = faces[i]->GetNEdges();
5977  o.SetSize(ne);
5978  for (int j = 0; j < ne; j++)
5979  {
5980  const int *e = faces[i]->GetEdgeVertices(j);
5981  o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5982  }
5983 }
5984 
5985 void Mesh::GetEdgeVertices(int i, Array<int> &vert) const
5986 {
5987  // the two vertices are sorted: vert[0] < vert[1]
5988  // this is consistent with the global edge orientation
5989  // generate edge_vertex Table (if not generated)
5990  if (!edge_vertex) { GetEdgeVertexTable(); }
5991  edge_vertex->GetRow(i, vert);
5992 }
5993 
5995 {
5996  if (face_edge)
5997  {
5998  return face_edge;
5999  }
6000 
6001  if (Dim != 3)
6002  {
6003  return NULL;
6004  }
6005 
6006 #ifdef MFEM_DEBUG
6007  if (faces.Size() != NumOfFaces)
6008  {
6009  mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!");
6010  }
6011 #endif
6012 
6013  DSTable v_to_v(NumOfVertices);
6014  GetVertexToVertexTable(v_to_v);
6015 
6016  face_edge = new Table;
6018 
6019  return (face_edge);
6020 }
6021 
6023 {
6024  if (edge_vertex)
6025  {
6026  return edge_vertex;
6027  }
6028 
6029  DSTable v_to_v(NumOfVertices);
6030  GetVertexToVertexTable(v_to_v);
6031 
6032  int nedges = v_to_v.NumberOfEntries();
6033  edge_vertex = new Table(nedges, 2);
6034  for (int i = 0; i < NumOfVertices; i++)
6035  {
6036  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
6037  {
6038  int j = it.Index();
6039  edge_vertex->Push(j, i);
6040  edge_vertex->Push(j, it.Column());
6041  }
6042  }
6043  edge_vertex->Finalize();
6044 
6045  return edge_vertex;
6046 }
6047 
6049 {
6050  int i, j, nv, *v;
6051 
6052  Table *vert_elem = new Table;
6053 
6054  vert_elem->MakeI(NumOfVertices);
6055 
6056  for (i = 0; i < NumOfElements; i++)
6057  {
6058  nv = elements[i]->GetNVertices();
6059  v = elements[i]->GetVertices();
6060  for (j = 0; j < nv; j++)
6061  {
6062  vert_elem->AddAColumnInRow(v[j]);
6063  }
6064  }
6065 
6066  vert_elem->MakeJ();
6067 
6068  for (i = 0; i < NumOfElements; i++)
6069  {
6070  nv = elements[i]->GetNVertices();
6071  v = elements[i]->GetVertices();
6072  for (j = 0; j < nv; j++)
6073  {
6074  vert_elem->AddConnection(v[j], i);
6075  }
6076  }
6077 
6078  vert_elem->ShiftUpI();
6079 
6080  return vert_elem;
6081 }
6082 
6084 {
6085  Table *face_elem = new Table;
6086 
6087  face_elem->MakeI(faces_info.Size());
6088 
6089  for (int i = 0; i < faces_info.Size(); i++)
6090  {
6091  if (faces_info[i].Elem2No >= 0)
6092  {
6093  face_elem->AddColumnsInRow(i, 2);
6094  }
6095  else
6096  {
6097  face_elem->AddAColumnInRow(i);
6098  }
6099  }
6100 
6101  face_elem->MakeJ();
6102 
6103  for (int i = 0; i < faces_info.Size(); i++)
6104  {
6105  face_elem->AddConnection(i, faces_info[i].Elem1No);
6106  if (faces_info[i].Elem2No >= 0)
6107  {
6108  face_elem->AddConnection(i, faces_info[i].Elem2No);
6109  }
6110  }
6111 
6112  face_elem->ShiftUpI();
6113 
6114  return face_elem;
6115 }
6116 
6117 void Mesh::GetElementFaces(int i, Array<int> &el_faces, Array<int> &ori) const
6118 {
6119  MFEM_VERIFY(el_to_face != NULL, "el_to_face not generated");
6120 
6121  el_to_face->GetRow(i, el_faces);
6122 
6123  int n = el_faces.Size();
6124  ori.SetSize(n);
6125 
6126  for (int j = 0; j < n; j++)
6127  {
6128  if (faces_info[el_faces[j]].Elem1No == i)
6129  {
6130  ori[j] = faces_info[el_faces[j]].Elem1Inf % 64;
6131  }
6132  else
6133  {
6134  MFEM_ASSERT(faces_info[el_faces[j]].Elem2No == i, "internal error");
6135  ori[j] = faces_info[el_faces[j]].Elem2Inf % 64;
6136  }
6137  }
6138 }
6139 
6140 void Mesh::GetBdrElementFace(int i, int *f, int *o) const
6141 {
6142  const int *bv, *fv;
6143 
6144  *f = be_to_face[i];
6145  bv = boundary[i]->GetVertices();
6146  fv = faces[be_to_face[i]]->GetVertices();
6147 
6148  // find the orientation of the bdr. elem. w.r.t.
6149  // the corresponding face element (that's the base)
6150  switch (GetBdrElementType(i))
6151  {
6152  case Element::TRIANGLE:
6153  *o = GetTriOrientation(fv, bv);
6154  break;
6156  *o = GetQuadOrientation(fv, bv);
6157  break;
6158  default:
6159  MFEM_ABORT("invalid geometry");
6160  }
6161 }
6162 
6164 {
6165  switch (Dim)
6166  {
6167  case 1: return boundary[i]->GetVertices()[0];
6168  case 2: return be_to_edge[i];
6169  case 3: return be_to_face[i];
6170  default: MFEM_ABORT("invalid dimension!");
6171  }
6172  return -1;
6173 }
6174 
6175 void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
6176 {
6177  int fid = GetBdrElementEdgeIndex(bdr_el);
6178 
6179  const FaceInfo &fi = faces_info[fid];
6180  MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
6181 
6182  const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
6183  const int *bv = boundary[bdr_el]->GetVertices();
6184  int ori;
6185  switch (GetBdrElementGeometry(bdr_el))
6186  {
6187  case Geometry::POINT: ori = 0; break;
6188  case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
6189  case Geometry::TRIANGLE: ori = GetTriOrientation(fv, bv); break;
6190  case Geometry::SQUARE: ori = GetQuadOrientation(fv, bv); break;
6191  default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
6192  }
6193  el = fi.Elem1No;
6194  info = fi.Elem1Inf + ori;
6195 }
6196 
6198 {
6199  return elements[i]->GetType();
6200 }
6201 
6203 {
6204  return boundary[i]->GetType();
6205 }
6206 
6207 void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const
6208 {
6209  int k, j, nv;
6210  const int *v;
6211 
6212  v = elements[i]->GetVertices();
6213  nv = elements[i]->GetNVertices();
6214 
6215  pointmat.SetSize(spaceDim, nv);
6216  for (k = 0; k < spaceDim; k++)
6217  {
6218  for (j = 0; j < nv; j++)
6219  {
6220  pointmat(k, j) = vertices[v[j]](k);
6221  }
6222  }
6223 }
6224 
6225 void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const
6226 {
6227  int k, j, nv;
6228  const int *v;
6229 
6230  v = boundary[i]->GetVertices();
6231  nv = boundary[i]->GetNVertices();
6232 
6233  pointmat.SetSize(spaceDim, nv);
6234  for (k = 0; k < spaceDim; k++)
6235  for (j = 0; j < nv; j++)
6236  {
6237  pointmat(k, j) = vertices[v[j]](k);
6238  }
6239 }
6240 
6241 double Mesh::GetLength(int i, int j) const
6242 {
6243  const double *vi = vertices[i]();
6244  const double *vj = vertices[j]();
6245  double length = 0.;
6246 
6247  for (int k = 0; k < spaceDim; k++)
6248  {
6249  length += (vi[k]-vj[k])*(vi[k]-vj[k]);
6250  }
6251 
6252  return sqrt(length);
6253 }
6254 
6255 // static method
6257  const DSTable &v_to_v, Table &el_to_edge)
6258 {
6259  el_to_edge.MakeI(elem_array.Size());
6260  for (int i = 0; i < elem_array.Size(); i++)
6261  {
6262  el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges());
6263  }
6264  el_to_edge.MakeJ();
6265  for (int i = 0; i < elem_array.Size(); i++)
6266  {
6267  const int *v = elem_array[i]->GetVertices();
6268  const int ne = elem_array[i]->GetNEdges();
6269  for (int j = 0; j < ne; j++)
6270  {
6271  const int *e = elem_array[i]->GetEdgeVertices(j);
6272  el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]]));
6273  }
6274  }
6275  el_to_edge.ShiftUpI();
6276 }
6277 
6279 {
6280  if (edge_vertex)
6281  {
6282  for (int i = 0; i < edge_vertex->Size(); i++)
6283  {
6284  const int *v = edge_vertex->GetRow(i);
6285  v_to_v.Push(v[0], v[1]);
6286  }
6287  }
6288  else
6289  {
6290  for (int i = 0; i < NumOfElements; i++)
6291  {
6292  const int *v = elements[i]->GetVertices();
6293  const int ne = elements[i]->GetNEdges();
6294  for (int j = 0; j < ne; j++)
6295  {
6296  const int *e = elements[i]->GetEdgeVertices(j);
6297  v_to_v.Push(v[e[0]], v[e[1]]);
6298  }
6299  }
6300  }
6301 }
6302 
6304 {
6305  int i, NumberOfEdges;
6306 
6307  DSTable v_to_v(NumOfVertices);
6308  GetVertexToVertexTable(v_to_v);
6309 
6310  NumberOfEdges = v_to_v.NumberOfEntries();
6311 
6312  // Fill the element to edge table
6313  GetElementArrayEdgeTable(elements, v_to_v, e_to_f);
6314 
6315  if (Dim == 2)
6316  {
6317  // Initialize the indices for the boundary elements.
6318  be_to_f.SetSize(NumOfBdrElements);
6319  for (i = 0; i < NumOfBdrElements; i++)
6320  {
6321  const int *v = boundary[i]->GetVertices();
6322  be_to_f[i] = v_to_v(v[0], v[1]);
6323  }
6324  }
6325  else if (Dim == 3)
6326  {
6327  if (bel_to_edge == NULL)
6328  {
6329  bel_to_edge = new Table;
6330  }
6332  }
6333  else
6334  {
6335  mfem_error("1D GetElementToEdgeTable is not yet implemented.");
6336  }
6337 
6338  // Return the number of edges
6339  return NumberOfEdges;
6340 }
6341 
6343 {
6344  if (el_to_el)
6345  {
6346  return *el_to_el;
6347  }
6348 
6349  // Note that, for ParNCMeshes, faces_info will contain also the ghost faces
6350  MFEM_ASSERT(faces_info.Size() >= GetNumFaces(), "faces were not generated!");
6351 
6352  Array<Connection> conn;
6353  conn.Reserve(2*faces_info.Size());
6354 
6355  for (int i = 0; i < faces_info.Size(); i++)
6356  {
6357  const FaceInfo &fi = faces_info[i];
6358  if (fi.Elem2No >= 0)
6359  {
6360  conn.Append(Connection(fi.Elem1No, fi.Elem2No));
6361  conn.Append(Connection(fi.Elem2No, fi.Elem1No));
6362  }
6363  else if (fi.Elem2Inf >= 0)
6364  {
6365  int nbr_elem_idx = NumOfElements - 1 - fi.Elem2No;
6366  conn.Append(Connection(fi.Elem1No, nbr_elem_idx));
6367  conn.Append(Connection(nbr_elem_idx, fi.Elem1No));
6368  }
6369  }
6370 
6371  conn.Sort();
6372  conn.Unique();
6373  el_to_el = new Table(NumOfElements, conn);
6374 
6375  return *el_to_el;
6376 }
6377 
6379 {
6380  if (el_to_face == NULL)
6381  {
6382  mfem_error("Mesh::ElementToFaceTable()");
6383  }
6384  return *el_to_face;
6385 }
6386 
6388 {
6389  if (el_to_edge == NULL)
6390  {
6391  mfem_error("Mesh::ElementToEdgeTable()");
6392  }
6393  return *el_to_edge;
6394 }
6395 
6396 void Mesh::AddPointFaceElement(int lf, int gf, int el)
6397 {
6398  if (faces_info[gf].Elem1No == -1) // this will be elem1
6399  {
6400  // faces[gf] = new Point(&gf);
6401  faces_info[gf].Elem1No = el;
6402  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6403  faces_info[gf].Elem2No = -1; // in case there's no other side
6404  faces_info[gf].Elem2Inf = -1; // face is not shared
6405  }
6406  else // this will be elem2
6407  {
6408  /* WARNING: Without the following check the mesh faces_info data structure
6409  may contain unreliable data. Normally, the order in which elements are
6410  processed could swap which elements appear as Elem1No and Elem2No. In
6411  branched meshes, where more than two elements can meet at a given node,
6412  the indices stored in Elem1No and Elem2No will be the first and last,
6413  respectively, elements found which touch a given node. This can lead to
6414  inconsistencies in any algorithms which rely on this data structure. To
6415  properly support branched meshes this data structure should be extended
6416  to support multiple elements per face. */
6417  /*
6418  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6419  "Interior point found connecting 1D elements "
6420  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6421  << " and " << el << ".");
6422  */
6423  faces_info[gf].Elem2No = el;
6424  faces_info[gf].Elem2Inf = 64 * lf + 1;
6425  }
6426 }
6427 
6428 void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
6429 {
6430  if (faces[gf] == NULL) // this will be elem1
6431  {
6432  faces[gf] = new Segment(v0, v1);
6433  faces_info[gf].Elem1No = el;
6434  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6435  faces_info[gf].Elem2No = -1; // in case there's no other side
6436  faces_info[gf].Elem2Inf = -1; // face is not shared
6437  }
6438  else // this will be elem2
6439  {
6440  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6441  "Interior edge found between 2D elements "
6442  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6443  << " and " << el << ".");
6444  int *v = faces[gf]->GetVertices();
6445  faces_info[gf].Elem2No = el;
6446  if ( v[1] == v0 && v[0] == v1 )
6447  {
6448  faces_info[gf].Elem2Inf = 64 * lf + 1;
6449  }
6450  else if ( v[0] == v0 && v[1] == v1 )
6451  {
6452  // Temporarily allow even edge orientations: see the remark in
6453  // AddTriangleFaceElement().
6454  // Also, in a non-orientable surface mesh, the orientation will be even
6455  // for edges that connect elements with opposite orientations.
6456  faces_info[gf].Elem2Inf = 64 * lf;
6457  }
6458  else
6459  {
6460  MFEM_ABORT("internal error");
6461  }
6462  }
6463 }
6464 
6465 void Mesh::AddTriangleFaceElement(int lf, int gf, int el,
6466  int v0, int v1, int v2)
6467 {
6468  if (faces[gf] == NULL) // this will be elem1
6469  {
6470  faces[gf] = new Triangle(v0, v1, v2);
6471  faces_info[gf].Elem1No = el;
6472  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6473  faces_info[gf].Elem2No = -1; // in case there's no other side
6474  faces_info[gf].Elem2Inf = -1; // face is not shared
6475  }
6476  else // this will be elem2
6477  {
6478  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6479  "Interior triangular face found connecting elements "
6480  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6481  << " and " << el << ".");
6482  int orientation, vv[3] = { v0, v1, v2 };
6483  orientation = GetTriOrientation(faces[gf]->GetVertices(), vv);
6484  // In a valid mesh, we should have (orientation % 2 != 0), however, if
6485  // one of the adjacent elements has wrong orientation, both face
6486  // orientations can be even, until the element orientations are fixed.
6487  // MFEM_ASSERT(orientation % 2 != 0, "");
6488  faces_info[gf].Elem2No = el;
6489  faces_info[gf].Elem2Inf = 64 * lf + orientation;
6490  }
6491 }
6492 
6493 void Mesh::AddQuadFaceElement(int lf, int gf, int el,
6494  int v0, int v1, int v2, int v3)
6495 {
6496  if (faces_info[gf].Elem1No < 0) // this will be elem1
6497  {
6498  faces[gf] = new Quadrilateral(v0, v1, v2, v3);
6499  faces_info[gf].Elem1No = el;
6500  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6501  faces_info[gf].Elem2No = -1; // in case there's no other side
6502  faces_info[gf].Elem2Inf = -1; // face is not shared
6503  }
6504  else // this will be elem2
6505  {
6506  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6507  "Interior quadrilateral face found connecting elements "
6508  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6509  << " and " << el << ".");
6510  int vv[4] = { v0, v1, v2, v3 };
6511  int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv);
6512  // Temporarily allow even face orientations: see the remark in
6513  // AddTriangleFaceElement().
6514  // MFEM_ASSERT(oo % 2 != 0, "");
6515  faces_info[gf].Elem2No = el;
6516  faces_info[gf].Elem2Inf = 64 * lf + oo;
6517  }
6518 }
6519 
6521 {
6522  int i, nfaces = GetNumFaces();
6523 
6524  for (i = 0; i < faces.Size(); i++)
6525  {
6526  FreeElement(faces[i]);
6527  }
6528 
6529  // (re)generate the interior faces and the info for them
6530  faces.SetSize(nfaces);
6531  faces_info.SetSize(nfaces);
6532  for (i = 0; i < nfaces; i++)
6533  {
6534  faces[i] = NULL;
6535  faces_info[i].Elem1No = -1;
6536  faces_info[i].NCFace = -1;
6537  }
6538  for (i = 0; i < NumOfElements; i++)
6539  {
6540  const int *v = elements[i]->GetVertices();
6541  const int *ef;
6542  if (Dim == 1)
6543  {
6544  AddPointFaceElement(0, v[0], i);
6545  AddPointFaceElement(1, v[1], i);
6546  }
6547  else if (Dim == 2)
6548  {
6549  ef = el_to_edge->GetRow(i);
6550  const int ne = elements[i]->GetNEdges();
6551  for (int j = 0; j < ne; j++)
6552  {
6553  const int *e = elements[i]->GetEdgeVertices(j);
6554  AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]);
6555  }
6556  }
6557  else
6558  {
6559  ef = el_to_face->GetRow(i);
6560  switch (GetElementType(i))
6561  {
6562  case Element::TETRAHEDRON:
6563  {
6564  for (int j = 0; j < 4; j++)
6565  {
6566  const int *fv = tet_t::FaceVert[j];
6567  AddTriangleFaceElement(j, ef[j], i,
6568  v[fv[0]], v[fv[1]], v[fv[2]]);
6569  }
6570  break;
6571  }
6572  case Element::WEDGE:
6573  {
6574  for (int j = 0; j < 2; j++)
6575  {
6576  const int *fv = pri_t::FaceVert[j];
6577  AddTriangleFaceElement(j, ef[j], i,
6578  v[fv[0]], v[fv[1]], v[fv[2]]);
6579  }
6580  for (int j = 2; j < 5; j++)
6581  {
6582  const int *fv = pri_t::FaceVert[j];
6583  AddQuadFaceElement(j, ef[j], i,
6584  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6585  }
6586  break;
6587  }
6588  case Element::PYRAMID:
6589  {
6590  for (int j = 0; j < 1; j++)
6591  {
6592  const int *fv = pyr_t::FaceVert[j];
6593  AddQuadFaceElement(j, ef[j], i,
6594  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6595  }
6596  for (int j = 1; j < 5; j++)
6597  {
6598  const int *fv = pyr_t::FaceVert[j];
6599  AddTriangleFaceElement(j, ef[j], i,
6600  v[fv[0]], v[fv[1]], v[fv[2]]);
6601  }
6602  break;
6603  }
6604  case Element::HEXAHEDRON:
6605  {
6606  for (int j = 0; j < 6; j++)
6607  {
6608  const int *fv = hex_t::FaceVert[j];
6609  AddQuadFaceElement(j, ef[j], i,
6610  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6611  }
6612  break;
6613  }
6614  default:
6615  MFEM_ABORT("Unexpected type of Element.");
6616  }
6617  }
6618  }
6619 }
6620 
6622 {
6623  MFEM_VERIFY(ncmesh, "missing NCMesh.");
6624 
6625  for (int i = 0; i < faces_info.Size(); i++)
6626  {
6627  faces_info[i].NCFace = -1;
6628  }
6629 
6630  const NCMesh::NCList &list =
6631  (Dim == 2) ? ncmesh->GetEdgeList() : ncmesh->GetFaceList();
6632 
6633  nc_faces_info.SetSize(0);
6634  nc_faces_info.Reserve(list.masters.Size() + list.slaves.Size());
6635 
6636  int nfaces = GetNumFaces();
6637 
6638  // add records for master faces
6639  for (int i = 0; i < list.masters.Size(); i++)
6640  {
6641  const NCMesh::Master &master = list.masters[i];
6642  if (master.index >= nfaces) { continue; }
6643 
6644  FaceInfo &master_fi = faces_info[master.index];
6645  master_fi.NCFace = nc_faces_info.Size();
6646  nc_faces_info.Append(NCFaceInfo(false, master.local, NULL));
6647  // NOTE: one of the unused members stores local face no. to be used below
6648  MFEM_ASSERT(master_fi.Elem2No == -1, "internal error");
6649  MFEM_ASSERT(master_fi.Elem2Inf == -1, "internal error");
6650  }
6651 
6652  // add records for slave faces
6653  for (int i = 0; i < list.slaves.Size(); i++)
6654  {
6655  const NCMesh::Slave &slave = list.slaves[i];
6656 
6657  if (slave.index < 0 || // degenerate slave face
6658  slave.index >= nfaces || // ghost slave
6659  slave.master >= nfaces) // has ghost master
6660  {
6661  continue;
6662  }
6663 
6664  FaceInfo &slave_fi = faces_info[slave.index];
6665  FaceInfo &master_fi = faces_info[slave.master];
6666  NCFaceInfo &master_nc = nc_faces_info[master_fi.NCFace];
6667 
6668  slave_fi.NCFace = nc_faces_info.Size();
6669  slave_fi.Elem2No = master_fi.Elem1No;
6670  slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
6671  // NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
6672  // matrix. In 2D, the point matrix has the orientation of the parent
6673  // edge, so its columns need to be flipped when applying it, see
6674  // ApplyLocalSlaveTransformation.
6675 
6676  nc_faces_info.Append(
6677  NCFaceInfo(true, slave.master,
6678  list.point_matrices[slave.geom][slave.matrix]));
6679  }
6680 }
6681 
6683 {
6684  STable3D *faces_tbl = new STable3D(NumOfVertices);
6685  for (int i = 0; i < NumOfElements; i++)
6686  {
6687  const int *v = elements[i]->GetVertices();
6688  switch (GetElementType(i))
6689  {
6690  case Element::TETRAHEDRON:
6691  {
6692  for (int j = 0; j < 4; j++)
6693  {
6694  const int *fv = tet_t::FaceVert[j];
6695  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6696  }
6697  break;
6698  }
6699  case Element::PYRAMID:
6700  {
6701  for (int j = 0; j < 1; j++)
6702  {
6703  const int *fv = pyr_t::FaceVert[j];
6704  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6705  }
6706  for (int j = 1; j < 5; j++)
6707  {
6708  const int *fv = pyr_t::FaceVert[j];
6709  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6710  }
6711  break;
6712  }
6713  case Element::WEDGE:
6714  {
6715  for (int j = 0; j < 2; j++)
6716  {
6717  const int *fv = pri_t::FaceVert[j];
6718  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6719  }
6720  for (int j = 2; j < 5; j++)
6721  {
6722  const int *fv = pri_t::FaceVert[j];
6723  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6724  }
6725  break;
6726  }
6727  case Element::HEXAHEDRON:
6728  {
6729  // find the face by the vertices with the smallest 3 numbers
6730  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
6731  for (int j = 0; j < 6; j++)
6732  {
6733  const int *fv = hex_t::FaceVert[j];
6734  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6735  }
6736  break;
6737  }
6738  default:
6739  MFEM_ABORT("Unexpected type of Element.");
6740  }
6741  }
6742  return faces_tbl;
6743 }
6744 
6746 {
6747  int i, *v;
6748  STable3D *faces_tbl;
6749 
6750  if (el_to_face != NULL)
6751  {
6752  delete el_to_face;
6753  }
6754  el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra
6755  faces_tbl = new STable3D(NumOfVertices);
6756  for (i = 0; i < NumOfElements; i++)
6757  {
6758  v = elements[i]->GetVertices();
6759  switch (GetElementType(i))
6760  {
6761  case Element::TETRAHEDRON:
6762  {
6763  for (int j = 0; j < 4; j++)
6764  {
6765  const int *fv = tet_t::FaceVert[j];
6766  el_to_face->Push(
6767  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6768  }
6769  break;
6770  }
6771  case Element::WEDGE:
6772  {
6773  for (int j = 0; j < 2; j++)
6774  {
6775  const int *fv = pri_t::FaceVert[j];
6776  el_to_face->Push(
6777  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6778  }
6779  for (int j = 2; j < 5; j++)
6780  {
6781  const int *fv = pri_t::FaceVert[j];
6782  el_to_face->Push(
6783  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6784  }
6785  break;
6786  }
6787  case Element::PYRAMID:
6788  {
6789  for (int j = 0; j < 1; j++)
6790  {
6791  const int *fv = pyr_t::FaceVert[j];
6792  el_to_face->Push(
6793  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6794  }
6795  for (int j = 1; j < 5; j++)
6796  {
6797  const int *fv = pyr_t::FaceVert[j];
6798  el_to_face->Push(
6799  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6800  }
6801  break;
6802  }
6803  case Element::HEXAHEDRON:
6804  {
6805  // find the face by the vertices with the smallest 3 numbers
6806  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
6807  for (int j = 0; j < 6; j++)
6808  {
6809  const int *fv = hex_t::FaceVert[j];
6810  el_to_face->Push(
6811  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6812  }
6813  break;
6814  }
6815  default:
6816  MFEM_ABORT("Unexpected type of Element.");
6817  }
6818  }
6819  el_to_face->Finalize();
6820  NumOfFaces = faces_tbl->NumberOfElements();
6822  for (i = 0; i < NumOfBdrElements; i++)
6823  {
6824  v = boundary[i]->GetVertices();
6825  switch (GetBdrElementType(i))
6826  {
6827  case Element::TRIANGLE:
6828  {
6829  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]);
6830  break;
6831  }
6833  {
6834  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
6835  break;
6836  }
6837  default:
6838  MFEM_ABORT("Unexpected type of boundary Element.");
6839  }
6840  }
6841 
6842  if (ret_ftbl)
6843  {
6844  return faces_tbl;
6845  }
6846  delete faces_tbl;
6847  return NULL;
6848 }
6849 
6850 // shift cyclically 3 integers so that the smallest is first
6851 static inline
6852 void Rotate3(int &a, int &b, int &c)
6853 {
6854  if (a < b)
6855  {
6856  if (a > c)
6857  {
6858  ShiftRight(a, b, c);
6859  }
6860  }
6861  else
6862  {
6863  if (b < c)
6864  {
6865  ShiftRight(c, b, a);
6866  }
6867  else
6868  {
6869  ShiftRight(a, b, c);
6870  }
6871  }
6872 }
6873 
6875 {
6876  if (Dim != 3 || !(meshgen & 1))
6877  {
6878  return;
6879  }
6880 
6881  ResetLazyData();
6882 
6883  DSTable *old_v_to_v = NULL;
6884  Table *old_elem_vert = NULL;
6885 
6886  if (Nodes)
6887  {
6888  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
6889  }
6890 
6891  for (int i = 0; i < NumOfElements; i++)
6892  {
6894  {
6895  int *v = elements[i]->GetVertices();
6896 
6897  Rotate3(v[0], v[1], v[2]);
6898  if (v[0] < v[3])
6899  {
6900  Rotate3(v[1], v[2], v[3]);
6901  }
6902  else
6903  {
6904  ShiftRight(v[0], v[1], v[3]);
6905  }
6906  }
6907  }
6908 
6909  for (int i = 0; i < NumOfBdrElements; i++)
6910  {
6912  {
6913  int *v = boundary[i]->GetVertices();
6914 
6915  Rotate3(v[0], v[1], v[2]);
6916  }
6917  }
6918 
6919  if (!Nodes)
6920  {
6922  GenerateFaces();
6923  if (el_to_edge)
6924  {
6926  }
6927  }
6928  else
6929  {
6930  DoNodeReorder(old_v_to_v, old_elem_vert);
6931  delete old_elem_vert;
6932  delete old_v_to_v;
6933  }
6934 }
6935 
6937 {
6938  int *partitioning;
6939  double pmin[3] = { infinity(), infinity(), infinity() };
6940  double pmax[3] = { -infinity(), -infinity(), -infinity() };
6941  // find a bounding box using the vertices
6942  for (int vi = 0; vi < NumOfVertices; vi++)
6943  {
6944  const double *p = vertices[vi]();
6945  for (int i = 0; i < spaceDim; i++)
6946  {
6947  if (p[i] < pmin[i]) { pmin[i] = p[i]; }
6948  if (p[i] > pmax[i]) { pmax[i] = p[i]; }
6949  }
6950  }
6951 
6952  partitioning = new int[NumOfElements];
6953 
6954  // determine the partitioning using the centers of the elements
6955  double ppt[3];
6956  Vector pt(ppt, spaceDim);
6957  for (int el = 0; el < NumOfElements; el++)
6958  {
6959  GetElementTransformation(el)->Transform(
6961  int part = 0;
6962  for (int i = spaceDim-1; i >= 0; i--)
6963  {
6964  int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i])));
6965  if (idx < 0) { idx = 0; }
6966  if (idx >= nxyz[i]) { idx = nxyz[i]-1; }
6967  part = part * nxyz[i] + idx;
6968  }
6969  partitioning[el] = part;
6970  }
6971 
6972  return partitioning;
6973 }
6974 
6975 int *Mesh::GeneratePartitioning(int nparts, int part_method)
6976 {
6977 #ifdef MFEM_USE_METIS
6978 
6979  int print_messages = 1;
6980  // If running in parallel, print messages only from rank 0.
6981 #ifdef MFEM_USE_MPI
6982  int init_flag, fin_flag;
6983  MPI_Initialized(&init_flag);
6984  MPI_Finalized(&fin_flag);
6985  if (init_flag && !fin_flag)
6986  {
6987  int rank;
6988  MPI_Comm_rank(GetGlobalMPI_Comm(), &rank);
6989  if (rank != 0) { print_messages = 0; }
6990  }
6991 #endif
6992 
6993  int i, *partitioning;
6994 
6996 
6997  partitioning = new int[NumOfElements];
6998 
6999  if (nparts == 1)
7000  {
7001  for (i = 0; i < NumOfElements; i++)
7002  {
7003  partitioning[i] = 0;
7004  }
7005  }
7006  else if (NumOfElements <= nparts)
7007  {
7008  for (i = 0; i < NumOfElements; i++)
7009  {
7010  partitioning[i] = i;
7011  }
7012  }
7013  else
7014  {
7015  idx_t *I, *J, n;
7016 #ifndef MFEM_USE_METIS_5
7017  idx_t wgtflag = 0;
7018  idx_t numflag = 0;
7019  idx_t options[5];
7020 #else
7021  idx_t ncon = 1;
7022  idx_t errflag;
7023  idx_t options[40];
7024 #endif
7025  idx_t edgecut;
7026 
7027  // In case METIS have been compiled with 64bit indices
7028  bool freedata = false;
7029  idx_t mparts = (idx_t) nparts;
7030  idx_t *mpartitioning;
7031 
7032  n = NumOfElements;
7033  if (sizeof(idx_t) == sizeof(int))
7034  {
7035  I = (idx_t*) el_to_el->GetI();
7036  J = (idx_t*) el_to_el->GetJ();
7037  mpartitioning = (idx_t*) partitioning;
7038  }
7039  else
7040  {
7041  int *iI = el_to_el->GetI();
7042  int *iJ = el_to_el->GetJ();
7043  int m = iI[n];
7044  I = new idx_t[n+1];
7045  J = new idx_t[m];
7046  for (int k = 0; k < n+1; k++) { I[k] = iI[k]; }
7047  for (int k = 0; k < m; k++) { J[k] = iJ[k]; }
7048  mpartitioning = new idx_t[n];
7049  freedata = true;
7050  }
7051 #ifndef MFEM_USE_METIS_5
7052  options[0] = 0;
7053 #else
7054  METIS_SetDefaultOptions(options);
7055  options[METIS_OPTION_CONTIG] = 1; // set METIS_OPTION_CONTIG
7056 #endif
7057 
7058  // Sort the neighbor lists
7059  if (part_method >= 0 && part_method <= 2)
7060  {
7061  for (i = 0; i < n; i++)
7062  {
7063  // Sort in increasing order.
7064  // std::sort(J+I[i], J+I[i+1]);
7065 
7066  // Sort in decreasing order, as in previous versions of MFEM.
7067  std::sort(J+I[i], J+I[i+1], std::greater<idx_t>());
7068  }
7069  }
7070 
7071  // This function should be used to partition a graph into a small
7072  // number of partitions (less than 8).
7073  if (part_method == 0 || part_method == 3)
7074  {
7075 #ifndef MFEM_USE_METIS_5
7077  I,
7078  J,
7079  NULL,
7080  NULL,
7081  &wgtflag,
7082  &numflag,
7083  &mparts,
7084  options,
7085  &edgecut,
7086  mpartitioning);
7087 #else
7088  errflag = METIS_PartGraphRecursive(&n,
7089  &ncon,
7090  I,
7091  J,
7092  NULL,
7093  NULL,
7094  NULL,
7095  &mparts,
7096  NULL,
7097  NULL,
7098  options,
7099  &edgecut,
7100  mpartitioning);
7101  if (errflag != 1)
7102  {
7103  mfem_error("Mesh::GeneratePartitioning: "
7104  " error in METIS_PartGraphRecursive!");
7105  }
7106 #endif
7107  }
7108 
7109  // This function should be used to partition a graph into a large
7110  // number of partitions (greater than 8).
7111  if (part_method == 1 || part_method == 4)
7112  {
7113 #ifndef MFEM_USE_METIS_5
7115  I,
7116  J,
7117  NULL,
7118  NULL,
7119  &wgtflag,
7120  &numflag,
7121  &mparts,
7122  options,
7123  &edgecut,
7124  mpartitioning);
7125 #else
7126  errflag = METIS_PartGraphKway(&n,
7127  &ncon,
7128  I,
7129  J,
7130  NULL,
7131  NULL,
7132  NULL,
7133  &mparts,
7134  NULL,
7135  NULL,
7136  options,
7137  &edgecut,
7138  mpartitioning);
7139  if (errflag != 1)
7140  {
7141  mfem_error("Mesh::GeneratePartitioning: "
7142  " error in METIS_PartGraphKway!");
7143  }
7144 #endif
7145  }
7146 
7147  // The objective of this partitioning is to minimize the total
7148  // communication volume
7149  if (part_method == 2 || part_method == 5)
7150  {
7151 #ifndef MFEM_USE_METIS_5
7153  I,
7154  J,
7155  NULL,
7156  NULL,
7157  &wgtflag,
7158  &numflag,
7159  &mparts,
7160  options,
7161  &edgecut,
7162  mpartitioning);
7163 #else
7164  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
7165  errflag = METIS_PartGraphKway(&n,
7166  &ncon,
7167  I,
7168  J,
7169  NULL,
7170  NULL,
7171  NULL,
7172  &mparts,
7173  NULL,
7174  NULL,
7175  options,
7176  &edgecut,
7177  mpartitioning);
7178  if (errflag != 1)
7179  {
7180  mfem_error("Mesh::GeneratePartitioning: "
7181  " error in METIS_PartGraphKway!");
7182  }
7183 #endif
7184  }
7185 
7186 #ifdef MFEM_DEBUG
7187  if (print_messages)
7188  {
7189  mfem::out << "Mesh::GeneratePartitioning(...): edgecut = "
7190  << edgecut << endl;
7191  }
7192 #endif
7193  nparts = (int) mparts;
7194  if (mpartitioning != (idx_t*)partitioning)
7195  {
7196  for (int k = 0; k<NumOfElements; k++)
7197  {
7198  partitioning[k] = mpartitioning[k];
7199  }
7200  }
7201  if (freedata)
7202  {
7203  delete[] I;
7204  delete[] J;
7205  delete[] mpartitioning;
7206  }
7207  }
7208 
7209  delete el_to_el;
7210  el_to_el = NULL;
7211 
7212  // Check for empty partitionings (a "feature" in METIS)
7213  if (nparts > 1 && NumOfElements > nparts)
7214  {
7215  Array< Pair<int,int> > psize(nparts);
7216  int empty_parts;
7217 
7218  // Count how many elements are in each partition, and store the result in
7219  // psize, where psize[i].one is the number of elements, and psize[i].two
7220  // is partition index. Keep track of the number of empty parts.
7221  auto count_partition_elements = [&]()
7222  {
7223  for (i = 0; i < nparts; i++)
7224  {
7225  psize[i].one = 0;
7226  psize[i].two = i;
7227  }
7228 
7229  for (i = 0; i < NumOfElements; i++)
7230  {
7231  psize[partitioning[i]].one++;
7232  }
7233 
7234  empty_parts = 0;
7235  for (i = 0; i < nparts; i++)
7236  {
7237  if (psize[i].one == 0) { empty_parts++; }
7238  }
7239  };
7240 
7241  count_partition_elements();
7242 
7243  // This code just split the largest partitionings in two.
7244  // Do we need to replace it with something better?
7245  while (empty_parts)
7246  {
7247  if (print_messages)
7248  {
7249  mfem::err << "Mesh::GeneratePartitioning(...): METIS returned "
7250  << empty_parts << " empty parts!"
7251  << " Applying a simple fix ..." << endl;
7252  }
7253 
7254  SortPairs<int,int>(psize, nparts);
7255 
7256  for (i = nparts-1; i > nparts-1-empty_parts; i--)
7257  {
7258  psize[i].one /= 2;
7259  }
7260 
7261  for (int j = 0; j < NumOfElements; j++)
7262  {
7263  for (i = nparts-1; i > nparts-1-empty_parts; i--)
7264  {
7265  if (psize[i].one == 0 || partitioning[j] != psize[i].two)
7266  {
7267  continue;
7268  }
7269  else
7270  {
7271  partitioning[j] = psize[nparts-1-i].two;
7272  psize[i].one--;
7273  }
7274  }
7275  }
7276 
7277  // Check for empty partitionings again
7278  count_partition_elements();
7279  }
7280  }
7281 
7282  return partitioning;
7283 
7284 #else
7285 
7286  mfem_error("Mesh::GeneratePartitioning(...): "
7287  "MFEM was compiled without Metis.");
7288 
7289  return NULL;
7290 
7291 #endif
7292 }
7293 
7294 /* required: 0 <= partitioning[i] < num_part */
7296  const Array<int> &partitioning,
7297  Array<int> &component,
7298  Array<int> &num_comp)
7299 {
7300  int i, j, k;
7301  int num_elem, *i_elem_elem, *j_elem_elem;
7302 
7303  num_elem = elem_elem.Size();
7304  i_elem_elem = elem_elem.GetI();
7305  j_elem_elem = elem_elem.GetJ();
7306 
7307  component.SetSize(num_elem);
7308 
7309  Array<int> elem_stack(num_elem);
7310  int stack_p, stack_top_p, elem;
7311  int num_part;
7312 
7313  num_part = -1;
7314  for (i = 0; i < num_elem; i++)
7315  {
7316  if (partitioning[i] > num_part)
7317  {
7318  num_part = partitioning[i];
7319  }
7320  component[i] = -1;
7321  }
7322  num_part++;
7323 
7324  num_comp.SetSize(num_part);
7325  for (i = 0; i < num_part; i++)
7326  {
7327  num_comp[i] = 0;
7328  }
7329 
7330  stack_p = 0;
7331  stack_top_p = 0; // points to the first unused element in the stack
7332  for (elem = 0; elem < num_elem; elem++)
7333  {
7334  if (component[elem] >= 0)
7335  {
7336  continue;
7337  }
7338 
7339  component[elem] = num_comp[partitioning[elem]]++;
7340 
7341  elem_stack[stack_top_p++] = elem;
7342 
7343  for ( ; stack_p < stack_top_p; stack_p++)
7344  {
7345  i = elem_stack[stack_p];
7346  for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++)
7347  {
7348  k = j_elem_elem[j];
7349  if (partitioning[k] == partitioning[i])
7350  {
7351  if (component[k] < 0)
7352  {
7353  component[k] = component[i];
7354  elem_stack[stack_top_p++] = k;
7355  }
7356  else if (component[k] != component[i])
7357  {
7358  mfem_error("FindPartitioningComponents");
7359  }
7360  }
7361  }
7362  }
7363  }
7364 }
7365 
7366 void Mesh::CheckPartitioning(int *partitioning_)
7367 {
7368  int i, n_empty, n_mcomp;
7369  Array<int> component, num_comp;
7370  const Array<int> partitioning(partitioning_, GetNE());
7371 
7373 
7374  FindPartitioningComponents(*el_to_el, partitioning, component, num_comp);
7375 
7376  n_empty = n_mcomp = 0;
7377  for (i = 0; i < num_comp.Size(); i++)
7378  if (num_comp[i] == 0)
7379  {
7380  n_empty++;
7381  }
7382  else if (num_comp[i] > 1)
7383  {
7384  n_mcomp++;
7385  }
7386 
7387  if (n_empty > 0)
7388  {
7389  mfem::out << "Mesh::CheckPartitioning(...) :\n"
7390  << "The following subdomains are empty :\n";
7391  for (i = 0; i < num_comp.Size(); i++)
7392  if (num_comp[i] == 0)
7393  {
7394  mfem::out << ' ' << i;
7395  }
7396  mfem::out << endl;
7397  }
7398  if (n_mcomp > 0)
7399  {
7400  mfem::out << "Mesh::CheckPartitioning(...) :\n"
7401  << "The following subdomains are NOT connected :\n";
7402  for (i = 0; i < num_comp.Size(); i++)
7403  if (num_comp[i] > 1)
7404  {
7405  mfem::out << ' ' << i;
7406  }
7407  mfem::out << endl;
7408  }
7409  if (n_empty == 0 && n_mcomp == 0)
7410  mfem::out << "Mesh::CheckPartitioning(...) : "
7411  "All subdomains are connected." << endl;
7412 
7413  if (el_to_el)
7414  {
7415  delete el_to_el;
7416  }
7417  el_to_el = NULL;
7418 }
7419 
7420 // compute the coefficients of the polynomial in t:
7421 // c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B)
7422 // where A, B are (d x d), d=2,3
7423 void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
7424 {
7425  const double *a = A.Data();
7426  const double *b = B.Data();
7427 
7428  c.SetSize(A.Width()+1);
7429  switch (A.Width())
7430  {
7431  case 2:
7432  {
7433  // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ |b0 b2|
7434  // |a1 a3| + \ |a1 b3| |b1 a3| / * t + |b1 b3| * t^2
7435  c(0) = a[0]*a[3]-a[1]*a[2];
7436  c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2];
7437  c(2) = b[0]*b[3]-b[1]*b[2];
7438  }
7439  break;
7440 
7441  case 3:
7442  {
7443  /* |a0 a3 a6|
7444  * det(A+t*B) = |a1 a4 a7| +
7445  * |a2 a5 a8|
7446 
7447  * / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \
7448  * + | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t +
7449  * \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| /
7450 
7451  * / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \
7452  * + | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 +
7453  * \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| /
7454 
7455  * |b0 b3 b6|
7456  * + |b1 b4 b7| * t^3
7457  * |b2 b5 b8| */
7458  c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) +
7459  a[1] * (a[5] * a[6] - a[3] * a[8]) +
7460  a[2] * (a[3] * a[7] - a[4] * a[6]));
7461 
7462  c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) +
7463  b[1] * (a[5] * a[6] - a[3] * a[8]) +
7464  b[2] * (a[3] * a[7] - a[4] * a[6]) +
7465 
7466  a[0] * (b[4] * a[8] - b[5] * a[7]) +
7467  a[1] * (b[5] * a[6] - b[3] * a[8]) +
7468  a[2] * (b[3] * a[7] - b[4] * a[6]) +
7469 
7470  a[0] * (a[4] * b[8] - a[5] * b[7]) +
7471  a[1] * (a[5] * b[6] - a[3] * b[8]) +
7472  a[2] * (a[3] * b[7] - a[4] * b[6]));
7473 
7474  c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) +
7475  a[1] * (b[5] * b[6] - b[3] * b[8]) +
7476  a[2] * (b[3] * b[7] - b[4] * b[6]) +
7477 
7478  b[0] * (a[4] * b[8] - a[5] * b[7]) +
7479  b[1] * (a[5] * b[6] - a[3] * b[8]) +
7480  b[2] * (a[3] * b[7] - a[4] * b[6]) +
7481 
7482  b[0] * (b[4] * a[8] - b[5] * a[7]) +
7483  b[1] * (b[5] * a[6] - b[3] * a[8]) +
7484  b[2] * (b[3] * a[7] - b[4] * a[6]));
7485 
7486  c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) +
7487  b[1] * (b[5] * b[6] - b[3] * b[8]) +
7488  b[2] * (b[3] * b[7] - b[4] * b[6]));
7489  }
7490  break;
7491 
7492  default:
7493  mfem_error("DetOfLinComb(...)");
7494  }
7495 }
7496 
7497 // compute the real roots of
7498 // z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3;
7499 // the roots are returned in x, sorted in increasing order;
7500 // it is assumed that x is at least of size d;
7501 // return the number of roots counting multiplicity;
7502 // return -1 if all z(i) are 0.
7503 int FindRoots(const Vector &z, Vector &x)
7504 {
7505  int d = z.Size()-1;
7506  if (d > 3 || d < 0)
7507  {
7508  mfem_error("FindRoots(...)");
7509  }
7510 
7511  while (z(d) == 0.0)
7512  {
7513  if (d == 0)
7514  {
7515  return (-1);
7516  }
7517  d--;
7518  }
7519  switch (d)
7520  {
7521  case 0:
7522  {
7523  return 0;
7524  }
7525 
7526  case 1:
7527  {
7528  x(0) = -z(0)/z(1);
7529  return 1;
7530  }
7531 
7532  case 2:
7533  {
7534  double a = z(2), b = z(1), c = z(0);
7535  double D = b*b-4*a*c;
7536  if (D < 0.0)
7537  {
7538  return 0;
7539  }
7540  if (D == 0.0)
7541  {
7542  x(0) = x(1) = -0.5 * b / a;
7543  return 2; // root with multiplicity 2
7544  }
7545  if (b == 0.0)
7546  {
7547  x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a));
7548  return 2;
7549  }
7550  else
7551  {
7552  double t;
7553  if (b > 0.0)
7554  {
7555  t = -0.5 * (b + sqrt(D));
7556  }
7557  else
7558  {
7559  t = -0.5 * (b - sqrt(D));
7560  }
7561  x(0) = t / a;
7562  x(1) = c / t;
7563  if (x(0) > x(1))
7564  {
7565  Swap<double>(x(0), x(1));
7566  }
7567  return 2;
7568  }
7569  }
7570 
7571  case 3:
7572  {
7573  double a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3);
7574 
7575  // find the real roots of x^3 + a x^2 + b x + c = 0
7576  double Q = (a * a - 3 * b) / 9;
7577  double R = (2 * a * a * a - 9 * a * b + 27 * c) / 54;
7578  double Q3 = Q * Q * Q;
7579  double R2 = R * R;
7580 
7581  if (R2 == Q3)
7582  {
7583  if (Q == 0)
7584  {
7585  x(0) = x(1) = x(2) = - a / 3;
7586  }
7587  else
7588  {
7589  double sqrtQ = sqrt(Q);
7590 
7591  if (R > 0)
7592  {
7593  x(0) = -2 * sqrtQ - a / 3;
7594  x(1) = x(2) = sqrtQ - a / 3;
7595  }
7596  else
7597  {
7598  x(0) = x(1) = - sqrtQ - a / 3;
7599  x(2) = 2 * sqrtQ - a / 3;
7600  }
7601  }
7602  return 3;
7603  }
7604  else if (R2 < Q3)
7605  {
7606  double theta = acos(R / sqrt(Q3));
7607  double A = -2 * sqrt(Q);
7608  double x0, x1, x2;
7609  x0 = A * cos(theta / 3) - a / 3;
7610  x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3;
7611  x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3;
7612 
7613  /* Sort x0, x1, x2 */
7614  if (x0 > x1)
7615  {
7616  Swap<double>(x0, x1);
7617  }
7618  if (x1 > x2)
7619  {
7620  Swap<double>(x1, x2);
7621  if (x0 > x1)
7622  {
7623  Swap<double>(x0, x1);
7624  }
7625  }
7626  x(0) = x0;
7627  x(1) = x1;
7628  x(2) = x2;
7629  return 3;
7630  }
7631  else
7632  {
7633  double A;
7634  if (R >= 0.0)
7635  {
7636  A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0);
7637  }
7638  else
7639  {
7640  A = pow(sqrt(R2 - Q3) - R, 1.0/3.0);
7641  }
7642  x(0) = A + Q / A - a / 3;
7643  return 1;
7644  }
7645  }
7646  }
7647  return 0;
7648 }
7649 
7650 void FindTMax(Vector &c, Vector &x, double &tmax,
7651  const double factor, const int Dim)
7652 {
7653  const double c0 = c(0);
7654  c(0) = c0 * (1.0 - pow(factor, -Dim));
7655  int nr = FindRoots(c, x);
7656  for (int j = 0; j < nr; j++)
7657  {
7658  if (x(j) > tmax)
7659  {
7660  break;
7661  }
7662  if (x(j) >= 0.0)
7663  {
7664  tmax = x(j);
7665  break;
7666  }
7667  }
7668  c(0) = c0 * (1.0 - pow(factor, Dim));
7669  nr = FindRoots(c, x);
7670  for (int j = 0; j < nr; j++)
7671  {
7672  if (x(j) > tmax)
7673  {
7674  break;
7675  }
7676  if (x(j) >= 0.0)
7677  {
7678  tmax = x(j);
7679  break;
7680  }
7681  }
7682 }
7683 
7684 void Mesh::CheckDisplacements(const Vector &displacements, double &tmax)
7685 {
7686  int nvs = vertices.Size();
7687  DenseMatrix P, V, DS, PDS(spaceDim), VDS(spaceDim);
7688  Vector c(spaceDim+1), x(spaceDim);
7689  const double factor = 2.0;
7690 
7691  // check for tangling assuming constant speed
7692  if (tmax < 1.0)
7693  {
7694  tmax = 1.0;
7695  }
7696  for (int i = 0; i < NumOfElements; i++)
7697  {
7698  Element *el = elements[i];
7699  int nv = el->GetNVertices();
7700  int *v = el->GetVertices();
7701  P.SetSize(spaceDim, nv);
7702  V.SetSize(spaceDim, nv);
7703  for (int j = 0; j < spaceDim; j++)
7704  for (int k = 0; k < nv; k++)
7705  {
7706  P(j, k) = vertices[v[k]](j);
7707  V(j, k) = displacements(v[k]+j*nvs);
7708  }
7709  DS.SetSize(nv, spaceDim);
7710  const FiniteElement *fe =
7712  // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1
7713  switch (el->GetType())
7714  {
7715  case Element::TRIANGLE:
7716  case Element::TETRAHEDRON:
7717  {
7718  // DS is constant
7719  fe->CalcDShape(Geometries.GetCenter(fe->GetGeomType()), DS);
7720  Mult(P, DS, PDS);
7721  Mult(V, DS, VDS);
7722  DetOfLinComb(PDS, VDS, c);
7723  if (c(0) <= 0.0)
7724  {
7725  tmax = 0.0;
7726  }
7727  else
7728  {
7729  FindTMax(c, x, tmax, factor, Dim);
7730  }
7731  }
7732  break;
7733 
7735  {
7736  const IntegrationRule &ir = fe->GetNodes();
7737  for (int j = 0; j < nv; j++)
7738  {
7739  fe->CalcDShape(ir.IntPoint(j), DS);
7740  Mult(P, DS, PDS);
7741  Mult(V, DS, VDS);
7742  DetOfLinComb(PDS, VDS, c);
7743  if (c(0) <= 0.0)
7744  {
7745  tmax = 0.0;
7746  }
7747  else
7748  {
7749  FindTMax(c, x, tmax, factor, Dim);
7750  }
7751  }
7752  }
7753  break;
7754 
7755  default:
7756  mfem_error("Mesh::CheckDisplacements(...)");
7757  }
7758  }
7759 }
7760 
7761 void Mesh::MoveVertices(const Vector &displacements)
7762 {
7763  for (int i = 0, nv = vertices.Size(); i < nv; i++)
7764  for (int j = 0; j < spaceDim; j++)
7765  {
7766  vertices[i](j) += displacements(j*nv+i);
7767  }
7768 }
7769 
7770 void Mesh::GetVertices(Vector &vert_coord) const
7771 {
7772  int nv = vertices.Size();
7773  vert_coord.SetSize(nv*spaceDim);
7774  for (int i = 0; i < nv; i++)
7775  for (int j = 0; j < spaceDim; j++)
7776  {
7777  vert_coord(j*nv+i) = vertices[i](j);
7778  }
7779 }
7780 
7781 void Mesh::SetVertices(const Vector &vert_coord)
7782 {
7783  for (int i = 0, nv = vertices.Size(); i < nv; i++)
7784  for (int j = 0; j < spaceDim; j++)
7785  {
7786  vertices[i](j) = vert_coord(j*nv+i);
7787  }
7788 }
7789 
7790 void Mesh::GetNode(int i, double *coord) const
7791 {
7792  if (Nodes)
7793  {
7794  FiniteElementSpace *fes = Nodes->FESpace();
7795  for (int j = 0; j < spaceDim; j++)
7796  {
7797  coord[j] = (*Nodes)(fes->DofToVDof(i, j));
7798  }
7799  }
7800  else
7801  {
7802  for (int j = 0; j < spaceDim; j++)
7803  {
7804  coord[j] = vertices[i](j);
7805  }
7806  }
7807 }
7808 
7809 void Mesh::SetNode(int i, const double *coord)
7810 {
7811  if (Nodes)
7812  {
7813  FiniteElementSpace *fes = Nodes->FESpace();
7814  for (int j = 0; j < spaceDim; j++)
7815  {
7816  (*Nodes)(fes->DofToVDof(i, j)) = coord[j];
7817  }
7818  }
7819  else
7820  {
7821  for (int j = 0; j < spaceDim; j++)
7822  {
7823  vertices[i](j) = coord[j];
7824  }
7825 
7826  }
7827 }
7828 
7829 void Mesh::MoveNodes(const Vector &displacements)
7830 {
7831  if (Nodes)
7832  {
7833  (*Nodes) += displacements;
7834  }
7835  else
7836  {
7837  MoveVertices(displacements);
7838  }
7839 }
7840 
7841 void Mesh::GetNodes(Vector &node_coord) const
7842 {
7843  if (Nodes)
7844  {
7845  node_coord = (*Nodes);
7846  }
7847  else
7848  {
7849  GetVertices(node_coord);
7850  }
7851 }
7852 
7853 void Mesh::SetNodes(const Vector &node_coord)
7854 {
7855  if (Nodes)
7856  {
7857  (*Nodes) = node_coord;
7858  }
7859  else
7860  {
7861  SetVertices(node_coord);
7862  }
7863 }
7864 
7865 void Mesh::NewNodes(GridFunction &nodes, bool make_owner)
7866 {
7867  if (own_nodes) { delete Nodes; }
7868  Nodes = &nodes;
7869  spaceDim = Nodes->FESpace()->GetVDim();
7870  own_nodes = (int)make_owner;
7871 
7872  if (NURBSext != nodes.FESpace()->GetNURBSext())
7873  {
7874  delete NURBSext;
7875  NURBSext = nodes.FESpace()->StealNURBSext();
7876  }
7877 
7878  if (ncmesh)
7879  {
7881  }
7882 }
7883 
7884 void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_)
7885 {
7886  mfem::Swap<GridFunction*>(Nodes, nodes);
7887  mfem::Swap<int>(own_nodes, own_nodes_);
7888  // TODO:
7889  // if (nodes)
7890  // nodes->FESpace()->MakeNURBSextOwner();
7891  // NURBSext = (Nodes) ? Nodes->FESpace()->StealNURBSext() : NULL;
7892 }
7893 
7894 void Mesh::AverageVertices(const int *indexes, int n, int result)
7895 {
7896  int j, k;
7897 
7898  for (k = 0; k < spaceDim; k++)
7899  {
7900  vertices[result](k) = vertices[indexes[0]](k);
7901  }
7902 
7903  for (j = 1; j < n; j++)
7904  for (k = 0; k < spaceDim; k++)
7905  {
7906  vertices[result](k) += vertices[indexes[j]](k);
7907  }
7908 
7909  for (k = 0; k < spaceDim; k++)
7910  {
7911  vertices[result](k) *= (1.0 / n);
7912  }
7913 }
7914 
7916 {
7917  if (Nodes)
7918  {
7919  Nodes->FESpace()->Update();
7920  Nodes->Update();
7921 
7922  // update vertex coordinates for compatibility (e.g., GetVertex())
7924  }
7925 }
7926 
7927 void Mesh::UniformRefinement2D_base(bool update_nodes)
7928 {
7929  ResetLazyData();
7930 
7931  if (el_to_edge == NULL)
7932  {
7933  el_to_edge = new Table;
7935  }
7936 
7937  int quad_counter = 0;
7938  for (int i = 0; i < NumOfElements; i++)
7939  {
7940  if (elements[i]->GetType() == Element::QUADRILATERAL)
7941  {
7942  quad_counter++;
7943  }
7944  }
7945 
7946  const int oedge = NumOfVertices;
7947  const int oelem = oedge + NumOfEdges;
7948 
7949  Array<Element*> new_elements;
7950  Array<Element*> new_boundary;
7951 
7952  vertices.SetSize(oelem + quad_counter);
7953  new_elements.SetSize(4 * NumOfElements);
7954  quad_counter = 0;
7955 
7956  for (int i = 0, j = 0; i < NumOfElements; i++)
7957  {
7958  const Element::Type el_type = elements[i]->GetType();
7959  const int attr = elements[i]->GetAttribute();
7960  int *v = elements[i]->GetVertices();
7961  const int *e = el_to_edge->GetRow(i);
7962  int vv[2];
7963 
7964  if (el_type == Element::TRIANGLE)
7965  {
7966  for (int ei = 0; ei < 3; ei++)
7967  {
7968  for (int k = 0; k < 2; k++)
7969  {
7970  vv[k] = v[tri_t::Edges[ei][k]];
7971  }
7972  AverageVertices(vv, 2, oedge+e[ei]);
7973  }
7974 
7975  new_elements[j++] =
7976  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
7977  new_elements[j++] =
7978  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
7979  new_elements[j++] =
7980  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
7981  new_elements[j++] =
7982  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
7983  }
7984  else if (el_type == Element::QUADRILATERAL)
7985  {
7986  const int qe = quad_counter;
7987  quad_counter++;
7988  AverageVertices(v, 4, oelem+qe);
7989 
7990  for (int ei = 0; ei < 4; ei++)
7991  {
7992  for (int k = 0; k < 2; k++)
7993  {
7994  vv[k] = v[quad_t::Edges[ei][k]];
7995  }
7996  AverageVertices(vv, 2, oedge+e[ei]);
7997  }
7998 
7999  new_elements[j++] =
8000  new Quadrilateral(v[0], oedge+e[0], oelem+qe, oedge+e[3], attr);
8001  new_elements[j++] =
8002  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oelem+qe, attr);
8003  new_elements[j++] =
8004  new Quadrilateral(oelem+qe, oedge+e[1], v[2], oedge+e[2], attr);
8005  new_elements[j++] =
8006  new Quadrilateral(oedge+e[3], oelem+qe, oedge+e[2], v[3], attr);
8007  }
8008  else
8009  {
8010  MFEM_ABORT("unknown element type: " << el_type);
8011  }
8012  FreeElement(elements[i]);
8013  }
8014  mfem::Swap(elements, new_elements);
8015 
8016  // refine boundary elements
8017  new_boundary.SetSize(2 * NumOfBdrElements);
8018  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
8019  {
8020  const int attr = boundary[i]->GetAttribute();
8021  int *v = boundary[i]->GetVertices();
8022 
8023  new_boundary[j++] = new Segment(v[0], oedge+be_to_edge[i], attr);
8024  new_boundary[j++] = new Segment(oedge+be_to_edge[i], v[1], attr);
8025 
8026  FreeElement(boundary[i]);
8027  }
8028  mfem::Swap(boundary, new_boundary);
8029 
8030  static const double A = 0.0, B = 0.5, C = 1.0;
8031  static double tri_children[2*3*4] =
8032  {
8033  A,A, B,A, A,B,
8034  B,B, A,B, B,A,
8035  B,A, C,A, B,B,
8036  A,B, B,B, A,C
8037  };
8038  static double quad_children[2*4*4] =
8039  {
8040  A,A, B,A, B,B, A,B, // lower-left
8041  B,A, C,A, C,B, B,B, // lower-right
8042  B,B, C,B, C,C, B,C, // upper-right
8043  A,B, B,B, B,C, A,C // upper-left
8044  };
8045 
8047  .UseExternalData(tri_children, 2, 3, 4);
8049  .UseExternalData(quad_children, 2, 4, 4);
8050  CoarseFineTr.embeddings.SetSize(elements.Size());
8051 
8052  for (int i = 0; i < elements.Size(); i++)
8053  {
8054  Embedding &emb = CoarseFineTr.embeddings[i];
8055  emb.parent = i / 4;
8056  emb.matrix = i % 4;
8057  }
8058 
8059  NumOfVertices = vertices.Size();
8060  NumOfElements = 4 * NumOfElements;
8061  NumOfBdrElements = 2 * NumOfBdrElements;
8062  NumOfFaces = 0;
8063 
8065  GenerateFaces();
8066 
8068  sequence++;
8069 
8070  if (update_nodes) { UpdateNodes(); }
8071 
8072 #ifdef MFEM_DEBUG
8073  if (!Nodes || update_nodes)
8074  {
8075  CheckElementOrientation(false);
8076  }
8078 #endif
8079 }
8080 
8081 static inline double sqr(const double &x)
8082 {
8083  return x*x;
8084 }
8085 
8087  bool update_nodes)
8088 {
8089  ResetLazyData();
8090 
8091  if (el_to_edge == NULL)
8092  {
8093  el_to_edge = new Table;
8095  }
8096 
8097  if (el_to_face == NULL)
8098  {
8100  }
8101 
8102  Array<int> f2qf_loc;
8103  Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
8104  f2qf.SetSize(0);
8105 
8106  int NumOfQuadFaces = 0;
8108  {
8110  {
8111  f2qf.SetSize(faces.Size());
8112  for (int i = 0; i < faces.Size(); i++)
8113  {
8114  if (faces[i]->GetType() == Element::QUADRILATERAL)
8115  {
8116  f2qf[i] = NumOfQuadFaces;
8117  NumOfQuadFaces++;
8118  }
8119  }
8120  }
8121  else
8122  {
8123  NumOfQuadFaces = faces.Size();
8124  }
8125  }
8126 
8127  int hex_counter = 0;
8129  {
8130  for (int i = 0; i < elements.Size(); i++)
8131  {
8132  if (elements[i]->GetType() == Element::HEXAHEDRON)
8133  {
8134  hex_counter++;
8135  }
8136  }
8137  }
8138 
8139  int pyr_counter = 0;
8141  {
8142  for (int i = 0; i < elements.Size(); i++)
8143  {
8144  if (elements[i]->GetType() == Element::PYRAMID)
8145  {
8146  pyr_counter++;
8147  }
8148  }
8149  }
8150 
8151  // Map from edge-index to vertex-index, needed for ReorientTetMesh() for
8152  // parallel meshes.
8153  // Note: with the removal of ReorientTetMesh() this may no longer
8154  // be needed. Unfortunately, it's hard to be sure.
8155  Array<int> e2v;
8157  {
8158  e2v.SetSize(NumOfEdges);
8159 
8160  DSTable *v_to_v_ptr = v_to_v_p;
8161  if (!v_to_v_p)
8162  {
8163  v_to_v_ptr = new DSTable(NumOfVertices);
8164  GetVertexToVertexTable(*v_to_v_ptr);
8165  }
8166 
8167  Array<Pair<int,int> > J_v2v(NumOfEdges); // (second vertex id, edge id)
8168  J_v2v.SetSize(0);
8169  for (int i = 0; i < NumOfVertices; i++)
8170  {
8171  Pair<int,int> *row_start = J_v2v.end();
8172  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
8173  {
8174  J_v2v.Append(Pair<int,int>(it.Column(), it.Index()));
8175  }
8176  std::sort(row_start, J_v2v.end());
8177  }
8178 
8179  for (int i = 0; i < J_v2v.Size(); i++)
8180  {
8181  e2v[J_v2v[i].two] = i;
8182  }
8183 
8184  if (!v_to_v_p)
8185  {
8186  delete v_to_v_ptr;
8187  }
8188  else
8189  {
8190  for (int i = 0; i < NumOfVertices; i++)
8191  {
8192  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
8193  {
8194  it.SetIndex(e2v[it.Index()]);
8195  }
8196  }
8197  }
8198  }
8199 
8200  // Offsets for new vertices from edges, faces (quads only), and elements
8201  // (hexes only); each of these entities generates one new vertex.
8202  const int oedge = NumOfVertices;
8203  const int oface = oedge + NumOfEdges;
8204  const int oelem = oface + NumOfQuadFaces;
8205 
8206  Array<Element*> new_elements;
8207  Array<Element*> new_boundary;
8208 
8209  vertices.SetSize(oelem + hex_counter);
8210  new_elements.SetSize(8 * NumOfElements + 2 * pyr_counter);
8211  CoarseFineTr.embeddings.SetSize(new_elements.Size());
8212 
8213  hex_counter = 0;
8214  for (int i = 0, j = 0; i < NumOfElements; i++)
8215  {
8216  const Element::Type el_type = elements[i]->GetType();
8217  const int attr = elements[i]->GetAttribute();
8218  int *v = elements[i]->GetVertices();
8219  const int *e = el_to_edge->GetRow(i);
8220  int vv[4], ev[12];
8221 
8222  if (e2v.Size())
8223  {
8224  const int ne = el_to_edge->RowSize(i);
8225  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
8226  e = ev;
8227  }
8228 
8229  switch (el_type)
8230  {
8231  case Element::TETRAHEDRON:
8232  {
8233  for (int ei = 0; ei < 6; ei++)
8234  {
8235  for (int k = 0; k < 2; k++)
8236  {
8237  vv[k] = v[tet_t::Edges[ei][k]];
8238  }
8239  AverageVertices(vv, 2, oedge+e[ei]);
8240  }
8241 
8242  // Algorithm for choosing refinement type:
8243  // 0: smallest octahedron diagonal
8244  // 1: best aspect ratio
8245  const int rt_algo = 1;
8246  // Refinement type:
8247  // 0: (v0,v1)-(v2,v3), 1: (v0,v2)-(v1,v3), 2: (v0,v3)-(v1,v2)
8248  // 0: e0-e5, 1: e1-e4, 2: e2-e3
8249  int rt;
8252  const DenseMatrix &J = T->Jacobian();
8253  if (rt_algo == 0)
8254  {
8255  // smallest octahedron diagonal
8256  double len_sqr, min_len;
8257 
8258  min_len = sqr(J(0,0)-J(0,1)-J(0,2)) +
8259  sqr(J(1,0)-J(1,1)-J(1,2)) +
8260  sqr(J(2,0)-J(2,1)-J(2,2));
8261  rt = 0;
8262 
8263  len_sqr = sqr(J(0,1)-J(0,0)-J(0,2)) +
8264  sqr(J(1,1)-J(1,0)-J(1,2)) +
8265  sqr(J(2,1)-J(2,0)-J(2,2));
8266  if (len_sqr < min_len) { min_len = len_sqr; rt = 1; }
8267 
8268  len_sqr = sqr(J(0,2)-J(0,0)-J(0,1)) +
8269  sqr(J(1,2)-J(1,0)-J(1,1)) +
8270  sqr(J(2,2)-J(2,0)-J(2,1));
8271  if (len_sqr < min_len) { rt = 2; }
8272  }
8273  else
8274  {
8275  // best aspect ratio
8276  double Em_data[18], Js_data[9], Jp_data[9];
8277  DenseMatrix Em(Em_data, 3, 6);
8278  DenseMatrix Js(Js_data, 3, 3), Jp(Jp_data, 3, 3);
8279  double ar1, ar2, kappa, kappa_min;
8280 
8281  for (int s = 0; s < 3; s++)
8282  {
8283  for (int t = 0; t < 3; t++)
8284  {
8285  Em(t,s) = 0.5*J(t,s);
8286  }
8287  }
8288  for (int t = 0; t < 3; t++)
8289  {
8290  Em(t,3) = 0.5*(J(t,0)+J(t,1));
8291  Em(t,4) = 0.5*(J(t,0)+J(t,2));
8292  Em(t,5) = 0.5*(J(t,1)+J(t,2));
8293  }
8294 
8295  // rt = 0; Em: {0,5,1,2}, {0,5,2,4}
8296  for (int t = 0; t < 3; t++)
8297  {
8298  Js(t,0) = Em(t,5)-Em(t,0);
8299  Js(t,1) = Em(t,1)-Em(t,0);
8300  Js(t,2) = Em(t,2)-Em(t,0);
8301  }
8303  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8304  for (int t = 0; t < 3; t++)
8305  {
8306  Js(t,0) = Em(t,5)-Em(t,0);
8307  Js(t,1) = Em(t,2)-Em(t,0);
8308  Js(t,2) = Em(t,4)-Em(t,0);
8309  }
8311  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8312  kappa_min = std::max(ar1, ar2);
8313  rt = 0;
8314 
8315  // rt = 1; Em: {1,0,4,2}, {1,2,4,5}
8316  for (int t = 0; t < 3; t++)
8317  {
8318  Js(t,0) = Em(t,0)-Em(t,1);
8319  Js(t,1) = Em(t,4)-Em(t,1);
8320  Js(t,2) = Em(t,2)-Em(t,1);
8321  }
8323  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8324  for (int t = 0; t < 3; t++)
8325  {
8326  Js(t,0) = Em(t,2)-Em(t,1);
8327  Js(t,1) = Em(t,4)-Em(t,1);
8328  Js(t,2) = Em(t,5)-Em(t,1);
8329  }
8331  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8332  kappa = std::max(ar1, ar2);
8333  if (kappa < kappa_min) { kappa_min = kappa; rt = 1; }
8334 
8335  // rt = 2; Em: {2,0,1,3}, {2,1,5,3}
8336  for (int t = 0; t < 3; t++)
8337  {
8338  Js(t,0) = Em(t,0)-Em(t,2);
8339  Js(t,1) = Em(t,1)-Em(t,2);
8340  Js(t,2) = Em(t,3)-Em(t,2);
8341  }
8343  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8344  for (int t = 0; t < 3; t++)
8345  {
8346  Js(t,0) = Em(t,1)-Em(t,2);
8347  Js(t,1) = Em(t,5)-Em(t,2);
8348  Js(t,2) = Em(t,3)-Em(t,2);
8349  }
8351  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
8352  kappa = std::max(ar1, ar2);
8353  if (kappa < kappa_min) { rt = 2; }
8354  }
8355 
8356  static const int mv_all[3][4][4] =
8357  {
8358  { {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1} }, // rt = 0
8359  { {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0} }, // rt = 1
8360  { {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3} } // rt = 2
8361  };
8362  const int (&mv)[4][4] = mv_all[rt];
8363 
8364 #ifndef MFEM_USE_MEMALLOC
8365  new_elements[j+0] =
8366  new Tetrahedron(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
8367  new_elements[j+1] =
8368  new Tetrahedron(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
8369  new_elements[j+2] =
8370  new Tetrahedron(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
8371  new_elements[j+3] =
8372  new Tetrahedron(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
8373 
8374  for (int k = 0; k < 4; k++)
8375  {
8376  new_elements[j+4+k] =
8377  new Tetrahedron(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
8378  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
8379  }
8380 #else
8381  Tetrahedron *tet;
8382  new_elements[j+0] = tet = TetMemory.Alloc();
8383  tet->Init(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
8384 
8385  new_elements[j+1] = tet = TetMemory.Alloc();
8386  tet->Init(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
8387 
8388  new_elements[j+2] = tet = TetMemory.Alloc();
8389  tet->Init(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
8390 
8391  new_elements[j+3] = tet = TetMemory.Alloc();
8392  tet->Init(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
8393 
8394  for (int k = 0; k < 4; k++)
8395  {
8396  new_elements[j+4+k] = tet = TetMemory.Alloc();
8397  tet->Init(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
8398  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
8399  }
8400 #endif
8401  for (int k = 0; k < 4; k++)
8402  {
8403  CoarseFineTr.embeddings[j+k].parent = i;
8404  CoarseFineTr.embeddings[j+k].matrix = k;
8405  }
8406  for (int k = 0; k < 4; k++)
8407  {
8408  CoarseFineTr.embeddings[j+4+k].parent = i;
8409  CoarseFineTr.embeddings[j+4+k].matrix = 4*(rt+1)+k;
8410  }
8411 
8412  j += 8;
8413  }
8414  break;
8415 
8416  case Element::WEDGE:
8417  {
8418  const int *f = el_to_face->GetRow(i);
8419 
8420  for (int fi = 2; fi < 5; fi++)
8421  {
8422  for (int k = 0; k < 4; k++)
8423  {
8424  vv[k] = v[pri_t::FaceVert[fi][k]];
8425  }
8426  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
8427  }
8428 
8429  for (int ei = 0; ei < 9; ei++)
8430  {
8431  for (int k = 0; k < 2; k++)
8432  {
8433  vv[k] = v[pri_t::Edges[ei][k]];
8434  }
8435  AverageVertices(vv, 2, oedge+e[ei]);
8436  }
8437 
8438  const int qf2 = f2qf[f[2]];
8439  const int qf3 = f2qf[f[3]];
8440  const int qf4 = f2qf[f[4]];
8441 
8442  new_elements[j++] =
8443  new Wedge(v[0], oedge+e[0], oedge+e[2],
8444  oedge+e[6], oface+qf2, oface+qf4, attr);
8445 
8446  new_elements[j++] =
8447  new Wedge(oedge+e[1], oedge+e[2], oedge+e[0],
8448  oface+qf3, oface+qf4, oface+qf2, attr);
8449 
8450  new_elements[j++] =
8451  new Wedge(oedge+e[0], v[1], oedge+e[1],
8452  oface+qf2, oedge+e[7], oface+qf3, attr);
8453 
8454  new_elements[j++] =
8455  new Wedge(oedge+e[2], oedge+e[1], v[2],
8456  oface+qf4, oface+qf3, oedge+e[8], attr);
8457 
8458  new_elements[j++] =
8459  new Wedge(oedge+e[6], oface+qf2, oface+qf4,
8460  v[3], oedge+e[3], oedge+e[5], attr);
8461 
8462  new_elements[j++] =
8463  new Wedge(oface+qf3, oface+qf4, oface+qf2,
8464  oedge+e[4], oedge+e[5], oedge+e[3], attr);
8465 
8466  new_elements[j++] =
8467  new Wedge(oface+qf2, oedge+e[7], oface+qf3,
8468  oedge+e[3], v[4], oedge+e[4], attr);
8469 
8470  new_elements[j++] =
8471  new Wedge(oface+qf4, oface+qf3, oedge+e[8],
8472  oedge+e[5], oedge+e[4], v[5], attr);
8473  }
8474  break;
8475 
8476  case Element::PYRAMID:
8477  {
8478  const int *f = el_to_face->GetRow(i);
8479  // pyr_counter++;
8480 
8481  for (int fi = 0; fi < 1; fi++)
8482  {
8483  for (int k = 0; k < 4; k++)
8484  {
8485  vv[k] = v[pyr_t::FaceVert[fi][k]];
8486  }
8487  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
8488  }
8489 
8490  for (int ei = 0; ei < 8; ei++)
8491  {
8492  for (int k = 0; k < 2; k++)
8493  {
8494  vv[k] = v[pyr_t::Edges[ei][k]];
8495  }
8496  AverageVertices(vv, 2, oedge+e[ei]);
8497  }
8498 
8499  const int qf0 = f2qf[f[0]];
8500 
8501  new_elements[j++] =
8502  new Pyramid(v[0], oedge+e[0], oface+qf0,
8503  oedge+e[3], oedge+e[4], attr);
8504 
8505  new_elements[j++] =
8506  new Pyramid(oedge+e[0], v[1], oedge+e[1],
8507  oface+qf0, oedge+e[5], attr);
8508 
8509  new_elements[j++] =
8510  new Pyramid(oface+qf0, oedge+e[1], v[2],
8511  oedge+e[2], oedge+e[6], attr);
8512 
8513  new_elements[j++] =
8514  new Pyramid(oedge+e[3], oface+qf0, oedge+e[2],
8515  v[3], oedge+e[7], attr);
8516 
8517  new_elements[j++] =
8518  new Pyramid(oedge+e[4], oedge+e[5], oedge+e[6],
8519  oedge+e[7], v[4], attr);
8520 
8521  new_elements[j++] =
8522  new Pyramid(oedge+e[7], oedge+e[6], oedge+e[5],
8523  oedge+e[4], oface+qf0, attr);
8524 
8525  new_elements[j++] =
8526  new Tetrahedron(oedge+e[0], oedge+e[4], oedge+e[5],
8527  oface+qf0, attr);
8528 
8529  new_elements[j++] =
8530  new Tetrahedron(oedge+e[1], oedge+e[5], oedge+e[6],
8531  oface+qf0, attr);
8532 
8533  new_elements[j++] =
8534  new Tetrahedron(oedge+e[2], oedge+e[6], oedge+e[7],
8535  oface+qf0, attr);
8536 
8537  new_elements[j++] =
8538  new Tetrahedron(oedge+e[3], oedge+e[7], oedge+e[4],
8539  oface+qf0, attr);
8540  }
8541  break;
8542 
8543  case Element::HEXAHEDRON:
8544  {
8545  const int *f = el_to_face->GetRow(i);
8546  const int he = hex_counter;
8547  hex_counter++;
8548 
8549  const int *qf;
8550  int qf_data[6];
8551  if (f2qf.Size() == 0)
8552  {
8553  qf = f;
8554  }
8555  else
8556  {
8557  for (int k = 0; k < 6; k++) { qf_data[k] = f2qf[f[k]]; }
8558  qf = qf_data;
8559  }
8560 
8561  AverageVertices(v, 8, oelem+he);
8562 
8563  for (int fi = 0; fi < 6; fi++)
8564  {
8565  for (int k = 0; k < 4; k++)
8566  {
8567  vv[k] = v[hex_t::FaceVert[fi][k]];
8568  }
8569  AverageVertices(vv, 4, oface + qf[fi]);
8570  }
8571 
8572  for (int ei = 0; ei < 12; ei++)
8573  {
8574  for (int k = 0; k < 2; k++)
8575  {
8576  vv[k] = v[hex_t::Edges[ei][k]];
8577  }
8578  AverageVertices(vv, 2, oedge+e[ei]);
8579  }
8580 
8581  new_elements[j++] =
8582  new Hexahedron(v[0], oedge+e[0], oface+qf[0],
8583  oedge+e[3], oedge+e[8], oface+qf[1],
8584  oelem+he, oface+qf[4], attr);
8585  new_elements[j++] =
8586  new Hexahedron(oedge+e[0], v[1], oedge+e[1],
8587  oface+qf[0], oface+qf[1], oedge+e[9],
8588  oface+qf[2], oelem+he, attr);
8589  new_elements[j++] =
8590  new Hexahedron(oface+qf[0], oedge+e[1], v[2],
8591  oedge+e[2], oelem+he, oface+qf[2],
8592  oedge+e[10], oface+qf[3], attr);
8593  new_elements[j++] =
8594  new Hexahedron(oedge+e[3], oface+qf[0], oedge+e[2],
8595  v[3], oface+qf[4], oelem+he,
8596  oface+qf[3], oedge+e[11], attr);
8597  new_elements[j++] =
8598  new Hexahedron(oedge+e[8], oface+qf[1], oelem+he,
8599  oface+qf[4], v[4], oedge+e[4],
8600  oface+qf[5], oedge+e[7], attr);
8601  new_elements[j++] =
8602  new Hexahedron(oface+qf[1], oedge+e[9], oface+qf[2],
8603  oelem+he, oedge+e[4], v[5],
8604  oedge+e[5], oface+qf[5], attr);
8605  new_elements[j++] =
8606  new Hexahedron(oelem+he, oface+qf[2], oedge+e[10],
8607  oface+qf[3], oface+qf[5], oedge+e[5],
8608  v[6], oedge+e[6], attr);
8609  new_elements[j++] =
8610  new Hexahedron(oface+qf[4], oelem+he, oface+qf[3],
8611  oedge+e[11], oedge+e[7], oface+qf[5],
8612  oedge+e[6], v[7], attr);
8613  }
8614  break;
8615 
8616  default:
8617  MFEM_ABORT("Unknown 3D element type \"" << el_type << "\"");
8618  break;
8619  }
8620  FreeElement(elements[i]);
8621  }
8622  mfem::Swap(elements, new_elements);
8623 
8624  // refine boundary elements
8625  new_boundary.SetSize(4 * NumOfBdrElements);
8626  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
8627  {
8628  const Element::Type bdr_el_type = boundary[i]->GetType();
8629  const int attr = boundary[i]->GetAttribute();
8630  int *v = boundary[i]->GetVertices();
8631  const int *e = bel_to_edge->GetRow(i);
8632  int ev[4];
8633 
8634  if (e2v.Size())
8635  {
8636  const int ne = bel_to_edge->RowSize(i);
8637  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
8638  e = ev;
8639  }
8640 
8641  if (bdr_el_type == Element::TRIANGLE)
8642  {
8643  new_boundary[j++] =
8644  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
8645  new_boundary[j++] =
8646  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
8647  new_boundary[j++] =
8648  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
8649  new_boundary[j++] =
8650  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
8651  }
8652  else if (bdr_el_type == Element::QUADRILATERAL)
8653  {
8654  const int qf =
8655  (f2qf.Size() == 0) ? be_to_face[i] : f2qf[be_to_face[i]];
8656 
8657  new_boundary[j++] =
8658  new Quadrilateral(v[0], oedge+e[0], oface+qf, oedge+e[3], attr);
8659  new_boundary[j++] =
8660  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oface+qf, attr);
8661  new_boundary[j++] =
8662  new Quadrilateral(oface+qf, oedge+e[1], v[2], oedge+e[2], attr);
8663  new_boundary[j++] =
8664  new Quadrilateral(oedge+e[3], oface+qf, oedge+e[2], v[3], attr);
8665  }
8666  else
8667  {
8668  MFEM_ABORT("boundary Element is not a triangle or a quad!");
8669  }
8670  FreeElement(boundary[i]);
8671  }
8672  mfem::Swap(boundary, new_boundary);
8673 
8674  static const double A = 0.0, B = 0.5, C = 1.0, D = -1.0;
8675  static double tet_children[3*4*16] =
8676  {
8677  A,A,A, B,A,A, A,B,A, A,A,B,
8678  B,A,A, C,A,A, B,B,A, B,A,B,
8679  A,B,A, B,B,A, A,C,A, A,B,B,
8680  A,A,B, B,A,B, A,B,B, A,A,C,
8681  // edge coordinates:
8682  // 0 -> B,A,A 1 -> A,B,A 2 -> A,A,B
8683  // 3 -> B,B,A 4 -> B,A,B 5 -> A,B,B
8684  // rt = 0: {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1}
8685  B,A,A, A,B,B, A,B,A, A,A,B,
8686  B,A,A, A,B,B, A,A,B, B,A,B,
8687  B,A,A, A,B,B, B,A,B, B,B,A,
8688  B,A,A, A,B,B, B,B,A, A,B,A,
8689  // rt = 1: {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0}
8690  A,B,A, B,A,A, B,A,B, A,A,B,
8691  A,B,A, A,A,B, B,A,B, A,B,B,
8692  A,B,A, A,B,B, B,A,B, B,B,A,
8693  A,B,A, B,B,A, B,A,B, B,A,A,
8694  // rt = 2: {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3}
8695  A,A,B, B,A,A, A,B,A, B,B,A,
8696  A,A,B, A,B,A, A,B,B, B,B,A,
8697  A,A,B, A,B,B, B,A,B, B,B,A,
8698  A,A,B, B,A,B, B,A,A, B,B,A
8699  };
8700  static double pyr_children[3*5*10] =
8701  {
8702  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B,
8703  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B,
8704  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B,
8705  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B,
8706  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C,
8707  A,B,B, B,B,B, B,A,B, A,A,B, B,B,A,
8708  B,A,A, A,A,B, B,A,B, B,B,A, D,D,D,
8709  C,B,A, B,A,B, B,B,B, B,B,A, D,D,D,
8710  B,C,A, B,B,B, A,B,B, B,B,A, D,D,D,
8711  A,B,A, A,B,B, A,A,B, B,B,A, D,D,D
8712  };
8713  static double pri_children[3*6*8] =
8714  {
8715  A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
8716  B,B,A, A,B,A, B,A,A, B,B,B, A,B,B, B,A,B,
8717  B,A,A, C,A,A, B,B,A, B,A,B, C,A,B, B,B,B,
8718  A,B,A, B,B,A, A,C,A, A,B,B, B,B,B, A,C,B,
8719  A,A,B, B,A,B, A,B,B, A,A,C, B,A,C, A,B,C,
8720  B,B,B, A,B,B, B,A,B, B,B,C, A,B,C, B,A,C,
8721  B,A,B, C,A,B, B,B,B, B,A,C, C,A,C, B,B,C,
8722  A,B,B, B,B,B, A,C,B, A,B,C, B,B,C, A,C,C
8723  };
8724  static double hex_children[3*8*8] =
8725  {
8726  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B, B,A,B, B,B,B, A,B,B,
8727  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B, C,A,B, C,B,B, B,B,B,
8728  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B, C,B,B, C,C,B, B,C,B,
8729  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B, B,B,B, B,C,B, A,C,B,
8730  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C, B,A,C, B,B,C, A,B,C,
8731  B,A,B, C,A,B, C,B,B, B,B,B, B,A,C, C,A,C, C,B,C, B,B,C,
8732  B,B,B, C,B,B, C,C,B, B,C,B, B,B,C, C,B,C, C,C,C, B,C,C,
8733  A,B,B, B,B,B, B,C,B, A,C,B, A,B,C, B,B,C, B,C,C, A,C,C
8734  };
8735 
8737  .UseExternalData(tet_children, 3, 4, 16);
8739  .UseExternalData(pyr_children, 3, 5, 10);
8741  .UseExternalData(pri_children, 3, 6, 8);
8743  .UseExternalData(hex_children, 3, 8, 8);
8744 
8745  for (int i = 0; i < elements.Size(); i++)
8746  {
8747  // tetrahedron elements are handled above:
8748  if (elements[i]->GetType() == Element::TETRAHEDRON) { continue; }
8749 
8750  Embedding &emb = CoarseFineTr.embeddings[i];
8751  emb.parent = i / 8;
8752  emb.matrix = i % 8;
8753  }
8754 
8755  NumOfVertices = vertices.Size();
8756  NumOfElements = 8 * NumOfElements + 2 * pyr_counter;
8757  NumOfBdrElements = 4 * NumOfBdrElements;
8758 
8760  GenerateFaces();
8761 
8762 #ifdef MFEM_DEBUG
8764 #endif
8765 
8767 
8769  sequence++;
8770 
8771  if (update_nodes) { UpdateNodes(); }
8772 }
8773 
8774 void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
8775 {
8776  int i, j, ind, nedges;
8777  Array<int> v;
8778 
8779  ResetLazyData();
8780 
8781  if (ncmesh)
8782  {
8783  MFEM_ABORT("Local and nonconforming refinements cannot be mixed.");
8784  }
8785 
8787 
8788  if (Dim == 1) // --------------------------------------------------------
8789  {
8790  int cne = NumOfElements, cnv = NumOfVertices;
8791  NumOfVertices += marked_el.Size();
8792  NumOfElements += marked_el.Size();
8793  vertices.SetSize(NumOfVertices);
8794  elements.SetSize(NumOfElements);
8796 
8797  for (j = 0; j < marked_el.Size(); j++)
8798  {
8799  i = marked_el[j];
8800  Segment *c_seg = (Segment *)elements[i];
8801  int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
8802  int new_v = cnv + j, new_e = cne + j;
8803  AverageVertices(vert, 2, new_v);
8804  elements[new_e] = new Segment(new_v, vert[1], attr);
8805  vert[1] = new_v;
8806 
8809  }
8810 
8811  static double seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
8813  UseExternalData(seg_children, 1, 2, 3);
8814 
8815  GenerateFaces();
8816 
8817  } // end of 'if (Dim == 1)'
8818  else if (Dim == 2) // ---------------------------------------------------
8819  {
8820  // 1. Get table of vertex to vertex connections.
8821  DSTable v_to_v(NumOfVertices);
8822  GetVertexToVertexTable(v_to_v);
8823 
8824  // 2. Get edge to element connections in arrays edge1 and edge2
8825  nedges = v_to_v.NumberOfEntries();
8826  int *edge1 = new int[nedges];
8827  int *edge2 = new int[nedges];
8828  int *middle = new int[nedges];
8829 
8830  for (i = 0; i < nedges; i++)
8831  {
8832  edge1[i] = edge2[i] = middle[i] = -1;
8833  }
8834 
8835  for (i = 0; i < NumOfElements; i++)
8836  {
8837  elements[i]->GetVertices(v);
8838  for (j = 1; j < v.Size(); j++)
8839  {
8840  ind = v_to_v(v[j-1], v[j]);
8841  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
8842  }
8843  ind = v_to_v(v[0], v[v.Size()-1]);
8844  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
8845  }
8846 
8847  // 3. Do the red refinement.
8848  for (i = 0; i < marked_el.Size(); i++)
8849  {
8850  RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
8851  }
8852 
8853  // 4. Do the green refinement (to get conforming mesh).
8854  int need_refinement;
8855  do
8856  {
8857  need_refinement = 0;
8858  for (i = 0; i < nedges; i++)
8859  {
8860  if (middle[i] != -1 && edge1[i] != -1)
8861  {
8862  need_refinement = 1;
8863  GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
8864  }
8865  }
8866  }
8867  while (need_refinement == 1);
8868 
8869  // 5. Update the boundary elements.
8870  int v1[2], v2[2], bisect, temp;
8871  temp = NumOfBdrElements;
8872  for (i = 0; i < temp; i++)
8873  {
8874  boundary[i]->GetVertices(v);
8875  bisect = v_to_v(v[0], v[1]);
8876  if (middle[bisect] != -1) // the element was refined (needs updating)
8877  {
8878  if (boundary[i]->GetType() == Element::SEGMENT)
8879  {
8880  v1[0] = v[0]; v1[1] = middle[bisect];
8881  v2[0] = middle[bisect]; v2[1] = v[1];
8882 
8883  boundary[i]->SetVertices(v1);
8884  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
8885  }
8886  else
8887  mfem_error("Only bisection of segment is implemented"
8888  " for bdr elem.");
8889  }
8890  }
8891  NumOfBdrElements = boundary.Size();
8892 
8893  // 6. Free the allocated memory.
8894  delete [] edge1;
8895  delete [] edge2;
8896  delete [] middle;
8897 
8898  if (el_to_edge != NULL)
8899  {
8901  GenerateFaces();
8902  }
8903 
8904  }
8905  else if (Dim == 3) // ---------------------------------------------------
8906  {
8907  // 1. Hash table of vertex to vertex connections corresponding to refined
8908  // edges.
8909  HashTable<Hashed2> v_to_v;
8910 
8911  MFEM_VERIFY(GetNE() == 0 ||
8912  ((Tetrahedron*)elements[0])->GetRefinementFlag() != 0,
8913  "tetrahedral mesh is not marked for refinement:"
8914  " call Finalize(true)");
8915 
8916  // 2. Do the red refinement.
8917  int ii;
8918  switch (type)
8919  {
8920  case 1:
8921  for (i = 0; i < marked_el.Size(); i++)
8922  {
8923  Bisection(marked_el[i], v_to_v);
8924  }
8925  break;
8926  case 2:
8927  for (i = 0; i < marked_el.Size(); i++)
8928  {
8929  Bisection(marked_el[i], v_to_v);
8930 
8931  Bisection(NumOfElements - 1, v_to_v);
8932  Bisection(marked_el[i], v_to_v);
8933  }
8934  break;
8935  case 3:
8936  for (i = 0; i < marked_el.Size(); i++)
8937  {
8938  Bisection(marked_el[i], v_to_v);
8939 
8940  ii = NumOfElements - 1;
8941  Bisection(ii, v_to_v);
8942  Bisection(NumOfElements - 1, v_to_v);
8943  Bisection(ii, v_to_v);
8944 
8945  Bisection(marked_el[i], v_to_v);
8946  Bisection(NumOfElements-1, v_to_v);
8947  Bisection(marked_el[i], v_to_v);
8948  }
8949  break;
8950  }
8951 
8952  // 3. Do the green refinement (to get conforming mesh).
8953  int need_refinement;
8954  // int need_refinement, onoe, max_gen = 0;
8955  do
8956  {
8957  // int redges[2], type, flag;
8958  need_refinement = 0;
8959  // onoe = NumOfElements;
8960  // for (i = 0; i < onoe; i++)
8961  for (i = 0; i < NumOfElements; i++)
8962  {
8963  // ((Tetrahedron *)elements[i])->
8964  // ParseRefinementFlag(redges, type, flag);
8965  // if (flag > max_gen) max_gen = flag;
8966  if (elements[i]->NeedRefinement(v_to_v))
8967  {
8968  need_refinement = 1;
8969  Bisection(i, v_to_v);
8970  }
8971  }
8972  }
8973  while (need_refinement == 1);
8974 
8975  // mfem::out << "Maximum generation: " << max_gen << endl;
8976 
8977  // 4. Update the boundary elements.
8978  do
8979  {
8980  need_refinement = 0;
8981  for (i = 0; i < NumOfBdrElements; i++)
8982  if (boundary[i]->NeedRefinement(v_to_v))
8983  {
8984  need_refinement = 1;
8985  BdrBisection(i, v_to_v);
8986  }
8987  }
8988  while (need_refinement == 1);
8989 
8990  NumOfVertices = vertices.Size();
8991  NumOfBdrElements = boundary.Size();
8992 
8993  // 5. Update element-to-edge and element-to-face relations.
8994  if (el_to_edge != NULL)
8995  {
8997  }
8998  if (el_to_face != NULL)
8999  {
9001  GenerateFaces();
9002  }
9003 
9004  } // end 'if (Dim == 3)'
9005 
9007  sequence++;
9008 
9009  UpdateNodes();
9010 
9011 #ifdef MFEM_DEBUG
9012  CheckElementOrientation(false);
9013 #endif
9014 }
9015 
9017  int nc_limit)
9018 {
9019  MFEM_VERIFY(!NURBSext, "Nonconforming refinement of NURBS meshes is "
9020  "not supported. Project the NURBS to Nodes first.");
9021 
9022  ResetLazyData();
9023 
9024  if (!ncmesh)
9025  {
9026  // start tracking refinement hierarchy
9027  ncmesh = new NCMesh(this);
9028  }
9029 
9030  if (!refinements.Size())
9031  {
9033  return;
9034  }
9035 
9036  // do the refinements
9038  ncmesh->Refine(refinements);
9039 
9040  if (nc_limit > 0)
9041  {
9042  ncmesh->LimitNCLevel(nc_limit);
9043  }
9044 
9045  // create a second mesh containing the finest elements from 'ncmesh'
9046  Mesh* mesh2 = new Mesh(*ncmesh);
9047  ncmesh->OnMeshUpdated(mesh2);
9048 
9049  // now swap the meshes, the second mesh will become the old coarse mesh
9050  // and this mesh will be the new fine mesh
9051  Swap(*mesh2, false);
9052  delete mesh2;
9053 
9055 
9057  sequence++;
9058 
9059  if (Nodes) // update/interpolate curved mesh
9060  {
9061  Nodes->FESpace()->Update();
9062  Nodes->Update();
9063  }
9064 }
9065 
9066 double Mesh::AggregateError(const Array<double> &elem_error,
9067  const int *fine, int nfine, int op)
9068 {
9069  double error = 0.0;
9070  for (int i = 0; i < nfine; i++)
9071  {
9072  MFEM_VERIFY(fine[i] < elem_error.Size(), "");
9073 
9074  double err_fine = elem_error[fine[i]];
9075  switch (op)
9076  {
9077  case 0: error = std::min(error, err_fine); break;
9078  case 1: error += err_fine; break;
9079  case 2: error = std::max(error, err_fine); break;
9080  }
9081  }
9082  return error;
9083 }
9084 
9086  double threshold, int nc_limit, int op)
9087 {
9088  MFEM_VERIFY(ncmesh, "Only supported for non-conforming meshes.");
9089  MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. "
9090  "Project the NURBS to Nodes first.");
9091 
9092  ResetLazyData();
9093 
9094  const Table &dt = ncmesh->GetDerefinementTable();
9095 
9096  Array<int> level_ok;
9097  if (nc_limit > 0)
9098  {
9099  ncmesh->CheckDerefinementNCLevel(dt, level_ok, nc_limit);
9100  }
9101 
9102  Array<int> derefs;
9103  for (int i = 0; i < dt.Size(); i++)
9104  {
9105  if (nc_limit > 0 && !level_ok[i]) { continue; }
9106 
9107  double error =
9108  AggregateError(elem_error, dt.GetRow(i), dt.RowSize(i), op);
9109 
9110  if (error < threshold) { derefs.Append(i); }
9111  }
9112 
9113  if (!derefs.Size()) { return false; }
9114 
9115  ncmesh->Derefine(derefs);
9116 
9117  Mesh* mesh2 = new Mesh(*ncmesh);
9118  ncmesh->OnMeshUpdated(mesh2);
9119 
9120  Swap(*mesh2, false);
9121  delete mesh2;
9122 
9124 
9126  sequence++;
9127 
9128  UpdateNodes();
9129 
9130  return true;
9131 }
9132 
9133 bool Mesh::DerefineByError(Array<double> &elem_error, double threshold,
9134  int nc_limit, int op)
9135 {
9136  // NOTE: the error array is not const because it will be expanded in parallel
9137  // by ghost element errors
9138  if (Nonconforming())
9139  {
9140  return NonconformingDerefinement(elem_error, threshold, nc_limit, op);
9141  }
9142  else
9143  {
9144  MFEM_ABORT("Derefinement is currently supported for non-conforming "
9145  "meshes only.");
9146  return false;
9147  }
9148 }
9149 
9150 bool Mesh::DerefineByError(const Vector &elem_error, double threshold,
9151  int nc_limit, int op)
9152 {
9153  Array<double> tmp(elem_error.Size());
9154  for (int i = 0; i < tmp.Size(); i++)
9155  {
9156  tmp[i] = elem_error(i);
9157  }
9158  return DerefineByError(tmp, threshold, nc_limit, op);
9159 }
9160 
9161 
9162 void Mesh::InitFromNCMesh(const NCMesh &ncmesh_)
9163 {
9164  Dim = ncmesh_.Dimension();
9165  spaceDim = ncmesh_.SpaceDimension();
9166 
9167  DeleteTables();
9168 
9169  ncmesh_.GetMeshComponents(*this);
9170 
9171  NumOfVertices = vertices.Size();
9172  NumOfElements = elements.Size();
9173  NumOfBdrElements = boundary.Size();
9174 
9175  SetMeshGen(); // set the mesh type: 'meshgen', ...
9176 
9177  NumOfEdges = NumOfFaces = 0;
9179 
9180  if (Dim > 1)
9181  {
9182  el_to_edge = new Table;
9184  }
9185  if (Dim > 2)
9186  {
9188  }
9189  GenerateFaces();
9190 #ifdef MFEM_DEBUG
9192 #endif
9193 
9194  // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
9195  // outside after this method.
9196 }
9197 
9198 Mesh::Mesh(const NCMesh &ncmesh_)
9199 {
9200  Init();
9201  InitTables();
9202  InitFromNCMesh(ncmesh_);
9203  SetAttributes();
9204 }
9205 
9206 void Mesh::Swap(Mesh& other, bool non_geometry)
9207 {
9208  mfem::Swap(Dim, other.Dim);
9209  mfem::Swap(spaceDim, other.spaceDim);
9210 
9216 
9217  mfem::Swap(meshgen, other.meshgen);
9219 
9220  mfem::Swap(elements, other.elements);
9221  mfem::Swap(vertices, other.vertices);
9222  mfem::Swap(boundary, other.boundary);
9223  mfem::Swap(faces, other.faces);
9226 
9229  mfem::Swap(el_to_el, other.el_to_el);
9233  mfem::Swap(face_edge, other.face_edge);
9235 
9238 
9240 
9241 #ifdef MFEM_USE_MEMALLOC
9242  TetMemory.Swap(other.TetMemory);
9243 #endif
9244 
9245  if (non_geometry)
9246  {
9247  mfem::Swap(NURBSext, other.NURBSext);
9248  mfem::Swap(ncmesh, other.ncmesh);
9249 
9250  mfem::Swap(Nodes, other.Nodes);
9251  if (Nodes) { Nodes->FESpace()->UpdateMeshPointer(this); }
9252  if (other.Nodes) { other.Nodes->FESpace()->UpdateMeshPointer(&other); }
9253  mfem::Swap(own_nodes, other.own_nodes);
9254 
9256 
9257  mfem::Swap(sequence, other.sequence);
9259  }
9260 }
9261 
9262 void Mesh::GetElementData(const Array<Element*> &elem_array, int geom,
9263  Array<int> &elem_vtx, Array<int> &attr) const
9264 {
9265  // protected method
9266  const int nv = Geometry::NumVerts[geom];
9267  int num_elems = 0;
9268  for (int i = 0; i < elem_array.Size(); i++)
9269  {
9270  if (elem_array[i]->GetGeometryType() == geom)
9271  {
9272  num_elems++;
9273  }
9274  }
9275  elem_vtx.SetSize(nv*num_elems);
9276  attr.SetSize(num_elems);
9277  elem_vtx.SetSize(0);
9278  attr.SetSize(0);
9279  for (int i = 0; i < elem_array.Size(); i++)
9280  {
9281  Element *el = elem_array[i];
9282  if (el->GetGeometryType() != geom) { continue; }
9283 
9284  Array<int> loc_vtx(el->GetVertices(), nv);
9285  elem_vtx.Append(loc_vtx);
9286  attr.Append(el->GetAttribute());
9287  }
9288 }
9289 
9290 static Array<int>& AllElements(Array<int> &list, int nelem)
9291 {
9292  list.SetSize(nelem);
9293  for (int i = 0; i < nelem; i++) { list[i] = i; }
9294  return list;
9295 }
9296 
9297 void Mesh::UniformRefinement(int ref_algo)
9298 {
9299  Array<int> list;
9300 
9301  if (NURBSext)
9302  {
9304  }
9305  else if (ncmesh)
9306  {
9307  GeneralRefinement(AllElements(list, GetNE()));
9308  }
9309  else if (ref_algo == 1 && meshgen == 1 && Dim == 3)
9310  {
9311  // algorithm "B" for an all-tet mesh
9312  LocalRefinement(AllElements(list, GetNE()));
9313  }
9314  else
9315  {
9316  switch (Dim)
9317  {
9318  case 1: LocalRefinement(AllElements(list, GetNE())); break;
9319  case 2: UniformRefinement2D(); break;
9320  case 3: UniformRefinement3D(); break;
9321  default: MFEM_ABORT("internal error");
9322  }
9323  }
9324 }
9325 
9327  int nonconforming, int nc_limit)
9328 {
9329  if (ncmesh)
9330  {
9331  nonconforming = 1;
9332  }
9333  else if (Dim == 1 || (Dim == 3 && (meshgen & 1)))
9334  {
9335  nonconforming = 0;
9336  }
9337  else if (nonconforming < 0)
9338  {
9339  // determine if nonconforming refinement is suitable
9340  if ((meshgen & 2) || (meshgen & 4) || (meshgen & 8))
9341  {
9342  nonconforming = 1; // tensor product elements and wedges
9343  }
9344  else
9345  {
9346  nonconforming = 0; // simplices
9347  }
9348  }
9349 
9350  if (nonconforming)
9351  {
9352  // non-conforming refinement (hanging nodes)
9353  NonconformingRefinement(refinements, nc_limit);
9354  }
9355  else
9356  {
9357  Array<int> el_to_refine(refinements.Size());
9358  for (int i = 0; i < refinements.Size(); i++)
9359  {
9360  el_to_refine[i] = refinements[i].index;
9361  }
9362 
9363  // infer 'type' of local refinement from first element's 'ref_type'
9364  int type, rt = (refinements.Size() ? refinements[0].ref_type : 7);
9365  if (rt == 1 || rt == 2 || rt == 4)
9366  {
9367  type = 1; // bisection
9368  }
9369  else if (rt == 3 || rt == 5 || rt == 6)
9370  {
9371  type = 2; // quadrisection
9372  }
9373  else
9374  {
9375  type = 3; // octasection
9376  }
9377 
9378  // red-green refinement and bisection, no hanging nodes
9379  LocalRefinement(el_to_refine, type);
9380  }
9381 }
9382 
9383 void Mesh::GeneralRefinement(const Array<int> &el_to_refine, int nonconforming,
9384  int nc_limit)
9385 {
9386  Array<Refinement> refinements(el_to_refine.Size());
9387  for (int i = 0; i < el_to_refine.Size(); i++)
9388  {
9389  refinements[i] = Refinement(el_to_refine[i]);
9390  }
9391  GeneralRefinement(refinements, nonconforming, nc_limit);
9392 }
9393 
9394 void Mesh::EnsureNCMesh(bool simplices_nonconforming)
9395 {
9396  MFEM_VERIFY(!NURBSext, "Cannot convert a NURBS mesh to an NC mesh. "
9397  "Please project the NURBS to Nodes first, with SetCurvature().");
9398 
9399 #ifdef MFEM_USE_MPI
9400  MFEM_VERIFY(ncmesh != NULL || dynamic_cast<const ParMesh*>(this) == NULL,
9401  "Sorry, converting a conforming ParMesh to an NC mesh is "
9402  "not possible.");
9403 #endif
9404 
9405  if (!ncmesh)
9406  {
9407  if ((meshgen & 0x2) /* quads/hexes */ ||
9408  (meshgen & 0x4) /* wedges */ ||
9409  (simplices_nonconforming && (meshgen & 0x1)) /* simplices */)
9410  {
9411  ncmesh = new NCMesh(this);
9412  ncmesh->OnMeshUpdated(this);
9414  }
9415  }
9416 }
9417 
9418 void Mesh::RandomRefinement(double prob, bool aniso, int nonconforming,
9419  int nc_limit)
9420 {
9421  Array<Refinement> refs;
9422  for (int i = 0; i < GetNE(); i++)
9423  {
9424  if ((double) rand() / RAND_MAX < prob)
9425  {
9426  int type = 7;
9427  if (aniso)
9428  {
9429  type = (Dim == 3) ? (rand() % 7 + 1) : (rand() % 3 + 1);
9430  }
9431  refs.Append(Refinement(i, type));
9432  }
9433  }
9434  GeneralRefinement(refs, nonconforming, nc_limit);
9435 }
9436 
9437 void Mesh::RefineAtVertex(const Vertex& vert, double eps, int nonconforming)
9438 {
9439  Array<int> v;
9440  Array<Refinement> refs;
9441  for (int i = 0; i < GetNE(); i++)
9442  {
9443  GetElementVertices(i, v);
9444  bool refine = false;
9445  for (int j = 0; j < v.Size(); j++)
9446  {
9447  double dist = 0.0;
9448  for (int l = 0; l < spaceDim; l++)
9449  {
9450  double d = vert(l) - vertices[v[j]](l);
9451  dist += d*d;
9452  }
9453  if (dist <= eps*eps) { refine = true; break; }
9454  }
9455  if (refine)
9456  {
9457  refs.Append(Refinement(i));
9458  }
9459  }
9460  GeneralRefinement(refs, nonconforming);
9461 }
9462 
9463 bool Mesh::RefineByError(const Array<double> &elem_error, double threshold,
9464  int nonconforming, int nc_limit)
9465 {
9466  MFEM_VERIFY(elem_error.Size() == GetNE(), "");
9467  Array<Refinement> refs;
9468  for (int i = 0; i < GetNE(); i++)
9469  {
9470  if (elem_error[i] > threshold)
9471  {
9472  refs.Append(Refinement(i));
9473  }
9474  }
9475  if (ReduceInt(refs.Size()))
9476  {
9477  GeneralRefinement(refs, nonconforming, nc_limit);
9478  return true;
9479  }
9480  return false;
9481 }
9482 
9483 bool Mesh::RefineByError(const Vector &elem_error, double threshold,
9484  int nonconforming, int nc_limit)
9485 {
9486  Array<double> tmp(const_cast<double*>(elem_error.GetData()),
9487  elem_error.Size());
9488  return RefineByError(tmp, threshold, nonconforming, nc_limit);
9489 }
9490 
9491 
9492 void Mesh::Bisection(int i, const DSTable &v_to_v,
9493  int *edge1, int *edge2, int *middle)
9494 {
9495  int *vert;
9496  int v[2][4], v_new, bisect, t;
9497  Element *el = elements[i];
9498  Vertex V;
9499 
9500  t = el->GetType();
9501  if (t == Element::TRIANGLE)
9502  {
9503  Triangle *tri = (Triangle *) el;
9504 
9505  vert = tri->GetVertices();
9506 
9507  // 1. Get the index for the new vertex in v_new.
9508  bisect = v_to_v(vert[0], vert[1]);
9509  MFEM_ASSERT(bisect >= 0, "");
9510 
9511  if (middle[bisect] == -1)
9512  {
9513  v_new = NumOfVertices++;
9514  for (int d = 0; d < spaceDim; d++)
9515  {
9516  V(d) = 0.5 * (vertices[vert[0]](d) + vertices[vert[1]](d));
9517  }
9518  vertices.Append(V);
9519 
9520  // Put the element that may need refinement (because of this
9521  // bisection) in edge1, or -1 if no more refinement is needed.
9522  if (edge1[bisect] == i)
9523  {
9524  edge1[bisect] = edge2[bisect];
9525  }
9526 
9527  middle[bisect] = v_new;
9528  }
9529  else
9530  {
9531  v_new = middle[bisect];
9532 
9533  // This edge will require no more refinement.
9534  edge1[bisect] = -1;
9535  }
9536 
9537  // 2. Set the node indices for the new elements in v[0] and v[1] so that
9538  // the edge marked for refinement is between the first two nodes.
9539  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
9540  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
9541 
9542  tri->SetVertices(v[0]); // changes vert[0..2] !!!
9543 
9544  Triangle* tri_new = new Triangle(v[1], tri->GetAttribute());
9545  elements.Append(tri_new);
9546 
9547  int tr = tri->GetTransform();
9548  tri_new->ResetTransform(tr);
9549 
9550  // record the sequence of refinements
9551  tri->PushTransform(4);
9552  tri_new->PushTransform(5);
9553 
9554  int coarse = FindCoarseElement(i);
9555  CoarseFineTr.embeddings[i].parent = coarse;
9557 
9558  // 3. edge1 and edge2 may have to be changed for the second triangle.
9559  if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
9560  {
9561  bisect = v_to_v(v[1][0], v[1][1]);
9562  MFEM_ASSERT(bisect >= 0, "");
9563 
9564  if (edge1[bisect] == i)
9565  {
9566  edge1[bisect] = NumOfElements;
9567  }
9568  else if (edge2[bisect] == i)
9569  {
9570  edge2[bisect] = NumOfElements;
9571  }
9572  }
9573  NumOfElements++;
9574  }
9575  else
9576  {
9577  MFEM_ABORT("Bisection for now works only for triangles.");
9578  }
9579 }
9580 
9582 {
9583  int *vert;
9584  int v[2][4], v_new, bisect, t;
9585  Element *el = elements[i];
9586  Vertex V;
9587 
9588  t = el->GetType();
9589  if (t == Element::TETRAHEDRON)
9590  {
9591  int j, type, new_type, old_redges[2], new_redges[2][2], flag;
9592  Tetrahedron *tet = (Tetrahedron *) el;
9593 
9594  MFEM_VERIFY(tet->GetRefinementFlag() != 0,
9595  "TETRAHEDRON element is not marked for refinement.");
9596 
9597  vert = tet->GetVertices();
9598 
9599  // 1. Get the index for the new vertex in v_new.
9600  bisect = v_to_v.FindId(vert[0], vert[1]);
9601  if (bisect == -1)
9602  {
9603  v_new = NumOfVertices + v_to_v.GetId(vert[0],vert[1]);
9604  for (j = 0; j < 3; j++)
9605  {
9606  V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j));
9607  }
9608  vertices.Append(V);
9609  }
9610  else
9611  {
9612  v_new = NumOfVertices + bisect;
9613  }
9614 
9615  // 2. Set the node indices for the new elements in v[2][4] so that
9616  // the edge marked for refinement is between the first two nodes.
9617  tet->ParseRefinementFlag(old_redges, type, flag);
9618 
9619  v[0][3] = v_new;
9620  v[1][3] = v_new;
9621  new_redges[0][0] = 2;
9622  new_redges[0][1] = 1;
9623  new_redges[1][0] = 2;
9624  new_redges[1][1] = 1;
9625  int tr1 = -1, tr2 = -1;
9626  switch (old_redges[0])
9627  {
9628  case 2:
9629  v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3];
9630  if (type == Tetrahedron::TYPE_PF) { new_redges[0][1] = 4; }
9631  tr1 = 0;
9632  break;
9633  case 3:
9634  v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2];
9635  tr1 = 2;
9636  break;
9637  case 5:
9638  v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0];
9639  tr1 = 4;
9640  }
9641  switch (old_redges[1])
9642  {
9643  case 1:
9644  v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3];
9645  if (type == Tetrahedron::TYPE_PF) { new_redges[1][0] = 3; }
9646  tr2 = 1;
9647  break;
9648  case 4:
9649  v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2];
9650  tr2 = 3;
9651  break;
9652  case 5:
9653  v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1];
9654  tr2 = 5;
9655  }
9656 
9657  int attr = tet->GetAttribute();
9658  tet->SetVertices(v[0]);
9659 
9660 #ifdef MFEM_USE_MEMALLOC
9661  Tetrahedron *tet2 = TetMemory.Alloc();
9662  tet2->SetVertices(v[1]);
9663  tet2->SetAttribute(attr);
9664 #else
9665  Tetrahedron *tet2 = new Tetrahedron(v[1], attr);
9666 #endif
9667  tet2->ResetTransform(tet->GetTransform());
9668  elements.Append(tet2);
9669 
9670  // record the sequence of refinements
9671  tet->PushTransform(tr1);
9672  tet2->PushTransform(tr2);
9673 
9674  int coarse = FindCoarseElement(i);
9675  CoarseFineTr.embeddings[i].parent = coarse;
9677 
9678  // 3. Set the bisection flag
9679  switch (type)
9680  {
9681  case Tetrahedron::TYPE_PU:
9682  new_type = Tetrahedron::TYPE_PF; break;
9683  case Tetrahedron::TYPE_PF:
9684  new_type = Tetrahedron::TYPE_A; break;
9685  default:
9686  new_type = Tetrahedron::TYPE_PU;
9687  }
9688 
9689  tet->CreateRefinementFlag(new_redges[0], new_type, flag+1);
9690  tet2->CreateRefinementFlag(new_redges[1], new_type, flag+1);
9691 
9692  NumOfElements++;
9693  }
9694  else
9695  {
9696  MFEM_ABORT("Bisection with HashTable for now works only for tetrahedra.");
9697  }
9698 }
9699 
9700 void Mesh::BdrBisection(int i, const HashTable<Hashed2> &v_to_v)
9701 {
9702  int *vert;
9703  int v[2][3], v_new, bisect, t;
9704  Element *bdr_el = boundary[i];
9705 
9706  t = bdr_el->GetType();
9707  if (t == Element::TRIANGLE)
9708  {
9709  Triangle *tri = (Triangle *) bdr_el;
9710 
9711  vert = tri->GetVertices();
9712 
9713  // 1. Get the index for the new vertex in v_new.
9714  bisect = v_to_v.FindId(vert[0], vert[1]);
9715  MFEM_ASSERT(bisect >= 0, "");
9716  v_new = NumOfVertices + bisect;
9717  MFEM_ASSERT(v_new != -1, "");
9718 
9719  // 2. Set the node indices for the new elements in v[0] and v[1] so that
9720  // the edge marked for refinement is between the first two nodes.
9721  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
9722  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
9723 
9724  tri->SetVertices(v[0]);
9725 
9726  boundary.Append(new Triangle(v[1], tri->GetAttribute()));
9727 
9728  NumOfBdrElements++;
9729  }
9730  else
9731  {
9732  MFEM_ABORT("Bisection of boundary elements with HashTable works only for"
9733  " triangles!");
9734  }
9735 }
9736 
9737 void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
9738  int *edge1, int *edge2, int *middle)
9739 {
9740  Array<int> v;
9741  int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3];
9742  Vertex V;
9743 
9744  if (elements[i]->GetType() == Element::TRIANGLE)
9745  {
9746  Triangle *tri0 = (Triangle*) elements[i];
9747  tri0->GetVertices(v);
9748 
9749  // 1. Get the indeces for the new vertices in array v_new
9750  bisect[0] = v_to_v(v[0],v[1]);
9751  bisect[1] = v_to_v(v[1],v[2]);
9752  bisect[2] = v_to_v(v[0],v[2]);
9753  MFEM_ASSERT(bisect[0] >= 0 && bisect[1] >= 0 && bisect[2] >= 0, "");
9754 
9755  for (j = 0; j < 3; j++) // for the 3 edges fix v_new
9756  {
9757  if (middle[bisect[j]] == -1)
9758  {
9759  v_new[j] = NumOfVertices++;
9760  for (int d = 0; d < spaceDim; d++)
9761  {
9762  V(d) = (vertices[v[j]](d) + vertices[v[(j+1)%3]](d))/2.;
9763  }
9764  vertices.Append(V);
9765 
9766  // Put the element that may need refinement (because of this
9767  // bisection) in edge1, or -1 if no more refinement is needed.
9768  if (edge1[bisect[j]] == i)
9769  {
9770  edge1[bisect[j]] = edge2[bisect[j]];
9771  }
9772 
9773  middle[bisect[j]] = v_new[j];
9774  }
9775  else
9776  {
9777  v_new[j] = middle[bisect[j]];
9778 
9779  // This edge will require no more refinement.
9780  edge1[bisect[j]] = -1;
9781  }
9782  }
9783 
9784  // 2. Set the node indeces for the new elements in v1, v2, v3 & v4 so that
9785  // the edges marked for refinement be between the first two nodes.
9786  v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2];
9787  v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1];
9788  v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2];
9789  v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0];
9790 
9791  Triangle* tri1 = new Triangle(v1, tri0->GetAttribute());
9792  Triangle* tri2 = new Triangle(v2, tri0->GetAttribute());
9793  Triangle* tri3 = new Triangle(v3, tri0->GetAttribute());
9794 
9795  elements.Append(tri1);
9796  elements.Append(tri2);
9797  elements.Append(tri3);
9798 
9799  tri0->SetVertices(v4);
9800 
9801  // record the sequence of refinements
9802  unsigned code = tri0->GetTransform();
9803  tri1->ResetTransform(code);
9804  tri2->ResetTransform(code);
9805  tri3->ResetTransform(code);
9806 
9807  tri0->PushTransform(3);
9808  tri1->PushTransform(0);
9809  tri2->PushTransform(1);
9810  tri3->PushTransform(2);
9811 
9812  // set parent indices
9813  int coarse = FindCoarseElement(i);
9818 
9819  NumOfElements += 3;
9820  }
9821  else
9822  {
9823  MFEM_ABORT("Uniform refinement for now works only for triangles.");
9824  }
9825 }
9826 
9828 {
9829  // initialize CoarseFineTr
9830  CoarseFineTr.Clear();
9832  for (int i = 0; i < NumOfElements; i++)
9833  {
9834  elements[i]->ResetTransform(0);
9836  }
9837 }
9838 
9840 {
9841  int coarse;
9842  while ((coarse = CoarseFineTr.embeddings[i].parent) != i)
9843  {
9844  i = coarse;
9845  }
9846  return coarse;
9847 }
9848 
9850 {
9851  MFEM_VERIFY(GetLastOperation() == Mesh::REFINE, "");
9852 
9853  if (ncmesh)
9854  {
9855  return ncmesh->GetRefinementTransforms();
9856  }
9857 
9858  Mesh::GeometryList elem_geoms(*this);
9859  for (int i = 0; i < elem_geoms.Size(); i++)
9860  {
9861  const Geometry::Type geom = elem_geoms[i];
9862  if (CoarseFineTr.point_matrices[geom].SizeK()) { continue; }
9863 
9864  if (geom == Geometry::TRIANGLE ||
9865  geom == Geometry::TETRAHEDRON)
9866  {
9867  std::map<unsigned, int> mat_no;
9868  mat_no[0] = 1; // identity
9869 
9870  // assign matrix indices to element transformations
9871  for (int j = 0; j < elements.Size(); j++)
9872  {
9873  int index = 0;
9874  unsigned code = elements[j]->GetTransform();
9875  if (code)
9876  {
9877  int &matrix = mat_no[code];
9878  if (!matrix) { matrix = mat_no.size(); }
9879  index = matrix-1;
9880  }
9881  CoarseFineTr.embeddings[j].matrix = index;
9882  }
9883 
9884  DenseTensor &pmats = CoarseFineTr.point_matrices[geom];
9885  pmats.SetSize(Dim, Dim+1, mat_no.size());
9886 
9887  // calculate the point matrices used
9888  std::map<unsigned, int>::iterator it;
9889  for (it = mat_no.begin(); it != mat_no.end(); ++it)
9890  {
9891  if (geom == Geometry::TRIANGLE)
9892  {
9893  Triangle::GetPointMatrix(it->first, pmats(it->second-1));
9894  }
9895  else
9896  {
9897  Tetrahedron::GetPointMatrix(it->first, pmats(it->second-1));
9898  }
9899  }
9900  }
9901  else
9902  {
9903  MFEM_ABORT("Don't know how to construct CoarseFineTransformations for"
9904  " geom = " << geom);
9905  }
9906  }
9907 
9908  // NOTE: quads and hexes already have trivial transformations ready
9909  return CoarseFineTr;
9910 }
9911 
9912 void Mesh::PrintXG(std::ostream &os) const
9913 {
9914  MFEM_ASSERT(Dim==spaceDim, "2D Manifold meshes not supported");
9915  int i, j;
9916  Array<int> v;
9917 
9918  if (Dim == 2)
9919  {
9920  // Print the type of the mesh.
9921  if (Nodes == NULL)
9922  {
9923  os << "areamesh2\n\n";
9924  }
9925  else
9926  {
9927  os << "curved_areamesh2\n\n";
9928  }
9929 
9930  // Print the boundary elements.
9931  os << NumOfBdrElements << '\n';
9932  for (i = 0; i < NumOfBdrElements; i++)
9933  {
9934  boundary[i]->GetVertices(v);
9935 
9936  os << boundary[i]->GetAttribute();
9937  for (j = 0; j < v.Size(); j++)
9938  {
9939  os << ' ' << v[j] + 1;
9940  }
9941  os << '\n';
9942  }
9943 
9944  // Print the elements.
9945  os << NumOfElements << '\n';
9946  for (i = 0; i < NumOfElements; i++)
9947  {
9948  elements[i]->GetVertices(v);
9949 
9950  os << elements[i]->GetAttribute() << ' ' << v.Size();
9951  for (j = 0; j < v.Size(); j++)
9952  {
9953  os << ' ' << v[j] + 1;
9954  }
9955  os << '\n';
9956  }
9957 
9958  if (Nodes == NULL)
9959  {
9960  // Print the vertices.
9961  os << NumOfVertices << '\n';
9962  for (i = 0; i < NumOfVertices; i++)
9963  {
9964  os << vertices[i](0);
9965  for (j = 1; j < Dim; j++)
9966  {
9967  os << ' ' << vertices[i](j);
9968  }
9969  os << '\n';
9970  }
9971  }
9972  else
9973  {
9974  os << NumOfVertices << '\n';
9975  Nodes->Save(os);
9976  }
9977  }
9978  else // ===== Dim != 2 =====
9979  {
9980  if (Nodes)
9981  {
9982  mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D");
9983  }
9984 
9985  if (meshgen == 1)
9986  {
9987  int nv;
9988  const int *ind;
9989 
9990  os << "NETGEN_Neutral_Format\n";
9991  // print the vertices
9992  os << NumOfVertices << '\n';
9993  for (i = 0; i < NumOfVertices; i++)
9994  {
9995  for (j = 0; j < Dim; j++)
9996  {
9997  os << ' ' << vertices[i](j);
9998  }
9999  os << '\n';
10000  }
10001 
10002  // print the elements
10003  os << NumOfElements << '\n';
10004  for (i = 0; i < NumOfElements; i++)
10005  {
10006  nv = elements[i]->GetNVertices();
10007  ind = elements[i]->GetVertices();
10008  os << elements[i]->GetAttribute();
10009  for (j = 0; j < nv; j++)
10010  {
10011  os << ' ' << ind[j]+1;
10012  }
10013  os << '\n';
10014  }
10015 
10016  // print the boundary information.
10017  os << NumOfBdrElements << '\n';
10018  for (i = 0; i < NumOfBdrElements; i++)
10019  {
10020  nv = boundary[i]->GetNVertices();
10021  ind = boundary[i]->GetVertices();
10022  os << boundary[i]->GetAttribute();
10023  for (j = 0; j < nv; j++)
10024  {
10025  os << ' ' << ind[j]+1;
10026  }
10027  os << '\n';
10028  }
10029  }
10030  else if (meshgen == 2) // TrueGrid
10031  {
10032  int nv;
10033  const int *ind;
10034 
10035  os << "TrueGrid\n"
10036  << "1 " << NumOfVertices << " " << NumOfElements
10037  << " 0 0 0 0 0 0 0\n"
10038  << "0 0 0 1 0 0 0 0 0 0 0\n"
10039  << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
10040  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
10041  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
10042 
10043  for (i = 0; i < NumOfVertices; i++)
10044  os << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1)
10045  << ' ' << vertices[i](2) << " 0.0\n";
10046 
10047  for (i = 0; i < NumOfElements; i++)
10048  {
10049  nv = elements[i]->GetNVertices();
10050  ind = elements[i]->GetVertices();
10051  os << i+1 << ' ' << elements[i]->GetAttribute();
10052  for (j = 0; j < nv; j++)
10053  {
10054  os << ' ' << ind[j]+1;
10055  }
10056  os << '\n';
10057  }
10058 
10059  for (i = 0; i < NumOfBdrElements; i++)
10060  {
10061  nv = boundary[i]->GetNVertices();
10062  ind = boundary[i]->GetVertices();
10063  os << boundary[i]->GetAttribute();
10064  for (j = 0; j < nv; j++)
10065  {
10066  os << ' ' << ind[j]+1;
10067  }
10068  os << " 1.0 1.0 1.0 1.0\n";
10069  }
10070  }
10071  }
10072 
10073  os << flush;
10074 }
10075 
10076 void Mesh::Printer(std::ostream &os, std::string section_delimiter) const
10077 {
10078  int i, j;
10079 
10080  if (NURBSext)
10081  {
10082  // general format
10083  NURBSext->Print(os);
10084  os << '\n';
10085  Nodes->Save(os);
10086 
10087  // patch-wise format
10088  // NURBSext->ConvertToPatches(*Nodes);
10089  // NURBSext->Print(os);
10090 
10091  return;
10092  }
10093 
10094  if (Nonconforming())
10095  {
10096  // nonconforming mesh format
10097  ncmesh->Print(os);
10098 
10099  if (Nodes)
10100  {
10101  os << "\n# mesh curvature GridFunction";
10102  os << "\nnodes\n";
10103  Nodes->Save(os);
10104  }
10105 
10106  os << "\nmfem_mesh_end" << endl;
10107  return;
10108  }
10109 
10110  // serial/parallel conforming mesh format
10111  os << (section_delimiter.empty()
10112  ? "MFEM mesh v1.0\n" : "MFEM mesh v1.2\n");
10113 
10114  // optional
10115  os <<
10116  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10117  "# POINT = 0\n"
10118  "# SEGMENT = 1\n"
10119  "# TRIANGLE = 2\n"
10120  "# SQUARE = 3\n"
10121  "# TETRAHEDRON = 4\n"
10122  "# CUBE = 5\n"
10123  "# PRISM = 6\n"
10124  "# PYRAMID = 7\n"
10125  "#\n";
10126 
10127  os << "\ndimension\n" << Dim;
10128 
10129  os << "\n\nelements\n" << NumOfElements << '\n';
10130  for (i = 0; i < NumOfElements; i++)
10131  {
10132  PrintElement(elements[i], os);
10133  }
10134 
10135  os << "\nboundary\n" << NumOfBdrElements << '\n';
10136  for (i = 0; i < NumOfBdrElements; i++)
10137  {
10138  PrintElement(boundary[i], os);
10139  }
10140 
10141  os << "\nvertices\n" << NumOfVertices << '\n';
10142  if (Nodes == NULL)
10143  {
10144  os << spaceDim << '\n';
10145  for (i = 0; i < NumOfVertices; i++)
10146  {
10147  os << vertices[i](0);
10148  for (j = 1; j < spaceDim; j++)
10149  {
10150  os << ' ' << vertices[i](j);
10151  }
10152  os << '\n';
10153  }
10154  os.flush();
10155  }
10156  else
10157  {
10158  os << "\nnodes\n";
10159  Nodes->Save(os);
10160  }
10161 
10162  if (!section_delimiter.empty())
10163  {
10164  os << section_delimiter << endl; // only with format v1.2
10165  }
10166 }
10167 
10168 void Mesh::PrintTopo(std::ostream &os,const Array<int> &e_to_k) const
10169 {
10170  int i;
10171  Array<int> vert;
10172 
10173  os << "MFEM NURBS mesh v1.0\n";
10174 
10175  // optional
10176  os <<
10177  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10178  "# SEGMENT = 1\n"
10179  "# SQUARE = 3\n"
10180  "# CUBE = 5\n"
10181  "#\n";
10182 
10183  os << "\ndimension\n" << Dim
10184  << "\n\nelements\n" << NumOfElements << '\n';
10185  for (i = 0; i < NumOfElements; i++)
10186  {
10187  PrintElement(elements[i], os);
10188  }
10189 
10190  os << "\nboundary\n" << NumOfBdrElements << '\n';
10191  for (i = 0; i < NumOfBdrElements; i++)
10192  {
10193  PrintElement(boundary[i], os);
10194  }
10195 
10196  os << "\nedges\n" << NumOfEdges << '\n';
10197  for (i = 0; i < NumOfEdges; i++)
10198  {
10199  edge_vertex->GetRow(i, vert);
10200  int ki = e_to_k[i];
10201  if (ki < 0)
10202  {
10203  ki = -1 - ki;
10204  }
10205  os << ki << ' ' << vert[0] << ' ' << vert[1] << '\n';
10206  }
10207  os << "\nvertices\n" << NumOfVertices << '\n';
10208 }
10209 
10210 void Mesh::Save(const char *fname, int precision) const
10211 {
10212  ofstream ofs(fname);
10213  ofs.precision(precision);
10214  Print(ofs);
10215 }
10216 
10217 #ifdef MFEM_USE_ADIOS2
10218 void Mesh::Print(adios2stream &os) const
10219 {
10220  os.Print(*this);
10221 }
10222 #endif
10223 
10224 void Mesh::PrintVTK(std::ostream &os)
10225 {
10226  os <<
10227  "# vtk DataFile Version 3.0\n"
10228  "Generated by MFEM\n"
10229  "ASCII\n"
10230  "DATASET UNSTRUCTURED_GRID\n";
10231 
10232  if (Nodes == NULL)
10233  {
10234  os << "POINTS " << NumOfVertices << " double\n";
10235  for (int i = 0; i < NumOfVertices; i++)
10236  {
10237  os << vertices[i](0);
10238  int j;
10239  for (j = 1; j < spaceDim; j++)
10240  {
10241  os << ' ' << vertices[i](j);
10242  }
10243  for ( ; j < 3; j++)
10244  {
10245  os << ' ' << 0.0;
10246  }
10247  os << '\n';
10248  }
10249  }
10250  else
10251  {
10252  Array<int> vdofs(3);
10253  os << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n";
10254  for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++)
10255  {
10256  vdofs.SetSize(1);
10257  vdofs[0] = i;
10258  Nodes->FESpace()->DofsToVDofs(vdofs);
10259  os << (*Nodes)(vdofs[0]);
10260  int j;
10261  for (j = 1; j < spaceDim; j++)
10262  {
10263  os << ' ' << (*Nodes)(vdofs[j]);
10264  }
10265  for ( ; j < 3; j++)
10266  {
10267  os << ' ' << 0.0;
10268  }
10269  os << '\n';
10270  }
10271  }
10272 
10273  int order = -1;
10274  if (Nodes == NULL)
10275  {
10276  int size = 0;
10277  for (int i = 0; i < NumOfElements; i++)
10278  {
10279  size += elements[i]->GetNVertices() + 1;
10280  }
10281  os << "CELLS " << NumOfElements << ' ' << size << '\n';
10282  for (int i = 0; i < NumOfElements; i++)
10283  {
10284  const int *v = elements[i]->GetVertices();
10285  const int nv = elements[i]->GetNVertices();
10286  os << nv;
10287  Geometry::Type geom = elements[i]->GetGeometryType();
10288  const int *perm = VTKGeometry::VertexPermutation[geom];
10289  for (int j = 0; j < nv; j++)
10290  {
10291  os << ' ' << v[perm ? perm[j] : j];
10292  }
10293  os << '\n';
10294  }
10295  order = 1;
10296  }
10297  else
10298  {
10299  Array<int> dofs;
10300  int size = 0;
10301  for (int i = 0; i < NumOfElements; i++)
10302  {
10303  Nodes->FESpace()->GetElementDofs(i, dofs);
10304  MFEM_ASSERT(Dim != 0 || dofs.Size() == 1,
10305  "Point meshes should have a single dof per element");
10306  size += dofs.Size() + 1;
10307  }
10308  os << "CELLS " << NumOfElements << ' ' << size << '\n';
10309  const char *fec_name = Nodes->FESpace()->FEColl()->Name();
10310 
10311  if (!strcmp(fec_name, "Linear") ||
10312  !strcmp(fec_name, "H1_0D_P1") ||
10313  !strcmp(fec_name, "H1_1D_P1") ||
10314  !strcmp(fec_name, "H1_2D_P1") ||
10315  !strcmp(fec_name, "H1_3D_P1"))
10316  {
10317  order = 1;
10318  }
10319  else if (!strcmp(fec_name, "Quadratic") ||
10320  !strcmp(fec_name, "H1_1D_P2") ||
10321  !strcmp(fec_name, "H1_2D_P2") ||
10322  !strcmp(fec_name, "H1_3D_P2"))
10323  {
10324  order = 2;
10325  }
10326  if (order == -1)
10327  {
10328  mfem::err << "Mesh::PrintVTK : can not save '"
10329  << fec_name << "' elements!" << endl;
10330  mfem_error();
10331  }
10332  for (int i = 0; i < NumOfElements; i++)
10333  {
10334  Nodes->FESpace()->GetElementDofs(i, dofs);
10335  os << dofs.Size();
10336  if (order == 1)
10337  {
10338  for (int j = 0; j < dofs.Size(); j++)
10339  {
10340  os << ' ' << dofs[j];
10341  }
10342  }
10343  else if (order == 2)
10344  {
10345  const int *vtk_mfem;
10346  switch (elements[i]->GetGeometryType())
10347  {
10348  case Geometry::SEGMENT:
10349  case Geometry::TRIANGLE:
10350  case Geometry::SQUARE:
10351  vtk_mfem = vtk_quadratic_hex; break; // identity map
10352  case Geometry::TETRAHEDRON:
10353  vtk_mfem = vtk_quadratic_tet; break;
10354  case Geometry::PRISM:
10355  vtk_mfem = vtk_quadratic_wedge; break;
10356  case Geometry::CUBE:
10357  default:
10358  vtk_mfem = vtk_quadratic_hex; break;
10359  }
10360  for (int j = 0; j < dofs.Size(); j++)
10361  {
10362  os << ' ' << dofs[vtk_mfem[j]];
10363  }
10364  }
10365  os << '\n';
10366  }
10367  }
10368 
10369  os << "CELL_TYPES " << NumOfElements << '\n';
10370  for (int i = 0; i < NumOfElements; i++)
10371  {
10372  int vtk_cell_type = 5;
10374  if (order == 1) { vtk_cell_type = VTKGeometry::Map[geom]; }
10375  else if (order == 2) { vtk_cell_type = VTKGeometry::QuadraticMap[geom]; }
10376  os << vtk_cell_type << '\n';
10377  }
10378 
10379  // write attributes
10380  os << "CELL_DATA " << NumOfElements << '\n'
10381  << "SCALARS material int\n"
10382  << "LOOKUP_TABLE default\n";
10383  for (int i = 0; i < NumOfElements; i++)
10384  {
10385  os << elements[i]->GetAttribute() << '\n';
10386  }
10387  os.flush();
10388 }
10389 
10390 void Mesh::PrintVTU(std::string fname,
10391  VTKFormat format,
10392  bool high_order_output,
10393  int compression_level,
10394  bool bdr)
10395 {
10396  int ref = (high_order_output && Nodes)
10397  ? Nodes->FESpace()->GetElementOrder(0) : 1;
10398 
10399  fname = fname + ".vtu";
10400  std::fstream os(fname.c_str(),std::ios::out);
10401  os << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"";
10402  if (compression_level != 0)
10403  {
10404  os << " compressor=\"vtkZLibDataCompressor\"";
10405  }
10406  os << " byte_order=\"" << VTKByteOrder() << "\">\n";
10407  os << "<UnstructuredGrid>\n";
10408  PrintVTU(os, ref, format, high_order_output, compression_level, bdr);
10409  os << "</Piece>\n"; // need to close the piece open in the PrintVTU method
10410  os << "</UnstructuredGrid>\n";
10411  os << "</VTKFile>" << std::endl;
10412 
10413  os.close();
10414 }
10415 
10416 void Mesh::PrintBdrVTU(std::string fname,
10417  VTKFormat format,
10418  bool high_order_output,
10419  int compression_level)
10420 {
10421  PrintVTU(fname, format, high_order_output, compression_level, true);
10422 }
10423 
10424 void Mesh::PrintVTU(std::ostream &os, int ref, VTKFormat format,
10425  bool high_order_output, int compression_level,
10426  bool bdr_elements)
10427 {
10428  RefinedGeometry *RefG;
10429  DenseMatrix pmat;
10430 
10431  const char *fmt_str = (format == VTKFormat::ASCII) ? "ascii" : "binary";
10432  const char *type_str = (format != VTKFormat::BINARY32) ? "Float64" : "Float32";
10433  std::vector<char> buf;
10434 
10435  auto get_geom = [&](int i)
10436  {
10437  if (bdr_elements) { return GetBdrElementBaseGeometry(i); }
10438  else { return GetElementBaseGeometry(i); }
10439  };
10440 
10441  int ne = bdr_elements ? GetNBE() : GetNE();
10442  // count the points, cells, size
10443  int np = 0, nc_ref = 0, size = 0;
10444  for (int i = 0; i < ne; i++)
10445  {
10446  Geometry::Type geom = get_geom(i);
10447  int nv = Geometries.GetVertices(geom)->GetNPoints();
10448  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10449  np += RefG->RefPts.GetNPoints();
10450  nc_ref += RefG->RefGeoms.Size() / nv;
10451  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
10452  }
10453 
10454  os << "<Piece NumberOfPoints=\"" << np << "\" NumberOfCells=\""
10455  << (high_order_output ? ne : nc_ref) << "\">\n";
10456 
10457  // print out the points
10458  os << "<Points>\n";
10459  os << "<DataArray type=\"" << type_str
10460  << "\" NumberOfComponents=\"3\" format=\"" << fmt_str << "\">\n";
10461  for (int i = 0; i < ne; i++)
10462  {
10463  RefG = GlobGeometryRefiner.Refine(get_geom(i), ref, 1);
10464 
10465  if (bdr_elements)
10466  {
10467  GetBdrElementTransformation(i)->Transform(RefG->RefPts, pmat);
10468  }
10469  else
10470  {
10471  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
10472  }
10473 
10474  for (int j = 0; j < pmat.Width(); j++)
10475  {
10476  WriteBinaryOrASCII(os, buf, pmat(0,j), " ", format);
10477  if (pmat.Height() > 1)
10478  {
10479  WriteBinaryOrASCII(os, buf, pmat(1,j), " ", format);
10480  }
10481  else
10482  {
10483  WriteBinaryOrASCII(os, buf, 0.0, " ", format);
10484  }
10485  if (pmat.Height() > 2)
10486  {
10487  WriteBinaryOrASCII(os, buf, pmat(2,j), "", format);
10488  }
10489  else
10490  {
10491  WriteBinaryOrASCII(os, buf, 0.0, "", format);
10492  }
10493  if (format == VTKFormat::ASCII) { os << '\n'; }
10494  }
10495  }
10496  if (format != VTKFormat::ASCII)
10497  {
10498  WriteBase64WithSizeAndClear(os, buf, compression_level);
10499  }
10500  os << "</DataArray>" << std::endl;
10501  os << "</Points>" << std::endl;
10502 
10503  os << "<Cells>" << std::endl;
10504  os << "<DataArray type=\"Int32\" Name=\"connectivity\" format=\""
10505  << fmt_str << "\">" << std::endl;
10506  // connectivity
10507  std::vector<int> offset;
10508 
10509  np = 0;
10510  if (high_order_output)
10511  {
10512  Array<int> local_connectivity;
10513  for (int iel = 0; iel < ne; iel++)
10514  {
10515  Geometry::Type geom = get_geom(iel);
10516  CreateVTKElementConnectivity(local_connectivity, geom, ref);
10517  int nnodes = local_connectivity.Size();
10518  for (int i=0; i<nnodes; ++i)
10519  {
10520  WriteBinaryOrASCII(os, buf, np+local_connectivity[i], " ",
10521  format);
10522  }
10523  if (format == VTKFormat::ASCII) { os << '\n'; }
10524  np += nnodes;
10525  offset.push_back(np);
10526  }
10527  }
10528  else
10529  {
10530  int coff = 0;
10531  for (int i = 0; i < ne; i++)
10532  {
10533  Geometry::Type geom = get_geom(i);
10534  int nv = Geometries.GetVertices(geom)->GetNPoints();
10535  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10536  Array<int> &RG = RefG->RefGeoms;
10537  for (int j = 0; j < RG.Size(); )
10538  {
10539  coff = coff+nv;
10540  offset.push_back(coff);
10541  const int *p = VTKGeometry::VertexPermutation[geom];
10542  for (int k = 0; k < nv; k++, j++)
10543  {
10544  WriteBinaryOrASCII(os, buf, np + RG[p ? p[j] : j], " ",
10545  format);
10546  }
10547  if (format == VTKFormat::ASCII) { os << '\n'; }
10548  }
10549  np += RefG->RefPts.GetNPoints();
10550  }
10551  }
10552  if (format != VTKFormat::ASCII)
10553  {
10554  WriteBase64WithSizeAndClear(os, buf, compression_level);
10555  }
10556  os << "</DataArray>" << std::endl;
10557 
10558  os << "<DataArray type=\"Int32\" Name=\"offsets\" format=\""
10559  << fmt_str << "\">" << std::endl;
10560  // offsets
10561  for (size_t ii=0; ii<offset.size(); ii++)
10562  {
10563  WriteBinaryOrASCII(os, buf, offset[ii], "\n", format);
10564  }
10565  if (format != VTKFormat::ASCII)
10566  {
10567  WriteBase64WithSizeAndClear(os, buf, compression_level);
10568  }
10569  os << "</DataArray>" << std::endl;
10570  os << "<DataArray type=\"UInt8\" Name=\"types\" format=\""
10571  << fmt_str << "\">" << std::endl;
10572  // cell types
10573  const int *vtk_geom_map =
10574  high_order_output ? VTKGeometry::HighOrderMap : VTKGeometry::Map;
10575  for (int i = 0; i < ne; i++)
10576  {
10577  Geometry::Type geom = get_geom(i);
10578  uint8_t vtk_cell_type = 5;
10579 
10580  vtk_cell_type = vtk_geom_map[geom];
10581 
10582  if (high_order_output)
10583  {
10584  WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
10585  }
10586  else
10587  {
10588  int nv = Geometries.GetVertices(geom)->GetNPoints();
10589  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10590  Array<int> &RG = RefG->RefGeoms;
10591  for (int j = 0; j < RG.Size(); j += nv)
10592  {
10593  WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
10594  }
10595  }
10596  }
10597  if (format != VTKFormat::ASCII)
10598  {
10599  WriteBase64WithSizeAndClear(os, buf, compression_level);
10600  }
10601  os << "</DataArray>" << std::endl;
10602  os << "</Cells>" << std::endl;
10603 
10604  os << "<CellData Scalars=\"attribute\">" << std::endl;
10605  os << "<DataArray type=\"Int32\" Name=\"attribute\" format=\""
10606  << fmt_str << "\">" << std::endl;
10607  for (int i = 0; i < ne; i++)
10608  {
10609  int attr = bdr_elements ? GetBdrAttribute(i) : GetAttribute(i);
10610  if (high_order_output)
10611  {
10612  WriteBinaryOrASCII(os, buf, attr, "\n", format);
10613  }
10614  else
10615  {
10616  Geometry::Type geom = get_geom(i);
10617  int nv = Geometries.GetVertices(geom)->GetNPoints();
10618  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10619  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10620  {
10621  WriteBinaryOrASCII(os, buf, attr, "\n", format);
10622  }
10623  }
10624  }
10625  if (format != VTKFormat::ASCII)
10626  {
10627  WriteBase64WithSizeAndClear(os, buf, compression_level);
10628  }
10629  os << "</DataArray>" << std::endl;
10630  os << "</CellData>" << std::endl;
10631 }
10632 
10633 
10634 void Mesh::PrintVTK(std::ostream &os, int ref, int field_data)
10635 {
10636  int np, nc, size;
10637  RefinedGeometry *RefG;
10638  DenseMatrix pmat;
10639 
10640  os <<
10641  "# vtk DataFile Version 3.0\n"
10642  "Generated by MFEM\n"
10643  "ASCII\n"
10644  "DATASET UNSTRUCTURED_GRID\n";
10645 
10646  // additional dataset information
10647  if (field_data)
10648  {
10649  os << "FIELD FieldData 1\n"
10650  << "MaterialIds " << 1 << " " << attributes.Size() << " int\n";
10651  for (int i = 0; i < attributes.Size(); i++)
10652  {
10653  os << ' ' << attributes[i];
10654  }
10655  os << '\n';
10656  }
10657 
10658  // count the points, cells, size
10659  np = nc = size = 0;
10660  for (int i = 0; i < GetNE(); i++)
10661  {
10663  int nv = Geometries.GetVertices(geom)->GetNPoints();
10664  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10665  np += RefG->RefPts.GetNPoints();
10666  nc += RefG->RefGeoms.Size() / nv;
10667  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
10668  }
10669  os << "POINTS " << np << " double\n";
10670  // write the points
10671  for (int i = 0; i < GetNE(); i++)
10672  {
10673  RefG = GlobGeometryRefiner.Refine(
10674  GetElementBaseGeometry(i), ref, 1);
10675 
10676  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
10677 
10678  for (int j = 0; j < pmat.Width(); j++)
10679  {
10680  os << pmat(0, j) << ' ';
10681  if (pmat.Height() > 1)
10682  {
10683  os << pmat(1, j) << ' ';
10684  if (pmat.Height() > 2)
10685  {
10686  os << pmat(2, j);
10687  }
10688  else
10689  {
10690  os << 0.0;
10691  }
10692  }
10693  else
10694  {
10695  os << 0.0 << ' ' << 0.0;
10696  }
10697  os << '\n';
10698  }
10699  }
10700 
10701  // write the cells
10702  os << "CELLS " << nc << ' ' << size << '\n';
10703  np = 0;
10704  for (int i = 0; i < GetNE(); i++)
10705  {
10707  int nv = Geometries.GetVertices(geom)->GetNPoints();
10708  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10709  Array<int> &RG = RefG->RefGeoms;
10710 
10711  for (int j = 0; j < RG.Size(); )
10712  {
10713  os << nv;
10714  for (int k = 0; k < nv; k++, j++)
10715  {
10716  os << ' ' << np + RG[j];
10717  }
10718  os << '\n';
10719  }
10720  np += RefG->RefPts.GetNPoints();
10721  }
10722  os << "CELL_TYPES " << nc << '\n';
10723  for (int i = 0; i < GetNE(); i++)
10724  {
10726  int nv = Geometries.GetVertices(geom)->GetNPoints();
10727  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10728  Array<int> &RG = RefG->RefGeoms;
10729  int vtk_cell_type = VTKGeometry::Map[geom];
10730 
10731  for (int j = 0; j < RG.Size(); j += nv)
10732  {
10733  os << vtk_cell_type << '\n';
10734  }
10735  }
10736  // write attributes (materials)
10737  os << "CELL_DATA " << nc << '\n'
10738  << "SCALARS material int\n"
10739  << "LOOKUP_TABLE default\n";
10740  for (int i = 0; i < GetNE(); i++)
10741  {
10743  int nv = Geometries.GetVertices(geom)->GetNPoints();
10744  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10745  int attr = GetAttribute(i);
10746  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10747  {
10748  os << attr << '\n';
10749  }
10750  }
10751 
10752  if (Dim > 1)
10753  {
10754  Array<int> coloring;
10755  srand((unsigned)time(0));
10756  double a = double(rand()) / (double(RAND_MAX) + 1.);
10757  int el0 = (int)floor(a * GetNE());
10758  GetElementColoring(coloring, el0);
10759  os << "SCALARS element_coloring int\n"
10760  << "LOOKUP_TABLE default\n";
10761  for (int i = 0; i < GetNE(); i++)
10762  {
10764  int nv = Geometries.GetVertices(geom)->GetNPoints();
10765  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10766  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10767  {
10768  os << coloring[i] + 1 << '\n';
10769  }
10770  }
10771  }
10772 
10773  // prepare to write data
10774  os << "POINT_DATA " << np << '\n' << flush;
10775 }
10776 
10777 void Mesh::GetElementColoring(Array<int> &colors, int el0)
10778 {
10779  int delete_el_to_el = (el_to_el) ? (0) : (1);
10780  const Table &el_el = ElementToElementTable();
10781  int num_el = GetNE(), stack_p, stack_top_p, max_num_col;
10782  Array<int> el_stack(num_el);
10783 
10784  const int *i_el_el = el_el.GetI();
10785  const int *j_el_el = el_el.GetJ();
10786 
10787  colors.SetSize(num_el);
10788  colors = -2;
10789  max_num_col = 1;
10790  stack_p = stack_top_p = 0;
10791  for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el)
10792  {
10793  if (colors[el] != -2)
10794  {
10795  continue;
10796  }
10797 
10798  colors[el] = -1;
10799  el_stack[stack_top_p++] = el;
10800 
10801  for ( ; stack_p < stack_top_p; stack_p++)
10802  {
10803  int i = el_stack[stack_p];
10804  int num_nb = i_el_el[i+1] - i_el_el[i];
10805  if (max_num_col < num_nb + 1)
10806  {
10807  max_num_col = num_nb + 1;
10808  }
10809  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
10810  {
10811  int k = j_el_el[j];
10812  if (colors[k] == -2)
10813  {
10814  colors[k] = -1;
10815  el_stack[stack_top_p++] = k;
10816  }
10817  }
10818  }
10819  }
10820 
10821  Array<int> col_marker(max_num_col);
10822 
10823  for (stack_p = 0; stack_p < stack_top_p; stack_p++)
10824  {
10825  int i = el_stack[stack_p], col;
10826  col_marker = 0;
10827  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
10828  {
10829  col = colors[j_el_el[j]];
10830  if (col != -1)
10831  {
10832  col_marker[col] = 1;
10833  }
10834  }
10835 
10836  for (col = 0; col < max_num_col; col++)
10837  if (col_marker[col] == 0)
10838  {
10839  break;
10840  }
10841 
10842  colors[i] = col;
10843  }
10844 
10845  if (delete_el_to_el)
10846  {
10847  delete el_to_el;
10848  el_to_el = NULL;
10849  }
10850 }
10851 
10852 void Mesh::PrintWithPartitioning(int *partitioning, std::ostream &os,
10853  int elem_attr) const
10854 {
10855  if (Dim != 3 && Dim != 2) { return; }
10856 
10857  int i, j, k, l, nv, nbe, *v;
10858 
10859  os << "MFEM mesh v1.0\n";
10860 
10861  // optional
10862  os <<
10863  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10864  "# POINT = 0\n"
10865  "# SEGMENT = 1\n"
10866  "# TRIANGLE = 2\n"
10867  "# SQUARE = 3\n"
10868  "# TETRAHEDRON = 4\n"
10869  "# CUBE = 5\n"
10870  "# PRISM = 6\n"
10871  "#\n";
10872 
10873  os << "\ndimension\n" << Dim
10874  << "\n\nelements\n" << NumOfElements << '\n';
10875  for (i = 0; i < NumOfElements; i++)
10876  {
10877  os << int((elem_attr) ? partitioning[i]+1 : elements[i]->GetAttribute())
10878  << ' ' << elements[i]->GetGeometryType();
10879  nv = elements[i]->GetNVertices();
10880  v = elements[i]->GetVertices();
10881  for (j = 0; j < nv; j++)
10882  {
10883  os << ' ' << v[j];
10884  }
10885  os << '\n';
10886  }
10887  nbe = 0;
10888  for (i = 0; i < faces_info.Size(); i++)
10889  {
10890  if ((l = faces_info[i].Elem2No) >= 0)
10891  {
10892  k = partitioning[faces_info[i].Elem1No];
10893  l = partitioning[l];
10894  if (k != l)
10895  {
10896  nbe++;
10897  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
10898  {
10899  nbe++;
10900  }
10901  }
10902  }
10903  else
10904  {
10905  nbe++;
10906  }
10907  }
10908  os << "\nboundary\n" << nbe << '\n';
10909  for (i = 0; i < faces_info.Size(); i++)
10910  {
10911  if ((l = faces_info[i].Elem2No) >= 0)
10912  {
10913  k = partitioning[faces_info[i].Elem1No];
10914  l = partitioning[l];
10915  if (k != l)
10916  {
10917  nv = faces[i]->GetNVertices();
10918  v = faces[i]->GetVertices();
10919  os << k+1 << ' ' << faces[i]->GetGeometryType();
10920  for (j = 0; j < nv; j++)
10921  {
10922  os << ' ' << v[j];
10923  }
10924  os << '\n';
10925  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
10926  {
10927  os << l+1 << ' ' << faces[i]->GetGeometryType();
10928  for (j = nv-1; j >= 0; j--)
10929  {
10930  os << ' ' << v[j];
10931  }
10932  os << '\n';
10933  }
10934  }
10935  }
10936  else
10937  {
10938  k = partitioning[faces_info[i].Elem1No];
10939  nv = faces[i]->GetNVertices();
10940  v = faces[i]->GetVertices();
10941  os << k+1 << ' ' << faces[i]->GetGeometryType();
10942  for (j = 0; j < nv; j++)
10943  {
10944  os << ' ' << v[j];
10945  }
10946  os << '\n';
10947  }
10948  }
10949  os << "\nvertices\n" << NumOfVertices << '\n';
10950  if (Nodes == NULL)
10951  {
10952  os << spaceDim << '\n';
10953  for (i = 0; i < NumOfVertices; i++)
10954  {
10955  os << vertices[i](0);
10956  for (j = 1; j < spaceDim; j++)
10957  {
10958  os << ' ' << vertices[i](j);
10959  }
10960  os << '\n';
10961  }
10962  os.flush();
10963  }
10964  else
10965  {
10966  os << "\nnodes\n";
10967  Nodes->Save(os);
10968  }
10969 }
10970 
10972  std::ostream &os,
10973  int interior_faces)
10974 {
10975  MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported\n");
10976  if (Dim != 3 && Dim != 2) { return; }
10977 
10978  int *vcount = new int[NumOfVertices];
10979  for (int i = 0; i < NumOfVertices; i++)
10980  {
10981  vcount[i] = 0;
10982  }
10983  for (int i = 0; i < NumOfElements; i++)
10984  {
10985  int nv = elements[i]->GetNVertices();
10986  const int *ind = elements[i]->GetVertices();
10987  for (int j = 0; j < nv; j++)
10988  {
10989  vcount[ind[j]]++;
10990  }
10991  }
10992 
10993  int *voff = new int[NumOfVertices+1];
10994  voff[0] = 0;
10995  for (int i = 1; i <= NumOfVertices; i++)
10996  {
10997  voff[i] = vcount[i-1] + voff[i-1];
10998  }
10999 
11000  int **vown = new int*[NumOfVertices];
11001  for (int i = 0; i < NumOfVertices; i++)
11002  {
11003  vown[i] = new int[vcount[i]];
11004  }
11005 
11006  // 2D
11007  if (Dim == 2)
11008  {
11009  Table edge_el;
11010  Transpose(ElementToEdgeTable(), edge_el);
11011 
11012  // Fake printing of the elements.
11013  for (int i = 0; i < NumOfElements; i++)
11014  {
11015  int nv = elements[i]->GetNVertices();
11016  const int *ind = elements[i]->GetVertices();
11017  for (int j = 0; j < nv; j++)
11018  {
11019  vcount[ind[j]]--;
11020  vown[ind[j]][vcount[ind[j]]] = i;
11021  }
11022  }
11023 
11024  for (int i = 0; i < NumOfVertices; i++)
11025  {
11026  vcount[i] = voff[i+1] - voff[i];
11027  }
11028 
11029  int nbe = 0;
11030  for (int i = 0; i < edge_el.Size(); i++)
11031  {
11032  const int *el = edge_el.GetRow(i);
11033  if (edge_el.RowSize(i) > 1)
11034  {
11035  int k = partitioning[el[0]];
11036  int l = partitioning[el[1]];
11037  if (interior_faces || k != l)
11038  {
11039  nbe += 2;
11040  }
11041  }
11042  else
11043  {
11044  nbe++;
11045  }
11046  }
11047 
11048  // Print the type of the mesh and the boundary elements.
11049  os << "areamesh2\n\n" << nbe << '\n';
11050 
11051  for (int i = 0; i < edge_el.Size(); i++)
11052  {
11053  const int *el = edge_el.GetRow(i);
11054  if (edge_el.RowSize(i) > 1)
11055  {
11056  int k = partitioning[el[0]];
11057  int l = partitioning[el[1]];
11058  if (interior_faces || k != l)
11059  {
11060  Array<int> ev;
11061  GetEdgeVertices(i,ev);
11062  os << k+1; // attribute
11063  for (int j = 0; j < 2; j++)
11064  for (int s = 0; s < vcount[ev[j]]; s++)
11065  if (vown[ev[j]][s] == el[0])
11066  {
11067  os << ' ' << voff[ev[j]]+s+1;
11068  }
11069  os << '\n';
11070  os << l+1; // attribute
11071  for (int j = 1; j >= 0; j--)
11072  for (int s = 0; s < vcount[ev[j]]; s++)
11073  if (vown[ev[j]][s] == el[1])
11074  {
11075  os << ' ' << voff[ev[j]]+s+1;
11076  }
11077  os << '\n';
11078  }
11079  }
11080  else
11081  {
11082  int k = partitioning[el[0]];
11083  Array<int> ev;
11084  GetEdgeVertices(i,ev);
11085  os << k+1; // attribute
11086  for (int j = 0; j < 2; j++)
11087  for (int s = 0; s < vcount[ev[j]]; s++)
11088  if (vown[ev[j]][s] == el[0])
11089  {
11090  os << ' ' << voff[ev[j]]+s+1;
11091  }
11092  os << '\n';
11093  }
11094  }
11095 
11096  // Print the elements.
11097  os << NumOfElements << '\n';
11098  for (int i = 0; i < NumOfElements; i++)
11099  {
11100  int nv = elements[i]->GetNVertices();
11101  const int *ind = elements[i]->GetVertices();
11102  os << partitioning[i]+1 << ' '; // use subdomain number as attribute
11103  os << nv << ' ';
11104  for (int j = 0; j < nv; j++)
11105  {
11106  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11107  vown[ind[j]][vcount[ind[j]]] = i;
11108  }
11109  os << '\n';
11110  }
11111 
11112  for (int i = 0; i < NumOfVertices; i++)
11113  {
11114  vcount[i] = voff[i+1] - voff[i];
11115  }
11116 
11117  // Print the vertices.
11118  os << voff[NumOfVertices] << '\n';
11119  for (int i = 0; i < NumOfVertices; i++)
11120  for (int k = 0; k < vcount[i]; k++)
11121  {
11122  for (int j = 0; j < Dim; j++)
11123  {
11124  os << vertices[i](j) << ' ';
11125  }
11126  os << '\n';
11127  }
11128  }
11129  // Dim is 3
11130  else if (meshgen == 1)
11131  {
11132  os << "NETGEN_Neutral_Format\n";
11133  // print the vertices
11134  os << voff[NumOfVertices] << '\n';
11135  for (int i = 0; i < NumOfVertices; i++)
11136  for (int k = 0; k < vcount[i]; k++)
11137  {
11138  for (int j = 0; j < Dim; j++)
11139  {
11140  os << ' ' << vertices[i](j);
11141  }
11142  os << '\n';
11143  }
11144 
11145  // print the elements
11146  os << NumOfElements << '\n';
11147  for (int i = 0; i < NumOfElements; i++)
11148  {
11149  int nv = elements[i]->GetNVertices();
11150  const int *ind = elements[i]->GetVertices();
11151  os << partitioning[i]+1; // use subdomain number as attribute
11152  for (int j = 0; j < nv; j++)
11153  {
11154  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11155  vown[ind[j]][vcount[ind[j]]] = i;
11156  }
11157  os << '\n';
11158  }
11159 
11160  for (int i = 0; i < NumOfVertices; i++)
11161  {
11162  vcount[i] = voff[i+1] - voff[i];
11163  }
11164 
11165  // print the boundary information.
11166  int nbe = 0;
11167  for (int i = 0; i < NumOfFaces; i++)
11168  {
11169  int l = faces_info[i].Elem2No;
11170  if (l >= 0)
11171  {
11172  int k = partitioning[faces_info[i].Elem1No];
11173  l = partitioning[l];
11174  if (interior_faces || k != l)
11175  {
11176  nbe += 2;
11177  }
11178  }
11179  else
11180  {
11181  nbe++;
11182  }
11183  }
11184 
11185  os << nbe << '\n';
11186  for (int i = 0; i < NumOfFaces; i++)
11187  {
11188  int l = faces_info[i].Elem2No;
11189  if (l >= 0)
11190  {
11191  int k = partitioning[faces_info[i].Elem1No];
11192  l = partitioning[l];
11193  if (interior_faces || k != l)
11194  {
11195  int nv = faces[i]->GetNVertices();
11196  const int *ind = faces[i]->GetVertices();
11197  os << k+1; // attribute
11198  for (int j = 0; j < nv; j++)
11199  for (int s = 0; s < vcount[ind[j]]; s++)
11200  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11201  {
11202  os << ' ' << voff[ind[j]]+s+1;
11203  }
11204  os << '\n';
11205  os << l+1; // attribute
11206  for (int j = nv-1; j >= 0; j--)
11207  for (int s = 0; s < vcount[ind[j]]; s++)
11208  if (vown[ind[j]][s] == faces_info[i].Elem2No)
11209  {
11210  os << ' ' << voff[ind[j]]+s+1;
11211  }
11212  os << '\n';
11213  }
11214  }
11215  else
11216  {
11217  int k = partitioning[faces_info[i].Elem1No];
11218  int nv = faces[i]->GetNVertices();
11219  const int *ind = faces[i]->GetVertices();
11220  os << k+1; // attribute
11221  for (int j = 0; j < nv; j++)
11222  for (int s = 0; s < vcount[ind[j]]; s++)
11223  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11224  {
11225  os << ' ' << voff[ind[j]]+s+1;
11226  }
11227  os << '\n';
11228  }
11229  }
11230  }
11231  // Dim is 3
11232  else if (meshgen == 2) // TrueGrid
11233  {
11234  // count the number of the boundary elements.
11235  int nbe = 0;
11236  for (int i = 0; i < NumOfFaces; i++)
11237  {
11238  int l = faces_info[i].Elem2No;
11239  if (l >= 0)
11240  {
11241  int k = partitioning[faces_info[i].Elem1No];
11242  l = partitioning[l];
11243  if (interior_faces || k != l)
11244  {
11245  nbe += 2;
11246  }
11247  }
11248  else
11249  {
11250  nbe++;
11251  }
11252  }
11253 
11254  os << "TrueGrid\n"
11255  << "1 " << voff[NumOfVertices] << " " << NumOfElements
11256  << " 0 0 0 0 0 0 0\n"
11257  << "0 0 0 1 0 0 0 0 0 0 0\n"
11258  << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
11259  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
11260  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
11261 
11262  for (int i = 0; i < NumOfVertices; i++)
11263  for (int k = 0; k < vcount[i]; k++)
11264  os << voff[i]+k << " 0.0 " << vertices[i](0) << ' '
11265  << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n";
11266 
11267  for (int i = 0; i < NumOfElements; i++)
11268  {
11269  int nv = elements[i]->GetNVertices();
11270  const int *ind = elements[i]->GetVertices();
11271  os << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute
11272  for (int j = 0; j < nv; j++)
11273  {
11274  os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
11275  vown[ind[j]][vcount[ind[j]]] = i;
11276  }
11277  os << '\n';
11278  }
11279 
11280  for (int i = 0; i < NumOfVertices; i++)
11281  {
11282  vcount[i] = voff[i+1] - voff[i];
11283  }
11284 
11285  // boundary elements
11286  for (int i = 0; i < NumOfFaces; i++)
11287  {
11288  int l = faces_info[i].Elem2No;
11289  if (l >= 0)
11290  {
11291  int k = partitioning[faces_info[i].Elem1No];
11292  l = partitioning[l];
11293  if (interior_faces || k != l)
11294  {
11295  int nv = faces[i]->GetNVertices();
11296  const int *ind = faces[i]->GetVertices();
11297  os << k+1; // attribute
11298  for (int j = 0; j < nv; j++)
11299  for (int s = 0; s < vcount[ind[j]]; s++)
11300  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11301  {
11302  os << ' ' << voff[ind[j]]+s+1;
11303  }
11304  os << " 1.0 1.0 1.0 1.0\n";
11305  os << l+1; // attribute
11306  for (int j = nv-1; j >= 0; j--)
11307  for (int s = 0; s < vcount[ind[j]]; s++)
11308  if (vown[ind[j]][s] == faces_info[i].Elem2No)
11309  {
11310  os << ' ' << voff[ind[j]]+s+1;
11311  }
11312  os << " 1.0 1.0 1.0 1.0\n";
11313  }
11314  }
11315  else
11316  {
11317  int k = partitioning[faces_info[i].Elem1No];
11318  int nv = faces[i]->GetNVertices();
11319  const int *ind = faces[i]->GetVertices();
11320  os << k+1; // attribute
11321  for (int j = 0; j < nv; j++)
11322  for (int s = 0; s < vcount[ind[j]]; s++)
11323  if (vown[ind[j]][s] == faces_info[i].Elem1No)
11324  {
11325  os << ' ' << voff[ind[j]]+s+1;
11326  }
11327  os << " 1.0 1.0 1.0 1.0\n";
11328  }
11329  }
11330  }
11331 
11332  os << flush;
11333 
11334  for (int i = 0; i < NumOfVertices; i++)
11335  {
11336  delete [] vown[i];
11337  }
11338 
11339  delete [] vcount;
11340  delete [] voff;
11341  delete [] vown;
11342 }
11343 
11344 void Mesh::PrintSurfaces(const Table & Aface_face, std::ostream &os) const
11345 {
11346  int i, j;
11347 
11348  if (NURBSext)
11349  {
11350  mfem_error("Mesh::PrintSurfaces"
11351  " NURBS mesh is not supported!");
11352  return;
11353  }
11354 
11355  os << "MFEM mesh v1.0\n";
11356 
11357  // optional
11358  os <<
11359  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
11360  "# POINT = 0\n"
11361  "# SEGMENT = 1\n"
11362  "# TRIANGLE = 2\n"
11363  "# SQUARE = 3\n"
11364  "# TETRAHEDRON = 4\n"
11365  "# CUBE = 5\n"
11366  "# PRISM = 6\n"
11367  "#\n";
11368 
11369  os << "\ndimension\n" << Dim
11370  << "\n\nelements\n" << NumOfElements << '\n';
11371  for (i = 0; i < NumOfElements; i++)
11372  {
11373  PrintElement(elements[i], os);
11374  }
11375 
11376  os << "\nboundary\n" << Aface_face.Size_of_connections() << '\n';
11377  const int * const i_AF_f = Aface_face.GetI();
11378  const int * const j_AF_f = Aface_face.GetJ();
11379 
11380  for (int iAF=0; iAF < Aface_face.Size(); ++iAF)
11381  for (const int * iface = j_AF_f + i_AF_f[iAF];
11382  iface < j_AF_f + i_AF_f[iAF+1];
11383  ++iface)
11384  {
11385  os << iAF+1 << ' ';
11386  PrintElementWithoutAttr(faces[*iface],os);
11387  }
11388 
11389  os << "\nvertices\n" << NumOfVertices << '\n';
11390  if (Nodes == NULL)
11391  {
11392  os << spaceDim << '\n';
11393  for (i = 0; i < NumOfVertices; i++)
11394  {
11395  os << vertices[i](0);
11396  for (j = 1; j < spaceDim; j++)
11397  {
11398  os << ' ' << vertices[i](j);
11399  }
11400  os << '\n';
11401  }
11402  os.flush();
11403  }
11404  else
11405  {
11406  os << "\nnodes\n";
11407  Nodes->Save(os);
11408  }
11409 }
11410 
11411 void Mesh::ScaleSubdomains(double sf)
11412 {
11413  int i,j,k;
11414  Array<int> vert;
11415  DenseMatrix pointmat;
11416  int na = attributes.Size();
11417  double *cg = new double[na*spaceDim];
11418  int *nbea = new int[na];
11419 
11420  int *vn = new int[NumOfVertices];
11421  for (i = 0; i < NumOfVertices; i++)
11422  {
11423  vn[i] = 0;
11424  }
11425  for (i = 0; i < na; i++)
11426  {
11427  for (j = 0; j < spaceDim; j++)
11428  {
11429  cg[i*spaceDim+j] = 0.0;
11430  }
11431  nbea[i] = 0;
11432  }
11433 
11434  for (i = 0; i < NumOfElements; i++)
11435  {
11436  GetElementVertices(i, vert);
11437  for (k = 0; k < vert.Size(); k++)
11438  {
11439  vn[vert[k]] = 1;
11440  }
11441  }
11442 
11443  for (i = 0; i < NumOfElements; i++)
11444  {
11445  int bea = GetAttribute(i)-1;
11446  GetPointMatrix(i, pointmat);
11447  GetElementVertices(i, vert);
11448 
11449  for (k = 0; k < vert.Size(); k++)
11450  if (vn[vert[k]] == 1)
11451  {
11452  nbea[bea]++;
11453  for (j = 0; j < spaceDim; j++)
11454  {
11455  cg[bea*spaceDim+j] += pointmat(j,k);
11456  }
11457  vn[vert[k]] = 2;
11458  }
11459  }
11460 
11461  for (i = 0; i < NumOfElements; i++)
11462  {
11463  int bea = GetAttribute(i)-1;
11464  GetElementVertices (i, vert);
11465 
11466  for (k = 0; k < vert.Size(); k++)
11467  if (vn[vert[k]])
11468  {
11469  for (j = 0; j < spaceDim; j++)
11470  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
11471  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
11472  vn[vert[k]] = 0;
11473  }
11474  }
11475 
11476  delete [] cg;
11477  delete [] nbea;
11478  delete [] vn;
11479 }
11480 
11481 void Mesh::ScaleElements(double sf)
11482 {
11483  int i,j,k;
11484  Array<int> vert;
11485  DenseMatrix pointmat;
11486  int na = NumOfElements;
11487  double *cg = new double[na*spaceDim];
11488  int *nbea = new int[na];
11489 
11490  int *vn = new int[NumOfVertices];
11491  for (i = 0; i < NumOfVertices; i++)
11492  {
11493  vn[i] = 0;
11494  }
11495  for (i = 0; i < na; i++)
11496  {
11497  for (j = 0; j < spaceDim; j++)
11498  {
11499  cg[i*spaceDim+j] = 0.0;
11500  }
11501  nbea[i] = 0;
11502  }
11503 
11504  for (i = 0; i < NumOfElements; i++)
11505  {
11506  GetElementVertices(i, vert);
11507  for (k = 0; k < vert.Size(); k++)
11508  {
11509  vn[vert[k]] = 1;
11510  }
11511  }
11512 
11513  for (i = 0; i < NumOfElements; i++)
11514  {
11515  int bea = i;
11516  GetPointMatrix(i, pointmat);
11517  GetElementVertices(i, vert);
11518 
11519  for (k = 0; k < vert.Size(); k++)
11520  if (vn[vert[k]] == 1)
11521  {
11522  nbea[bea]++;
11523  for (j = 0; j < spaceDim; j++)
11524  {
11525  cg[bea*spaceDim+j] += pointmat(j,k);
11526  }
11527  vn[vert[k]] = 2;
11528  }
11529  }
11530 
11531  for (i = 0; i < NumOfElements; i++)
11532  {
11533  int bea = i;
11534  GetElementVertices(i, vert);
11535 
11536  for (k = 0; k < vert.Size(); k++)
11537  if (vn[vert[k]])
11538  {
11539  for (j = 0; j < spaceDim; j++)
11540  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
11541  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
11542  vn[vert[k]] = 0;
11543  }
11544  }
11545 
11546  delete [] cg;
11547  delete [] nbea;
11548  delete [] vn;
11549 }
11550 
11551 void Mesh::Transform(void (*f)(const Vector&, Vector&))
11552 {
11553  // TODO: support for different new spaceDim.
11554  if (Nodes == NULL)
11555  {
11556  Vector vold(spaceDim), vnew(NULL, spaceDim);
11557  for (int i = 0; i < vertices.Size(); i++)
11558  {
11559  for (int j = 0; j < spaceDim; j++)
11560  {
11561  vold(j) = vertices[i](j);
11562  }
11563  vnew.SetData(vertices[i]());
11564  (*f)(vold, vnew);
11565  }
11566  }
11567  else
11568  {
11569  GridFunction xnew(Nodes->FESpace());
11571  xnew.ProjectCoefficient(f_pert);
11572  *Nodes = xnew;
11573  }
11574 }
11575 
11577 {
11578  MFEM_VERIFY(spaceDim == deformation.GetVDim(),
11579  "incompatible vector dimensions");
11580  if (Nodes == NULL)
11581  {
11582  LinearFECollection fec;
11583  FiniteElementSpace fes(this, &fec, spaceDim, Ordering::byVDIM);
11584  GridFunction xnew(&fes);
11585  xnew.ProjectCoefficient(deformation);
11586  for (int i = 0; i < NumOfVertices; i++)
11587  for (int d = 0; d < spaceDim; d++)
11588  {
11589  vertices[i](d) = xnew(d + spaceDim*i);
11590  }
11591  }
11592  else
11593  {
11594  GridFunction xnew(Nodes->FESpace());
11595  xnew.ProjectCoefficient(deformation);
11596  *Nodes = xnew;
11597  }
11598 }
11599 
11601 {
11602  if (NURBSext || ncmesh) { return; }
11603 
11604  Array<int> v2v(GetNV());
11605  v2v = -1;
11606  for (int i = 0; i < GetNE(); i++)
11607  {
11608  Element *el = GetElement(i);
11609  int nv = el->GetNVertices();
11610  int *v = el->GetVertices();
11611  for (int j = 0; j < nv; j++)
11612  {
11613  v2v[v[j]] = 0;
11614  }
11615  }
11616  for (int i = 0; i < GetNBE(); i++)
11617  {
11618  Element *el = GetBdrElement(i);
11619  int *v = el->GetVertices();
11620  int nv = el->GetNVertices();
11621  for (int j = 0; j < nv; j++)
11622  {
11623  v2v[v[j]] = 0;
11624  }
11625  }
11626  int num_vert = 0;
11627  for (int i = 0; i < v2v.Size(); i++)
11628  {
11629  if (v2v[i] == 0)
11630  {
11631  vertices[num_vert] = vertices[i];
11632  v2v[i] = num_vert++;
11633  }
11634  }
11635 
11636  if (num_vert == v2v.Size()) { return; }
11637 
11638  Vector nodes_by_element;
11639  Array<int> vdofs;
11640  if (Nodes)
11641  {
11642  int s = 0;
11643  for (int i = 0; i < GetNE(); i++)
11644  {
11645  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11646  s += vdofs.Size();
11647  }
11648  nodes_by_element.SetSize(s);
11649  s = 0;
11650  for (int i = 0; i < GetNE(); i++)
11651  {
11652  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11653  Nodes->GetSubVector(vdofs, &nodes_by_element(s));
11654  s += vdofs.Size();
11655  }
11656  }
11657  vertices.SetSize(num_vert);
11658  NumOfVertices = num_vert;
11659  for (int i = 0; i < GetNE(); i++)
11660  {
11661  Element *el = GetElement(i);
11662  int *v = el->GetVertices();
11663  int nv = el->GetNVertices();
11664  for (int j = 0; j < nv; j++)
11665  {
11666  v[j] = v2v[v[j]];
11667  }
11668  }
11669  for (int i = 0; i < GetNBE(); i++)
11670  {
11671  Element *el = GetBdrElement(i);
11672  int *v = el->GetVertices();
11673  int nv = el->GetNVertices();
11674  for (int j = 0; j < nv; j++)
11675  {
11676  v[j] = v2v[v[j]];
11677  }
11678  }
11679  DeleteTables();
11680  if (Dim > 1)
11681  {
11682  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
11683  el_to_edge = new Table;
11685  }
11686  if (Dim > 2)
11687  {
11688  // generate el_to_face, be_to_face
11690  }
11691  // Update faces and faces_info
11692  GenerateFaces();
11693  if (Nodes)
11694  {
11695  Nodes->FESpace()->Update();
11696  Nodes->Update();
11697  int s = 0;
11698  for (int i = 0; i < GetNE(); i++)
11699  {
11700  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11701  Nodes->SetSubVector(vdofs, &nodes_by_element(s));
11702  s += vdofs.Size();
11703  }
11704  }
11705 }
11706 
11708 {
11709  if (NURBSext || ncmesh) { return; }
11710 
11711  int num_bdr_elem = 0;
11712  int new_bel_to_edge_nnz = 0;
11713  for (int i = 0; i < GetNBE(); i++)
11714  {
11716  {
11717  FreeElement(boundary[i]);
11718  }
11719  else
11720  {
11721  num_bdr_elem++;
11722  if (Dim == 3)
11723  {
11724  new_bel_to_edge_nnz += bel_to_edge->RowSize(i);
11725  }
11726  }
11727  }
11728 
11729  if (num_bdr_elem == GetNBE()) { return; }
11730 
11731  Array<Element *> new_boundary(num_bdr_elem);
11732  Array<int> new_be_to_edge, new_be_to_face;
11733  Table *new_bel_to_edge = NULL;
11734  new_boundary.SetSize(0);
11735  if (Dim == 2)
11736  {
11737  new_be_to_edge.Reserve(num_bdr_elem);
11738  }
11739  else if (Dim == 3)
11740  {
11741  new_be_to_face.Reserve(num_bdr_elem);
11742  new_bel_to_edge = new Table;
11743  new_bel_to_edge->SetDims(num_bdr_elem, new_bel_to_edge_nnz);
11744  }
11745  for (int i = 0; i < GetNBE(); i++)
11746  {
11748  {
11749  new_boundary.Append(boundary[i]);
11750  if (Dim == 2)
11751  {
11752  new_be_to_edge.Append(be_to_edge[i]);
11753  }
11754  else if (Dim == 3)
11755  {
11756  int row = new_be_to_face.Size();
11757  new_be_to_face.Append(be_to_face[i]);
11758  int *e = bel_to_edge->GetRow(i);
11759  int ne = bel_to_edge->RowSize(i);
11760  int *new_e = new_bel_to_edge->GetRow(row);
11761  for (int j = 0; j < ne; j++)
11762  {
11763  new_e[j] = e[j];
11764  }
11765  new_bel_to_edge->GetI()[row+1] = new_bel_to_edge->GetI()[row] + ne;
11766  }
11767  }
11768  }
11769 
11770  NumOfBdrElements = new_boundary.Size();
11771  mfem::Swap(boundary, new_boundary);
11772 
11773  if (Dim == 2)
11774  {
11775  mfem::Swap(be_to_edge, new_be_to_edge);
11776  }
11777  else if (Dim == 3)
11778  {
11779  mfem::Swap(be_to_face, new_be_to_face);
11780  delete bel_to_edge;
11781  bel_to_edge = new_bel_to_edge;
11782  }
11783 
11784  Array<int> attribs(num_bdr_elem);
11785  for (int i = 0; i < attribs.Size(); i++)
11786  {
11787  attribs[i] = GetBdrAttribute(i);
11788  }
11789  attribs.Sort();
11790  attribs.Unique();
11792  attribs.Copy(bdr_attributes);
11793 }
11794 
11796 {
11797 #ifdef MFEM_USE_MEMALLOC
11798  if (E)
11799  {
11800  if (E->GetType() == Element::TETRAHEDRON)
11801  {
11802  TetMemory.Free((Tetrahedron*) E);
11803  }
11804  else
11805  {
11806  delete E;
11807  }
11808  }
11809 #else
11810  delete E;
11811 #endif
11812 }
11813 
11814 std::ostream &operator<<(std::ostream &os, const Mesh &mesh)
11815 {
11816  mesh.Print(os);
11817  return os;
11818 }
11819 
11820 int Mesh::FindPoints(DenseMatrix &point_mat, Array<int>& elem_ids,
11821  Array<IntegrationPoint>& ips, bool warn,
11822  InverseElementTransformation *inv_trans)
11823 {
11824  const int npts = point_mat.Width();
11825  if (!npts) { return 0; }
11826  MFEM_VERIFY(point_mat.Height() == spaceDim,"Invalid points matrix");
11827  elem_ids.SetSize(npts);
11828  ips.SetSize(npts);
11829  elem_ids = -1;
11830  if (!GetNE()) { return 0; }
11831 
11832  double *data = point_mat.GetData();
11833  InverseElementTransformation *inv_tr = inv_trans;
11834  inv_tr = inv_tr ? inv_tr : new InverseElementTransformation;
11835 
11836  // For each point in 'point_mat', find the element whose center is closest.
11837  Vector min_dist(npts);
11838  Array<int> e_idx(npts);
11839  min_dist = std::numeric_limits<double>::max();
11840  e_idx = -1;
11841 
11842  Vector pt(spaceDim);
11843  for (int i = 0; i < GetNE(); i++)
11844  {
11845  GetElementTransformation(i)->Transform(
11847  for (int k = 0; k < npts; k++)
11848  {
11849  double dist = pt.DistanceTo(data+k*spaceDim);
11850  if (dist < min_dist(k))
11851  {
11852  min_dist(k) = dist;
11853  e_idx[k] = i;
11854  }
11855  }
11856  }
11857 
11858  // Checks if the points lie in the closest element
11859  int pts_found = 0;
11860  pt.NewDataAndSize(NULL, spaceDim);
11861  for (int k = 0; k < npts; k++)
11862  {
11863  pt.SetData(data+k*spaceDim);
11864  inv_tr->SetTransformation(*GetElementTransformation(e_idx[k]));
11865  int res = inv_tr->Transform(pt, ips[k]);
11867  {
11868  elem_ids[k] = e_idx[k];
11869  pts_found++;
11870  }
11871  }
11872  if (pts_found != npts)
11873  {
11874  Array<int> elvertices;
11875  Table *vtoel = GetVertexToElementTable();
11876  for (int k = 0; k < npts; k++)
11877  {
11878  if (elem_ids[k] != -1) { continue; }
11879  // Try all vertex-neighbors of element e_idx[k]
11880  pt.SetData(data+k*spaceDim);
11881  GetElementVertices(e_idx[k], elvertices);
11882  for (int v = 0; v < elvertices.Size(); v++)
11883  {
11884  int vv = elvertices[v];
11885  int ne = vtoel->RowSize(vv);
11886  const int* els = vtoel->GetRow(vv);
11887  for (int e = 0; e < ne; e++)
11888  {
11889  if (els[e] == e_idx[k]) { continue; }
11890  inv_tr->SetTransformation(*GetElementTransformation(els[e]));
11891  int res = inv_tr->Transform(pt, ips[k]);
11893  {
11894  elem_ids[k] = els[e];
11895  pts_found++;
11896  goto next_point;
11897  }
11898  }
11899  }
11900  // Try neighbors for non-conforming meshes
11901  if (ncmesh)
11902  {
11903  Array<int> neigh;
11904  int le = ncmesh->leaf_elements[e_idx[k]];
11905  ncmesh->FindNeighbors(le,neigh);
11906  for (int e = 0; e < neigh.Size(); e++)
11907  {
11908  int nn = neigh[e];
11909  if (ncmesh->IsGhost(ncmesh->elements[nn])) { continue; }
11910  int el = ncmesh->elements[nn].index;
11912  int res = inv_tr->Transform(pt, ips[k]);
11914  {
11915  elem_ids[k] = el;
11916  pts_found++;
11917  goto next_point;
11918  }
11919  }
11920  }
11921  next_point: ;
11922  }
11923  delete vtoel;
11924  }
11925  if (inv_trans == NULL) { delete inv_tr; }
11926 
11927  if (warn && pts_found != npts)
11928  {
11929  MFEM_WARNING((npts-pts_found) << " points were not found");
11930  }
11931  return pts_found;
11932 }
11933 
11934 
11936  int flags, MemoryType d_mt)
11937 {
11938  this->mesh = mesh;
11939  IntRule = &ir;
11940  computed_factors = flags;
11941 
11942  MFEM_ASSERT(mesh->GetNumGeometries(mesh->Dimension()) <= 1,
11943  "mixed meshes are not supported!");
11944  MFEM_ASSERT(mesh->GetNodes(), "meshes without nodes are not supported!");
11945 
11946  Compute(*mesh->GetNodes(), d_mt);
11947 }
11948 
11950  const IntegrationRule &ir,
11951  int flags, MemoryType d_mt)
11952 {
11953  this->mesh = nodes.FESpace()->GetMesh();
11954  IntRule = &ir;
11955  computed_factors = flags;
11956 
11957  Compute(nodes, d_mt);
11958 }
11959 
11960 void GeometricFactors::Compute(const GridFunction &nodes,
11961  MemoryType d_mt)
11962 {
11963 
11964  const FiniteElementSpace *fespace = nodes.FESpace();
11965  const FiniteElement *fe = fespace->GetFE(0);
11966  const int dim = fe->GetDim();
11967  const int vdim = fespace->GetVDim();
11968  const int NE = fespace->GetNE();
11969  const int ND = fe->GetDof();
11970  const int NQ = IntRule->GetNPoints();
11971 
11972  unsigned eval_flags = 0;
11973  MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
11976  {
11977  X.SetSize(vdim*NQ*NE, my_d_mt); // NQ x SDIM x NE
11978  eval_flags |= QuadratureInterpolator::VALUES;
11979  }
11981  {
11982  J.SetSize(dim*vdim*NQ*NE, my_d_mt); // NQ x SDIM x DIM x NE
11984  }
11986  {
11987  detJ.SetSize(NQ*NE, my_d_mt); // NQ x NE
11989  }
11990 
11991  const QuadratureInterpolator *qi = fespace->GetQuadratureInterpolator(*IntRule);
11992  // All X, J, and detJ use this layout:
11994 
11995  const bool use_tensor_products = UsesTensorBasis(*fespace);
11996 
11997  qi->DisableTensorProducts(!use_tensor_products);
11998  const ElementDofOrdering e_ordering = use_tensor_products ?
12001  const Operator *elem_restr = fespace->GetElementRestriction(e_ordering);
12002 
12003  if (elem_restr) // Always true as of 2021-04-27
12004  {
12005  Vector Enodes(vdim*ND*NE, my_d_mt);
12006  elem_restr->Mult(nodes, Enodes);
12007  qi->Mult(Enodes, eval_flags, X, J, detJ);
12008  }
12009  else
12010  {
12011  qi->Mult(nodes, eval_flags, X, J, detJ);
12012  }
12013 }
12014 
12016  const IntegrationRule &ir,
12017  int flags, FaceType type)
12018  : type(type)
12019 {
12020  this->mesh = mesh;
12021  IntRule = &ir;
12022  computed_factors = flags;
12023 
12024  const GridFunction *nodes = mesh->GetNodes();
12025  const FiniteElementSpace *fespace = nodes->FESpace();
12026  const int vdim = fespace->GetVDim();
12027  const int NF = fespace->GetNFbyType(type);
12028  const int NQ = ir.GetNPoints();
12029 
12030  const FaceRestriction *face_restr = fespace->GetFaceRestriction(
12032  type,
12034  Vector Fnodes(face_restr->Height());
12035  face_restr->Mult(*nodes, Fnodes);
12036 
12037  unsigned eval_flags = 0;
12039  {
12040  X.SetSize(vdim*NQ*NF);
12041  eval_flags |= FaceQuadratureInterpolator::VALUES;
12042  }
12043  if (flags & FaceGeometricFactors::JACOBIANS)
12044  {
12045  J.SetSize(vdim*vdim*NQ*NF);
12047  }
12049  {
12050  detJ.SetSize(NQ*NF);
12052  }
12053  if (flags & FaceGeometricFactors::NORMALS)
12054  {
12055  normal.SetSize(vdim*NQ*NF);
12057  }
12058 
12060  ir, type);
12061  qi->Mult(Fnodes, eval_flags, X, J, detJ, normal);
12062 }
12063 
12065  const double s_)
12066  : VectorCoefficient(dim), n(n_), s(s_), tip(p, dim-1)
12067 {
12068 }
12069 
12071  const IntegrationPoint &ip)
12072 {
12073  V.SetSize(vdim);
12074  T.Transform(ip, tip);
12075  V(0) = p[0];
12076  if (vdim == 2)
12077  {
12078  V(1) = s * ((ip.y + layer) / n);
12079  }
12080  else
12081  {
12082  V(1) = p[1];
12083  V(2) = s * ((ip.z + layer) / n);
12084  }
12085 }
12086 
12087 
12088 Mesh *Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
12089 {
12090  if (mesh->Dimension() != 1)
12091  {
12092  mfem::err << "Extrude1D : Not a 1D mesh!" << endl;
12093  mfem_error();
12094  }
12095 
12096  int nvy = (closed) ? (ny) : (ny + 1);
12097  int nvt = mesh->GetNV() * nvy;
12098 
12099  Mesh *mesh2d;
12100 
12101  if (closed)
12102  {
12103  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny, mesh->GetNBE()*ny);
12104  }
12105  else
12106  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny,
12107  mesh->GetNBE()*ny+2*mesh->GetNE());
12108 
12109  // vertices
12110  double vc[2];
12111  for (int i = 0; i < mesh->GetNV(); i++)
12112  {
12113  vc[0] = mesh->GetVertex(i)[0];
12114  for (int j = 0; j < nvy; j++)
12115  {
12116  vc[1] = sy * (double(j) / ny);
12117  mesh2d->AddVertex(vc);
12118  }
12119  }
12120  // elements
12121  Array<int> vert;
12122  for (int i = 0; i < mesh->GetNE(); i++)
12123  {
12124  const Element *elem = mesh->GetElement(i);
12125  elem->GetVertices(vert);
12126  const int attr = elem->GetAttribute();
12127  for (int j = 0; j < ny; j++)
12128  {
12129  int qv[4];
12130  qv[0] = vert[0] * nvy + j;
12131  qv[1] = vert[1] * nvy + j;
12132  qv[2] = vert[1] * nvy + (j + 1) % nvy;
12133  qv[3] = vert[0] * nvy + (j + 1) % nvy;
12134 
12135  mesh2d->AddQuad(qv, attr);
12136  }
12137  }
12138  // 2D boundary from the 1D boundary
12139  for (int i = 0; i < mesh->GetNBE(); i++)
12140  {
12141  const Element *elem = mesh->GetBdrElement(i);
12142  elem->GetVertices(vert);
12143  const int attr = elem->GetAttribute();
12144  for (int j = 0; j < ny; j++)
12145  {
12146  int sv[2];
12147  sv[0] = vert[0] * nvy + j;
12148  sv[1] = vert[0] * nvy + (j + 1) % nvy;
12149 
12150  if (attr%2)
12151  {
12152  Swap<int>(sv[0], sv[1]);
12153  }
12154 
12155  mesh2d->AddBdrSegment(sv, attr);
12156  }
12157  }
12158 
12159  if (!closed)
12160  {
12161  // 2D boundary from the 1D elements (bottom + top)
12162  int nba = (mesh->bdr_attributes.Size() > 0 ?
12163  mesh->bdr_attributes.Max() : 0);
12164  for (int i = 0; i < mesh->GetNE(); i++)
12165  {
12166  const Element *elem = mesh->GetElement(i);
12167  elem->GetVertices(vert);
12168  const int attr = nba + elem->GetAttribute();
12169  int sv[2];
12170  sv[0] = vert[0] * nvy;
12171  sv[1] = vert[1] * nvy;
12172 
12173  mesh2d->AddBdrSegment(sv, attr);
12174 
12175  sv[0] = vert[1] * nvy + ny;
12176  sv[1] = vert[0] * nvy + ny;
12177 
12178  mesh2d->AddBdrSegment(sv, attr);
12179  }
12180  }
12181 
12182  mesh2d->FinalizeQuadMesh(1, 0, false);
12183 
12184  GridFunction *nodes = mesh->GetNodes();
12185  if (nodes)
12186  {
12187  // duplicate the fec of the 1D mesh so that it can be deleted safely
12188  // along with its nodes, fes and fec
12189  FiniteElementCollection *fec2d = NULL;
12190  FiniteElementSpace *fes2d;
12191  const char *name = nodes->FESpace()->FEColl()->Name();
12192  string cname = name;
12193  if (cname == "Linear")
12194  {
12195  fec2d = new LinearFECollection;
12196  }
12197  else if (cname == "Quadratic")
12198  {
12199  fec2d = new QuadraticFECollection;
12200  }
12201  else if (cname == "Cubic")
12202  {
12203  fec2d = new CubicFECollection;
12204  }
12205  else if (!strncmp(name, "H1_", 3))
12206  {
12207  fec2d = new H1_FECollection(atoi(name + 7), 2);
12208  }
12209  else if (!strncmp(name, "L2_T", 4))
12210  {
12211  fec2d = new L2_FECollection(atoi(name + 10), 2, atoi(name + 4));
12212  }
12213  else if (!strncmp(name, "L2_", 3))
12214  {
12215  fec2d = new L2_FECollection(atoi(name + 7), 2);
12216  }
12217  else
12218  {
12219  delete mesh2d;
12220  mfem::err << "Extrude1D : The mesh uses unknown FE collection : "
12221  << cname << endl;
12222  mfem_error();
12223  }
12224  fes2d = new FiniteElementSpace(mesh2d, fec2d, 2);
12225  mesh2d->SetNodalFESpace(fes2d);
12226  GridFunction *nodes2d = mesh2d->GetNodes();
12227  nodes2d->MakeOwner(fec2d);
12228 
12229  NodeExtrudeCoefficient ecoeff(2, ny, sy);
12230  Vector lnodes;
12231  Array<int> vdofs2d;
12232  for (int i = 0; i < mesh->GetNE(); i++)
12233  {
12235  for (int j = ny-1; j >= 0; j--)
12236  {
12237  fes2d->GetElementVDofs(i*ny+j, vdofs2d);
12238  lnodes.SetSize(vdofs2d.Size());
12239  ecoeff.SetLayer(j);
12240  fes2d->GetFE(i*ny+j)->Project(ecoeff, T, lnodes);
12241  nodes2d->SetSubVector(vdofs2d, lnodes);
12242  }
12243  }
12244  }
12245  return mesh2d;
12246 }
12247 
12248 Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz)
12249 {
12250  if (mesh->Dimension() != 2)
12251  {
12252  mfem::err << "Extrude2D : Not a 2D mesh!" << endl;
12253  mfem_error();
12254  }
12255 
12256  int nvz = nz + 1;
12257  int nvt = mesh->GetNV() * nvz;
12258 
12259  Mesh *mesh3d = new Mesh(3, nvt, mesh->GetNE()*nz,
12260  mesh->GetNBE()*nz+2*mesh->GetNE());
12261 
12262  bool wdgMesh = false;
12263  bool hexMesh = false;
12264 
12265  // vertices
12266  double vc[3];
12267  for (int i = 0; i < mesh->GetNV(); i++)
12268  {
12269  vc[0] = mesh->GetVertex(i)[0];
12270  vc[1] = mesh->GetVertex(i)[1];
12271  for (int j = 0; j < nvz; j++)
12272  {
12273  vc[2] = sz * (double(j) / nz);
12274  mesh3d->AddVertex(vc);
12275  }
12276  }
12277  // elements
12278  Array<int> vert;
12279  for (int i = 0; i < mesh->GetNE(); i++)
12280  {
12281  const Element *elem = mesh->GetElement(i);
12282  elem->GetVertices(vert);
12283  const int attr = elem->GetAttribute();
12284  Geometry::Type geom = elem->GetGeometryType();
12285  switch (geom)
12286  {
12287  case Geometry::TRIANGLE:
12288  wdgMesh = true;
12289  for (int j = 0; j < nz; j++)
12290  {
12291  int pv[6];
12292  pv[0] = vert[0] * nvz + j;
12293  pv[1] = vert[1] * nvz + j;
12294  pv[2] = vert[2] * nvz + j;
12295  pv[3] = vert[0] * nvz + (j + 1) % nvz;
12296  pv[4] = vert[1] * nvz + (j + 1) % nvz;
12297  pv[5] = vert[2] * nvz + (j + 1) % nvz;
12298 
12299  mesh3d->AddWedge(pv, attr);
12300  }
12301  break;
12302  case Geometry::SQUARE:
12303  hexMesh = true;
12304  for (int j = 0; j < nz; j++)
12305  {
12306  int hv[8];
12307  hv[0] = vert[0] * nvz + j;
12308  hv[1] = vert[1] * nvz + j;
12309  hv[2] = vert[2] * nvz + j;
12310  hv[3] = vert[3] * nvz + j;
12311  hv[4] = vert[0] * nvz + (j + 1) % nvz;
12312  hv[5] = vert[1] * nvz + (j + 1) % nvz;
12313  hv[6] = vert[2] * nvz + (j + 1) % nvz;
12314  hv[7] = vert[3] * nvz + (j + 1) % nvz;
12315 
12316  mesh3d->AddHex(hv, attr);
12317  }
12318  break;
12319  default:
12320  mfem::err << "Extrude2D : Invalid 2D element type \'"
12321  << geom << "\'" << endl;
12322  mfem_error();
12323  break;
12324  }
12325  }
12326  // 3D boundary from the 2D boundary
12327  for (int i = 0; i < mesh->GetNBE(); i++)
12328  {
12329  const Element *elem = mesh->GetBdrElement(i);
12330  elem->GetVertices(vert);
12331  const int attr = elem->GetAttribute();
12332  for (int j = 0; j < nz; j++)
12333  {
12334  int qv[4];
12335  qv[0] = vert[0] * nvz + j;
12336  qv[1] = vert[1] * nvz + j;
12337  qv[2] = vert[1] * nvz + (j + 1) % nvz;
12338  qv[3] = vert[0] * nvz + (j + 1) % nvz;
12339 
12340  mesh3d->AddBdrQuad(qv, attr);
12341  }
12342  }
12343 
12344  // 3D boundary from the 2D elements (bottom + top)
12345  int nba = (mesh->bdr_attributes.Size() > 0 ?
12346  mesh->bdr_attributes.Max() : 0);
12347  for (int i = 0; i < mesh->GetNE(); i++)
12348  {
12349  const Element *elem = mesh->GetElement(i);
12350  elem->GetVertices(vert);
12351  const int attr = nba + elem->GetAttribute();
12352  Geometry::Type geom = elem->GetGeometryType();
12353  switch (geom)
12354  {
12355  case Geometry::TRIANGLE:
12356  {
12357  int tv[3];
12358  tv[0] = vert[0] * nvz;
12359  tv[1] = vert[2] * nvz;
12360  tv[2] = vert[1] * nvz;
12361 
12362  mesh3d->AddBdrTriangle(tv, attr);
12363 
12364  tv[0] = vert[0] * nvz + nz;
12365  tv[1] = vert[1] * nvz + nz;
12366  tv[2] = vert[2] * nvz + nz;
12367 
12368  mesh3d->AddBdrTriangle(tv, attr);
12369  }
12370  break;
12371  case Geometry::SQUARE:
12372  {
12373  int qv[4];
12374  qv[0] = vert[0] * nvz;
12375  qv[1] = vert[3] * nvz;
12376  qv[2] = vert[2] * nvz;
12377  qv[3] = vert[1] * nvz;
12378 
12379  mesh3d->AddBdrQuad(qv, attr);
12380 
12381  qv[0] = vert[0] * nvz + nz;
12382  qv[1] = vert[1] * nvz + nz;
12383  qv[2] = vert[2] * nvz + nz;
12384  qv[3] = vert[3] * nvz + nz;
12385 
12386  mesh3d->AddBdrQuad(qv, attr);
12387  }
12388  break;
12389  default:
12390  mfem::err << "Extrude2D : Invalid 2D element type \'"
12391  << geom << "\'" << endl;
12392  mfem_error();
12393  break;
12394  }
12395  }
12396 
12397  if ( hexMesh && wdgMesh )
12398  {
12399  mesh3d->FinalizeMesh(0, false);
12400  }
12401  else if ( hexMesh )
12402  {
12403  mesh3d->FinalizeHexMesh(1, 0, false);
12404  }
12405  else if ( wdgMesh )
12406  {
12407  mesh3d->FinalizeWedgeMesh(1, 0, false);
12408  }
12409 
12410  GridFunction *nodes = mesh->GetNodes();
12411  if (nodes)
12412  {
12413  // duplicate the fec of the 2D mesh so that it can be deleted safely
12414  // along with its nodes, fes and fec
12415  FiniteElementCollection *fec3d = NULL;
12416  FiniteElementSpace *fes3d;
12417  const char *name = nodes->FESpace()->FEColl()->Name();
12418  string cname = name;
12419  if (cname == "Linear")
12420  {
12421  fec3d = new LinearFECollection;
12422  }
12423  else if (cname == "Quadratic")
12424  {
12425  fec3d = new QuadraticFECollection;
12426  }
12427  else if (cname == "Cubic")
12428  {
12429  fec3d = new CubicFECollection;
12430  }
12431  else if (!strncmp(name, "H1_", 3))
12432  {
12433  fec3d = new H1_FECollection(atoi(name + 7), 3);
12434  }
12435  else if (!strncmp(name, "L2_T", 4))
12436  {
12437  fec3d = new L2_FECollection(atoi(name + 10), 3, atoi(name + 4));
12438  }
12439  else if (!strncmp(name, "L2_", 3))
12440  {
12441  fec3d = new L2_FECollection(atoi(name + 7), 3);
12442  }
12443  else
12444  {
12445  delete mesh3d;
12446  mfem::err << "Extrude3D : The mesh uses unknown FE collection : "
12447  << cname << endl;
12448  mfem_error();
12449  }
12450  fes3d = new FiniteElementSpace(mesh3d, fec3d, 3);
12451  mesh3d->SetNodalFESpace(fes3d);
12452  GridFunction *nodes3d = mesh3d->GetNodes();
12453  nodes3d->MakeOwner(fec3d);
12454 
12455  NodeExtrudeCoefficient ecoeff(3, nz, sz);
12456  Vector lnodes;
12457  Array<int> vdofs3d;
12458  for (int i = 0; i < mesh->GetNE(); i++)
12459  {
12461  for (int j = nz-1; j >= 0; j--)
12462  {
12463  fes3d->GetElementVDofs(i*nz+j, vdofs3d);
12464  lnodes.SetSize(vdofs3d.Size());
12465  ecoeff.SetLayer(j);
12466  fes3d->GetFE(i*nz+j)->Project(ecoeff, T, lnodes);
12467  nodes3d->SetSubVector(vdofs3d, lnodes);
12468  }
12469  }
12470  }
12471  return mesh3d;
12472 }
12473 
12474 #ifdef MFEM_DEBUG
12475 void Mesh::DebugDump(std::ostream &os) const
12476 {
12477  // dump vertices and edges (NCMesh "nodes")
12478  os << NumOfVertices + NumOfEdges << "\n";
12479  for (int i = 0; i < NumOfVertices; i++)
12480  {
12481  const double *v = GetVertex(i);
12482  os << i << " " << v[0] << " " << v[1] << " " << v[2]
12483  << " 0 0 " << i << " -1 0\n";
12484  }
12485 
12486  Array<int> ev;
12487  for (int i = 0; i < NumOfEdges; i++)
12488  {
12489  GetEdgeVertices(i, ev);
12490  double mid[3] = {0, 0, 0};
12491  for (int j = 0; j < 2; j++)
12492  {
12493  for (int k = 0; k < spaceDim; k++)
12494  {
12495  mid[k] += GetVertex(ev[j])[k];
12496  }
12497  }
12498  os << NumOfVertices+i << " "
12499  << mid[0]/2 << " " << mid[1]/2 << " " << mid[2]/2 << " "
12500  << ev[0] << " " << ev[1] << " -1 " << i << " 0\n";
12501  }
12502 
12503  // dump elements
12504  os << NumOfElements << "\n";
12505  for (int i = 0; i < NumOfElements; i++)
12506  {
12507  const Element* e = elements[i];
12508  os << e->GetNVertices() << " ";
12509  for (int j = 0; j < e->GetNVertices(); j++)
12510  {
12511  os << e->GetVertices()[j] << " ";
12512  }
12513  os << e->GetAttribute() << " 0 " << i << "\n";
12514  }
12515 
12516  // dump faces
12517  os << "0\n";
12518 }
12519 #endif
12520 
12521 }
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:247
static Mesh MakePeriodic(const Mesh &orig_mesh, const std::vector< int > &v2v)
Create a periodic mesh by identifying vertices of orig_mesh.
Definition: mesh.cpp:4879
Abstract class for all finite elements.
Definition: fe_base.hpp:235
const IntegrationRule * IntRule
Definition: mesh.hpp:1872
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition: fespace.hpp:607
Geometry::Type GetGeometryType() const
Definition: element.hpp:52
void Loader(std::istream &input, int generate_edges=0, std::string parse_tag="")
Definition: mesh.cpp:3954
Mesh * Make3D(int nsteps, double rstep, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:370
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:575
int Size() const
Return the logical size of the array.
Definition: array.hpp:138
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:560
void SetCoordsFromPatches(Vector &Nodes)
Definition: nurbs.cpp:2966
void PrintSurfaces(const Table &Aface_face, std::ostream &out) const
Print set of disjoint surfaces:
Definition: mesh.cpp:11344
void Get(double *p, const int dim) const
Definition: intrules.hpp:51
virtual void Save(const char *fname, int precision=16) const
Definition: mesh.cpp:10210
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:6207
static const int vtk_quadratic_hex[27]
Definition: mesh.hpp:246
int * CartesianPartitioning(int nxyz[])
Definition: mesh.cpp:6936
void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
int GetDim() const
Returns the reference space dimension for the finite element.
Definition: fe_base.hpp:311
int Push(int i, int j)
Definition: table.cpp:216
int GetNDofs() const
Returns number of degrees of freedom.
Definition: fespace.hpp:560
int * GetJ()
Definition: table.hpp:114
Arc::Index insert_arc(Node::Index i, Node::Index j, Float w=1, Float b=1)
Definition: gecko.cpp:679
FaceInformation GetFaceInformation(int f) const
Definition: mesh.cpp:1130
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
int GetNV() const
Definition: nurbs.hpp:358
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition: mesh.hpp:1461
void Init(int ind1, int ind2, int ind3, int ind4, int attr=1, int ref_flag=0)
Initialize the vertex indices and the attribute of a Tetrahedron.
Definition: tetrahedron.cpp:43
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:1005
void NewDataAndSize(double *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition: vector.hpp:162
void ScaleElements(double sf)
Definition: mesh.cpp:11481
static const int HighOrderMap[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to arbitrary-order Lagrange VTK geometries.
Definition: vtk.hpp:77
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
int DofToVDof(int dof, int vd, int ndofs=-1) const
Definition: fespace.cpp:251
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T...
Definition: array.hpp:256
Table * GetEdgeVertexTable() const
Returns the edge-to-vertex Table (3D)
Definition: mesh.cpp:6022
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:5923
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition: array.hpp:292
void ReadVTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo)
void UseExternalData(double *ext_data, int i, int j, int k)
Definition: densemat.hpp:847
void FreeElement(Element *E)
Definition: mesh.cpp:11795
void Mult(const Vector &x, Vector &y) const override=0
Extract the face degrees of freedom from x into y.
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition: fespace.cpp:3336
int AddQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1662
int CheckElementOrientation(bool fix_it=true)
Check (and optionally attempt to fix) the orientation of the elements.
Definition: mesh.cpp:5389
void SetVertices(const Vector &vert_coord)
Definition: mesh.cpp:7781
virtual Element * Duplicate(Mesh *m) const =0
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Definition: intrules.cpp:923
static const int vtk_quadratic_tet[10]
Definition: mesh.hpp:243
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:5985
void Make2D(int nx, int ny, Element::Type type, double sx, double sy, bool generate_edges, bool sfc_ordering)
Definition: mesh.cpp:3327
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition: eltrans.hpp:162
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:1902
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:78
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:1846
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:12070
static Mesh MakeSimplicial(const Mesh &orig_mesh)
Definition: mesh.cpp:4550
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:8086
bool IsNonconformingCoarse() const
Return true if the face is a nonconforming coarse face.
Definition: mesh.hpp:1412
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:81
void METIS_PartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Given a coefficient and a transformation, compute its projection (approximation) in the local finite ...
Definition: fe_base.cpp:125
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
class LinearPyramidFiniteElement PyramidFE
Definition: fe.cpp:44
static const int NumGeom
Definition: geom.hpp:42
Array< Slave > slaves
Definition: ncmesh.hpp:231
Array< Element * > boundary
Definition: mesh.hpp:91
void JacToPerfJac(int GeomType, const DenseMatrix &J, DenseMatrix &PJ) const
Definition: geom.cpp:867
int * GeneratePartitioning(int nparts, int part_method=1)
Definition: mesh.cpp:6975
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:6140
CoarseFineTransformations CoarseFineTr
Definition: mesh.hpp:235
int own_nodes
Definition: mesh.hpp:241
virtual void LimitNCLevel(int max_nc_level)
Definition: ncmesh.cpp:5201
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition: mesh.cpp:5877
bool Conforming() const
Definition: mesh.hpp:1625
void MoveVertices(const Vector &displacements)
Definition: mesh.cpp:7761
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:521
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:931
double Det() const
Definition: densemat.cpp:436
static FiniteElement * GetTransformationFEforElementType(Element::Type)
Definition: mesh.cpp:327
virtual DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element &#39;bel&#39;.
Definition: fespace.cpp:2814
void SetElementOrder(int i, int p)
Sets the order of the i&#39;th finite element.
Definition: fespace.cpp:151
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:3711
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
Definition: mesh.cpp:7865
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:308
int NumOfEdges
Definition: mesh.hpp:70
virtual int Transform(const Vector &pt, IntegrationPoint &ip)
Given a point, pt, in physical space, find its reference coordinates, ip.
Definition: eltrans.cpp:336
void UniformRefinement()
Definition: nurbs.cpp:3105
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:227
virtual void UniformRefinement2D()
Refine a mixed 2D mesh uniformly.
Definition: mesh.hpp:392
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Definition: mesh.cpp:7884
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:472
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:72
int SizeK() const
Definition: densemat.hpp:834
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition: mesh.cpp:6197
double Norml2() const
Returns the l2 norm of the vector.
Definition: vector.cpp:792
void ReadNetgen2DMesh(std::istream &input, int &curved)
void ShiftRight(int &a, int &b, int &c)
Definition: mesh.hpp:1943
void SetDims(int rows, int nnz)
Definition: table.cpp:140
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:206
int Push(int a, int b)
Definition: table.hpp:241
Element::Type GetBdrElementType(int i) const
Returns the type of boundary element i.
Definition: mesh.cpp:6202
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:93
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:856
static Mesh MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
Create a refined (by any factor) version of orig_mesh.
Definition: mesh.cpp:3721
A specialized ElementTransformation class representing a face and its two neighboring elements...
Definition: eltrans.hpp:480
unsigned matrix
index into NCList::point_matrices[geom]
Definition: ncmesh.hpp:217
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:534
T * GetData()
Returns the data.
Definition: array.hpp:112
unsigned int uint
Definition: gecko.hpp:204
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:1908
int GetNKV() const
Definition: nurbs.hpp:355
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:246
static const int Edges[NumEdges][2]
Definition: geom.hpp:242
void GetMeshComponents(Mesh &mesh) const
Fill Mesh::{vertices,elements,boundary} for the current finest level.
Definition: ncmesh.cpp:2301
int VectorDim() const
Definition: gridfunc.cpp:321
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:5888
int Push(int r, int c, int f)
Check to see if this entry is in the table and add it to the table if it is not there. Returns the number assigned to the table entry.
Definition: stable3d.cpp:64
void DeleteTables()
Definition: mesh.hpp:290
Piecewise-(bi/tri)linear continuous finite elements.
Definition: fe_coll.hpp:659
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
GridFunction * Nodes
Definition: mesh.hpp:240
int Size() const
Returns the size of the vector.
Definition: vector.hpp:199
int NumOfElements
Definition: mesh.hpp:69
void Print(std::ostream &out) const
I/O: Print the mesh in &quot;MFEM NC mesh v1.0&quot; format.
Definition: ncmesh.cpp:5398
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:187
Mesh * Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
Extrude a 1D mesh.
Definition: mesh.cpp:12088
int idxtype
Definition: mesh.cpp:44
int GetElementOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:178
void Transform(void(*f)(const Vector &, Vector &))
Definition: mesh.cpp:11551
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:524
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:6163
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:7894
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:928
static int GetQuadrature1D(int b_type)
Get the corresponding Quadrature1D constant, when that makes sense; otherwise return Quadrature1D::In...
Definition: fe_base.hpp:60
void FinalizeWedgeMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a wedge Mesh.
Definition: mesh.cpp:2806
virtual void SetVertices(const int *ind)
Set the indices the element according to the input.
Definition: element.cpp:17
void order(Functional *functional, uint iterations=1, uint window=2, uint period=2, uint seed=0, Progress *progress=0)
Definition: gecko.cpp:1232
FDualNumber< tbase > acos(const FDualNumber< tbase > &f)
acos([dual number])
Definition: fdual.hpp:423
double kappa
Definition: ex24.cpp:54
Evaluate the derivatives at quadrature points.
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition: mesh.hpp:1814
NodeExtrudeCoefficient(const int dim, const int n_, const double s_)
Definition: mesh.cpp:12064
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec and fes.
Definition: gridfunc.hpp:124
Data type for vertex.
Definition: vertex.hpp:22
void GetElementLocalToGlobal(Array< int > &lelem_elem)
Definition: nurbs.cpp:2903
void SetMeshGen()
Determine the mesh generator bitmask meshgen, see MeshGenerator().
Definition: mesh.cpp:3901
virtual void Transform(const IntegrationPoint &, Vector &)
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Definition: eltrans.cpp:492
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:5585
Data type quadrilateral element.
void GetVertices(Vector &vert_coord) const
Definition: mesh.cpp:7770
void ReadNetgen3DMesh(std::istream &input)
bool UsesTensorBasis(const FiniteElementSpace &fes)
Definition: fespace.hpp:983
Data arrays will be written in ASCII format.
The inverse transformation of a given ElementTransformation.
Definition: eltrans.hpp:185
double * GetData() const
Returns the matrix data array.
Definition: densemat.hpp:115
const IntegrationPoint & GetCenter(int GeomType)
Return the center of the given Geometry::Type, GeomType.
Definition: geom.hpp:71
void GetVertexLocalToGlobal(Array< int > &lvert_vert)
Definition: nurbs.cpp:2893
void ReadInlineMesh(std::istream &input, bool generate_edges=false)
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:208
T Min() const
Find the minimal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:85
void GetNodalValues(int i, Array< double > &nval, int vdim=1) const
Returns the values in the vertices of i&#39;th element for dimension vdim.
Definition: gridfunc.cpp:393
virtual int OrderJ() const =0
Return the order of the elements of the Jacobian of the transformation.
void RemoveInternalBoundaries()
Definition: mesh.cpp:11707
void DebugDump(std::ostream &out) const
Output an NCMesh-compatible debug dump.
Definition: mesh.cpp:12475
Mesh * Extrude2D(Mesh *mesh, const int nz, const double sz)
Extrude a 2D mesh.
Definition: mesh.cpp:12248
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:1062
void Print(const Mesh &mesh, const adios2stream::mode print_mode=mode::sync)
int Size_of_connections() const
Definition: table.hpp:98
Data type Wedge element.
Definition: wedge.hpp:22
void SetEmpty()
Definition: mesh.cpp:1460
Array< Element * > faces
Definition: mesh.hpp:92
int spaceDim
dimensions of the elements and the vertex coordinates
Definition: ncmesh.hpp:418
virtual long ReduceInt(int value) const
Utility function: sum integers from all processors (Allreduce).
Definition: mesh.hpp:957
const IntegrationRule * GetVertices(int GeomType)
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType...
Definition: geom.cpp:265
void FinalizeHexMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a hexahedral Mesh.
Definition: mesh.cpp:2841
friend class NURBSExtension
Definition: mesh.hpp:59
Geometry::Type GetBdrElementGeometry(int i) const
Definition: mesh.hpp:1053
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:6278
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:354
void WriteBinaryOrASCII(std::ostream &os, std::vector< char > &buf, const T &val, const char *suffix, VTKFormat format)
Write either ASCII data to the stream or binary data to the buffer depending on the given format...
Definition: vtk.hpp:142
Operation last_operation
Definition: mesh.hpp:284
void ReadCubit(const char *filename, int &curved, int &read_gf)
bool HasGeometry(Geometry::Type geom) const
Return true iff the given geom is encountered in the mesh. Geometries of dimensions lower than Dimens...
Definition: mesh.hpp:1070
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:300
void DeleteAll()
Delete the whole array.
Definition: array.hpp:846
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:104
int Dimension() const
Definition: nurbs.hpp:345
int master
master number (in Mesh numbering)
Definition: ncmesh.hpp:216
void InitRefinementTransforms()
Definition: mesh.cpp:9827
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:7927
Array< NCFaceInfo > nc_faces_info
Definition: mesh.hpp:218
Element * ReadElement(std::istream &)
Definition: mesh.cpp:3883
void KnotInsert(Array< KnotVector * > &kv)
Definition: mesh.cpp:5038
void OnMeshUpdated(Mesh *mesh)
Definition: ncmesh.cpp:2396
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:4913
Element * NewElement(int geom)
Definition: mesh.cpp:3829
Table * el_to_face
Definition: mesh.hpp:221
void SetTransformation(ElementTransformation &Trans)
Set a new forward ElementTransformation, Trans.
Definition: eltrans.hpp:292
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3078
void SetVerticesFromNodes(const GridFunction *nodes)
Helper to set vertex coordinates given a high-order curvature function.
Definition: mesh.cpp:5331
Structure for storing face geometric factors: coordinates, Jacobians, determinants of the Jacobians...
Definition: mesh.hpp:1868
ElementTransformation * GetBdrElementTransformation(int i)
Returns the transformation defining the i-th boundary element.
Definition: mesh.cpp:431
virtual void UpdateMeshPointer(Mesh *new_mesh)
Definition: fespace.cpp:3441
int AddBdrTriangle(int v1, int v2, int v3, int attr=1)
Definition: mesh.cpp:1825
Mesh * Make2D(int nsteps, double rstep, double phi, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:49
void PrintTopo(std::ostream &out, const Array< int > &e_to_k) const
Definition: mesh.cpp:10168
const Operator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition: fespace.cpp:1261
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:5345
void MakeRefined_(Mesh &orig_mesh, const Array< int > ref_factors, int ref_type)
Internal function used in Mesh::MakeRefined.
Definition: mesh.cpp:4321
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:3619
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe_base.hpp:320
friend class NCMesh
Definition: mesh.hpp:58
Piecewise-(bi)cubic continuous finite elements.
Definition: fe_coll.hpp:739
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:590
uint rank(Node::Index i) const
Definition: gecko.hpp:672
double Weight() const
Definition: densemat.cpp:493
PointFiniteElement PointFE
Definition: point.cpp:30
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: segment.cpp:40
void GetElementJacobian(int i, DenseMatrix &J)
Definition: mesh.cpp:60
Data type hexahedron element.
Definition: hexahedron.hpp:22
static int GetTetOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:5633
Geometry Geometries
Definition: fe.cpp:49
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:250
long GetSequence() const
Definition: mesh.hpp:1639
void GetVertexDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3035
int AddVertex(double x, double y=0.0, double z=0.0)
Definition: mesh.cpp:1601
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition: eltrans.hpp:401
bool Nonconforming() const
Definition: mesh.hpp:1626
const int * GetDofMap(Geometry::Type GeomType) const
Get the Cartesian to local H1 dof map.
Definition: fe_coll.cpp:1917
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:188
uint Index
Definition: gecko.hpp:595
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:1855
FaceType
Definition: mesh.hpp:45
Data type Pyramid element.
Definition: pyramid.hpp:22
static const int Edges[NumEdges][2]
Definition: geom.hpp:156
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:281
void MoveNodes(const Vector &displacements)
Definition: mesh.cpp:7829
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:10852
The point is inside the element.
Definition: eltrans.hpp:224
double f(const Vector &xvec)
Definition: lor_mms.hpp:32
void UpdateNURBS()
Definition: mesh.cpp:5112
Symmetric 3D Table stored as an array of rows each of which has a stack of column, floor, number nodes. The number of the node is assigned by counting the nodes from zero as they are pushed into the table. Diagonals of any kind are not allowed so the row, column and floor must all be different for each node. Only one node is stored for all 6 symmetric entries that are indexable by unique triplets of row, column, and floor.
Definition: stable3d.hpp:34
const Table & GetDerefinementTable()
Definition: ncmesh.cpp:1805
void PrintVTK(std::ostream &os)
Definition: mesh.cpp:10224
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:7423
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:66
void Make3D(int nx, int ny, int nz, Element::Type type, double sx, double sy, double sz, bool sfc_ordering)
Definition: mesh.cpp:3046
unsigned matrix
Definition: ncmesh.hpp:58
void AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
Definition: mesh.cpp:6428
virtual void SetAttributes()
Definition: mesh.cpp:1547
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:751
void SetType(const int t)
Set the Quadrature1D type of points to use for subdivision.
Definition: geom.hpp:306
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition: mesh.cpp:9394
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: triangle.hpp:61
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:433
IntegrationPointTransformation Loc1
Definition: eltrans.hpp:524
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:1861
int FindCoarseElement(int i)
Definition: mesh.cpp:9839
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:1849
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:3587
void Mult(const Vector &e_vec, unsigned eval_flags, Vector &q_val, Vector &q_der, Vector &q_det, Vector &q_nor) const
Interpolate the E-vector e_vec to quadrature points.
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:9737
static const int Map[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to linear VTK geometries.
Definition: vtk.hpp:73
Float cost() const
Definition: gecko.cpp:857
void AddQuadFaceElement(int lf, int gf, int el, int v0, int v1, int v2, int v3)
Definition: mesh.cpp:6493
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:7366
Timing object.
Definition: tic_toc.hpp:34
void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
void AddConnection(int r, int c)
Definition: table.hpp:80
void LoadPatchTopo(std::istream &input, Array< int > &edge_to_knot)
Read NURBS patch/macro-element mesh.
Definition: mesh.cpp:5177
void ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:6745
void Reset()
Force the reevaluation of the Jacobian in the next call.
Definition: eltrans.hpp:89
A pair of objects.
Definition: sort_pairs.hpp:23
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Definition: mesh.cpp:5312
Type
Constants for the classes derived from Element.
Definition: element.hpp:41
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:68
void GetBdrPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:6225
void InitTables()
Definition: mesh.cpp:1454
void CheckDisplacements(const Vector &displacements, double &tmax)
Definition: mesh.cpp:7684
This structure stores the low level information necessary to interpret the configuration of elements ...
Definition: mesh.hpp:153
NURBSExtension * StealNURBSext()
Definition: fespace.cpp:2231
Array< DenseMatrix * > point_matrices[Geometry::NumGeom]
List of unique point matrices for each slave geometry.
Definition: ncmesh.hpp:234
VTKFormat
Data array format for VTK and VTU files.
Definition: vtk.hpp:93
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition: fe_base.hpp:390
int mesh_geoms
Definition: mesh.hpp:78
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:156
int AddBdrSegment(int v1, int v2, int attr=1)
Definition: mesh.cpp:1811
int AddElement(Element *elem)
The parameter elem should be allocated using the NewElement() method.
Definition: mesh.cpp:1797
int GetMaxElementOrder() const
Return the maximum polynomial order.
Definition: fespace.hpp:451
void ReadLineMesh(std::istream &input)
Array< Embedding > embeddings
Fine element positions in their parents.
Definition: ncmesh.hpp:73
void GetBdrElementTopo(Array< Element * > &boundary) const
Definition: nurbs.cpp:2540
virtual void Load(std::istream &input, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition: mesh.hpp:896
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:1773
const CoarseFineTransformations & GetRefinementTransforms()
Definition: ncmesh.cpp:4348
void SetLayer(const int l)
Definition: mesh.hpp:1927
int GetAttribute() const
Return element&#39;s attribute.
Definition: element.hpp:55
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:6303
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition: array.hpp:289
void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
For the given boundary element, bdr_el, return its adjacent element and its info, i...
Definition: mesh.cpp:6175
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition: fespace.hpp:901
void SetKnotsFromPatches()
Definition: nurbs.cpp:2974
double Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition: eltrans.hpp:131
int nbBoundaryFaces
Definition: mesh.hpp:75
void RandomRefinement(double prob, bool aniso=false, int nonconforming=-1, int nc_limit=0)
Refine each element with given probability. Uses GeneralRefinement.
Definition: mesh.cpp:9418
Data type triangle element.
Definition: triangle.hpp:23
void MarkCoarseLevel()
Definition: ncmesh.cpp:4300
const Element * GetElement(int i) const
Definition: mesh.hpp:1033
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Definition: triangle.cpp:45
void ResetLazyData()
Definition: mesh.cpp:1537
void GetElementTopo(Array< Element * > &elements) const
Definition: nurbs.cpp:2445
IntegrationRule RefPts
Definition: geom.hpp:282
signed char local
local number within &#39;element&#39;
Definition: ncmesh.hpp:191
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
Definition: densemat.hpp:838
double Float
Definition: gecko.hpp:208
void Sort()
Sorts the array in ascending order. This requires operator&lt; to be defined for T.
Definition: array.hpp:248
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
Definition: geom.cpp:1099
int GetVDim()
Returns dimension of the vector.
void Init()
Definition: mesh.cpp:1436
void SetNodalFESpace(FiniteElementSpace *nfes)
Definition: mesh.cpp:5273
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: tetrahedron.hpp:81
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:557
Vector normal
Normals at all quadrature points.
Definition: mesh.hpp:1915
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
Definition: ncmesh.hpp:121
static const int Edges[NumEdges][2]
Definition: geom.hpp:202
void SetData(double *d)
Definition: vector.hpp:149
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:652
int Dimension() const
Definition: mesh.hpp:999
virtual MFEM_DEPRECATED void ReorientTetMesh()
Definition: mesh.cpp:6874
prob_type prob
Definition: ex25.cpp:153
int NumOfBdrElements
Definition: mesh.hpp:69
Table * el_to_edge
Definition: mesh.hpp:220
virtual const FaceRestriction * GetFaceRestriction(ElementDofOrdering e_ordering, FaceType, L2FaceValues mul=L2FaceValues::DoubleValued) const
Return an Operator that converts L-vectors to E-vectors on each face.
Definition: fespace.cpp:1294
static const int QuadraticMap[Geometry::NUM_GEOMETRIES]
Map from MFEM&#39;s Geometry::Type to legacy quadratic VTK geometries/.
Definition: vtk.hpp:75
void GetColumn(int c, Vector &col) const
Definition: densemat.cpp:1270
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: triangle.cpp:188
A class that performs interpolation from a face E-vector to quadrature point values and/or derivative...
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:442
double DistanceTo(const double *p) const
Compute the Euclidean distance to another vector.
Definition: vector.hpp:662
void ReadMFEMMesh(std::istream &input, int version, int &curved)
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: triangle.hpp:62
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:8774
virtual DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element &#39;elem&#39;.
Definition: fespace.cpp:2680
void FindPartitioningComponents(Table &elem_elem, const Array< int > &partitioning, Array< int > &component, Array< int > &num_comp)
Definition: mesh.cpp:7295
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
FDualNumber< tbase > cos(const FDualNumber< tbase > &f)
cos([dual number])
Definition: fdual.hpp:471
void MakeTopologyOnly()
Definition: ncmesh.hpp:413
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3045
bool IsOfFaceType(FaceType type) const
Return true if the face is of the same type as type.
Definition: mesh.hpp:1381
FDualNumber< tbase > pow(const FDualNumber< tbase > &a, const FDualNumber< tbase > &b)
pow([dual number],[dual number])
Definition: fdual.hpp:543
List of mesh geometries stored as Array&lt;Geometry::Type&gt;.
Definition: mesh.hpp:1085
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:10424
This structure is used as a human readable output format that decipheres the information contained in...
Definition: mesh.hpp:1333
int CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition: mesh.cpp:5766
int SpaceDimension() const
Definition: mesh.hpp:1000
GeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, MemoryType d_mt=MemoryType::DEFAULT)
Definition: mesh.cpp:11935
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: tetrahedron.hpp:82
void PrintElementsWithPartitioning(int *partitioning, std::ostream &out, int interior_faces=0)
Definition: mesh.cpp:10971
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition: mesh.hpp:1257
static const int Edges[NumEdges][2]
Definition: geom.hpp:182
void AddPointFaceElement(int lf, int gf, int el)
Used in GenerateFaces()
Definition: mesh.cpp:6396
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:3505
double * Data() const
Returns the matrix data array.
Definition: densemat.hpp:111
virtual const int * DofOrderForOrientation(Geometry::Type GeomType, int Or) const =0
Returns an array, say p, that maps a local permuted index i to a local base index: base_i = p[i]...
void Swap(Array< T > &, Array< T > &)
Definition: array.hpp:630
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:270
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:9016
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:2871
static int CheckClosed(int type)
If the Quadrature1D type is not closed return Invalid; otherwise return type.
Definition: intrules.cpp:854
const NURBSExtension * GetNURBSext() const
Definition: fespace.hpp:435
Table * el_to_el
Definition: mesh.hpp:222
struct mfem::Mesh::FaceInformation::@3 element[2]
MPI_Comm GetComm() const
Definition: pmesh.hpp:288
int SpaceDimension() const
Return the space dimension of the NCMesh.
Definition: ncmesh.hpp:146
void Finalize()
Definition: table.cpp:239
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:88
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe_base.hpp:323
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition: globals.hpp:71
static Mesh LoadFromFile(const char *filename, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition: mesh.cpp:3683
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition: mesh.cpp:11600
static void PrintElement(const Element *, std::ostream &)
Definition: mesh.cpp:3895
virtual void NURBSUniformRefinement()
Refine NURBS mesh.
Definition: mesh.cpp:5082
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int attr=1)
Definition: mesh.cpp:1725
const IntegrationRule * IntRule
Definition: mesh.hpp:1823
MemoryType
Memory types supported by MFEM.
Definition: mem_manager.hpp:31
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:1893
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition: mesh.cpp:2878
static void GetElementArrayEdgeTable(const Array< Element * > &elem_array, const DSTable &v_to_v, Table &el_to_edge)
Definition: mesh.cpp:6256
void AddAColumnInRow(int r)
Definition: table.hpp:77
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition: mesh.hpp:1516
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:679
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
Definition: mesh.cpp:2469
int AddBdrQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1839
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:410
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition: eltrans.cpp:546
int FindRoots(const Vector &z, Vector &x)
Definition: mesh.cpp:7503
bool IsSlaveFace(const FaceInfo &fi) const
Definition: mesh.cpp:1050
Array< Vertex > vertices
Definition: mesh.hpp:90
int Push4(int r, int c, int f, int t)
Check to see if this entry is in the table and add it to the table if it is not there. The entry is addressed by the three smallest values of (r,c,f,t). Returns the number assigned to the table entry.
Definition: stable3d.cpp:140
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, double sx=1.0, double sy=1.0, bool sfc_ordering=true)
Definition: mesh.cpp:3701
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Definition: mesh.cpp:1578
void ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo, const std::string &xml_prefix="")
Helper struct for defining a connectivity table, see Table::MakeFromList.
Definition: table.hpp:27
Geometry::Type GetElementGeometry(int i) const
Definition: mesh.hpp:1048
void RefineAtVertex(const Vertex &vert, double eps=0.0, int nonconforming=-1)
Refine elements sharing the specified vertex. Uses GeneralRefinement.
Definition: mesh.cpp:9437
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:3693
Array< Element * > elements
Definition: mesh.hpp:85
const Table & ElementToElementTable()
Definition: mesh.cpp:6342
double GetLength(int i, int j) const
Return the length of the segment from node i to node j.
Definition: mesh.cpp:6241
void SetRelaxedHpConformity(bool relaxed=true)
Definition: fespace.hpp:915
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition: gridfunc.cpp:164
void ShiftUpI()
Definition: table.cpp:115
Linear2DFiniteElement TriangleFE
Definition: fe.cpp:32
int meshgen
Definition: mesh.hpp:77
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:228
const CoarseFineTransformations & GetRefinementTransforms()
Definition: mesh.cpp:9849
bool RefineByError(const Array< double > &elem_error, double threshold, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:9463
Table * bel_to_edge
Definition: mesh.hpp:224
Evaluate the values at quadrature points.
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition: mesh.hpp:1633
Table * GetFaceToElementTable() const
Definition: mesh.cpp:6083
int GetNE() const
Definition: nurbs.hpp:360
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
double a
Definition: lissajous.cpp:41
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:272
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:925
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:10416
void GetNode(int i, double *coord) const
Definition: mesh.cpp:7790
Array< int > be_to_edge
Definition: mesh.hpp:223
virtual const char * Name() const
Definition: fe_coll.hpp:61
const Table & ElementToFaceTable() const
Definition: mesh.cpp:6378
static const int Edges[NumEdges][2]
Definition: geom.hpp:260
Class for integration point with weight.
Definition: intrules.hpp:25
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
Element * ReadElementWithoutAttr(std::istream &)
Definition: mesh.cpp:3853
void Swap(Mesh &other, bool non_geometry)
Definition: mesh.cpp:9206
FaceGeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, FaceType type)
Definition: mesh.cpp:12015
int GetNumFacesWithGhost() const
Return the number of faces (3D), edges (2D) or vertices (1D) including ghost faces.
Definition: mesh.cpp:5356
A standard isoparametric element transformation.
Definition: eltrans.hpp:361
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Definition: mesh.cpp:5901
static const int vtk_quadratic_wedge[18]
Definition: mesh.hpp:245
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: mesh.cpp:348
static const int DimStart[MaxDim+2]
Definition: geom.hpp:48
const FiniteElementSpace * GetNodalFESpace() const
Definition: mesh.cpp:5307
class LinearWedgeFiniteElement WedgeFE
Definition: fe.cpp:40
virtual void Print(std::ostream &os=mfem::out) const
Definition: mesh.hpp:1646
Table * face_edge
Definition: mesh.hpp:226
void FinalizeQuadMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a quadrilateral Mesh.
Definition: mesh.cpp:1956
Array< int > leaf_elements
finest elements, in Mesh ordering (+ ghosts)
Definition: ncmesh.hpp:531
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
Definition: mesh.cpp:2971
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:193
bool DerefineByError(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
Definition: mesh.cpp:9133
Array< Master > masters
Definition: ncmesh.hpp:230
FDualNumber< tbase > sqrt(const FDualNumber< tbase > &f)
sqrt([dual number])
Definition: fdual.hpp:600
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
Definition: mesh.cpp:5955
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3066
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition: fespace.cpp:1329
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition: fespace.hpp:66
const char * VTKByteOrder()
Determine the byte order and return either &quot;BigEndian&quot; or &quot;LittleEndian&quot;.
Definition: vtk.cpp:590
void MakeJ()
Definition: table.cpp:91
void DegreeElevate(int rel_degree, int degree=16)
Definition: mesh.cpp:5095
int dim
Definition: ex24.cpp:53
Table * edge_vertex
Definition: mesh.hpp:227
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition: eltrans.hpp:381
long sequence
Definition: mesh.hpp:83
signed char geom
Geometry::Type (faces only) (char to save RAM)
Definition: ncmesh.hpp:192
void FindTMax(Vector &c, Vector &x, double &tmax, const double factor, const int Dim)
Definition: mesh.cpp:7650
IsoparametricTransformation Transf
Definition: eltrans.hpp:464
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th element in t...
Definition: fespace.cpp:2783
int index(int i, int j, int nx, int ny)
Definition: life.cpp:237
ElementTransformation * Elem1
Definition: eltrans.hpp:522
static const int Edges[NumEdges][2]
Definition: geom.hpp:224
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
Definition: densemat.cpp:1207
const Mesh * mesh
Definition: mesh.hpp:1822
void MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
Definition: mesh.cpp:4557
Lexicographic ordering for tensor-product FiniteElements.
Array< FaceInfo > faces_info
Definition: mesh.hpp:217
double infinity()
Define a shortcut for std::numeric_limits&lt;double&gt;::infinity()
Definition: vector.hpp:46
virtual int GetNVertices() const =0
int parent
Coarse Element index in the coarse mesh.
Definition: ncmesh.hpp:52
void SetAttribute(const int attr)
Set element&#39;s attribute.
Definition: element.hpp:58
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Definition: gridfunc.cpp:2395
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:215
STable3D * GetFacesTable()
Definition: mesh.cpp:6682
Piecewise-(bi)quadratic continuous finite elements.
Definition: fe_coll.hpp:687
int Dimension() const
Return the dimension of the NCMesh.
Definition: ncmesh.hpp:144
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
Definition: sparsemat.hpp:680
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition: mesh.hpp:273
Geometry::Type GetBdrElementBaseGeometry(int i) const
Definition: mesh.hpp:1065
virtual void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level)
Definition: ncmesh.cpp:1820
virtual void UniformRefinement3D()
Refine a mixed 3D mesh uniformly.
Definition: mesh.hpp:402
int AddBdrElement(Element *elem)
Definition: mesh.cpp:1804
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:3871
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr=1)
Definition: mesh.cpp:1697
BlockArray< Element > elements
Definition: ncmesh.hpp:502
virtual bool NonconformingDerefinement(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
NC version of GeneralDerefinement.
Definition: mesh.cpp:9085
int Dim
Definition: mesh.hpp:66
void Clear()
Clear the contents of the Mesh.
Definition: mesh.hpp:904
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:934
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:45
ElementConformity conformity
Definition: mesh.hpp:1340
double AggregateError(const Array< double > &elem_error, const int *fine, int nfine, int op)
Derefinement helper.
Definition: mesh.cpp:9066
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:937
BiLinear2DFiniteElement QuadrilateralFE
virtual int FindPoints(DenseMatrix &point_mat, Array< int > &elem_ids, Array< IntegrationPoint > &ips, bool warn=true, InverseElementTransformation *inv_trans=NULL)
Find the ids of the elements that contain the given points, and their corresponding reference coordin...
Definition: mesh.cpp:11820
Mesh & operator=(Mesh &&mesh)
Move assignment operstor.
Definition: mesh.cpp:3677
virtual void PrintXG(std::ostream &os=mfem::out) const
Print the mesh to the given stream using Netgen/Truegrid format.
Definition: mesh.cpp:9912
Evaluate the derivatives at quadrature points.
Vector data type.
Definition: vector.hpp:60
Data type point element.
Definition: point.hpp:22
void ReadTrueGridMesh(std::istream &input)
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:577
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:7841
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:5361
int NumberOfEntries() const
Definition: table.hpp:240
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:5537
void SetNode(int i, const double *coord)
Definition: mesh.cpp:7809
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:489
int * GetI()
Definition: table.hpp:113
int GetId(int p1, int p2)
Get id of item whose parents are p1, p2... Create it if it doesn&#39;t exist.
Definition: hash.hpp:608
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:216
void XYZ_VectorFunction(const Vector &p, Vector &v)
Definition: mesh.cpp:5236
void GenerateFaces()
Definition: mesh.cpp:6520
void GetElementColoring(Array< int > &colors, int el0=0)
Definition: mesh.cpp:10777
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:3763
int spaceDim
Definition: mesh.hpp:67
Defines the coarse-fine transformations of all fine elements.
Definition: ncmesh.hpp:70
RefCoord s[3]
const std::string filename
Definition: zstr.hpp:805
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Definition: ncmesh.hpp:260
MemAlloc< Tetrahedron, 1024 > TetMemory
Definition: mesh.hpp:250
int GetNBE() const
Definition: nurbs.hpp:362
Table * GetFaceEdgeTable() const
Returns the face-to-edge Table (3D)
Definition: mesh.cpp:5994
bool IsGhost(const Element &el) const
Return true if the Element el is a ghost element.
Definition: ncmesh.hpp:593
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag)
Definition: tetrahedron.cpp:55
Node::Index insert_node(Float length=1)
Definition: gecko.cpp:657
TriLinear3DFiniteElement HexahedronFE
Definition: hexahedron.cpp:52
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
Definition: mesh.cpp:2535
void SetNodes(const Vector &node_coord)
Definition: mesh.cpp:7853
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
int RowSize(int i) const
Definition: table.hpp:108
friend class ParNCMesh
Definition: mesh.hpp:56
void SetNodalGridFunction(GridFunction *nodes, bool make_owner=false)
Definition: mesh.cpp:5301
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:70
void ScaleSubdomains(double sf)
Definition: mesh.cpp:11411
Array< int > be_to_face
Definition: mesh.hpp:225
void DegreeElevate(int rel_degree, int degree=16)
Definition: nurbs.cpp:3089
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
Definition: mesh.cpp:9162
int NumberOfRows() const
Definition: table.hpp:239
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:9492
int FindId(int p1, int p2) const
Find id of item whose parents are p1, p2... Return -1 if it doesn&#39;t exist.
Definition: hash.hpp:699
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition: eltrans.hpp:404
virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const =0
Evaluate the gradients of all shape functions of a scalar finite element in reference space at the gi...
int index
Mesh number.
Definition: ncmesh.hpp:189
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:9326
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:786
ElementLocation location
Definition: mesh.hpp:1339
Class for parallel meshes.
Definition: pmesh.hpp:32
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:379
Abstract data type element.
Definition: element.hpp:28
int GetAttribute(int i) const
Return the attribute of element i.
Definition: mesh.hpp:1455
void AddTriangleFaceElement(int lf, int gf, int el, int v0, int v1, int v2)
Definition: mesh.cpp:6465
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:642
const Table & ElementToEdgeTable() const
Definition: mesh.cpp:6387
Data type line segment element.
Definition: segment.hpp:22
Linear1DFiniteElement SegmentFE
Definition: segment.cpp:49
Array< GeometricFactors * > geom_factors
Optional geometric factors.
Definition: mesh.hpp:274
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition: fespace.hpp:584
void BdrBisection(int i, const HashTable< Hashed2 > &)
Bisect a boundary triangle: boundary element with index i is bisected.
Definition: mesh.cpp:9700
MPI_Comm GetGlobalMPI_Comm()
Get MFEM&#39;s &quot;global&quot; MPI communicator.
Definition: globals.cpp:62
void GetBdrElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of boundary element i.
Definition: mesh.hpp:1106
int NumberOfElements()
Return the number of elements added to the table.
Definition: stable3d.hpp:70
void GenerateNCFaceInfo()
Definition: mesh.cpp:6621
Array< int > RefGeoms
Definition: geom.hpp:283
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition: mesh.hpp:1102
friend class Tetrahedron
Definition: mesh.hpp:249
virtual Type GetType() const =0
Returns element&#39;s type.
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition: mesh.hpp:268
class Mesh * mesh
The Mesh object containing the element.
Definition: eltrans.hpp:84
Table * GetVertexToElementTable()
The returned Table must be destroyed by the caller.
Definition: mesh.cpp:6048
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:1037
void EnsureNodes()
Definition: mesh.cpp:5279
void ConvertToPatches(const Vector &Nodes)
Definition: nurbs.cpp:2955
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:172
void GetElementData(const Array< Element * > &elem_array, int geom, Array< int > &elem_vtx, Array< int > &attr) const
Definition: mesh.cpp:9262
const DenseMatrix * point_matrix
Definition: mesh.hpp:1348
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
Definition: triangle.cpp:126
void UpdateNodes()
Update the nodes of a curved mesh after refinement.
Definition: mesh.cpp:7915
Defines the position of a fine element within a coarse element.
Definition: ncmesh.hpp:49
void KnotInsert(Array< KnotVector * > &kv)
Definition: nurbs.cpp:3113
int idx_t
Definition: mesh.cpp:43
void Print(std::ostream &out) const
Definition: nurbs.cpp:1701
virtual void Refine(const Array< Refinement > &refinements)
Definition: ncmesh.cpp:1524
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
Definition: mesh.cpp:6117
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:360
Arbitrary order &quot;L2-conforming&quot; discontinuous finite elements.
Definition: fe_coll.hpp:284
Evaluate the values at quadrature points.
double f(const Vector &p)
void Printer(std::ostream &out=mfem::out, std::string section_delimiter="") const
Definition: mesh.cpp:10076
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:264
Class used to extrude the nodes of a mesh.
Definition: mesh.hpp:1919
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:215
const FaceQuadratureInterpolator * GetFaceQuadratureInterpolator(const IntegrationRule &ir, FaceType type) const
Return a FaceQuadratureInterpolator that interpolates E-vectors to quadrature point values and/or der...
Definition: fespace.cpp:1358
int NumOfFaces
Definition: mesh.hpp:70