MFEM  v4.3.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-2021, 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(Dim);
79 
81  T->SetIntPoint(&Geometries.GetCenter(geom));
82  Geometries.JacToPerfJac(geom, T->Jacobian(), J);
83 
84  if (type == 0)
85  {
86  return pow(fabs(J.Det()), 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(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 &out)
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) { out << " + "; }
237  else { first = 0; }
238  out << num_elems_by_geom[g] << ' ' << Geometry::Name[g] << "(s)";
239  }
240 }
241 
242 void Mesh::PrintCharacteristics(Vector *Vh, Vector *Vk, std::ostream &out)
243 {
244  double h_min, h_max, kappa_min, kappa_max;
245 
246  out << "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  out << '\n'
258  << "Dimension : " << Dimension() << '\n'
259  << "Space dimension : " << SpaceDimension();
260  if (Dim == 0)
261  {
262  out << '\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  out << '\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  out << '\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, out);
283  out << '\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  out << '\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, out);
311  out << '\n'
312  << "Number of elements : " << GetNE() << " -- ";
313  PrintElementsByGeometry(Dim, num_elems_by_geom, out);
314  out << '\n'
315  << "Number of bdr elem : " << GetNBE() << " -- ";
316  PrintElementsByGeometry(Dim-1, num_bdr_elems_by_geom, out);
317  out << '\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  out << '\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  default:
339  MFEM_ABORT("Unknown element type \"" << ElemType << "\"");
340  break;
341  }
342  MFEM_ABORT("Unknown element type");
343  return NULL;
344 }
345 
346 
347 void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr)
348 {
349  ElTr->Attribute = GetAttribute(i);
350  ElTr->ElementNo = i;
351  ElTr->ElementType = ElementTransformation::ELEMENT;
352  ElTr->Reset();
353  if (Nodes == NULL)
354  {
355  GetPointMatrix(i, ElTr->GetPointMat());
356  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
357  }
358  else
359  {
360  DenseMatrix &pm = ElTr->GetPointMat();
361  Array<int> vdofs;
362  Nodes->FESpace()->GetElementVDofs(i, vdofs);
363  Nodes->HostRead();
364  const GridFunction &nodes = *Nodes;
365  int n = vdofs.Size()/spaceDim;
366  pm.SetSize(spaceDim, n);
367  for (int k = 0; k < spaceDim; k++)
368  {
369  for (int j = 0; j < n; j++)
370  {
371  pm(k,j) = nodes(vdofs[n*k+j]);
372  }
373  }
374  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
375  }
376 }
377 
378 void Mesh::GetElementTransformation(int i, const Vector &nodes,
380 {
381  ElTr->Attribute = GetAttribute(i);
382  ElTr->ElementNo = i;
383  ElTr->ElementType = ElementTransformation::ELEMENT;
384  DenseMatrix &pm = ElTr->GetPointMat();
385  ElTr->Reset();
386  nodes.HostRead();
387  if (Nodes == NULL)
388  {
389  MFEM_ASSERT(nodes.Size() == spaceDim*GetNV(), "");
390  int nv = elements[i]->GetNVertices();
391  const int *v = elements[i]->GetVertices();
392  int n = vertices.Size();
393  pm.SetSize(spaceDim, nv);
394  for (int k = 0; k < spaceDim; k++)
395  {
396  for (int j = 0; j < nv; j++)
397  {
398  pm(k, j) = nodes(k*n+v[j]);
399  }
400  }
401  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
402  }
403  else
404  {
405  MFEM_ASSERT(nodes.Size() == Nodes->Size(), "");
406  Array<int> vdofs;
407  Nodes->FESpace()->GetElementVDofs(i, vdofs);
408  int n = vdofs.Size()/spaceDim;
409  pm.SetSize(spaceDim, n);
410  for (int k = 0; k < spaceDim; k++)
411  {
412  for (int j = 0; j < n; j++)
413  {
414  pm(k,j) = nodes(vdofs[n*k+j]);
415  }
416  }
417  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
418  }
419 }
420 
421 ElementTransformation *Mesh::GetElementTransformation(int i)
422 {
423  GetElementTransformation(i, &Transformation);
424 
425  return &Transformation;
426 }
427 
428 ElementTransformation *Mesh::GetBdrElementTransformation(int i)
429 {
430  GetBdrElementTransformation(i, &BdrTransformation);
431  return &BdrTransformation;
432 }
433 
434 void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr)
435 {
436  ElTr->Attribute = GetBdrAttribute(i);
437  ElTr->ElementNo = i; // boundary element number
438  ElTr->ElementType = ElementTransformation::BDR_ELEMENT;
439  DenseMatrix &pm = ElTr->GetPointMat();
440  ElTr->Reset();
441  if (Nodes == NULL)
442  {
443  GetBdrPointMatrix(i, pm);
444  ElTr->SetFE(GetTransformationFEforElementType(GetBdrElementType(i)));
445  }
446  else
447  {
448  const FiniteElement *bdr_el = Nodes->FESpace()->GetBE(i);
449  Nodes->HostRead();
450  const GridFunction &nodes = *Nodes;
451  if (bdr_el)
452  {
453  Array<int> vdofs;
454  Nodes->FESpace()->GetBdrElementVDofs(i, vdofs);
455  int n = vdofs.Size()/spaceDim;
456  pm.SetSize(spaceDim, n);
457  for (int k = 0; k < spaceDim; k++)
458  {
459  for (int j = 0; j < n; j++)
460  {
461  pm(k,j) = nodes(vdofs[n*k+j]);
462  }
463  }
464  ElTr->SetFE(bdr_el);
465  }
466  else // L2 Nodes (e.g., periodic mesh)
467  {
468  int elem_id, face_info;
469  GetBdrElementAdjacentElement(i, elem_id, face_info);
470 
471  GetLocalFaceTransformation(GetBdrElementType(i),
472  GetElementType(elem_id),
473  FaceElemTr.Loc1.Transf, face_info);
474  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
475 
476  Geometry::Type face_geom = GetBdrElementBaseGeometry(i);
477  const FiniteElement *face_el =
478  Nodes->FESpace()->GetTraceElement(elem_id, face_geom);
479  MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
480  "Mesh requires nodal Finite Element.");
481  IntegrationRule eir(face_el->GetDof());
482  FaceElemTr.Loc1.Transf.ElementNo = elem_id;
483  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
484  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
485  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
486 
487  ElTr->SetFE(face_el);
488  }
489  }
490 }
491 
492 void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr)
493 {
494  FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute();
495  FTr->ElementNo = FaceNo;
496  FTr->ElementType = ElementTransformation::FACE;
497  DenseMatrix &pm = FTr->GetPointMat();
498  FTr->Reset();
499  if (Nodes == NULL)
500  {
501  const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
502  const int nv = (Dim == 1) ? 1 : faces[FaceNo]->GetNVertices();
503  pm.SetSize(spaceDim, nv);
504  for (int i = 0; i < spaceDim; i++)
505  {
506  for (int j = 0; j < nv; j++)
507  {
508  pm(i, j) = vertices[v[j]](i);
509  }
510  }
511  FTr->SetFE(GetTransformationFEforElementType(GetFaceElementType(FaceNo)));
512  }
513  else // curved mesh
514  {
515  const FiniteElement *face_el = Nodes->FESpace()->GetFaceElement(FaceNo);
516  Nodes->HostRead();
517  const GridFunction &nodes = *Nodes;
518  if (face_el)
519  {
520  Array<int> vdofs;
521  Nodes->FESpace()->GetFaceVDofs(FaceNo, vdofs);
522  int n = vdofs.Size()/spaceDim;
523  pm.SetSize(spaceDim, n);
524  for (int i = 0; i < spaceDim; i++)
525  {
526  for (int j = 0; j < n; j++)
527  {
528  pm(i, j) = nodes(vdofs[n*i+j]);
529  }
530  }
531  FTr->SetFE(face_el);
532  }
533  else // L2 Nodes (e.g., periodic mesh), go through the volume of Elem1
534  {
535  FaceInfo &face_info = faces_info[FaceNo];
536 
537  Geometry::Type face_geom = GetFaceGeometryType(FaceNo);
538  Element::Type face_type = GetFaceElementType(FaceNo);
539 
540  GetLocalFaceTransformation(face_type,
541  GetElementType(face_info.Elem1No),
542  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
543  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
544 
545  face_el = Nodes->FESpace()->GetTraceElement(face_info.Elem1No,
546  face_geom);
547  MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
548  "Mesh requires nodal Finite Element.");
549 
550  IntegrationRule eir(face_el->GetDof());
551  FaceElemTr.Loc1.Transf.ElementNo = face_info.Elem1No;
552  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
553  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
554  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
555 
556  FTr->SetFE(face_el);
557  }
558  }
559 }
560 
561 ElementTransformation *Mesh::GetFaceTransformation(int FaceNo)
562 {
563  GetFaceTransformation(FaceNo, &FaceTransformation);
564  return &FaceTransformation;
565 }
566 
567 void Mesh::GetEdgeTransformation(int EdgeNo, IsoparametricTransformation *EdTr)
568 {
569  if (Dim == 2)
570  {
571  GetFaceTransformation(EdgeNo, EdTr);
572  return;
573  }
574  if (Dim == 1)
575  {
576  mfem_error("Mesh::GetEdgeTransformation not defined in 1D \n");
577  }
578 
579  EdTr->Attribute = 1;
580  EdTr->ElementNo = EdgeNo;
581  EdTr->ElementType = ElementTransformation::EDGE;
582  DenseMatrix &pm = EdTr->GetPointMat();
583  EdTr->Reset();
584  if (Nodes == NULL)
585  {
586  Array<int> v;
587  GetEdgeVertices(EdgeNo, v);
588  const int nv = 2;
589  pm.SetSize(spaceDim, nv);
590  for (int i = 0; i < spaceDim; i++)
591  {
592  for (int j = 0; j < nv; j++)
593  {
594  pm(i, j) = vertices[v[j]](i);
595  }
596  }
597  EdTr->SetFE(GetTransformationFEforElementType(Element::SEGMENT));
598  }
599  else
600  {
601  const FiniteElement *edge_el = Nodes->FESpace()->GetEdgeElement(EdgeNo);
602  Nodes->HostRead();
603  const GridFunction &nodes = *Nodes;
604  if (edge_el)
605  {
606  Array<int> vdofs;
607  Nodes->FESpace()->GetEdgeVDofs(EdgeNo, vdofs);
608  int n = vdofs.Size()/spaceDim;
609  pm.SetSize(spaceDim, n);
610  for (int i = 0; i < spaceDim; i++)
611  {
612  for (int j = 0; j < n; j++)
613  {
614  pm(i, j) = nodes(vdofs[n*i+j]);
615  }
616  }
617  EdTr->SetFE(edge_el);
618  }
619  else
620  {
621  MFEM_ABORT("Not implemented.");
622  }
623  }
624 }
625 
626 ElementTransformation *Mesh::GetEdgeTransformation(int EdgeNo)
627 {
628  GetEdgeTransformation(EdgeNo, &EdgeTransformation);
629  return &EdgeTransformation;
630 }
631 
632 
633 void Mesh::GetLocalPtToSegTransformation(
634  IsoparametricTransformation &Transf, int i)
635 {
636  const IntegrationRule *SegVert;
637  DenseMatrix &locpm = Transf.GetPointMat();
638  Transf.Reset();
639 
640  Transf.SetFE(&PointFE);
641  SegVert = Geometries.GetVertices(Geometry::SEGMENT);
642  locpm.SetSize(1, 1);
643  locpm(0, 0) = SegVert->IntPoint(i/64).x;
644  // (i/64) is the local face no. in the segment
645  // (i%64) is the orientation of the point (not used)
646 }
647 
648 void Mesh::GetLocalSegToTriTransformation(
649  IsoparametricTransformation &Transf, int i)
650 {
651  const int *tv, *so;
652  const IntegrationRule *TriVert;
653  DenseMatrix &locpm = Transf.GetPointMat();
654  Transf.Reset();
655 
656  Transf.SetFE(&SegmentFE);
657  tv = tri_t::Edges[i/64]; // (i/64) is the local face no. in the triangle
658  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
659  TriVert = Geometries.GetVertices(Geometry::TRIANGLE);
660  locpm.SetSize(2, 2);
661  for (int j = 0; j < 2; j++)
662  {
663  locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x;
664  locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y;
665  }
666 }
667 
668 void Mesh::GetLocalSegToQuadTransformation(
669  IsoparametricTransformation &Transf, int i)
670 {
671  const int *qv, *so;
672  const IntegrationRule *QuadVert;
673  DenseMatrix &locpm = Transf.GetPointMat();
674  Transf.Reset();
675 
676  Transf.SetFE(&SegmentFE);
677  qv = quad_t::Edges[i/64]; // (i/64) is the local face no. in the quad
678  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
679  QuadVert = Geometries.GetVertices(Geometry::SQUARE);
680  locpm.SetSize(2, 2);
681  for (int j = 0; j < 2; j++)
682  {
683  locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x;
684  locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y;
685  }
686 }
687 
688 void Mesh::GetLocalTriToTetTransformation(
689  IsoparametricTransformation &Transf, int i)
690 {
691  DenseMatrix &locpm = Transf.GetPointMat();
692  Transf.Reset();
693 
694  Transf.SetFE(&TriangleFE);
695  // (i/64) is the local face no. in the tet
696  const int *tv = tet_t::FaceVert[i/64];
697  // (i%64) is the orientation of the tetrahedron face
698  // w.r.t. the face element
699  const int *to = tri_t::Orient[i%64];
700  const IntegrationRule *TetVert =
701  Geometries.GetVertices(Geometry::TETRAHEDRON);
702  locpm.SetSize(3, 3);
703  for (int j = 0; j < 3; j++)
704  {
705  const IntegrationPoint &vert = TetVert->IntPoint(tv[to[j]]);
706  locpm(0, j) = vert.x;
707  locpm(1, j) = vert.y;
708  locpm(2, j) = vert.z;
709  }
710 }
711 
712 void Mesh::GetLocalTriToWdgTransformation(
713  IsoparametricTransformation &Transf, int i)
714 {
715  DenseMatrix &locpm = Transf.GetPointMat();
716  Transf.Reset();
717 
718  Transf.SetFE(&TriangleFE);
719  // (i/64) is the local face no. in the pri
720  MFEM_VERIFY(i < 128, "Local face index " << i/64
721  << " is not a triangular face of a wedge.");
722  const int *pv = pri_t::FaceVert[i/64];
723  // (i%64) is the orientation of the wedge face
724  // w.r.t. the face element
725  const int *to = tri_t::Orient[i%64];
726  const IntegrationRule *PriVert =
727  Geometries.GetVertices(Geometry::PRISM);
728  locpm.SetSize(3, 3);
729  for (int j = 0; j < 3; j++)
730  {
731  const IntegrationPoint &vert = PriVert->IntPoint(pv[to[j]]);
732  locpm(0, j) = vert.x;
733  locpm(1, j) = vert.y;
734  locpm(2, j) = vert.z;
735  }
736 }
737 
738 void Mesh::GetLocalQuadToHexTransformation(
739  IsoparametricTransformation &Transf, int i)
740 {
741  DenseMatrix &locpm = Transf.GetPointMat();
742  Transf.Reset();
743 
744  Transf.SetFE(&QuadrilateralFE);
745  // (i/64) is the local face no. in the hex
746  const int *hv = hex_t::FaceVert[i/64];
747  // (i%64) is the orientation of the quad
748  const int *qo = quad_t::Orient[i%64];
749  const IntegrationRule *HexVert = Geometries.GetVertices(Geometry::CUBE);
750  locpm.SetSize(3, 4);
751  for (int j = 0; j < 4; j++)
752  {
753  const IntegrationPoint &vert = HexVert->IntPoint(hv[qo[j]]);
754  locpm(0, j) = vert.x;
755  locpm(1, j) = vert.y;
756  locpm(2, j) = vert.z;
757  }
758 }
759 
760 void Mesh::GetLocalQuadToWdgTransformation(
761  IsoparametricTransformation &Transf, int i)
762 {
763  DenseMatrix &locpm = Transf.GetPointMat();
764  Transf.Reset();
765 
766  Transf.SetFE(&QuadrilateralFE);
767  // (i/64) is the local face no. in the pri
768  MFEM_VERIFY(i >= 128, "Local face index " << i/64
769  << " is not a quadrilateral face of a wedge.");
770  const int *pv = pri_t::FaceVert[i/64];
771  // (i%64) is the orientation of the quad
772  const int *qo = quad_t::Orient[i%64];
773  const IntegrationRule *PriVert = Geometries.GetVertices(Geometry::PRISM);
774  locpm.SetSize(3, 4);
775  for (int j = 0; j < 4; j++)
776  {
777  const IntegrationPoint &vert = PriVert->IntPoint(pv[qo[j]]);
778  locpm(0, j) = vert.x;
779  locpm(1, j) = vert.y;
780  locpm(2, j) = vert.z;
781  }
782 }
783 
784 const GeometricFactors* Mesh::GetGeometricFactors(const IntegrationRule& ir,
785  const int flags,
786  MemoryType d_mt)
787 {
788  for (int i = 0; i < geom_factors.Size(); i++)
789  {
790  GeometricFactors *gf = geom_factors[i];
791  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags)
792  {
793  return gf;
794  }
795  }
796 
797  this->EnsureNodes();
798 
799  GeometricFactors *gf = new GeometricFactors(this, ir, flags, d_mt);
800  geom_factors.Append(gf);
801  return gf;
802 }
803 
804 const FaceGeometricFactors* Mesh::GetFaceGeometricFactors(
805  const IntegrationRule& ir,
806  const int flags, FaceType type)
807 {
808  for (int i = 0; i < face_geom_factors.Size(); i++)
809  {
810  FaceGeometricFactors *gf = face_geom_factors[i];
811  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags &&
812  gf->type==type)
813  {
814  return gf;
815  }
816  }
817 
818  this->EnsureNodes();
819 
820  FaceGeometricFactors *gf = new FaceGeometricFactors(this, ir, flags, type);
821  face_geom_factors.Append(gf);
822  return gf;
823 }
824 
825 void Mesh::DeleteGeometricFactors()
826 {
827  for (int i = 0; i < geom_factors.Size(); i++)
828  {
829  delete geom_factors[i];
830  }
831  geom_factors.SetSize(0);
832  for (int i = 0; i < face_geom_factors.Size(); i++)
833  {
834  delete face_geom_factors[i];
835  }
836  face_geom_factors.SetSize(0);
837 }
838 
839 void Mesh::GetLocalFaceTransformation(
840  int face_type, int elem_type, IsoparametricTransformation &Transf, int info)
841 {
842  switch (face_type)
843  {
844  case Element::POINT:
845  GetLocalPtToSegTransformation(Transf, info);
846  break;
847 
848  case Element::SEGMENT:
849  if (elem_type == Element::TRIANGLE)
850  {
851  GetLocalSegToTriTransformation(Transf, info);
852  }
853  else
854  {
855  MFEM_ASSERT(elem_type == Element::QUADRILATERAL, "");
856  GetLocalSegToQuadTransformation(Transf, info);
857  }
858  break;
859 
860  case Element::TRIANGLE:
861  if (elem_type == Element::TETRAHEDRON)
862  {
863  GetLocalTriToTetTransformation(Transf, info);
864  }
865  else
866  {
867  MFEM_ASSERT(elem_type == Element::WEDGE, "");
868  GetLocalTriToWdgTransformation(Transf, info);
869  }
870  break;
871 
872  case Element::QUADRILATERAL:
873  if (elem_type == Element::HEXAHEDRON)
874  {
875  GetLocalQuadToHexTransformation(Transf, info);
876  }
877  else
878  {
879  MFEM_ASSERT(elem_type == Element::WEDGE, "");
880  GetLocalQuadToWdgTransformation(Transf, info);
881  }
882  break;
883  }
884 }
885 
886 FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo,
887  int mask)
888 {
889  FaceInfo &face_info = faces_info[FaceNo];
890 
891  int cmask = 0;
892  FaceElemTr.SetConfigurationMask(cmask);
893  FaceElemTr.Elem1 = NULL;
894  FaceElemTr.Elem2 = NULL;
895 
896  // setup the transformation for the first element
897  FaceElemTr.Elem1No = face_info.Elem1No;
898  if (mask & FaceElementTransformations::HAVE_ELEM1)
899  {
900  GetElementTransformation(FaceElemTr.Elem1No, &Transformation);
901  FaceElemTr.Elem1 = &Transformation;
902  cmask |= 1;
903  }
904 
905  // setup the transformation for the second element
906  // return NULL in the Elem2 field if there's no second element, i.e.
907  // the face is on the "boundary"
908  FaceElemTr.Elem2No = face_info.Elem2No;
909  if ((mask & FaceElementTransformations::HAVE_ELEM2) &&
910  FaceElemTr.Elem2No >= 0)
911  {
912 #ifdef MFEM_DEBUG
913  if (NURBSext && (mask & FaceElementTransformations::HAVE_ELEM1))
914  { MFEM_ABORT("NURBS mesh not supported!"); }
915 #endif
916  GetElementTransformation(FaceElemTr.Elem2No, &Transformation2);
917  FaceElemTr.Elem2 = &Transformation2;
918  cmask |= 2;
919  }
920 
921  // setup the face transformation
922  if (mask & FaceElementTransformations::HAVE_FACE)
923  {
924  GetFaceTransformation(FaceNo, &FaceElemTr);
925  cmask |= 16;
926  }
927  else
928  {
929  FaceElemTr.SetGeometryType(GetFaceGeometryType(FaceNo));
930  }
931 
932  // setup Loc1 & Loc2
933  int face_type = GetFaceElementType(FaceNo);
934  if (mask & FaceElementTransformations::HAVE_LOC1)
935  {
936  int elem_type = GetElementType(face_info.Elem1No);
937  GetLocalFaceTransformation(face_type, elem_type,
938  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
939  cmask |= 4;
940  }
941  if ((mask & FaceElementTransformations::HAVE_LOC2) &&
942  FaceElemTr.Elem2No >= 0)
943  {
944  int elem_type = GetElementType(face_info.Elem2No);
945  GetLocalFaceTransformation(face_type, elem_type,
946  FaceElemTr.Loc2.Transf, face_info.Elem2Inf);
947 
948  // NC meshes: prepend slave edge/face transformation to Loc2
949  if (Nonconforming() && IsSlaveFace(face_info))
950  {
951  ApplyLocalSlaveTransformation(FaceElemTr, face_info, false);
952  }
953  cmask |= 8;
954  }
955 
956  FaceElemTr.SetConfigurationMask(cmask);
957 
958  // This check can be useful for internal debugging, however it will fail on
959  // periodic boundary faces, so we keep it disabled in general.
960 #if 0
961 #ifdef MFEM_DEBUG
962  double dist = FaceElemTr.CheckConsistency();
963  if (dist >= 1e-12)
964  {
965  mfem::out << "\nInternal error: face id = " << FaceNo
966  << ", dist = " << dist << '\n';
967  FaceElemTr.CheckConsistency(1); // print coordinates
968  MFEM_ABORT("internal error");
969  }
970 #endif
971 #endif
972 
973  return &FaceElemTr;
974 }
975 
976 bool Mesh::IsSlaveFace(const FaceInfo &fi) const
977 {
978  return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
979 }
980 
981 void Mesh::ApplyLocalSlaveTransformation(FaceElementTransformations &FT,
982  const FaceInfo &fi, bool is_ghost)
983 {
984 #ifdef MFEM_THREAD_SAFE
985  DenseMatrix composition;
986 #else
987  static DenseMatrix composition;
988 #endif
989  MFEM_ASSERT(fi.NCFace >= 0, "");
990  MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error");
991  if (!is_ghost)
992  {
993  // side 1 -> child side, side 2 -> parent side
995  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
996  // In 2D, we need to flip the point matrix since it is aligned with the
997  // parent side.
998  if (Dim == 2)
999  {
1000  // swap points (columns) 0 and 1
1001  std::swap(composition(0,0), composition(0,1));
1002  std::swap(composition(1,0), composition(1,1));
1003  }
1004  LT.SetPointMat(composition);
1005  }
1006  else // is_ghost == true
1007  {
1008  // side 1 -> parent side, side 2 -> child side
1010  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1011  // In 2D, there is no need to flip the point matrix since it is already
1012  // aligned with the parent side, see also ParNCMesh::GetFaceNeighbors.
1013  // In 3D the point matrix was flipped during construction in
1014  // ParNCMesh::GetFaceNeighbors and due to that it is already aligned with
1015  // the parent side.
1016  LT.SetPointMat(composition);
1017  }
1018 }
1019 
1020 FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
1021 {
1023  int fn = GetBdrFace(BdrElemNo);
1024 
1025  // Check if the face is interior, shared, or non-conforming.
1026  if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
1027  {
1028  return NULL;
1029  }
1030  tr = GetFaceElementTransformations(fn, 21);
1031  tr->Attribute = boundary[BdrElemNo]->GetAttribute();
1032  tr->ElementNo = BdrElemNo;
1033  tr->ElementType = ElementTransformation::BDR_FACE;
1034  return tr;
1035 }
1036 
1037 int Mesh::GetBdrFace(int BdrElemNo) const
1038 {
1039  int fn;
1040  if (Dim == 3)
1041  {
1042  fn = be_to_face[BdrElemNo];
1043  }
1044  else if (Dim == 2)
1045  {
1046  fn = be_to_edge[BdrElemNo];
1047  }
1048  else
1049  {
1050  fn = boundary[BdrElemNo]->GetVertices()[0];
1051  }
1052  return fn;
1053 }
1054 
1055 void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2) const
1056 {
1057  *Elem1 = faces_info[Face].Elem1No;
1058  *Elem2 = faces_info[Face].Elem2No;
1059 }
1060 
1061 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const
1062 {
1063  *Inf1 = faces_info[Face].Elem1Inf;
1064  *Inf2 = faces_info[Face].Elem2Inf;
1065 }
1066 
1067 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2, int *NCFace) const
1068 {
1069  *Inf1 = faces_info[Face].Elem1Inf;
1070  *Inf2 = faces_info[Face].Elem2Inf;
1071  *NCFace = faces_info[Face].NCFace;
1072 }
1073 
1074 Geometry::Type Mesh::GetFaceGeometryType(int Face) const
1075 {
1076  switch (Dim)
1077  {
1078  case 1: return Geometry::POINT;
1079  case 2: return Geometry::SEGMENT;
1080  case 3:
1081  if (Face < NumOfFaces) // local (non-ghost) face
1082  {
1083  return faces[Face]->GetGeometryType();
1084  }
1085  // ghost face
1086  const int nc_face_id = faces_info[Face].NCFace;
1087  MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported");
1088  return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType();
1089  }
1090  return Geometry::INVALID;
1091 }
1092 
1093 Element::Type Mesh::GetFaceElementType(int Face) const
1094 {
1095  return (Dim == 1) ? Element::POINT : faces[Face]->GetType();
1096 }
1097 
1098 void Mesh::Init()
1099 {
1100  // in order of declaration:
1101  Dim = spaceDim = 0;
1102  NumOfVertices = -1;
1103  NumOfElements = NumOfBdrElements = 0;
1104  NumOfEdges = NumOfFaces = 0;
1105  nbInteriorFaces = -1;
1106  nbBoundaryFaces = -1;
1107  meshgen = mesh_geoms = 0;
1108  sequence = 0;
1109  Nodes = NULL;
1110  own_nodes = 1;
1111  NURBSext = NULL;
1112  ncmesh = NULL;
1113  last_operation = Mesh::NONE;
1114 }
1115 
1116 void Mesh::InitTables()
1117 {
1118  el_to_edge =
1119  el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
1120 }
1121 
1122 void Mesh::SetEmpty()
1123 {
1124  Init();
1125  InitTables();
1126 }
1127 
1128 void Mesh::DestroyTables()
1129 {
1130  delete el_to_edge;
1131  delete el_to_face;
1132  delete el_to_el;
1133  DeleteGeometricFactors();
1134 
1135  if (Dim == 3)
1136  {
1137  delete bel_to_edge;
1138  }
1139 
1140  delete face_edge;
1141  delete edge_vertex;
1142 }
1143 
1144 void Mesh::DestroyPointers()
1145 {
1146  if (own_nodes) { delete Nodes; }
1147 
1148  delete ncmesh;
1149 
1150  delete NURBSext;
1151 
1152  for (int i = 0; i < NumOfElements; i++)
1153  {
1154  FreeElement(elements[i]);
1155  }
1156 
1157  for (int i = 0; i < NumOfBdrElements; i++)
1158  {
1159  FreeElement(boundary[i]);
1160  }
1161 
1162  for (int i = 0; i < faces.Size(); i++)
1163  {
1164  FreeElement(faces[i]);
1165  }
1166 
1167  DestroyTables();
1168 }
1169 
1170 void Mesh::Destroy()
1171 {
1172  DestroyPointers();
1173 
1174  elements.DeleteAll();
1175  vertices.DeleteAll();
1176  boundary.DeleteAll();
1177  faces.DeleteAll();
1178  faces_info.DeleteAll();
1179  nc_faces_info.DeleteAll();
1180  be_to_edge.DeleteAll();
1181  be_to_face.DeleteAll();
1182 
1183  // TODO:
1184  // IsoparametricTransformations
1185  // Transformation, Transformation2, BdrTransformation, FaceTransformation,
1186  // EdgeTransformation;
1187  // FaceElementTransformations FaceElemTr;
1188 
1189  CoarseFineTr.Clear();
1190 
1191 #ifdef MFEM_USE_MEMALLOC
1192  TetMemory.Clear();
1193 #endif
1194 
1195  attributes.DeleteAll();
1196  bdr_attributes.DeleteAll();
1197 }
1198 
1199 void Mesh::ResetLazyData()
1200 {
1201  delete el_to_el; el_to_el = NULL;
1202  delete face_edge; face_edge = NULL;
1203  delete edge_vertex; edge_vertex = NULL;
1204  DeleteGeometricFactors();
1205  nbInteriorFaces = -1;
1206  nbBoundaryFaces = -1;
1207 }
1208 
1209 void Mesh::SetAttributes()
1210 {
1211  Array<int> attribs;
1212 
1213  attribs.SetSize(GetNBE());
1214  for (int i = 0; i < attribs.Size(); i++)
1215  {
1216  attribs[i] = GetBdrAttribute(i);
1217  }
1218  attribs.Sort();
1219  attribs.Unique();
1220  attribs.Copy(bdr_attributes);
1221  if (bdr_attributes.Size() > 0 && bdr_attributes[0] <= 0)
1222  {
1223  MFEM_WARNING("Non-positive attributes on the boundary!");
1224  }
1225 
1226  attribs.SetSize(GetNE());
1227  for (int i = 0; i < attribs.Size(); i++)
1228  {
1229  attribs[i] = GetAttribute(i);
1230  }
1231  attribs.Sort();
1232  attribs.Unique();
1233  attribs.Copy(attributes);
1234  if (attributes.Size() > 0 && attributes[0] <= 0)
1235  {
1236  MFEM_WARNING("Non-positive attributes in the domain!");
1237  }
1238 }
1239 
1240 void Mesh::InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
1241 {
1242  SetEmpty();
1243 
1244  Dim = Dim_;
1245  spaceDim = spaceDim_;
1246 
1247  NumOfVertices = 0;
1248  vertices.SetSize(NVert); // just allocate space for vertices
1249 
1250  NumOfElements = 0;
1251  elements.SetSize(NElem); // just allocate space for Element *
1252 
1253  NumOfBdrElements = 0;
1254  boundary.SetSize(NBdrElem); // just allocate space for Element *
1255 }
1256 
1257 template<typename T>
1258 static void CheckEnlarge(Array<T> &array, int size)
1259 {
1260  if (size >= array.Size()) { array.SetSize(size + 1); }
1261 }
1262 
1263 int Mesh::AddVertex(double x, double y, double z)
1264 {
1265  CheckEnlarge(vertices, NumOfVertices);
1266  double *v = vertices[NumOfVertices]();
1267  v[0] = x;
1268  v[1] = y;
1269  v[2] = z;
1270  return NumOfVertices++;
1271 }
1272 
1273 int Mesh::AddVertex(const double *coords)
1274 {
1275  CheckEnlarge(vertices, NumOfVertices);
1276  vertices[NumOfVertices].SetCoords(spaceDim, coords);
1277  return NumOfVertices++;
1278 }
1279 
1280 void Mesh::AddVertexParents(int i, int p1, int p2)
1281 {
1282  tmp_vertex_parents.Append(Triple<int, int, int>(i, p1, p2));
1283 
1284  // if vertex coordinates are defined, make sure the hanging vertex has the
1285  // correct position
1286  if (i < vertices.Size())
1287  {
1288  double *vi = vertices[i](), *vp1 = vertices[p1](), *vp2 = vertices[p2]();
1289  for (int j = 0; j < 3; j++)
1290  {
1291  vi[j] = (vp1[j] + vp2[j]) * 0.5;
1292  }
1293  }
1294 }
1295 
1296 int Mesh::AddSegment(int v1, int v2, int attr)
1297 {
1298  CheckEnlarge(elements, NumOfElements);
1299  elements[NumOfElements] = new Segment(v1, v2, attr);
1300  return NumOfElements++;
1301 }
1302 
1303 int Mesh::AddSegment(const int *vi, int attr)
1304 {
1305  CheckEnlarge(elements, NumOfElements);
1306  elements[NumOfElements] = new Segment(vi, attr);
1307  return NumOfElements++;
1308 }
1309 
1310 int Mesh::AddTriangle(int v1, int v2, int v3, int attr)
1311 {
1312  CheckEnlarge(elements, NumOfElements);
1313  elements[NumOfElements] = new Triangle(v1, v2, v3, attr);
1314  return NumOfElements++;
1315 }
1316 
1317 int Mesh::AddTriangle(const int *vi, int attr)
1318 {
1319  CheckEnlarge(elements, NumOfElements);
1320  elements[NumOfElements] = new Triangle(vi, attr);
1321  return NumOfElements++;
1322 }
1323 
1324 int Mesh::AddQuad(int v1, int v2, int v3, int v4, int attr)
1325 {
1326  CheckEnlarge(elements, NumOfElements);
1327  elements[NumOfElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1328  return NumOfElements++;
1329 }
1330 
1331 int Mesh::AddQuad(const int *vi, int attr)
1332 {
1333  CheckEnlarge(elements, NumOfElements);
1334  elements[NumOfElements] = new Quadrilateral(vi, attr);
1335  return NumOfElements++;
1336 }
1337 
1338 int Mesh::AddTet(int v1, int v2, int v3, int v4, int attr)
1339 {
1340  int vi[4] = {v1, v2, v3, v4};
1341  return AddTet(vi, attr);
1342 }
1343 
1344 int Mesh::AddTet(const int *vi, int attr)
1345 {
1346  CheckEnlarge(elements, NumOfElements);
1347 #ifdef MFEM_USE_MEMALLOC
1348  Tetrahedron *tet;
1349  tet = TetMemory.Alloc();
1350  tet->SetVertices(vi);
1351  tet->SetAttribute(attr);
1352  elements[NumOfElements] = tet;
1353 #else
1354  elements[NumOfElements] = new Tetrahedron(vi, attr);
1355 #endif
1356  return NumOfElements++;
1357 }
1358 
1359 int Mesh::AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr)
1360 {
1361  CheckEnlarge(elements, NumOfElements);
1362  elements[NumOfElements] = new Wedge(v1, v2, v3, v4, v5, v6, attr);
1363  return NumOfElements++;
1364 }
1365 
1366 int Mesh::AddWedge(const int *vi, int attr)
1367 {
1368  CheckEnlarge(elements, NumOfElements);
1369  elements[NumOfElements] = new Wedge(vi, attr);
1370  return NumOfElements++;
1371 }
1372 
1373 int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
1374  int attr)
1375 {
1376  CheckEnlarge(elements, NumOfElements);
1377  elements[NumOfElements] =
1378  new Hexahedron(v1, v2, v3, v4, v5, v6, v7, v8, attr);
1379  return NumOfElements++;
1380 }
1381 
1382 int Mesh::AddHex(const int *vi, int attr)
1383 {
1384  CheckEnlarge(elements, NumOfElements);
1385  elements[NumOfElements] = new Hexahedron(vi, attr);
1386  return NumOfElements++;
1387 }
1388 
1389 void Mesh::AddHexAsTets(const int *vi, int attr)
1390 {
1391  static const int hex_to_tet[6][4] =
1392  {
1393  { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
1394  { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
1395  };
1396  int ti[4];
1397 
1398  for (int i = 0; i < 6; i++)
1399  {
1400  for (int j = 0; j < 4; j++)
1401  {
1402  ti[j] = vi[hex_to_tet[i][j]];
1403  }
1404  AddTet(ti, attr);
1405  }
1406 }
1407 
1408 void Mesh::AddHexAsWedges(const int *vi, int attr)
1409 {
1410  static const int hex_to_wdg[2][6] =
1411  {
1412  { 0, 1, 2, 4, 5, 6 }, { 0, 2, 3, 4, 6, 7 }
1413  };
1414  int ti[6];
1415 
1416  for (int i = 0; i < 2; i++)
1417  {
1418  for (int j = 0; j < 6; j++)
1419  {
1420  ti[j] = vi[hex_to_wdg[i][j]];
1421  }
1422  AddWedge(ti, attr);
1423  }
1424 }
1425 
1426 int Mesh::AddElement(Element *elem)
1427 {
1428  CheckEnlarge(elements, NumOfElements);
1429  elements[NumOfElements] = elem;
1430  return NumOfElements++;
1431 }
1432 
1433 int Mesh::AddBdrElement(Element *elem)
1434 {
1435  CheckEnlarge(boundary, NumOfBdrElements);
1436  boundary[NumOfBdrElements] = elem;
1437  return NumOfBdrElements++;
1438 }
1439 
1440 int Mesh::AddBdrSegment(int v1, int v2, int attr)
1441 {
1442  CheckEnlarge(boundary, NumOfBdrElements);
1443  boundary[NumOfBdrElements] = new Segment(v1, v2, attr);
1444  return NumOfBdrElements++;
1445 }
1446 
1447 int Mesh::AddBdrSegment(const int *vi, int attr)
1448 {
1449  CheckEnlarge(boundary, NumOfBdrElements);
1450  boundary[NumOfBdrElements] = new Segment(vi, attr);
1451  return NumOfBdrElements++;
1452 }
1453 
1454 int Mesh::AddBdrTriangle(int v1, int v2, int v3, int attr)
1455 {
1456  CheckEnlarge(boundary, NumOfBdrElements);
1457  boundary[NumOfBdrElements] = new Triangle(v1, v2, v3, attr);
1458  return NumOfBdrElements++;
1459 }
1460 
1461 int Mesh::AddBdrTriangle(const int *vi, int attr)
1462 {
1463  CheckEnlarge(boundary, NumOfBdrElements);
1464  boundary[NumOfBdrElements] = new Triangle(vi, attr);
1465  return NumOfBdrElements++;
1466 }
1467 
1468 int Mesh::AddBdrQuad(int v1, int v2, int v3, int v4, int attr)
1469 {
1470  CheckEnlarge(boundary, NumOfBdrElements);
1471  boundary[NumOfBdrElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1472  return NumOfBdrElements++;
1473 }
1474 
1475 int Mesh::AddBdrQuad(const int *vi, int attr)
1476 {
1477  CheckEnlarge(boundary, NumOfBdrElements);
1478  boundary[NumOfBdrElements] = new Quadrilateral(vi, attr);
1479  return NumOfBdrElements++;
1480 }
1481 
1482 void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
1483 {
1484  static const int quad_to_tri[2][3] = { { 0, 1, 2 }, { 0, 2, 3 } };
1485  int ti[3];
1486 
1487  for (int i = 0; i < 2; i++)
1488  {
1489  for (int j = 0; j < 3; j++)
1490  {
1491  ti[j] = vi[quad_to_tri[i][j]];
1492  }
1493  AddBdrTriangle(ti, attr);
1494  }
1495 }
1496 
1497 int Mesh::AddBdrPoint(int v, int attr)
1498 {
1499  CheckEnlarge(boundary, NumOfBdrElements);
1500  boundary[NumOfBdrElements] = new Point(&v, attr);
1501  return NumOfBdrElements++;
1502 }
1503 
1504 void Mesh::GenerateBoundaryElements()
1505 {
1506  int i, j;
1507  Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
1508 
1509  // GenerateFaces();
1510 
1511  for (i = 0; i < boundary.Size(); i++)
1512  {
1513  FreeElement(boundary[i]);
1514  }
1515 
1516  if (Dim == 3)
1517  {
1518  delete bel_to_edge;
1519  bel_to_edge = NULL;
1520  }
1521 
1522  // count the 'NumOfBdrElements'
1523  NumOfBdrElements = 0;
1524  for (i = 0; i < faces_info.Size(); i++)
1525  {
1526  if (faces_info[i].Elem2No < 0) { NumOfBdrElements++; }
1527  }
1528 
1529  boundary.SetSize(NumOfBdrElements);
1530  be2face.SetSize(NumOfBdrElements);
1531  for (j = i = 0; i < faces_info.Size(); i++)
1532  {
1533  if (faces_info[i].Elem2No < 0)
1534  {
1535  boundary[j] = faces[i]->Duplicate(this);
1536  be2face[j++] = i;
1537  }
1538  }
1539  // In 3D, 'bel_to_edge' is destroyed but it's not updated.
1540 }
1541 
1542 void Mesh::FinalizeCheck()
1543 {
1544  MFEM_VERIFY(vertices.Size() == NumOfVertices ||
1545  vertices.Size() == 0,
1546  "incorrect number of vertices: preallocated: " << vertices.Size()
1547  << ", actually added: " << NumOfVertices);
1548  MFEM_VERIFY(elements.Size() == NumOfElements,
1549  "incorrect number of elements: preallocated: " << elements.Size()
1550  << ", actually added: " << NumOfElements);
1551  MFEM_VERIFY(boundary.Size() == NumOfBdrElements,
1552  "incorrect number of boundary elements: preallocated: "
1553  << boundary.Size() << ", actually added: " << NumOfBdrElements);
1554 }
1555 
1556 void Mesh::FinalizeTriMesh(int generate_edges, int refine, bool fix_orientation)
1557 {
1558  FinalizeCheck();
1559  CheckElementOrientation(fix_orientation);
1560 
1561  if (refine)
1562  {
1563  MarkTriMeshForRefinement();
1564  }
1565 
1566  if (generate_edges)
1567  {
1568  el_to_edge = new Table;
1569  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1570  GenerateFaces();
1571  CheckBdrElementOrientation();
1572  }
1573  else
1574  {
1575  NumOfEdges = 0;
1576  }
1577 
1578  NumOfFaces = 0;
1579 
1580  SetAttributes();
1581 
1582  SetMeshGen();
1583 }
1584 
1585 void Mesh::FinalizeQuadMesh(int generate_edges, int refine,
1586  bool fix_orientation)
1587 {
1588  FinalizeCheck();
1589  if (fix_orientation)
1590  {
1591  CheckElementOrientation(fix_orientation);
1592  }
1593 
1594  if (generate_edges)
1595  {
1596  el_to_edge = new Table;
1597  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1598  GenerateFaces();
1599  CheckBdrElementOrientation();
1600  }
1601  else
1602  {
1603  NumOfEdges = 0;
1604  }
1605 
1606  NumOfFaces = 0;
1607 
1608  SetAttributes();
1609 
1610  SetMeshGen();
1611 }
1612 
1613 
1614 class GeckoProgress : public Gecko::Progress
1615 {
1616  double limit;
1617  mutable StopWatch sw;
1618 public:
1619  GeckoProgress(double limit) : limit(limit) { sw.Start(); }
1620  virtual bool quit() const { return limit > 0 && sw.UserTime() > limit; }
1621 };
1622 
1623 class GeckoVerboseProgress : public GeckoProgress
1624 {
1625  using Float = Gecko::Float;
1626  using Graph = Gecko::Graph;
1627  using uint = Gecko::uint;
1628 public:
1629  GeckoVerboseProgress(double limit) : GeckoProgress(limit) {}
1630 
1631  virtual void beginorder(const Graph* graph, Float cost) const
1632  { mfem::out << "Begin Gecko ordering, cost = " << cost << std::endl; }
1633  virtual void endorder(const Graph* graph, Float cost) const
1634  { mfem::out << "End ordering, cost = " << cost << std::endl; }
1635 
1636  virtual void beginiter(const Graph* graph,
1637  uint iter, uint maxiter, uint window) const
1638  {
1639  mfem::out << "Iteration " << iter << "/" << maxiter << ", window "
1640  << window << std::flush;
1641  }
1642  virtual void enditer(const Graph* graph, Float mincost, Float cost) const
1643  { mfem::out << ", cost = " << cost << endl; }
1644 };
1645 
1646 
1647 double Mesh::GetGeckoElementOrdering(Array<int> &ordering,
1648  int iterations, int window,
1649  int period, int seed, bool verbose,
1650  double time_limit)
1651 {
1652  Gecko::Graph graph;
1653  Gecko::FunctionalGeometric functional; // edge product cost
1654 
1655  GeckoProgress progress(time_limit);
1656  GeckoVerboseProgress vprogress(time_limit);
1657 
1658  // insert elements as nodes in the graph
1659  for (int elemid = 0; elemid < GetNE(); ++elemid)
1660  {
1661  graph.insert_node();
1662  }
1663 
1664  // insert graph edges for element neighbors
1665  // NOTE: indices in Gecko are 1 based hence the +1 on insertion
1666  const Table &my_el_to_el = ElementToElementTable();
1667  for (int elemid = 0; elemid < GetNE(); ++elemid)
1668  {
1669  const int *neighid = my_el_to_el.GetRow(elemid);
1670  for (int i = 0; i < my_el_to_el.RowSize(elemid); ++i)
1671  {
1672  graph.insert_arc(elemid + 1, neighid[i] + 1);
1673  }
1674  }
1675 
1676  // get the ordering from Gecko and copy it into the Array<int>
1677  graph.order(&functional, iterations, window, period, seed,
1678  verbose ? &vprogress : &progress);
1679 
1680  ordering.SetSize(GetNE());
1681  Gecko::Node::Index NE = GetNE();
1682  for (Gecko::Node::Index gnodeid = 1; gnodeid <= NE; ++gnodeid)
1683  {
1684  ordering[gnodeid - 1] = graph.rank(gnodeid);
1685  }
1686 
1687  return graph.cost();
1688 }
1689 
1690 
1691 struct HilbertCmp
1692 {
1693  int coord;
1694  bool dir;
1695  const Array<double> &points;
1696  double mid;
1697 
1698  HilbertCmp(int coord, bool dir, const Array<double> &points, double mid)
1699  : coord(coord), dir(dir), points(points), mid(mid) {}
1700 
1701  bool operator()(int i) const
1702  {
1703  return (points[3*i + coord] < mid) != dir;
1704  }
1705 };
1706 
1707 static void HilbertSort2D(int coord1, // major coordinate to sort points by
1708  bool dir1, // sort coord1 ascending/descending?
1709  bool dir2, // sort coord2 ascending/descending?
1710  const Array<double> &points, int *beg, int *end,
1711  double xmin, double ymin, double xmax, double ymax)
1712 {
1713  if (end - beg <= 1) { return; }
1714 
1715  double xmid = (xmin + xmax)*0.5;
1716  double ymid = (ymin + ymax)*0.5;
1717 
1718  int coord2 = (coord1 + 1) % 2; // the 'other' coordinate
1719 
1720  // sort (partition) points into four quadrants
1721  int *p0 = beg, *p4 = end;
1722  int *p2 = std::partition(p0, p4, HilbertCmp(coord1, dir1, points, xmid));
1723  int *p1 = std::partition(p0, p2, HilbertCmp(coord2, dir2, points, ymid));
1724  int *p3 = std::partition(p2, p4, HilbertCmp(coord2, !dir2, points, ymid));
1725 
1726  if (p1 != p4)
1727  {
1728  HilbertSort2D(coord2, dir2, dir1, points, p0, p1,
1729  ymin, xmin, ymid, xmid);
1730  }
1731  if (p1 != p0 || p2 != p4)
1732  {
1733  HilbertSort2D(coord1, dir1, dir2, points, p1, p2,
1734  xmin, ymid, xmid, ymax);
1735  }
1736  if (p2 != p0 || p3 != p4)
1737  {
1738  HilbertSort2D(coord1, dir1, dir2, points, p2, p3,
1739  xmid, ymid, xmax, ymax);
1740  }
1741  if (p3 != p0)
1742  {
1743  HilbertSort2D(coord2, !dir2, !dir1, points, p3, p4,
1744  ymid, xmax, ymin, xmid);
1745  }
1746 }
1747 
1748 static void HilbertSort3D(int coord1, bool dir1, bool dir2, bool dir3,
1749  const Array<double> &points, int *beg, int *end,
1750  double xmin, double ymin, double zmin,
1751  double xmax, double ymax, double zmax)
1752 {
1753  if (end - beg <= 1) { return; }
1754 
1755  double xmid = (xmin + xmax)*0.5;
1756  double ymid = (ymin + ymax)*0.5;
1757  double zmid = (zmin + zmax)*0.5;
1758 
1759  int coord2 = (coord1 + 1) % 3;
1760  int coord3 = (coord1 + 2) % 3;
1761 
1762  // sort (partition) points into eight octants
1763  int *p0 = beg, *p8 = end;
1764  int *p4 = std::partition(p0, p8, HilbertCmp(coord1, dir1, points, xmid));
1765  int *p2 = std::partition(p0, p4, HilbertCmp(coord2, dir2, points, ymid));
1766  int *p6 = std::partition(p4, p8, HilbertCmp(coord2, !dir2, points, ymid));
1767  int *p1 = std::partition(p0, p2, HilbertCmp(coord3, dir3, points, zmid));
1768  int *p3 = std::partition(p2, p4, HilbertCmp(coord3, !dir3, points, zmid));
1769  int *p5 = std::partition(p4, p6, HilbertCmp(coord3, dir3, points, zmid));
1770  int *p7 = std::partition(p6, p8, HilbertCmp(coord3, !dir3, points, zmid));
1771 
1772  if (p1 != p8)
1773  {
1774  HilbertSort3D(coord3, dir3, dir1, dir2, points, p0, p1,
1775  zmin, xmin, ymin, zmid, xmid, ymid);
1776  }
1777  if (p1 != p0 || p2 != p8)
1778  {
1779  HilbertSort3D(coord2, dir2, dir3, dir1, points, p1, p2,
1780  ymin, zmid, xmin, ymid, zmax, xmid);
1781  }
1782  if (p2 != p0 || p3 != p8)
1783  {
1784  HilbertSort3D(coord2, dir2, dir3, dir1, points, p2, p3,
1785  ymid, zmid, xmin, ymax, zmax, xmid);
1786  }
1787  if (p3 != p0 || p4 != p8)
1788  {
1789  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p3, p4,
1790  xmin, ymax, zmid, xmid, ymid, zmin);
1791  }
1792  if (p4 != p0 || p5 != p8)
1793  {
1794  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p4, p5,
1795  xmid, ymax, zmid, xmax, ymid, zmin);
1796  }
1797  if (p5 != p0 || p6 != p8)
1798  {
1799  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p5, p6,
1800  ymax, zmid, xmax, ymid, zmax, xmid);
1801  }
1802  if (p6 != p0 || p7 != p8)
1803  {
1804  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p6, p7,
1805  ymid, zmid, xmax, ymin, zmax, xmid);
1806  }
1807  if (p7 != p0)
1808  {
1809  HilbertSort3D(coord3, !dir3, !dir1, dir2, points, p7, p8,
1810  zmid, xmax, ymin, zmin, xmid, ymid);
1811  }
1812 }
1813 
1814 void Mesh::GetHilbertElementOrdering(Array<int> &ordering)
1815 {
1816  MFEM_VERIFY(spaceDim <= 3, "");
1817 
1818  Vector min, max, center;
1819  GetBoundingBox(min, max);
1820 
1821  Array<int> indices(GetNE());
1822  Array<double> points(3*GetNE());
1823 
1824  if (spaceDim < 3) { points = 0.0; }
1825 
1826  // calculate element centers
1827  for (int i = 0; i < GetNE(); i++)
1828  {
1829  GetElementCenter(i, center);
1830  for (int j = 0; j < spaceDim; j++)
1831  {
1832  points[3*i + j] = center(j);
1833  }
1834  indices[i] = i;
1835  }
1836 
1837  if (spaceDim == 1)
1838  {
1839  indices.Sort([&](int a, int b)
1840  { return points[3*a] < points[3*b]; });
1841  }
1842  else if (spaceDim == 2)
1843  {
1844  // recursively partition the points in 2D
1845  HilbertSort2D(0, false, false,
1846  points, indices.begin(), indices.end(),
1847  min(0), min(1), max(0), max(1));
1848  }
1849  else
1850  {
1851  // recursively partition the points in 3D
1852  HilbertSort3D(0, false, false, false,
1853  points, indices.begin(), indices.end(),
1854  min(0), min(1), min(2), max(0), max(1), max(2));
1855  }
1856 
1857  // return ordering in the format required by ReorderElements
1858  ordering.SetSize(GetNE());
1859  for (int i = 0; i < GetNE(); i++)
1860  {
1861  ordering[indices[i]] = i;
1862  }
1863 }
1864 
1865 
1866 void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
1867 {
1868  if (NURBSext)
1869  {
1870  MFEM_WARNING("element reordering of NURBS meshes is not supported.");
1871  return;
1872  }
1873  if (ncmesh)
1874  {
1875  MFEM_WARNING("element reordering of non-conforming meshes is not"
1876  " supported.");
1877  return;
1878  }
1879  MFEM_VERIFY(ordering.Size() == GetNE(), "invalid reordering array.")
1880 
1881  // Data members that need to be updated:
1882 
1883  // - elements - reorder of the pointers and the vertex ids if reordering
1884  // the vertices
1885  // - vertices - if reordering the vertices
1886  // - boundary - update the vertex ids, if reordering the vertices
1887  // - faces - regenerate
1888  // - faces_info - regenerate
1889 
1890  // Deleted by DeleteTables():
1891  // - el_to_edge - rebuild in 2D and 3D only
1892  // - el_to_face - rebuild in 3D only
1893  // - bel_to_edge - rebuild in 3D only
1894  // - el_to_el - no need to rebuild
1895  // - face_edge - no need to rebuild
1896  // - edge_vertex - no need to rebuild
1897  // - geom_factors - no need to rebuild
1898 
1899  // - be_to_edge - 2D only
1900  // - be_to_face - 3D only
1901 
1902  // - Nodes
1903 
1904  // Save the locations of the Nodes so we can rebuild them later
1905  Array<Vector*> old_elem_node_vals;
1906  FiniteElementSpace *nodes_fes = NULL;
1907  if (Nodes)
1908  {
1909  old_elem_node_vals.SetSize(GetNE());
1910  nodes_fes = Nodes->FESpace();
1911  Array<int> old_dofs;
1912  Vector vals;
1913  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
1914  {
1915  nodes_fes->GetElementVDofs(old_elid, old_dofs);
1916  Nodes->GetSubVector(old_dofs, vals);
1917  old_elem_node_vals[old_elid] = new Vector(vals);
1918  }
1919  }
1920 
1921  // Get the newly ordered elements
1922  Array<Element *> new_elements(GetNE());
1923  for (int old_elid = 0; old_elid < ordering.Size(); ++old_elid)
1924  {
1925  int new_elid = ordering[old_elid];
1926  new_elements[new_elid] = elements[old_elid];
1927  }
1928  mfem::Swap(elements, new_elements);
1929  new_elements.DeleteAll();
1930 
1931  if (reorder_vertices)
1932  {
1933  // Get the new vertex ordering permutation vectors and fill the new
1934  // vertices
1935  Array<int> vertex_ordering(GetNV());
1936  vertex_ordering = -1;
1937  Array<Vertex> new_vertices(GetNV());
1938  int new_vertex_ind = 0;
1939  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
1940  {
1941  int *elem_vert = elements[new_elid]->GetVertices();
1942  int nv = elements[new_elid]->GetNVertices();
1943  for (int vi = 0; vi < nv; ++vi)
1944  {
1945  int old_vertex_ind = elem_vert[vi];
1946  if (vertex_ordering[old_vertex_ind] == -1)
1947  {
1948  vertex_ordering[old_vertex_ind] = new_vertex_ind;
1949  new_vertices[new_vertex_ind] = vertices[old_vertex_ind];
1950  new_vertex_ind++;
1951  }
1952  }
1953  }
1954  mfem::Swap(vertices, new_vertices);
1955  new_vertices.DeleteAll();
1956 
1957  // Replace the vertex ids in the elements with the reordered vertex
1958  // numbers
1959  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
1960  {
1961  int *elem_vert = elements[new_elid]->GetVertices();
1962  int nv = elements[new_elid]->GetNVertices();
1963  for (int vi = 0; vi < nv; ++vi)
1964  {
1965  elem_vert[vi] = vertex_ordering[elem_vert[vi]];
1966  }
1967  }
1968 
1969  // Replace the vertex ids in the boundary with reordered vertex numbers
1970  for (int belid = 0; belid < GetNBE(); ++belid)
1971  {
1972  int *be_vert = boundary[belid]->GetVertices();
1973  int nv = boundary[belid]->GetNVertices();
1974  for (int vi = 0; vi < nv; ++vi)
1975  {
1976  be_vert[vi] = vertex_ordering[be_vert[vi]];
1977  }
1978  }
1979  }
1980 
1981  // Destroy tables that need to be rebuild
1982  DeleteTables();
1983 
1984  if (Dim > 1)
1985  {
1986  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
1987  el_to_edge = new Table;
1988  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1989  }
1990  if (Dim > 2)
1991  {
1992  // generate el_to_face, be_to_face
1993  GetElementToFaceTable();
1994  }
1995  // Update faces and faces_info
1996  GenerateFaces();
1997 
1998  // Build the nodes from the saved locations if they were around before
1999  if (Nodes)
2000  {
2001  // To force FE space update, we need to increase 'sequence':
2002  sequence++;
2003  last_operation = Mesh::NONE;
2004  nodes_fes->Update(false); // want_transform = false
2005  Nodes->Update(); // just needed to update Nodes->sequence
2006  Array<int> new_dofs;
2007  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2008  {
2009  int new_elid = ordering[old_elid];
2010  nodes_fes->GetElementVDofs(new_elid, new_dofs);
2011  Nodes->SetSubVector(new_dofs, *(old_elem_node_vals[old_elid]));
2012  delete old_elem_node_vals[old_elid];
2013  }
2014  }
2015 }
2016 
2017 
2018 void Mesh::MarkForRefinement()
2019 {
2020  if (meshgen & 1)
2021  {
2022  if (Dim == 2)
2023  {
2024  MarkTriMeshForRefinement();
2025  }
2026  else if (Dim == 3)
2027  {
2028  DSTable v_to_v(NumOfVertices);
2029  GetVertexToVertexTable(v_to_v);
2030  MarkTetMeshForRefinement(v_to_v);
2031  }
2032  }
2033 }
2034 
2035 void Mesh::MarkTriMeshForRefinement()
2036 {
2037  // Mark the longest triangle edge by rotating the indeces so that
2038  // vertex 0 - vertex 1 is the longest edge in the triangle.
2039  DenseMatrix pmat;
2040  for (int i = 0; i < NumOfElements; i++)
2041  {
2042  if (elements[i]->GetType() == Element::TRIANGLE)
2043  {
2044  GetPointMatrix(i, pmat);
2045  static_cast<Triangle*>(elements[i])->MarkEdge(pmat);
2046  }
2047  }
2048 }
2049 
2050 void Mesh::GetEdgeOrdering(DSTable &v_to_v, Array<int> &order)
2051 {
2052  NumOfEdges = v_to_v.NumberOfEntries();
2053  order.SetSize(NumOfEdges);
2054  Array<Pair<double, int> > length_idx(NumOfEdges);
2055 
2056  for (int i = 0; i < NumOfVertices; i++)
2057  {
2058  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
2059  {
2060  int j = it.Index();
2061  length_idx[j].one = GetLength(i, it.Column());
2062  length_idx[j].two = j;
2063  }
2064  }
2065 
2066  // Sort by increasing edge-length.
2067  length_idx.Sort();
2068 
2069  for (int i = 0; i < NumOfEdges; i++)
2070  {
2071  order[length_idx[i].two] = i;
2072  }
2073 }
2074 
2075 void Mesh::MarkTetMeshForRefinement(DSTable &v_to_v)
2076 {
2077  // Mark the longest tetrahedral edge by rotating the indices so that
2078  // vertex 0 - vertex 1 is the longest edge in the element.
2079  Array<int> order;
2080  GetEdgeOrdering(v_to_v, order);
2081 
2082  for (int i = 0; i < NumOfElements; i++)
2083  {
2084  if (elements[i]->GetType() == Element::TETRAHEDRON)
2085  {
2086  elements[i]->MarkEdge(v_to_v, order);
2087  }
2088  }
2089  for (int i = 0; i < NumOfBdrElements; i++)
2090  {
2091  if (boundary[i]->GetType() == Element::TRIANGLE)
2092  {
2093  boundary[i]->MarkEdge(v_to_v, order);
2094  }
2095  }
2096 }
2097 
2098 void Mesh::PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
2099 {
2100  if (*old_v_to_v && *old_elem_vert)
2101  {
2102  return;
2103  }
2104 
2105  FiniteElementSpace *fes = Nodes->FESpace();
2106 
2107  if (*old_v_to_v == NULL)
2108  {
2109  bool need_v_to_v = false;
2110  Array<int> dofs;
2111  for (int i = 0; i < GetNEdges(); i++)
2112  {
2113  // Since edge indices may change, we need to permute edge interior dofs
2114  // any time an edge index changes and there is at least one dof on that
2115  // edge.
2116  fes->GetEdgeInteriorDofs(i, dofs);
2117  if (dofs.Size() > 0)
2118  {
2119  need_v_to_v = true;
2120  break;
2121  }
2122  }
2123  if (need_v_to_v)
2124  {
2125  *old_v_to_v = new DSTable(NumOfVertices);
2126  GetVertexToVertexTable(*(*old_v_to_v));
2127  }
2128  }
2129  if (*old_elem_vert == NULL)
2130  {
2131  bool need_elem_vert = false;
2132  Array<int> dofs;
2133  for (int i = 0; i < GetNE(); i++)
2134  {
2135  // Since element indices do not change, we need to permute element
2136  // interior dofs only when there are at least 2 interior dofs in an
2137  // element (assuming the nodal dofs are non-directional).
2138  fes->GetElementInteriorDofs(i, dofs);
2139  if (dofs.Size() > 1)
2140  {
2141  need_elem_vert = true;
2142  break;
2143  }
2144  }
2145  if (need_elem_vert)
2146  {
2147  *old_elem_vert = new Table;
2148  (*old_elem_vert)->MakeI(GetNE());
2149  for (int i = 0; i < GetNE(); i++)
2150  {
2151  (*old_elem_vert)->AddColumnsInRow(i, elements[i]->GetNVertices());
2152  }
2153  (*old_elem_vert)->MakeJ();
2154  for (int i = 0; i < GetNE(); i++)
2155  {
2156  (*old_elem_vert)->AddConnections(i, elements[i]->GetVertices(),
2157  elements[i]->GetNVertices());
2158  }
2159  (*old_elem_vert)->ShiftUpI();
2160  }
2161  }
2162 }
2163 
2164 void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
2165 {
2166  FiniteElementSpace *fes = Nodes->FESpace();
2167  const FiniteElementCollection *fec = fes->FEColl();
2168  Array<int> old_dofs, new_dofs;
2169 
2170  // assuming that all edges have the same number of dofs
2171  if (NumOfEdges) { fes->GetEdgeInteriorDofs(0, old_dofs); }
2172  const int num_edge_dofs = old_dofs.Size();
2173 
2174  // Save the original nodes
2175  const Vector onodes = *Nodes;
2176 
2177  // vertex dofs do not need to be moved
2178  fes->GetVertexDofs(0, old_dofs);
2179  int offset = NumOfVertices * old_dofs.Size();
2180 
2181  // edge dofs:
2182  // edge enumeration may be different but edge orientation is the same
2183  if (num_edge_dofs > 0)
2184  {
2185  DSTable new_v_to_v(NumOfVertices);
2186  GetVertexToVertexTable(new_v_to_v);
2187 
2188  for (int i = 0; i < NumOfVertices; i++)
2189  {
2190  for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it)
2191  {
2192  const int old_i = (*old_v_to_v)(i, it.Column());
2193  const int new_i = it.Index();
2194  if (new_i == old_i) { continue; }
2195 
2196  old_dofs.SetSize(num_edge_dofs);
2197  new_dofs.SetSize(num_edge_dofs);
2198  for (int j = 0; j < num_edge_dofs; j++)
2199  {
2200  old_dofs[j] = offset + old_i * num_edge_dofs + j;
2201  new_dofs[j] = offset + new_i * num_edge_dofs + j;
2202  }
2203  fes->DofsToVDofs(old_dofs);
2204  fes->DofsToVDofs(new_dofs);
2205  for (int j = 0; j < old_dofs.Size(); j++)
2206  {
2207  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2208  }
2209  }
2210  }
2211  offset += NumOfEdges * num_edge_dofs;
2212  }
2213 
2214  // face dofs:
2215  // both enumeration and orientation of the faces may be different
2216  if (fes->GetNFDofs() > 0)
2217  {
2218  // generate the old face-vertex table using the unmodified 'faces'
2219  Table old_face_vertex;
2220  old_face_vertex.MakeI(NumOfFaces);
2221  for (int i = 0; i < NumOfFaces; i++)
2222  {
2223  old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices());
2224  }
2225  old_face_vertex.MakeJ();
2226  for (int i = 0; i < NumOfFaces; i++)
2227  old_face_vertex.AddConnections(i, faces[i]->GetVertices(),
2228  faces[i]->GetNVertices());
2229  old_face_vertex.ShiftUpI();
2230 
2231  // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info'
2232  STable3D *faces_tbl = GetElementToFaceTable(1);
2233  GenerateFaces();
2234 
2235  // compute the new face dof offsets
2236  Array<int> new_fdofs(NumOfFaces+1);
2237  new_fdofs[0] = 0;
2238  for (int i = 0; i < NumOfFaces; i++) // i = old face index
2239  {
2240  const int *old_v = old_face_vertex.GetRow(i);
2241  int new_i; // new face index
2242  switch (old_face_vertex.RowSize(i))
2243  {
2244  case 3:
2245  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2246  break;
2247  case 4:
2248  default:
2249  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2250  break;
2251  }
2252  fes->GetFaceInteriorDofs(i, old_dofs);
2253  new_fdofs[new_i+1] = old_dofs.Size();
2254  }
2255  new_fdofs.PartialSum();
2256 
2257  // loop over the old face numbers
2258  for (int i = 0; i < NumOfFaces; i++)
2259  {
2260  const int *old_v = old_face_vertex.GetRow(i), *new_v;
2261  const int *dof_ord;
2262  int new_i, new_or;
2263  switch (old_face_vertex.RowSize(i))
2264  {
2265  case 3:
2266  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2267  new_v = faces[new_i]->GetVertices();
2268  new_or = GetTriOrientation(old_v, new_v);
2269  dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, new_or);
2270  break;
2271  case 4:
2272  default:
2273  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2274  new_v = faces[new_i]->GetVertices();
2275  new_or = GetQuadOrientation(old_v, new_v);
2276  dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, new_or);
2277  break;
2278  }
2279 
2280  fes->GetFaceInteriorDofs(i, old_dofs);
2281  new_dofs.SetSize(old_dofs.Size());
2282  for (int j = 0; j < old_dofs.Size(); j++)
2283  {
2284  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2285  const int old_j = dof_ord[j];
2286  new_dofs[old_j] = offset + new_fdofs[new_i] + j;
2287  }
2288  fes->DofsToVDofs(old_dofs);
2289  fes->DofsToVDofs(new_dofs);
2290  for (int j = 0; j < old_dofs.Size(); j++)
2291  {
2292  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2293  }
2294  }
2295 
2296  offset += fes->GetNFDofs();
2297  delete faces_tbl;
2298  }
2299 
2300  // element dofs:
2301  // element orientation may be different
2302  if (old_elem_vert) // have elements with 2 or more dofs
2303  {
2304  // matters when the 'fec' is
2305  // (this code is executed only for triangles/tets)
2306  // - Pk on triangles, k >= 4
2307  // - Qk on quads, k >= 3
2308  // - Pk on tets, k >= 5
2309  // - Qk on hexes, k >= 3
2310  // - DG spaces
2311  // - ...
2312 
2313  // loop over all elements
2314  for (int i = 0; i < GetNE(); i++)
2315  {
2316  const int *old_v = old_elem_vert->GetRow(i);
2317  const int *new_v = elements[i]->GetVertices();
2318  const int *dof_ord;
2319  int new_or;
2320  const Geometry::Type geom = elements[i]->GetGeometryType();
2321  switch (geom)
2322  {
2323  case Geometry::SEGMENT:
2324  new_or = (old_v[0] == new_v[0]) ? +1 : -1;
2325  break;
2326  case Geometry::TRIANGLE:
2327  new_or = GetTriOrientation(old_v, new_v);
2328  break;
2329  case Geometry::SQUARE:
2330  new_or = GetQuadOrientation(old_v, new_v);
2331  break;
2332  case Geometry::TETRAHEDRON:
2333  new_or = GetTetOrientation(old_v, new_v);
2334  break;
2335  default:
2336  new_or = 0;
2337  MFEM_ABORT(Geometry::Name[geom] << " elements (" << fec->Name()
2338  << " FE collection) are not supported yet!");
2339  break;
2340  }
2341  dof_ord = fec->DofOrderForOrientation(geom, new_or);
2342  MFEM_VERIFY(dof_ord != NULL,
2343  "FE collection '" << fec->Name()
2344  << "' does not define reordering for "
2345  << Geometry::Name[geom] << " elements!");
2346  fes->GetElementInteriorDofs(i, old_dofs);
2347  new_dofs.SetSize(old_dofs.Size());
2348  for (int j = 0; j < new_dofs.Size(); j++)
2349  {
2350  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2351  const int old_j = dof_ord[j];
2352  new_dofs[old_j] = offset + j;
2353  }
2354  offset += new_dofs.Size();
2355  fes->DofsToVDofs(old_dofs);
2356  fes->DofsToVDofs(new_dofs);
2357  for (int j = 0; j < old_dofs.Size(); j++)
2358  {
2359  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2360  }
2361  }
2362  }
2363 
2364  // Update Tables, faces, etc
2365  if (Dim > 2)
2366  {
2367  if (fes->GetNFDofs() == 0)
2368  {
2369  // needed for FE spaces that have face dofs, even if
2370  // the 'Nodes' do not have face dofs.
2371  GetElementToFaceTable();
2372  GenerateFaces();
2373  }
2374  CheckBdrElementOrientation();
2375  }
2376  if (el_to_edge)
2377  {
2378  // update 'el_to_edge', 'be_to_edge' (2D), 'bel_to_edge' (3D)
2379  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2380  if (Dim == 2)
2381  {
2382  // update 'faces' and 'faces_info'
2383  GenerateFaces();
2384  CheckBdrElementOrientation();
2385  }
2386  }
2387  // To force FE space update, we need to increase 'sequence':
2388  sequence++;
2389  last_operation = Mesh::NONE;
2390  fes->Update(false); // want_transform = false
2391  Nodes->Update(); // just needed to update Nodes->sequence
2392 }
2393 
2394 void Mesh::FinalizeTetMesh(int generate_edges, int refine, bool fix_orientation)
2395 {
2396  FinalizeCheck();
2397  CheckElementOrientation(fix_orientation);
2398 
2399  if (NumOfBdrElements == 0)
2400  {
2401  GetElementToFaceTable();
2402  GenerateFaces();
2403  GenerateBoundaryElements();
2404  }
2405 
2406  if (refine)
2407  {
2408  DSTable v_to_v(NumOfVertices);
2409  GetVertexToVertexTable(v_to_v);
2410  MarkTetMeshForRefinement(v_to_v);
2411  }
2412 
2413  GetElementToFaceTable();
2414  GenerateFaces();
2415 
2416  CheckBdrElementOrientation();
2417 
2418  if (generate_edges == 1)
2419  {
2420  el_to_edge = new Table;
2421  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2422  }
2423  else
2424  {
2425  el_to_edge = NULL; // Not really necessary -- InitTables was called
2426  bel_to_edge = NULL;
2427  NumOfEdges = 0;
2428  }
2429 
2430  SetAttributes();
2431 
2432  SetMeshGen();
2433 }
2434 
2435 void Mesh::FinalizeWedgeMesh(int generate_edges, int refine,
2436  bool fix_orientation)
2437 {
2438  FinalizeCheck();
2439  CheckElementOrientation(fix_orientation);
2440 
2441  if (NumOfBdrElements == 0)
2442  {
2443  GetElementToFaceTable();
2444  GenerateFaces();
2445  GenerateBoundaryElements();
2446  }
2447 
2448  GetElementToFaceTable();
2449  GenerateFaces();
2450 
2451  CheckBdrElementOrientation();
2452 
2453  if (generate_edges == 1)
2454  {
2455  el_to_edge = new Table;
2456  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2457  }
2458  else
2459  {
2460  el_to_edge = NULL; // Not really necessary -- InitTables was called
2461  bel_to_edge = NULL;
2462  NumOfEdges = 0;
2463  }
2464 
2465  SetAttributes();
2466 
2467  SetMeshGen();
2468 }
2469 
2470 void Mesh::FinalizeHexMesh(int generate_edges, int refine, bool fix_orientation)
2471 {
2472  FinalizeCheck();
2473  CheckElementOrientation(fix_orientation);
2474 
2475  GetElementToFaceTable();
2476  GenerateFaces();
2477 
2478  if (NumOfBdrElements == 0)
2479  {
2480  GenerateBoundaryElements();
2481  }
2482 
2483  CheckBdrElementOrientation();
2484 
2485  if (generate_edges)
2486  {
2487  el_to_edge = new Table;
2488  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2489  }
2490  else
2491  {
2492  NumOfEdges = 0;
2493  }
2494 
2495  SetAttributes();
2496 
2497  SetMeshGen();
2498 }
2499 
2500 void Mesh::FinalizeMesh(int refine, bool fix_orientation)
2501 {
2502  FinalizeTopology();
2503 
2504  Finalize(refine, fix_orientation);
2505 }
2506 
2507 void Mesh::FinalizeTopology(bool generate_bdr)
2508 {
2509  // Requirements: the following should be defined:
2510  // 1) Dim
2511  // 2) NumOfElements, elements
2512  // 3) NumOfBdrElements, boundary
2513  // 4) NumOfVertices
2514  // Optional:
2515  // 2) ncmesh may be defined
2516  // 3) el_to_edge may be allocated (it will be re-computed)
2517 
2518  FinalizeCheck();
2519  bool generate_edges = true;
2520 
2521  if (spaceDim == 0) { spaceDim = Dim; }
2522  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
2523 
2524  // if the user defined any hanging nodes (see AddVertexParent),
2525  // we're initializing a non-conforming mesh
2526  if (tmp_vertex_parents.Size())
2527  {
2528  MFEM_VERIFY(ncmesh == NULL, "");
2529  ncmesh = new NCMesh(this);
2530 
2531  // we need to recreate the Mesh because NCMesh reorders the vertices
2532  // (see NCMesh::UpdateVertices())
2533  InitFromNCMesh(*ncmesh);
2534  ncmesh->OnMeshUpdated(this);
2535  GenerateNCFaceInfo();
2536 
2537  SetAttributes();
2538 
2539  tmp_vertex_parents.DeleteAll();
2540  return;
2541  }
2542 
2543  // set the mesh type: 'meshgen', ...
2544  SetMeshGen();
2545 
2546  // generate the faces
2547  if (Dim > 2)
2548  {
2549  GetElementToFaceTable();
2550  GenerateFaces();
2551  if (NumOfBdrElements == 0 && generate_bdr)
2552  {
2553  GenerateBoundaryElements();
2554  GetElementToFaceTable(); // update be_to_face
2555  }
2556  }
2557  else
2558  {
2559  NumOfFaces = 0;
2560  }
2561 
2562  // generate edges if requested
2563  if (Dim > 1 && generate_edges)
2564  {
2565  // el_to_edge may already be allocated (P2 VTK meshes)
2566  if (!el_to_edge) { el_to_edge = new Table; }
2567  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2568  if (Dim == 2)
2569  {
2570  GenerateFaces(); // 'Faces' in 2D refers to the edges
2571  if (NumOfBdrElements == 0 && generate_bdr)
2572  {
2573  GenerateBoundaryElements();
2574  }
2575  }
2576  }
2577  else
2578  {
2579  NumOfEdges = 0;
2580  }
2581 
2582  if (Dim == 1)
2583  {
2584  GenerateFaces();
2585  }
2586 
2587  if (ncmesh)
2588  {
2589  // tell NCMesh the numbering of edges/faces
2590  ncmesh->OnMeshUpdated(this);
2591 
2592  // update faces_info with NC relations
2593  GenerateNCFaceInfo();
2594  }
2595 
2596  // generate the arrays 'attributes' and 'bdr_attributes'
2597  SetAttributes();
2598 }
2599 
2600 void Mesh::Finalize(bool refine, bool fix_orientation)
2601 {
2602  if (NURBSext || ncmesh)
2603  {
2604  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
2605  MFEM_ASSERT(CheckBdrElementOrientation() == 0, "");
2606  return;
2607  }
2608 
2609  // Requirements:
2610  // 1) FinalizeTopology() or equivalent was called
2611  // 2) if (Nodes == NULL), vertices must be defined
2612  // 3) if (Nodes != NULL), Nodes must be defined
2613 
2614  const bool check_orientation = true; // for regular elements, not boundary
2615  const bool curved = (Nodes != NULL);
2616  const bool may_change_topology =
2617  ( refine && (Dim > 1 && (meshgen & 1)) ) ||
2618  ( check_orientation && fix_orientation &&
2619  (Dim == 2 || (Dim == 3 && (meshgen & 1))) );
2620 
2621  DSTable *old_v_to_v = NULL;
2622  Table *old_elem_vert = NULL;
2623 
2624  if (curved && may_change_topology)
2625  {
2626  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
2627  }
2628 
2629  if (check_orientation)
2630  {
2631  // check and optionally fix element orientation
2632  CheckElementOrientation(fix_orientation);
2633  }
2634  if (refine)
2635  {
2636  MarkForRefinement(); // may change topology!
2637  }
2638 
2639  if (may_change_topology)
2640  {
2641  if (curved)
2642  {
2643  DoNodeReorder(old_v_to_v, old_elem_vert); // updates the mesh topology
2644  delete old_elem_vert;
2645  delete old_v_to_v;
2646  }
2647  else
2648  {
2649  FinalizeTopology(); // Re-computes some data unnecessarily.
2650  }
2651 
2652  // TODO: maybe introduce Mesh::NODE_REORDER operation and FESpace::
2653  // NodeReorderMatrix and do Nodes->Update() instead of DoNodeReorder?
2654  }
2655 
2656  // check and fix boundary element orientation
2657  CheckBdrElementOrientation();
2658 
2659 #ifdef MFEM_DEBUG
2660  // For non-orientable surfaces/manifolds, the check below will fail, so we
2661  // only perform it when Dim == spaceDim.
2662  if (Dim >= 2 && Dim == spaceDim)
2663  {
2664  const int num_faces = GetNumFaces();
2665  for (int i = 0; i < num_faces; i++)
2666  {
2667  MFEM_VERIFY(faces_info[i].Elem2No < 0 ||
2668  faces_info[i].Elem2Inf%2 != 0, "Invalid mesh topology."
2669  " Interior face with incompatible orientations.");
2670  }
2671  }
2672 #endif
2673 }
2674 
2675 void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
2676  double sx, double sy, double sz, bool sfc_ordering)
2677 {
2678  int x, y, z;
2679 
2680  int NVert, NElem, NBdrElem;
2681 
2682  NVert = (nx+1) * (ny+1) * (nz+1);
2683  NElem = nx * ny * nz;
2684  NBdrElem = 2*(nx*ny+nx*nz+ny*nz);
2685  if (type == Element::TETRAHEDRON)
2686  {
2687  NElem *= 6;
2688  NBdrElem *= 2;
2689  }
2690  else if (type == Element::WEDGE)
2691  {
2692  NElem *= 2;
2693  NBdrElem += 2*nx*ny;
2694  }
2695 
2696  InitMesh(3, 3, NVert, NElem, NBdrElem);
2697 
2698  double coord[3];
2699  int ind[8];
2700 
2701  // Sets vertices and the corresponding coordinates
2702  for (z = 0; z <= nz; z++)
2703  {
2704  coord[2] = ((double) z / nz) * sz;
2705  for (y = 0; y <= ny; y++)
2706  {
2707  coord[1] = ((double) y / ny) * sy;
2708  for (x = 0; x <= nx; x++)
2709  {
2710  coord[0] = ((double) x / nx) * sx;
2711  AddVertex(coord);
2712  }
2713  }
2714  }
2715 
2716 #define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
2717 
2718  // Sets elements and the corresponding indices of vertices
2719  if (sfc_ordering && type == Element::HEXAHEDRON)
2720  {
2721  Array<int> sfc;
2722  NCMesh::GridSfcOrdering3D(nx, ny, nz, sfc);
2723  MFEM_VERIFY(sfc.Size() == 3*nx*ny*nz, "");
2724 
2725  for (int k = 0; k < nx*ny*nz; k++)
2726  {
2727  x = sfc[3*k + 0];
2728  y = sfc[3*k + 1];
2729  z = sfc[3*k + 2];
2730 
2731  ind[0] = VTX(x , y , z );
2732  ind[1] = VTX(x+1, y , z );
2733  ind[2] = VTX(x+1, y+1, z );
2734  ind[3] = VTX(x , y+1, z );
2735  ind[4] = VTX(x , y , z+1);
2736  ind[5] = VTX(x+1, y , z+1);
2737  ind[6] = VTX(x+1, y+1, z+1);
2738  ind[7] = VTX(x , y+1, z+1);
2739 
2740  AddHex(ind, 1);
2741  }
2742  }
2743  else
2744  {
2745  for (z = 0; z < nz; z++)
2746  {
2747  for (y = 0; y < ny; y++)
2748  {
2749  for (x = 0; x < nx; x++)
2750  {
2751  ind[0] = VTX(x , y , z );
2752  ind[1] = VTX(x+1, y , z );
2753  ind[2] = VTX(x+1, y+1, z );
2754  ind[3] = VTX(x , y+1, z );
2755  ind[4] = VTX(x , y , z+1);
2756  ind[5] = VTX(x+1, y , z+1);
2757  ind[6] = VTX(x+1, y+1, z+1);
2758  ind[7] = VTX( x, y+1, z+1);
2759  if (type == Element::TETRAHEDRON)
2760  {
2761  AddHexAsTets(ind, 1);
2762  }
2763  else if (type == Element::WEDGE)
2764  {
2765  AddHexAsWedges(ind, 1);
2766  }
2767  else
2768  {
2769  AddHex(ind, 1);
2770  }
2771  }
2772  }
2773  }
2774  }
2775 
2776  // Sets boundary elements and the corresponding indices of vertices
2777  // bottom, bdr. attribute 1
2778  for (y = 0; y < ny; y++)
2779  {
2780  for (x = 0; x < nx; x++)
2781  {
2782  ind[0] = VTX(x , y , 0);
2783  ind[1] = VTX(x , y+1, 0);
2784  ind[2] = VTX(x+1, y+1, 0);
2785  ind[3] = VTX(x+1, y , 0);
2786  if (type == Element::TETRAHEDRON)
2787  {
2788  AddBdrQuadAsTriangles(ind, 1);
2789  }
2790  else if (type == Element::WEDGE)
2791  {
2792  AddBdrQuadAsTriangles(ind, 1);
2793  }
2794  else
2795  {
2796  AddBdrQuad(ind, 1);
2797  }
2798  }
2799  }
2800  // top, bdr. attribute 6
2801  for (y = 0; y < ny; y++)
2802  {
2803  for (x = 0; x < nx; x++)
2804  {
2805  ind[0] = VTX(x , y , nz);
2806  ind[1] = VTX(x+1, y , nz);
2807  ind[2] = VTX(x+1, y+1, nz);
2808  ind[3] = VTX(x , y+1, nz);
2809  if (type == Element::TETRAHEDRON)
2810  {
2811  AddBdrQuadAsTriangles(ind, 6);
2812  }
2813  else if (type == Element::WEDGE)
2814  {
2815  AddBdrQuadAsTriangles(ind, 1);
2816  }
2817  else
2818  {
2819  AddBdrQuad(ind, 6);
2820  }
2821  }
2822  }
2823  // left, bdr. attribute 5
2824  for (z = 0; z < nz; z++)
2825  {
2826  for (y = 0; y < ny; y++)
2827  {
2828  ind[0] = VTX(0 , y , z );
2829  ind[1] = VTX(0 , y , z+1);
2830  ind[2] = VTX(0 , y+1, z+1);
2831  ind[3] = VTX(0 , y+1, z );
2832  if (type == Element::TETRAHEDRON)
2833  {
2834  AddBdrQuadAsTriangles(ind, 5);
2835  }
2836  else
2837  {
2838  AddBdrQuad(ind, 5);
2839  }
2840  }
2841  }
2842  // right, bdr. attribute 3
2843  for (z = 0; z < nz; z++)
2844  {
2845  for (y = 0; y < ny; y++)
2846  {
2847  ind[0] = VTX(nx, y , z );
2848  ind[1] = VTX(nx, y+1, z );
2849  ind[2] = VTX(nx, y+1, z+1);
2850  ind[3] = VTX(nx, y , z+1);
2851  if (type == Element::TETRAHEDRON)
2852  {
2853  AddBdrQuadAsTriangles(ind, 3);
2854  }
2855  else
2856  {
2857  AddBdrQuad(ind, 3);
2858  }
2859  }
2860  }
2861  // front, bdr. attribute 2
2862  for (x = 0; x < nx; x++)
2863  {
2864  for (z = 0; z < nz; z++)
2865  {
2866  ind[0] = VTX(x , 0, z );
2867  ind[1] = VTX(x+1, 0, z );
2868  ind[2] = VTX(x+1, 0, z+1);
2869  ind[3] = VTX(x , 0, z+1);
2870  if (type == Element::TETRAHEDRON)
2871  {
2872  AddBdrQuadAsTriangles(ind, 2);
2873  }
2874  else
2875  {
2876  AddBdrQuad(ind, 2);
2877  }
2878  }
2879  }
2880  // back, bdr. attribute 4
2881  for (x = 0; x < nx; x++)
2882  {
2883  for (z = 0; z < nz; z++)
2884  {
2885  ind[0] = VTX(x , ny, z );
2886  ind[1] = VTX(x , ny, z+1);
2887  ind[2] = VTX(x+1, ny, z+1);
2888  ind[3] = VTX(x+1, ny, z );
2889  if (type == Element::TETRAHEDRON)
2890  {
2891  AddBdrQuadAsTriangles(ind, 4);
2892  }
2893  else
2894  {
2895  AddBdrQuad(ind, 4);
2896  }
2897  }
2898  }
2899 
2900 #undef VTX
2901 
2902 #if 0
2903  ofstream test_stream("debug.mesh");
2904  Print(test_stream);
2905  test_stream.close();
2906 #endif
2907 
2908  FinalizeTopology();
2909 
2910  // Finalize(...) can be called after this method, if needed
2911 }
2912 
2913 void Mesh::Make2D(int nx, int ny, Element::Type type,
2914  double sx, double sy,
2915  bool generate_edges, bool sfc_ordering)
2916 {
2917  int i, j, k;
2918 
2919  SetEmpty();
2920 
2921  Dim = spaceDim = 2;
2922 
2923  // Creates quadrilateral mesh
2924  if (type == Element::QUADRILATERAL)
2925  {
2926  NumOfVertices = (nx+1) * (ny+1);
2927  NumOfElements = nx * ny;
2928  NumOfBdrElements = 2 * nx + 2 * ny;
2929 
2930  vertices.SetSize(NumOfVertices);
2931  elements.SetSize(NumOfElements);
2932  boundary.SetSize(NumOfBdrElements);
2933 
2934  double cx, cy;
2935  int ind[4];
2936 
2937  // Sets vertices and the corresponding coordinates
2938  k = 0;
2939  for (j = 0; j < ny+1; j++)
2940  {
2941  cy = ((double) j / ny) * sy;
2942  for (i = 0; i < nx+1; i++)
2943  {
2944  cx = ((double) i / nx) * sx;
2945  vertices[k](0) = cx;
2946  vertices[k](1) = cy;
2947  k++;
2948  }
2949  }
2950 
2951  // Sets elements and the corresponding indices of vertices
2952  if (sfc_ordering)
2953  {
2954  Array<int> sfc;
2955  NCMesh::GridSfcOrdering2D(nx, ny, sfc);
2956  MFEM_VERIFY(sfc.Size() == 2*nx*ny, "");
2957 
2958  for (k = 0; k < nx*ny; k++)
2959  {
2960  i = sfc[2*k + 0];
2961  j = sfc[2*k + 1];
2962  ind[0] = i + j*(nx+1);
2963  ind[1] = i + 1 +j*(nx+1);
2964  ind[2] = i + 1 + (j+1)*(nx+1);
2965  ind[3] = i + (j+1)*(nx+1);
2966  elements[k] = new Quadrilateral(ind);
2967  }
2968  }
2969  else
2970  {
2971  k = 0;
2972  for (j = 0; j < ny; j++)
2973  {
2974  for (i = 0; i < nx; i++)
2975  {
2976  ind[0] = i + j*(nx+1);
2977  ind[1] = i + 1 +j*(nx+1);
2978  ind[2] = i + 1 + (j+1)*(nx+1);
2979  ind[3] = i + (j+1)*(nx+1);
2980  elements[k] = new Quadrilateral(ind);
2981  k++;
2982  }
2983  }
2984  }
2985 
2986  // Sets boundary elements and the corresponding indices of vertices
2987  int m = (nx+1)*ny;
2988  for (i = 0; i < nx; i++)
2989  {
2990  boundary[i] = new Segment(i, i+1, 1);
2991  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
2992  }
2993  m = nx+1;
2994  for (j = 0; j < ny; j++)
2995  {
2996  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
2997  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
2998  }
2999  }
3000  // Creates triangular mesh
3001  else if (type == Element::TRIANGLE)
3002  {
3003  NumOfVertices = (nx+1) * (ny+1);
3004  NumOfElements = 2 * nx * ny;
3005  NumOfBdrElements = 2 * nx + 2 * ny;
3006 
3007  vertices.SetSize(NumOfVertices);
3008  elements.SetSize(NumOfElements);
3009  boundary.SetSize(NumOfBdrElements);
3010 
3011  double cx, cy;
3012  int ind[3];
3013 
3014  // Sets vertices and the corresponding coordinates
3015  k = 0;
3016  for (j = 0; j < ny+1; j++)
3017  {
3018  cy = ((double) j / ny) * sy;
3019  for (i = 0; i < nx+1; i++)
3020  {
3021  cx = ((double) i / nx) * sx;
3022  vertices[k](0) = cx;
3023  vertices[k](1) = cy;
3024  k++;
3025  }
3026  }
3027 
3028  // Sets the elements and the corresponding indices of vertices
3029  k = 0;
3030  for (j = 0; j < ny; j++)
3031  {
3032  for (i = 0; i < nx; i++)
3033  {
3034  ind[0] = i + j*(nx+1);
3035  ind[1] = i + 1 + (j+1)*(nx+1);
3036  ind[2] = i + (j+1)*(nx+1);
3037  elements[k] = new Triangle(ind);
3038  k++;
3039  ind[1] = i + 1 + j*(nx+1);
3040  ind[2] = i + 1 + (j+1)*(nx+1);
3041  elements[k] = new Triangle(ind);
3042  k++;
3043  }
3044  }
3045 
3046  // Sets boundary elements and the corresponding indices of vertices
3047  int m = (nx+1)*ny;
3048  for (i = 0; i < nx; i++)
3049  {
3050  boundary[i] = new Segment(i, i+1, 1);
3051  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3052  }
3053  m = nx+1;
3054  for (j = 0; j < ny; j++)
3055  {
3056  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3057  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3058  }
3059 
3060  // MarkTriMeshForRefinement(); // done in Finalize(...)
3061  }
3062  else
3063  {
3064  MFEM_ABORT("Unsupported element type.");
3065  }
3066 
3067  SetMeshGen();
3068  CheckElementOrientation();
3069 
3070  if (generate_edges == 1)
3071  {
3072  el_to_edge = new Table;
3073  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3074  GenerateFaces();
3075  CheckBdrElementOrientation();
3076  }
3077  else
3078  {
3079  NumOfEdges = 0;
3080  }
3081 
3082  NumOfFaces = 0;
3083 
3084  attributes.Append(1);
3085  bdr_attributes.Append(1); bdr_attributes.Append(2);
3086  bdr_attributes.Append(3); bdr_attributes.Append(4);
3087 
3088  // Finalize(...) can be called after this method, if needed
3089 }
3090 
3091 void Mesh::Make1D(int n, double sx)
3092 {
3093  int j, ind[1];
3094 
3095  SetEmpty();
3096 
3097  Dim = 1;
3098  spaceDim = 1;
3099 
3100  NumOfVertices = n + 1;
3101  NumOfElements = n;
3102  NumOfBdrElements = 2;
3103  vertices.SetSize(NumOfVertices);
3104  elements.SetSize(NumOfElements);
3105  boundary.SetSize(NumOfBdrElements);
3106 
3107  // Sets vertices and the corresponding coordinates
3108  for (j = 0; j < n+1; j++)
3109  {
3110  vertices[j](0) = ((double) j / n) * sx;
3111  }
3112 
3113  // Sets elements and the corresponding indices of vertices
3114  for (j = 0; j < n; j++)
3115  {
3116  elements[j] = new Segment(j, j+1, 1);
3117  }
3118 
3119  // Sets the boundary elements
3120  ind[0] = 0;
3121  boundary[0] = new Point(ind, 1);
3122  ind[0] = n;
3123  boundary[1] = new Point(ind, 2);
3124 
3125  NumOfEdges = 0;
3126  NumOfFaces = 0;
3127 
3128  SetMeshGen();
3129  GenerateFaces();
3130 
3131  attributes.Append(1);
3132  bdr_attributes.Append(1); bdr_attributes.Append(2);
3133 }
3134 
3135 Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
3136 {
3137  Dim = mesh.Dim;
3138  spaceDim = mesh.spaceDim;
3139 
3140  NumOfVertices = mesh.NumOfVertices;
3141  NumOfElements = mesh.NumOfElements;
3142  NumOfBdrElements = mesh.NumOfBdrElements;
3143  NumOfEdges = mesh.NumOfEdges;
3144  NumOfFaces = mesh.NumOfFaces;
3145  nbInteriorFaces = mesh.nbInteriorFaces;
3146  nbBoundaryFaces = mesh.nbBoundaryFaces;
3147 
3148  meshgen = mesh.meshgen;
3149  mesh_geoms = mesh.mesh_geoms;
3150 
3151  // Create the new Mesh instance without a record of its refinement history
3152  sequence = 0;
3153  last_operation = Mesh::NONE;
3154 
3155  // Duplicate the elements
3156  elements.SetSize(NumOfElements);
3157  for (int i = 0; i < NumOfElements; i++)
3158  {
3159  elements[i] = mesh.elements[i]->Duplicate(this);
3160  }
3161 
3162  // Copy the vertices
3163  mesh.vertices.Copy(vertices);
3164 
3165  // Duplicate the boundary
3166  boundary.SetSize(NumOfBdrElements);
3167  for (int i = 0; i < NumOfBdrElements; i++)
3168  {
3169  boundary[i] = mesh.boundary[i]->Duplicate(this);
3170  }
3171 
3172  // Copy the element-to-face Table, el_to_face
3173  el_to_face = (mesh.el_to_face) ? new Table(*mesh.el_to_face) : NULL;
3174 
3175  // Copy the boundary-to-face Array, be_to_face.
3176  mesh.be_to_face.Copy(be_to_face);
3177 
3178  // Copy the element-to-edge Table, el_to_edge
3179  el_to_edge = (mesh.el_to_edge) ? new Table(*mesh.el_to_edge) : NULL;
3180 
3181  // Copy the boundary-to-edge Table, bel_to_edge (3D)
3182  bel_to_edge = (mesh.bel_to_edge) ? new Table(*mesh.bel_to_edge) : NULL;
3183 
3184  // Copy the boundary-to-edge Array, be_to_edge (2D)
3185  mesh.be_to_edge.Copy(be_to_edge);
3186 
3187  // Duplicate the faces and faces_info.
3188  faces.SetSize(mesh.faces.Size());
3189  for (int i = 0; i < faces.Size(); i++)
3190  {
3191  Element *face = mesh.faces[i]; // in 1D the faces are NULL
3192  faces[i] = (face) ? face->Duplicate(this) : NULL;
3193  }
3194  mesh.faces_info.Copy(faces_info);
3195  mesh.nc_faces_info.Copy(nc_faces_info);
3196 
3197  // Do NOT copy the element-to-element Table, el_to_el
3198  el_to_el = NULL;
3199 
3200  // Do NOT copy the face-to-edge Table, face_edge
3201  face_edge = NULL;
3202 
3203  // Copy the edge-to-vertex Table, edge_vertex
3204  edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
3205 
3206  // Copy the attributes and bdr_attributes
3207  mesh.attributes.Copy(attributes);
3208  mesh.bdr_attributes.Copy(bdr_attributes);
3209 
3210  // Deep copy the NURBSExtension.
3211 #ifdef MFEM_USE_MPI
3212  ParNURBSExtension *pNURBSext =
3213  dynamic_cast<ParNURBSExtension *>(mesh.NURBSext);
3214  if (pNURBSext)
3215  {
3216  NURBSext = new ParNURBSExtension(*pNURBSext);
3217  }
3218  else
3219 #endif
3220  {
3221  NURBSext = mesh.NURBSext ? new NURBSExtension(*mesh.NURBSext) : NULL;
3222  }
3223 
3224  // Deep copy the NCMesh.
3225 #ifdef MFEM_USE_MPI
3226  if (dynamic_cast<const ParMesh*>(&mesh))
3227  {
3228  ncmesh = NULL; // skip; will be done in ParMesh copy ctor
3229  }
3230  else
3231 #endif
3232  {
3233  ncmesh = mesh.ncmesh ? new NCMesh(*mesh.ncmesh) : NULL;
3234  }
3235 
3236  // Duplicate the Nodes, including the FiniteElementCollection and the
3237  // FiniteElementSpace
3238  if (mesh.Nodes && copy_nodes)
3239  {
3240  FiniteElementSpace *fes = mesh.Nodes->FESpace();
3241  const FiniteElementCollection *fec = fes->FEColl();
3242  FiniteElementCollection *fec_copy =
3243  FiniteElementCollection::New(fec->Name());
3244  FiniteElementSpace *fes_copy =
3245  new FiniteElementSpace(*fes, this, fec_copy);
3246  Nodes = new GridFunction(fes_copy);
3247  Nodes->MakeOwner(fec_copy);
3248  *Nodes = *mesh.Nodes;
3249  own_nodes = 1;
3250  }
3251  else
3252  {
3253  Nodes = mesh.Nodes;
3254  own_nodes = 0;
3255  }
3256 }
3257 
3258 Mesh::Mesh(Mesh &&mesh) : Mesh()
3259 {
3260  Swap(mesh, true);
3261 }
3262 
3264 {
3265  Swap(mesh, true);
3266  return *this;
3267 }
3268 
3269 Mesh Mesh::LoadFromFile(const char *filename, int generate_edges, int refine,
3270  bool fix_orientation)
3271 {
3272  Mesh mesh;
3273  named_ifgzstream imesh(filename);
3274  if (!imesh) { MFEM_ABORT("Mesh file not found: " << filename << '\n'); }
3275  else { mesh.Load(imesh, generate_edges, refine, fix_orientation); }
3276  return mesh;
3277 }
3278 
3279 Mesh Mesh::MakeCartesian1D(int n, double sx)
3280 {
3281  Mesh mesh;
3282  mesh.Make1D(n, sx);
3283  // mesh.Finalize(); not needed in this case
3284  return mesh;
3285 }
3286 
3288  int nx, int ny, Element::Type type, bool generate_edges,
3289  double sx, double sy, bool sfc_ordering)
3290 {
3291  Mesh mesh;
3292  mesh.Make2D(nx, ny, type, sx, sy, generate_edges, sfc_ordering);
3293  mesh.Finalize(true); // refine = true
3294  return mesh;
3295 }
3296 
3298  int nx, int ny, int nz, Element::Type type,
3299  double sx, double sy, double sz, bool sfc_ordering)
3300 {
3301  Mesh mesh;
3302  mesh.Make3D(nx, ny, nz, type, sx, sy, sz, sfc_ordering);
3303  mesh.Finalize(true); // refine = true
3304  return mesh;
3305 }
3306 
3307 Mesh Mesh::MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
3308 {
3309  Mesh mesh;
3310  Array<int> ref_factors(orig_mesh.GetNE());
3311  ref_factors = ref_factor;
3312  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3313  return mesh;
3314 }
3315 
3316 Mesh Mesh::MakeRefined(Mesh &orig_mesh, const Array<int> &ref_factors,
3317  int ref_type)
3318 {
3319  Mesh mesh;
3320  mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
3321  return mesh;
3322 }
3323 
3324 Mesh::Mesh(const char *filename, int generate_edges, int refine,
3325  bool fix_orientation)
3326 {
3327  // Initialization as in the default constructor
3328  SetEmpty();
3329 
3330  named_ifgzstream imesh(filename);
3331  if (!imesh)
3332  {
3333  // Abort with an error message.
3334  MFEM_ABORT("Mesh file not found: " << filename << '\n');
3335  }
3336  else
3337  {
3338  Load(imesh, generate_edges, refine, fix_orientation);
3339  }
3340 }
3341 
3342 Mesh::Mesh(std::istream &input, int generate_edges, int refine,
3343  bool fix_orientation)
3344 {
3345  SetEmpty();
3346  Load(input, generate_edges, refine, fix_orientation);
3347 }
3348 
3349 void Mesh::ChangeVertexDataOwnership(double *vertex_data, int len_vertex_data,
3350  bool zerocopy)
3351 {
3352  // A dimension of 3 is now required since we use mfem::Vertex objects as PODs
3353  // and these object have a hardcoded double[3] entry
3354  MFEM_VERIFY(len_vertex_data >= NumOfVertices * 3,
3355  "Not enough vertices in external array : "
3356  "len_vertex_data = "<< len_vertex_data << ", "
3357  "NumOfVertices * 3 = " << NumOfVertices * 3);
3358  // Allow multiple calls to this method with the same vertex_data
3359  if (vertex_data == (double *)(vertices.GetData()))
3360  {
3361  MFEM_ASSERT(!vertices.OwnsData(), "invalid ownership");
3362  return;
3363  }
3364  if (!zerocopy)
3365  {
3366  memcpy(vertex_data, vertices.GetData(),
3367  NumOfVertices * 3 * sizeof(double));
3368  }
3369  // Vertex is POD double[3]
3370  vertices.MakeRef(reinterpret_cast<Vertex*>(vertex_data), NumOfVertices);
3371 }
3372 
3373 Mesh::Mesh(double *vertices_, int num_vertices,
3374  int *element_indices, Geometry::Type element_type,
3375  int *element_attributes, int num_elements,
3376  int *boundary_indices, Geometry::Type boundary_type,
3377  int *boundary_attributes, int num_boundary_elements,
3378  int dimension, int space_dimension)
3379 {
3380  if (space_dimension == -1)
3381  {
3382  space_dimension = dimension;
3383  }
3384 
3385  InitMesh(dimension, space_dimension, /*num_vertices*/ 0, num_elements,
3386  num_boundary_elements);
3387 
3388  int element_index_stride = Geometry::NumVerts[element_type];
3389  int boundary_index_stride = num_boundary_elements > 0 ?
3390  Geometry::NumVerts[boundary_type] : 0;
3391 
3392  // assuming Vertex is POD
3393  vertices.MakeRef(reinterpret_cast<Vertex*>(vertices_), num_vertices);
3394  NumOfVertices = num_vertices;
3395 
3396  for (int i = 0; i < num_elements; i++)
3397  {
3398  elements[i] = NewElement(element_type);
3399  elements[i]->SetVertices(element_indices + i * element_index_stride);
3400  elements[i]->SetAttribute(element_attributes[i]);
3401  }
3402  NumOfElements = num_elements;
3403 
3404  for (int i = 0; i < num_boundary_elements; i++)
3405  {
3406  boundary[i] = NewElement(boundary_type);
3407  boundary[i]->SetVertices(boundary_indices + i * boundary_index_stride);
3408  boundary[i]->SetAttribute(boundary_attributes[i]);
3409  }
3410  NumOfBdrElements = num_boundary_elements;
3411 
3412  FinalizeTopology();
3413 }
3414 
3416 {
3417  switch (geom)
3418  {
3419  case Geometry::POINT: return (new Point);
3420  case Geometry::SEGMENT: return (new Segment);
3421  case Geometry::TRIANGLE: return (new Triangle);
3422  case Geometry::SQUARE: return (new Quadrilateral);
3423  case Geometry::TETRAHEDRON:
3424 #ifdef MFEM_USE_MEMALLOC
3425  return TetMemory.Alloc();
3426 #else
3427  return (new Tetrahedron);
3428 #endif
3429  case Geometry::CUBE: return (new Hexahedron);
3430  case Geometry::PRISM: return (new Wedge);
3431  default:
3432  MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
3433  }
3434 
3435  return NULL;
3436 }
3437 
3439 {
3440  int geom, nv, *v;
3441  Element *el;
3442 
3443  input >> geom;
3444  el = NewElement(geom);
3445  MFEM_VERIFY(el, "Unsupported element type: " << geom);
3446  nv = el->GetNVertices();
3447  v = el->GetVertices();
3448  for (int i = 0; i < nv; i++)
3449  {
3450  input >> v[i];
3451  }
3452 
3453  return el;
3454 }
3455 
3456 void Mesh::PrintElementWithoutAttr(const Element *el, std::ostream &out)
3457 {
3458  out << el->GetGeometryType();
3459  const int nv = el->GetNVertices();
3460  const int *v = el->GetVertices();
3461  for (int j = 0; j < nv; j++)
3462  {
3463  out << ' ' << v[j];
3464  }
3465  out << '\n';
3466 }
3467 
3468 Element *Mesh::ReadElement(std::istream &input)
3469 {
3470  int attr;
3471  Element *el;
3472 
3473  input >> attr;
3474  el = ReadElementWithoutAttr(input);
3475  el->SetAttribute(attr);
3476 
3477  return el;
3478 }
3479 
3480 void Mesh::PrintElement(const Element *el, std::ostream &out)
3481 {
3482  out << el->GetAttribute() << ' ';
3483  PrintElementWithoutAttr(el, out);
3484 }
3485 
3487 {
3488  meshgen = mesh_geoms = 0;
3489  for (int i = 0; i < NumOfElements; i++)
3490  {
3491  const Element::Type type = GetElement(i)->GetType();
3492  switch (type)
3493  {
3494  case Element::TETRAHEDRON:
3496  case Element::TRIANGLE:
3497  mesh_geoms |= (1 << Geometry::TRIANGLE);
3498  case Element::SEGMENT:
3499  mesh_geoms |= (1 << Geometry::SEGMENT);
3500  case Element::POINT:
3501  mesh_geoms |= (1 << Geometry::POINT);
3502  meshgen |= 1;
3503  break;
3504 
3505  case Element::HEXAHEDRON:
3506  mesh_geoms |= (1 << Geometry::CUBE);
3508  mesh_geoms |= (1 << Geometry::SQUARE);
3509  mesh_geoms |= (1 << Geometry::SEGMENT);
3510  mesh_geoms |= (1 << Geometry::POINT);
3511  meshgen |= 2;
3512  break;
3513 
3514  case Element::WEDGE:
3515  mesh_geoms |= (1 << Geometry::PRISM);
3516  mesh_geoms |= (1 << Geometry::SQUARE);
3517  mesh_geoms |= (1 << Geometry::TRIANGLE);
3518  mesh_geoms |= (1 << Geometry::SEGMENT);
3519  mesh_geoms |= (1 << Geometry::POINT);
3520  meshgen |= 4;
3521  break;
3522 
3523  default:
3524  MFEM_ABORT("invalid element type: " << type);
3525  break;
3526  }
3527  }
3528 }
3529 
3530 void Mesh::Loader(std::istream &input, int generate_edges,
3531  std::string parse_tag)
3532 {
3533  int curved = 0, read_gf = 1;
3534  bool finalize_topo = true;
3535 
3536  if (!input)
3537  {
3538  MFEM_ABORT("Input stream is not open");
3539  }
3540 
3541  Clear();
3542 
3543  string mesh_type;
3544  input >> ws;
3545  getline(input, mesh_type);
3546  filter_dos(mesh_type);
3547 
3548  // MFEM's conforming mesh formats
3549  int mfem_version = 0;
3550  if (mesh_type == "MFEM mesh v1.0") { mfem_version = 10; } // serial
3551  else if (mesh_type == "MFEM mesh v1.2") { mfem_version = 12; } // parallel
3552 
3553  // MFEM nonconforming mesh format
3554  // (NOTE: previous v1.1 is now under this branch for backward compatibility)
3555  int mfem_nc_version = 0;
3556  if (mesh_type == "MFEM NC mesh v1.0") { mfem_nc_version = 10; }
3557  else if (mesh_type == "MFEM mesh v1.1") { mfem_nc_version = 1 /*legacy*/; }
3558 
3559  if (mfem_version)
3560  {
3561  // Formats mfem_v12 and newer have a tag indicating the end of the mesh
3562  // section in the stream. A user provided parse tag can also be provided
3563  // via the arguments. For example, if this is called from parallel mesh
3564  // object, it can indicate to read until parallel mesh section begins.
3565  if (mfem_version == 12 && parse_tag.empty())
3566  {
3567  parse_tag = "mfem_mesh_end";
3568  }
3569  ReadMFEMMesh(input, mfem_version, curved);
3570  }
3571  else if (mfem_nc_version)
3572  {
3573  MFEM_ASSERT(ncmesh == NULL, "internal error");
3574  int is_nc = 1;
3575 
3576 #ifdef MFEM_USE_MPI
3577  ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
3578  if (pmesh)
3579  {
3580  MFEM_VERIFY(mfem_nc_version >= 10,
3581  "Legacy nonconforming format (MFEM mesh v1.1) cannot be "
3582  "used to load a parallel nonconforming mesh, sorry.");
3583 
3584  ncmesh = new ParNCMesh(pmesh->GetComm(),
3585  input, mfem_nc_version, curved, is_nc);
3586  }
3587  else
3588 #endif
3589  {
3590  ncmesh = new NCMesh(input, mfem_nc_version, curved, is_nc);
3591  }
3593 
3594  if (!is_nc)
3595  {
3596  // special case for backward compatibility with MFEM <=4.2:
3597  // if the "vertex_parents" section is missing in the v1.1 format,
3598  // the mesh is treated as conforming
3599  delete ncmesh;
3600  ncmesh = NULL;
3601  }
3602  }
3603  else if (mesh_type == "linemesh") // 1D mesh
3604  {
3605  ReadLineMesh(input);
3606  }
3607  else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2")
3608  {
3609  if (mesh_type == "curved_areamesh2")
3610  {
3611  curved = 1;
3612  }
3613  ReadNetgen2DMesh(input, curved);
3614  }
3615  else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format")
3616  {
3617  ReadNetgen3DMesh(input);
3618  }
3619  else if (mesh_type == "TrueGrid")
3620  {
3621  ReadTrueGridMesh(input);
3622  }
3623  else if (mesh_type.rfind("# vtk DataFile Version") == 0)
3624  {
3625  int major_vtk_version = mesh_type[mesh_type.length()-3] - '0';
3626  // int minor_vtk_version = mesh_type[mesh_type.length()-1] - '0';
3627  MFEM_VERIFY(major_vtk_version >= 2 && major_vtk_version <= 4,
3628  "Unsupported VTK format");
3629  ReadVTKMesh(input, curved, read_gf, finalize_topo);
3630  }
3631  else if (mesh_type.rfind("<VTKFile ") == 0 || mesh_type.rfind("<?xml") == 0)
3632  {
3633  ReadXML_VTKMesh(input, curved, read_gf, finalize_topo, mesh_type);
3634  }
3635  else if (mesh_type == "MFEM NURBS mesh v1.0")
3636  {
3637  ReadNURBSMesh(input, curved, read_gf);
3638  }
3639  else if (mesh_type == "MFEM INLINE mesh v1.0")
3640  {
3641  ReadInlineMesh(input, generate_edges);
3642  return; // done with inline mesh construction
3643  }
3644  else if (mesh_type == "$MeshFormat") // Gmsh
3645  {
3646  ReadGmshMesh(input, curved, read_gf);
3647  }
3648  else if
3649  ((mesh_type.size() > 2 &&
3650  mesh_type[0] == 'C' && mesh_type[1] == 'D' && mesh_type[2] == 'F') ||
3651  (mesh_type.size() > 3 &&
3652  mesh_type[1] == 'H' && mesh_type[2] == 'D' && mesh_type[3] == 'F'))
3653  {
3654  named_ifgzstream *mesh_input = dynamic_cast<named_ifgzstream *>(&input);
3655  if (mesh_input)
3656  {
3657 #ifdef MFEM_USE_NETCDF
3658  ReadCubit(mesh_input->filename.c_str(), curved, read_gf);
3659 #else
3660  MFEM_ABORT("NetCDF support requires configuration with"
3661  " MFEM_USE_NETCDF=YES");
3662  return;
3663 #endif
3664  }
3665  else
3666  {
3667  MFEM_ABORT("Can not determine Cubit mesh filename!"
3668  " Use mfem::named_ifgzstream for input.");
3669  return;
3670  }
3671  }
3672  else
3673  {
3674  MFEM_ABORT("Unknown input mesh format: " << mesh_type);
3675  return;
3676  }
3677 
3678  // at this point the following should be defined:
3679  // 1) Dim
3680  // 2) NumOfElements, elements
3681  // 3) NumOfBdrElements, boundary
3682  // 4) NumOfVertices, with allocated space in vertices
3683  // 5) curved
3684  // 5a) if curved == 0, vertices must be defined
3685  // 5b) if curved != 0 and read_gf != 0,
3686  // 'input' must point to a GridFunction
3687  // 5c) if curved != 0 and read_gf == 0,
3688  // vertices and Nodes must be defined
3689  // optional:
3690  // 1) el_to_edge may be allocated (as in the case of P2 VTK meshes)
3691  // 2) ncmesh may be allocated
3692 
3693  // FinalizeTopology() will:
3694  // - assume that generate_edges is true
3695  // - assume that refine is false
3696  // - does not check the orientation of regular and boundary elements
3697  if (finalize_topo)
3698  {
3699  // don't generate any boundary elements, especially in parallel
3700  bool generate_bdr = false;
3701 
3702  FinalizeTopology(generate_bdr);
3703  }
3704 
3705  if (curved && read_gf)
3706  {
3707  Nodes = new GridFunction(this, input);
3708 
3709  own_nodes = 1;
3710  spaceDim = Nodes->VectorDim();
3711  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
3712 
3713  // Set vertex coordinates from the 'Nodes'
3715  }
3716 
3717  // If a parse tag was supplied, keep reading the stream until the tag is
3718  // encountered.
3719  if (mfem_version == 12)
3720  {
3721  string line;
3722  do
3723  {
3724  skip_comment_lines(input, '#');
3725  MFEM_VERIFY(input.good(), "Required mesh-end tag not found");
3726  getline(input, line);
3727  filter_dos(line);
3728  // mfem v1.2 may not have parse_tag in it, e.g. if trying to read a
3729  // serial mfem v1.2 mesh as parallel with "mfem_serial_mesh_end" as
3730  // parse_tag. That's why, regardless of parse_tag, we stop reading if
3731  // we find "mfem_mesh_end" which is required by mfem v1.2 format.
3732  if (line == "mfem_mesh_end") { break; }
3733  }
3734  while (line != parse_tag);
3735  }
3736  else if (mfem_nc_version >= 10)
3737  {
3738  string ident;
3739  skip_comment_lines(input, '#');
3740  input >> ident;
3741  MFEM_VERIFY(ident == "mfem_mesh_end",
3742  "invalid mesh: end of file tag not found");
3743  }
3744 
3745  // Finalize(...) should be called after this, if needed.
3746 }
3747 
3748 Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
3749 {
3750  int i, j, ie, ib, iv, *v, nv;
3751  Element *el;
3752  Mesh *m;
3753 
3754  SetEmpty();
3755 
3756  Dim = mesh_array[0]->Dimension();
3757  spaceDim = mesh_array[0]->SpaceDimension();
3758 
3759  if (mesh_array[0]->NURBSext)
3760  {
3761  // assuming the pieces form a partition of a NURBS mesh
3762  NURBSext = new NURBSExtension(mesh_array, num_pieces);
3763 
3766 
3768 
3769  // NumOfBdrElements = NURBSext->GetNBE();
3770  // NURBSext->GetBdrElementTopo(boundary);
3771 
3772  Array<int> lvert_vert, lelem_elem;
3773 
3774  // Here, for visualization purposes, we copy the boundary elements from
3775  // the individual pieces which include the interior boundaries. This
3776  // creates 'boundary' array that is different from the one generated by
3777  // the NURBSExtension which, in particular, makes the boundary-dof table
3778  // invalid. This, in turn, causes GetBdrElementTransformation to not
3779  // function properly.
3780  NumOfBdrElements = 0;
3781  for (i = 0; i < num_pieces; i++)
3782  {
3783  NumOfBdrElements += mesh_array[i]->GetNBE();
3784  }
3785  boundary.SetSize(NumOfBdrElements);
3786  vertices.SetSize(NumOfVertices);
3787  ib = 0;
3788  for (i = 0; i < num_pieces; i++)
3789  {
3790  m = mesh_array[i];
3791  m->NURBSext->GetVertexLocalToGlobal(lvert_vert);
3792  m->NURBSext->GetElementLocalToGlobal(lelem_elem);
3793  // copy the element attributes
3794  for (j = 0; j < m->GetNE(); j++)
3795  {
3796  elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j));
3797  }
3798  // copy the boundary
3799  for (j = 0; j < m->GetNBE(); j++)
3800  {
3801  el = m->GetBdrElement(j)->Duplicate(this);
3802  v = el->GetVertices();
3803  nv = el->GetNVertices();
3804  for (int k = 0; k < nv; k++)
3805  {
3806  v[k] = lvert_vert[v[k]];
3807  }
3808  boundary[ib++] = el;
3809  }
3810  // copy the vertices
3811  for (j = 0; j < m->GetNV(); j++)
3812  {
3813  vertices[lvert_vert[j]].SetCoords(m->SpaceDimension(),
3814  m->GetVertex(j));
3815  }
3816  }
3817  }
3818  else // not a NURBS mesh
3819  {
3820  NumOfElements = 0;
3821  NumOfBdrElements = 0;
3822  NumOfVertices = 0;
3823  for (i = 0; i < num_pieces; i++)
3824  {
3825  m = mesh_array[i];
3826  NumOfElements += m->GetNE();
3827  NumOfBdrElements += m->GetNBE();
3828  NumOfVertices += m->GetNV();
3829  }
3830  elements.SetSize(NumOfElements);
3831  boundary.SetSize(NumOfBdrElements);
3832  vertices.SetSize(NumOfVertices);
3833  ie = ib = iv = 0;
3834  for (i = 0; i < num_pieces; i++)
3835  {
3836  m = mesh_array[i];
3837  // copy the elements
3838  for (j = 0; j < m->GetNE(); j++)
3839  {
3840  el = m->GetElement(j)->Duplicate(this);
3841  v = el->GetVertices();
3842  nv = el->GetNVertices();
3843  for (int k = 0; k < nv; k++)
3844  {
3845  v[k] += iv;
3846  }
3847  elements[ie++] = el;
3848  }
3849  // copy the boundary elements
3850  for (j = 0; j < m->GetNBE(); j++)
3851  {
3852  el = m->GetBdrElement(j)->Duplicate(this);
3853  v = el->GetVertices();
3854  nv = el->GetNVertices();
3855  for (int k = 0; k < nv; k++)
3856  {
3857  v[k] += iv;
3858  }
3859  boundary[ib++] = el;
3860  }
3861  // copy the vertices
3862  for (j = 0; j < m->GetNV(); j++)
3863  {
3864  vertices[iv++].SetCoords(m->SpaceDimension(), m->GetVertex(j));
3865  }
3866  }
3867  }
3868 
3869  FinalizeTopology();
3870 
3871  // copy the nodes (curvilinear meshes)
3872  GridFunction *g = mesh_array[0]->GetNodes();
3873  if (g)
3874  {
3875  Array<GridFunction *> gf_array(num_pieces);
3876  for (i = 0; i < num_pieces; i++)
3877  {
3878  gf_array[i] = mesh_array[i]->GetNodes();
3879  }
3880  Nodes = new GridFunction(this, gf_array, num_pieces);
3881  own_nodes = 1;
3882  }
3883 
3884 #ifdef MFEM_DEBUG
3885  CheckElementOrientation(false);
3887 #endif
3888 }
3889 
3890 Mesh::Mesh(Mesh *orig_mesh, int ref_factor, int ref_type)
3891 {
3892  Array<int> ref_factors(orig_mesh->GetNE());
3893  ref_factors = ref_factor;
3894  MakeRefined_(*orig_mesh, ref_factors, ref_type);
3895 }
3896 
3897 void Mesh::MakeRefined_(Mesh &orig_mesh, const Array<int> ref_factors,
3898  int ref_type)
3899 {
3900  SetEmpty();
3901  Dim = orig_mesh.Dimension();
3902  spaceDim = orig_mesh.SpaceDimension();
3903 
3904  int orig_ne = orig_mesh.GetNE();
3905  MFEM_VERIFY(ref_factors.Size() == orig_ne && orig_ne > 0,
3906  "Number of refinement factors must equal number of elements")
3907  MFEM_VERIFY(ref_factors.Min() >= 1, "Refinement factor must be >= 1");
3908  const int q_type = BasisType::GetQuadrature1D(ref_type);
3909  MFEM_VERIFY(Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid,
3910  "Invalid refinement type. Must use closed basis type.");
3911 
3912  int min_ref = ref_factors.Min();
3913  int max_ref = ref_factors.Max();
3914 
3915  bool var_order = (min_ref != max_ref);
3916 
3917  // variable order space can only be constructed over an NC mesh
3918  if (var_order) { orig_mesh.EnsureNCMesh(true); }
3919 
3920  // Construct a scalar H1 FE space of order ref_factor and use its dofs as
3921  // the indices of the new, refined vertices.
3922  H1_FECollection rfec(min_ref, Dim, ref_type);
3923  FiniteElementSpace rfes(&orig_mesh, &rfec);
3924 
3925  if (var_order)
3926  {
3927  rfes.SetRelaxedHpConformity(false);
3928  for (int i = 0; i < orig_ne; i++)
3929  {
3930  rfes.SetElementOrder(i, ref_factors[i]);
3931  }
3932  rfes.Update(false);
3933  }
3934 
3935  // Set the number of vertices, set the actual coordinates later
3936  NumOfVertices = rfes.GetNDofs();
3937  vertices.SetSize(NumOfVertices);
3938 
3939  Array<int> rdofs;
3940  DenseMatrix phys_pts;
3941 
3942  GeometryRefiner refiner;
3943  refiner.SetType(q_type);
3944 
3945  // Add refined elements and set vertex coordinates
3946  for (int el = 0; el < orig_ne; el++)
3947  {
3948  Geometry::Type geom = orig_mesh.GetElementGeometry(el);
3949  int attrib = orig_mesh.GetAttribute(el);
3950  int nvert = Geometry::NumVerts[geom];
3951  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el]);
3952 
3953  rfes.GetElementDofs(el, rdofs);
3954  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
3955  const FiniteElement *rfe = rfes.GetFE(el);
3956  orig_mesh.GetElementTransformation(el)->Transform(rfe->GetNodes(),
3957  phys_pts);
3958  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[el]);
3959  for (int i = 0; i < phys_pts.Width(); i++)
3960  {
3961  vertices[rdofs[i]].SetCoords(spaceDim, phys_pts.GetColumn(i));
3962  }
3963  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
3964  {
3965  Element *elem = NewElement(geom);
3966  elem->SetAttribute(attrib);
3967  int *v = elem->GetVertices();
3968  for (int k = 0; k < nvert; k++)
3969  {
3970  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
3971  v[k] = rdofs[c2h_map[cid]];
3972  }
3973  AddElement(elem);
3974  }
3975  }
3976 
3977  // Add refined boundary elements
3978  for (int el = 0; el < orig_mesh.GetNBE(); el++)
3979  {
3980  int i, info;
3981  orig_mesh.GetBdrElementAdjacentElement(el, i, info);
3983  int attrib = orig_mesh.GetBdrAttribute(el);
3984  int nvert = Geometry::NumVerts[geom];
3985  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[i]);
3986 
3987  rfes.GetBdrElementDofs(el, rdofs);
3988  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
3989  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[i]);
3990  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
3991  {
3992  Element *elem = NewElement(geom);
3993  elem->SetAttribute(attrib);
3994  int *v = elem->GetVertices();
3995  for (int k = 0; k < nvert; k++)
3996  {
3997  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
3998  v[k] = rdofs[c2h_map[cid]];
3999  }
4000  AddBdrElement(elem);
4001  }
4002  }
4003  FinalizeTopology(false);
4004  sequence = orig_mesh.GetSequence() + 1;
4006 
4007  // Set up the nodes of the new mesh (if the original mesh has nodes). The new
4008  // mesh is always straight-sided (i.e. degree 1 finite element space), but
4009  // the nodes are required for e.g. periodic meshes.
4010  if (orig_mesh.GetNodes())
4011  {
4012  bool discont = orig_mesh.GetNodalFESpace()->IsDGSpace();
4013  Ordering::Type dof_ordering = orig_mesh.GetNodalFESpace()->GetOrdering();
4014  Mesh::SetCurvature(1, discont, spaceDim, dof_ordering);
4015  FiniteElementSpace *nodal_fes = Nodes->FESpace();
4016  const FiniteElementCollection *nodal_fec = nodal_fes->FEColl();
4017  H1_FECollection vertex_fec(1, Dim);
4018  Array<int> dofs;
4019  int el_counter = 0;
4020  for (int iel = 0; iel < orig_ne; iel++)
4021  {
4022  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(iel);
4023  int nvert = Geometry::NumVerts[geom];
4024  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[iel]);
4025  rfes.GetElementDofs(iel, rdofs);
4026  const FiniteElement *rfe = rfes.GetFE(iel);
4027  orig_mesh.GetElementTransformation(iel)->Transform(rfe->GetNodes(),
4028  phys_pts);
4029  const int *node_map = NULL;
4030  const H1_FECollection *h1_fec =
4031  dynamic_cast<const H1_FECollection *>(nodal_fec);
4032  if (h1_fec != NULL) { node_map = h1_fec->GetDofMap(geom); }
4033  const int *vertex_map = vertex_fec.GetDofMap(geom);
4034  const int *c2h_map = rfec.GetDofMap(geom, ref_factors[iel]);
4035  for (int jel = 0; jel < RG.RefGeoms.Size()/nvert; jel++)
4036  {
4037  nodal_fes->GetElementVDofs(el_counter++, dofs);
4038  for (int iv_lex=0; iv_lex<nvert; ++iv_lex)
4039  {
4040  // convert from lexicographic to vertex index
4041  int iv = vertex_map[iv_lex];
4042  // index of vertex of current element in phys_pts matrix
4043  int pt_idx = c2h_map[RG.RefGeoms[iv+nvert*jel]];
4044  // index of current vertex into DOF array
4045  int node_idx = node_map ? node_map[iv_lex] : iv_lex;
4046  for (int d=0; d<spaceDim; ++d)
4047  {
4048  (*Nodes)[dofs[node_idx + d*nvert]] = phys_pts(d,pt_idx);
4049  }
4050  }
4051  }
4052  }
4053  }
4054 
4055  // Setup the data for the coarse-fine refinement transformations
4056  CoarseFineTr.embeddings.SetSize(GetNE());
4057  // First, compute total number of point matrices that we need per geometry
4058  // and the offsets into that array
4059  using GeomRef = std::pair<Geometry::Type, int>;
4060  std::map<GeomRef, int> point_matrices_offsets;
4061  int n_point_matrices[Geometry::NumGeom] = {}; // initialize to zero
4062  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4063  {
4064  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4065  // Have we seen this pair of (goemetry, refinement level) before?
4066  GeomRef id(geom, ref_factors[el_coarse]);
4067  if (point_matrices_offsets.find(id) == point_matrices_offsets.end())
4068  {
4069  RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el_coarse]);
4070  int nvert = Geometry::NumVerts[geom];
4071  int nref_el = RG.RefGeoms.Size()/nvert;
4072  // If not, then store the offset and add to the size required
4073  point_matrices_offsets[id] = n_point_matrices[geom];
4074  n_point_matrices[geom] += nref_el;
4075  }
4076  }
4077 
4078  // Set up the sizes
4079  for (int geom = 0; geom < Geometry::NumGeom; ++geom)
4080  {
4081  int nmatrices = n_point_matrices[geom];
4082  int nvert = Geometry::NumVerts[geom];
4083  CoarseFineTr.point_matrices[geom].SetSize(Dim, nvert, nmatrices);
4084  }
4085 
4086  // Compute the point matrices and embeddings
4087  int el_fine = 0;
4088  for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
4089  {
4090  Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
4091  int ref = ref_factors[el_coarse];
4092  int offset = point_matrices_offsets[GeomRef(geom, ref)];
4093  int nvert = Geometry::NumVerts[geom];
4094  RefinedGeometry &RG = *refiner.Refine(geom, ref);
4095  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4096  {
4097  DenseMatrix &Pj = CoarseFineTr.point_matrices[geom](offset + j);
4098  for (int k = 0; k < nvert; k++)
4099  {
4100  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4101  const IntegrationPoint &ip = RG.RefPts[cid];
4102  ip.Get(Pj.GetColumn(k), Dim);
4103  }
4104 
4105  Embedding &emb = CoarseFineTr.embeddings[el_fine];
4106  emb.parent = el_coarse;
4107  emb.matrix = offset + j;
4108  ++el_fine;
4109  }
4110  }
4111 
4112  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4113 
4114  // The check below is disabled because is fails for parallel meshes with
4115  // interior "boundary" element that, when such "boundary" element is between
4116  // two elements on different processors.
4117  // MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4118 }
4119 
4120 Mesh Mesh::MakeSimplicial(const Mesh &orig_mesh)
4121 {
4122  Mesh mesh;
4123  mesh.MakeSimplicial_(orig_mesh, NULL);
4124  return mesh;
4125 }
4126 
4127 void Mesh::MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
4128 {
4129  MFEM_VERIFY(const_cast<Mesh&>(orig_mesh).CheckElementOrientation(false) == 0,
4130  "Mesh::MakeSimplicial requires a properly oriented input mesh");
4131  MFEM_VERIFY(orig_mesh.Conforming(),
4132  "Mesh::MakeSimplicial does not support non-conforming meshes.")
4133 
4134  int dim = orig_mesh.Dimension();
4135  int sdim = orig_mesh.SpaceDimension();
4136 
4137  if (dim == 1)
4138  {
4139  Mesh copy(orig_mesh);
4140  Swap(copy, true);
4141  return;
4142  }
4143 
4144  int nv = orig_mesh.GetNV();
4145  int ne = orig_mesh.GetNE();
4146  int nbe = orig_mesh.GetNBE();
4147 
4148  static int num_subdivisions[Geometry::NUM_GEOMETRIES];
4149  num_subdivisions[Geometry::POINT] = 1;
4150  num_subdivisions[Geometry::SEGMENT] = 1;
4151  num_subdivisions[Geometry::TRIANGLE] = 1;
4152  num_subdivisions[Geometry::TETRAHEDRON] = 1;
4153  num_subdivisions[Geometry::SQUARE] = 2;
4154  num_subdivisions[Geometry::PRISM] = 3;
4155  num_subdivisions[Geometry::CUBE] = 6;
4156  // NOTE: some hexes may be subdivided into only 5 tets, so this is an
4157  // estimate only. The actual number of created tets may be less, so the
4158  // elements array will need to be shrunk after mesh creation.
4159  int new_ne = 0, new_nbe = 0;
4160  for (int i=0; i<ne; ++i)
4161  {
4162  new_ne += num_subdivisions[orig_mesh.GetElementBaseGeometry(i)];
4163  }
4164  for (int i=0; i<nbe; ++i)
4165  {
4166  new_nbe += num_subdivisions[orig_mesh.GetBdrElementBaseGeometry(i)];
4167  }
4168 
4169  InitMesh(dim, sdim, nv, new_ne, new_nbe);
4170 
4171  // Vertices of the new mesh are same as the original mesh
4172  NumOfVertices = nv;
4173  for (int i=0; i<nv; ++i)
4174  {
4175  vertices[i].SetCoords(dim, orig_mesh.vertices[i]());
4176  }
4177 
4178  // We need a global vertex numbering to identify which diagonals to split
4179  // (quad faces are split using the diagonal originating from the smallest
4180  // global vertex number). Use the supplied global numbering, if it is
4181  // non-NULL, otherwise use the local numbering.
4182  Array<int> vglobal_id;
4183  if (vglobal == NULL)
4184  {
4185  vglobal_id.SetSize(nv);
4186  for (int i=0; i<nv; ++i) { vglobal_id[i] = i; }
4187  vglobal = vglobal_id.GetData();
4188  }
4189 
4190  constexpr int nv_tri = 3, nv_quad = 4, nv_tet = 4, nv_prism = 6, nv_hex = 8;
4191  constexpr int quad_ntris = 2, prism_ntets = 3;
4192  static const int quad_trimap[2][nv_tri*quad_ntris] =
4193  {
4194  {
4195  0, 0,
4196  1, 2,
4197  2, 3
4198  },{
4199  0, 1,
4200  1, 2,
4201  3, 3
4202  }
4203  };
4204  static const int prism_rot[nv_prism*nv_prism] =
4205  {
4206  0, 1, 2, 3, 4, 5,
4207  1, 2, 0, 4, 5, 3,
4208  2, 0, 1, 5, 3, 4,
4209  3, 5, 4, 0, 2, 1,
4210  4, 3, 5, 1, 0, 2,
4211  5, 4, 3, 2, 1, 0
4212  };
4213  static const int prism_f[nv_quad] = {1, 2, 5, 4};
4214  static const int prism_tetmaps[2][nv_prism*prism_ntets] =
4215  {
4216  {
4217  0, 0, 0,
4218  1, 1, 4,
4219  2, 5, 5,
4220  5, 4, 3
4221  },{
4222  0, 0, 0,
4223  1, 4, 4,
4224  2, 2, 5,
4225  4, 5, 3
4226  }
4227  };
4228  static const int hex_rot[nv_hex*nv_hex] =
4229  {
4230  0, 1, 2, 3, 4, 5, 6, 7,
4231  1, 0, 4, 5, 2, 3, 7, 6,
4232  2, 1, 5, 6, 3, 0, 4, 7,
4233  3, 0, 1, 2, 7, 4, 5, 6,
4234  4, 0, 3, 7, 5, 1, 2, 6,
4235  5, 1, 0, 4, 6, 2, 3, 7,
4236  6, 2, 1, 5, 7, 3, 0, 4,
4237  7, 3, 2, 6, 4, 0, 1, 5
4238  };
4239  static const int hex_f0[nv_quad] = {1, 2, 6, 5};
4240  static const int hex_f1[nv_quad] = {2, 3, 7, 6};
4241  static const int hex_f2[nv_quad] = {4, 5, 6, 7};
4242  static const int num_rot[8] = {0, 1, 2, 0, 0, 2, 1, 0};
4243  static const int hex_tetmap0[nv_tet*5] =
4244  {
4245  0, 0, 0, 0, 2,
4246  1, 2, 2, 5, 7,
4247  2, 7, 3, 7, 5,
4248  5, 5, 7, 4, 6
4249  };
4250  static const int hex_tetmap1[nv_tet*6] =
4251  {
4252  0, 0, 1, 0, 0, 1,
4253  5, 1, 6, 7, 7, 7,
4254  7, 7, 7, 2, 1, 6,
4255  4, 5, 5, 3, 2, 2
4256  };
4257  static const int hex_tetmap2[nv_tet*6] =
4258  {
4259  0, 0, 0, 0, 0, 0,
4260  4, 3, 7, 1, 3, 6,
4261  5, 7, 4, 2, 6, 5,
4262  6, 6, 6, 5, 2, 2
4263  };
4264  static const int hex_tetmap3[nv_tet*6] =
4265  {
4266  0, 0, 0, 0, 1, 1,
4267  2, 3, 7, 5, 5, 6,
4268  3, 7, 4, 6, 6, 2,
4269  6, 6, 6, 4, 0, 0
4270  };
4271  static const int *hex_tetmaps[4] =
4272  {
4273  hex_tetmap0, hex_tetmap1, hex_tetmap2, hex_tetmap3
4274  };
4275 
4276  auto find_min = [](const int*a, int n) { return std::min_element(a,a+n)-a; };
4277 
4278  for (int i=0; i<ne; ++i)
4279  {
4280  const int *v = orig_mesh.elements[i]->GetVertices();
4281  const int attrib = orig_mesh.GetAttribute(i);
4282  const Geometry::Type orig_geom = orig_mesh.GetElementBaseGeometry(i);
4283 
4284  if (num_subdivisions[orig_geom] == 1)
4285  {
4286  // (num_subdivisions[orig_geom] == 1) implies that the element does
4287  // not need to be further split (it is either a segment, triangle,
4288  // or tetrahedron), and so it is left unchanged.
4289  Element *e = NewElement(orig_geom);
4290  e->SetAttribute(attrib);
4291  e->SetVertices(v);
4292  AddElement(e);
4293  }
4294  else if (orig_geom == Geometry::SQUARE)
4295  {
4296  for (int itri=0; itri<quad_ntris; ++itri)
4297  {
4299  e->SetAttribute(attrib);
4300  int *v2 = e->GetVertices();
4301  for (int iv=0; iv<nv_tri; ++iv)
4302  {
4303  v2[iv] = v[quad_trimap[0][itri + iv*quad_ntris]];
4304  }
4305  AddElement(e);
4306  }
4307  }
4308  else if (orig_geom == Geometry::PRISM)
4309  {
4310  int vg[nv_prism];
4311  for (int iv=0; iv<nv_prism; ++iv) { vg[iv] = vglobal[v[iv]]; }
4312  // Rotate the vertices of the prism so that the smallest vertex index
4313  // is in the first place
4314  int irot = find_min(vg, nv_prism);
4315  for (int iv=0; iv<nv_prism; ++iv)
4316  {
4317  int jv = prism_rot[iv + irot*nv_prism];
4318  vg[iv] = v[jv];
4319  }
4320  // Two cases according to which diagonal splits third quad face
4321  int q[nv_quad];
4322  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[prism_f[iv]]]; }
4323  int j = find_min(q, nv_quad);
4324  const int *tetmap = (j == 0 || j == 2) ? prism_tetmaps[0] : prism_tetmaps[1];
4325  for (int itet=0; itet<prism_ntets; ++itet)
4326  {
4328  e->SetAttribute(attrib);
4329  int *v2 = e->GetVertices();
4330  for (int iv=0; iv<nv_tet; ++iv)
4331  {
4332  v2[iv] = vg[tetmap[itet + iv*prism_ntets]];
4333  }
4334  AddElement(e);
4335  }
4336  }
4337  else if (orig_geom == Geometry::CUBE)
4338  {
4339  int vg[nv_hex];
4340  for (int iv=0; iv<nv_hex; ++iv) { vg[iv] = vglobal[v[iv]]; }
4341 
4342  // Rotate the vertices of the hex so that the smallest vertex index is
4343  // in the first place
4344  int irot = find_min(vg, nv_hex);
4345  for (int iv=0; iv<nv_hex; ++iv)
4346  {
4347  int jv = hex_rot[iv + irot*nv_hex];
4348  vg[iv] = v[jv];
4349  }
4350 
4351  int q[nv_quad];
4352  // Bitmask is three binary digits, each digit is 1 if the diagonal of
4353  // the corresponding face goes through the 7th vertex, and 0 if not.
4354  int bitmask = 0;
4355  int j;
4356  // First quad face
4357  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f0[iv]]]; }
4358  j = find_min(q, nv_quad);
4359  if (j == 0 || j == 2) { bitmask += 4; }
4360  // Second quad face
4361  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f1[iv]]]; }
4362  j = find_min(q, nv_quad);
4363  if (j == 1 || j == 3) { bitmask += 2; }
4364  // Third quad face
4365  for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f2[iv]]]; }
4366  j = find_min(q, nv_quad);
4367  if (j == 0 || j == 2) { bitmask += 1; }
4368 
4369  // Apply rotations
4370  int nrot = num_rot[bitmask];
4371  for (int irot=0; irot<nrot; ++irot)
4372  {
4373  int vtemp;
4374  vtemp = vg[1];
4375  vg[1] = vg[4];
4376  vg[4] = vg[3];
4377  vg[3] = vtemp;
4378  vtemp = vg[5];
4379  vg[5] = vg[7];
4380  vg[7] = vg[2];
4381  vg[2] = vtemp;
4382  }
4383 
4384  // Sum up nonzero bits in bitmask
4385  int ndiags = ((bitmask&4) >> 2) + ((bitmask&2) >> 1) + (bitmask&1);
4386  int ntets = (ndiags == 0) ? 5 : 6;
4387  const int *tetmap = hex_tetmaps[ndiags];
4388  for (int itet=0; itet<ntets; ++itet)
4389  {
4391  e->SetAttribute(attrib);
4392  int *v2 = e->GetVertices();
4393  for (int iv=0; iv<nv_tet; ++iv)
4394  {
4395  v2[iv] = vg[tetmap[itet + iv*ntets]];
4396  }
4397  AddElement(e);
4398  }
4399  }
4400  }
4401  // In 3D, shrink the element array because some hexes have only 5 tets
4402  if (dim == 3) { elements.SetSize(NumOfElements); }
4403 
4404  for (int i=0; i<nbe; ++i)
4405  {
4406  const int *v = orig_mesh.boundary[i]->GetVertices();
4407  const int attrib = orig_mesh.GetBdrAttribute(i);
4408  const Geometry::Type orig_geom = orig_mesh.GetBdrElementBaseGeometry(i);
4409  if (num_subdivisions[orig_geom] == 1)
4410  {
4411  Element *be = NewElement(orig_geom);
4412  be->SetAttribute(attrib);
4413  be->SetVertices(v);
4414  AddBdrElement(be);
4415  }
4416  else if (orig_geom == Geometry::SQUARE)
4417  {
4418  int vg[nv_quad];
4419  for (int iv=0; iv<nv_quad; ++iv) { vg[iv] = vglobal[v[iv]]; }
4420  // Split quad according the smallest (global) vertex
4421  int iv_min = find_min(vg, nv_quad);
4422  int isplit = (iv_min == 0 || iv_min == 2) ? 0 : 1;
4423  for (int itri=0; itri<quad_ntris; ++itri)
4424  {
4426  be->SetAttribute(attrib);
4427  int *v2 = be->GetVertices();
4428  for (int iv=0; iv<nv_tri; ++iv)
4429  {
4430  v2[iv] = v[quad_trimap[isplit][itri + iv*quad_ntris]];
4431  }
4432  AddBdrElement(be);
4433  }
4434  }
4435  else
4436  {
4437  MFEM_ABORT("Unreachable");
4438  }
4439  }
4440 
4441  FinalizeTopology(false);
4442  sequence = orig_mesh.GetSequence();
4443  last_operation = orig_mesh.last_operation;
4444 
4445  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
4446  MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
4447 }
4448 
4449 Mesh Mesh::MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v)
4450 {
4451  Mesh periodic_mesh(orig_mesh, true); // Make a copy of the original mesh
4452  const FiniteElementSpace *nodal_fes = orig_mesh.GetNodalFESpace();
4453  int nodal_order = nodal_fes ? nodal_fes->GetMaxElementOrder() : 1;
4454  periodic_mesh.SetCurvature(nodal_order, true);
4455 
4456  // renumber element vertices
4457  for (int i = 0; i < periodic_mesh.GetNE(); i++)
4458  {
4459  Element *el = periodic_mesh.GetElement(i);
4460  int *v = el->GetVertices();
4461  int nv = el->GetNVertices();
4462  for (int j = 0; j < nv; j++)
4463  {
4464  v[j] = v2v[v[j]];
4465  }
4466  }
4467  // renumber boundary element vertices
4468  for (int i = 0; i < periodic_mesh.GetNBE(); i++)
4469  {
4470  Element *el = periodic_mesh.GetBdrElement(i);
4471  int *v = el->GetVertices();
4472  int nv = el->GetNVertices();
4473  for (int j = 0; j < nv; j++)
4474  {
4475  v[j] = v2v[v[j]];
4476  }
4477  }
4478 
4479  periodic_mesh.RemoveUnusedVertices();
4480  return periodic_mesh;
4481 }
4482 
4484  const std::vector<Vector> &translations, double tol) const
4485 {
4486  int sdim = SpaceDimension();
4487 
4488  Vector coord(sdim), at(sdim), dx(sdim);
4489  Vector xMax(sdim), xMin(sdim), xDiff(sdim);
4490  xMax = xMin = xDiff = 0.0;
4491 
4492  // Get a list of all vertices on the boundary
4493  set<int> bdr_v;
4494  for (int be = 0; be < GetNBE(); be++)
4495  {
4496  Array<int> dofs;
4497  GetBdrElementVertices(be,dofs);
4498 
4499  for (int i = 0; i < dofs.Size(); i++)
4500  {
4501  bdr_v.insert(dofs[i]);
4502 
4503  coord = GetVertex(dofs[i]);
4504  for (int j = 0; j < sdim; j++)
4505  {
4506  xMax[j] = max(xMax[j], coord[j]);
4507  xMin[j] = min(xMin[j], coord[j]);
4508  }
4509  }
4510  }
4511  add(xMax, -1.0, xMin, xDiff);
4512  double dia = xDiff.Norml2(); // compute mesh diameter
4513 
4514  // We now identify coincident vertices. Several originally distinct vertices
4515  // may become coincident under the periodic mapping. One of these vertices
4516  // will be identified as the "primary" vertex, and all other coincident
4517  // vertices will be considered as "replicas".
4518 
4519  // replica2primary[v] is the index of the primary vertex of replica `v`
4520  map<int, int> replica2primary;
4521  // primary2replicas[v] is a set of indices of replicas of primary vertex `v`
4522  map<int, set<int>> primary2replicas;
4523 
4524  // We begin with the assumption that all vertices are primary, and that there
4525  // are no replicas.
4526  for (int v : bdr_v) { primary2replicas[v]; }
4527 
4528  // Make `r` and all of `r`'s replicas be replicas of `p`. Delete `r` from the
4529  // list of primary vertices.
4530  auto make_replica = [&replica2primary, &primary2replicas](int r, int p)
4531  {
4532  if (r == p) { return; }
4533  primary2replicas[p].insert(r);
4534  replica2primary[r] = p;
4535  for (int s : primary2replicas[r])
4536  {
4537  primary2replicas[p].insert(s);
4538  replica2primary[s] = p;
4539  }
4540  primary2replicas.erase(r);
4541  };
4542 
4543  for (unsigned int i = 0; i < translations.size(); i++)
4544  {
4545  for (int vi : bdr_v)
4546  {
4547  coord = GetVertex(vi);
4548  add(coord, translations[i], at);
4549 
4550  for (int vj : bdr_v)
4551  {
4552  coord = GetVertex(vj);
4553  add(at, -1.0, coord, dx);
4554  if (dx.Norml2() > dia*tol) { continue; }
4555 
4556  // The two vertices vi and vj are coincident.
4557 
4558  // Are vertices `vi` and `vj` already primary?
4559  bool pi = primary2replicas.find(vi) != primary2replicas.end();
4560  bool pj = primary2replicas.find(vj) != primary2replicas.end();
4561 
4562  if (pi && pj)
4563  {
4564  // Both vertices are currently primary
4565  // Demote `vj` to be a replica of `vi`
4566  make_replica(vj, vi);
4567  }
4568  else if (pi && !pj)
4569  {
4570  // `vi` is primary and `vj` is a replica
4571  int owner_of_vj = replica2primary[vj];
4572  // Make `vi` and its replicas be replicas of `vj`'s owner
4573  make_replica(vi, owner_of_vj);
4574  }
4575  else if (!pi && pj)
4576  {
4577  // `vi` is currently a replica and `vj` is currently primary
4578  // Make `vj` and its replicas be replicas of `vi`'s owner
4579  int owner_of_vi = replica2primary[vi];
4580  make_replica(vj, owner_of_vi);
4581  }
4582  else
4583  {
4584  // Both vertices are currently replicas
4585  // Make `vj`'s owner and all of its owner's replicas be replicas
4586  // of `vi`'s owner
4587  int owner_of_vi = replica2primary[vi];
4588  int owner_of_vj = replica2primary[vj];
4589  make_replica(owner_of_vj, owner_of_vi);
4590  }
4591  break;
4592  }
4593  }
4594  }
4595 
4596  std::vector<int> v2v(GetNV());
4597  for (size_t i = 0; i < v2v.size(); i++)
4598  {
4599  v2v[i] = i;
4600  }
4601  for (auto &&r2p : replica2primary)
4602  {
4603  v2v[r2p.first] = r2p.second;
4604  }
4605  return v2v;
4606 }
4607 
4609 {
4610  if (NURBSext == NULL)
4611  {
4612  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
4613  }
4614 
4615  if (kv.Size() != NURBSext->GetNKV())
4616  {
4617  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
4618  }
4619 
4621 
4622  NURBSext->KnotInsert(kv);
4623 
4624  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
4625  sequence++;
4626 
4627  UpdateNURBS();
4628 }
4629 
4631 {
4632  if (NURBSext == NULL)
4633  {
4634  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
4635  }
4636 
4637  if (kv.Size() != NURBSext->GetNKV())
4638  {
4639  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
4640  }
4641 
4643 
4644  NURBSext->KnotInsert(kv);
4645 
4646  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
4647  sequence++;
4648 
4649  UpdateNURBS();
4650 }
4651 
4653 {
4654  // do not check for NURBSext since this method is protected
4656 
4658 
4659  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
4660  sequence++;
4661 
4662  UpdateNURBS();
4663 }
4664 
4665 void Mesh::DegreeElevate(int rel_degree, int degree)
4666 {
4667  if (NURBSext == NULL)
4668  {
4669  mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!");
4670  }
4671 
4673 
4674  NURBSext->DegreeElevate(rel_degree, degree);
4675 
4676  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
4677  sequence++;
4678 
4679  UpdateNURBS();
4680 }
4681 
4683 {
4684  ResetLazyData();
4685 
4687 
4688  Dim = NURBSext->Dimension();
4689  spaceDim = Dim;
4690 
4691  if (NumOfElements != NURBSext->GetNE())
4692  {
4693  for (int i = 0; i < elements.Size(); i++)
4694  {
4695  FreeElement(elements[i]);
4696  }
4699  }
4700 
4701  if (NumOfBdrElements != NURBSext->GetNBE())
4702  {
4703  for (int i = 0; i < boundary.Size(); i++)
4704  {
4705  FreeElement(boundary[i]);
4706  }
4709  }
4710 
4711  Nodes->FESpace()->Update();
4712  Nodes->Update();
4714 
4715  if (NumOfVertices != NURBSext->GetNV())
4716  {
4718  vertices.SetSize(NumOfVertices);
4719  int vd = Nodes->VectorDim();
4720  for (int i = 0; i < vd; i++)
4721  {
4722  Vector vert_val;
4723  Nodes->GetNodalValues(vert_val, i+1);
4724  for (int j = 0; j < NumOfVertices; j++)
4725  {
4726  vertices[j](i) = vert_val(j);
4727  }
4728  }
4729  }
4730 
4731  if (el_to_edge)
4732  {
4734  if (Dim == 2)
4735  {
4736  GenerateFaces();
4737  }
4738  }
4739 
4740  if (el_to_face)
4741  {
4743  GenerateFaces();
4744  }
4745 }
4746 
4747 void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot)
4748 {
4749  SetEmpty();
4750 
4751  // Read MFEM NURBS mesh v1.0 format
4752  string ident;
4753 
4754  skip_comment_lines(input, '#');
4755 
4756  input >> ident; // 'dimension'
4757  input >> Dim;
4758  spaceDim = Dim;
4759 
4760  skip_comment_lines(input, '#');
4761 
4762  input >> ident; // 'elements'
4763  input >> NumOfElements;
4764  elements.SetSize(NumOfElements);
4765  for (int j = 0; j < NumOfElements; j++)
4766  {
4767  elements[j] = ReadElement(input);
4768  }
4769 
4770  skip_comment_lines(input, '#');
4771 
4772  input >> ident; // 'boundary'
4773  input >> NumOfBdrElements;
4774  boundary.SetSize(NumOfBdrElements);
4775  for (int j = 0; j < NumOfBdrElements; j++)
4776  {
4777  boundary[j] = ReadElement(input);
4778  }
4779 
4780  skip_comment_lines(input, '#');
4781 
4782  input >> ident; // 'edges'
4783  input >> NumOfEdges;
4784  edge_vertex = new Table(NumOfEdges, 2);
4785  edge_to_knot.SetSize(NumOfEdges);
4786  for (int j = 0; j < NumOfEdges; j++)
4787  {
4788  int *v = edge_vertex->GetRow(j);
4789  input >> edge_to_knot[j] >> v[0] >> v[1];
4790  if (v[0] > v[1])
4791  {
4792  edge_to_knot[j] = -1 - edge_to_knot[j];
4793  }
4794  }
4795 
4796  skip_comment_lines(input, '#');
4797 
4798  input >> ident; // 'vertices'
4799  input >> NumOfVertices;
4800  vertices.SetSize(0);
4801 
4802  FinalizeTopology();
4803  CheckBdrElementOrientation(); // check and fix boundary element orientation
4804 }
4805 
4807 {
4808  if (p.Size() >= v.Size())
4809  {
4810  for (int d = 0; d < v.Size(); d++)
4811  {
4812  v(d) = p(d);
4813  }
4814  }
4815  else
4816  {
4817  int d;
4818  for (d = 0; d < p.Size(); d++)
4819  {
4820  v(d) = p(d);
4821  }
4822  for ( ; d < v.Size(); d++)
4823  {
4824  v(d) = 0.0;
4825  }
4826  }
4827 }
4828 
4829 void Mesh::GetNodes(GridFunction &nodes) const
4830 {
4831  if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
4832  {
4833  const int newSpaceDim = nodes.FESpace()->GetVDim();
4835  nodes.ProjectCoefficient(xyz);
4836  }
4837  else
4838  {
4839  nodes = *Nodes;
4840  }
4841 }
4842 
4844 {
4845  GridFunction *nodes = new GridFunction(nfes);
4846  SetNodalGridFunction(nodes, true);
4847 }
4848 
4850 {
4851  if (Nodes)
4852  {
4854  if (dynamic_cast<const H1_FECollection*>(fec)
4855  || dynamic_cast<const L2_FECollection*>(fec))
4856  {
4857  return;
4858  }
4859  else // Mesh using a legacy FE_Collection
4860  {
4861  const int order = GetNodalFESpace()->GetElementOrder(0);
4862  SetCurvature(order, false, -1, Ordering::byVDIM);
4863  }
4864  }
4865  else // First order H1 mesh
4866  {
4867  SetCurvature(1, false, -1, Ordering::byVDIM);
4868  }
4869 }
4870 
4871 void Mesh::SetNodalGridFunction(GridFunction *nodes, bool make_owner)
4872 {
4873  GetNodes(*nodes);
4874  NewNodes(*nodes, make_owner);
4875 }
4876 
4878 {
4879  return ((Nodes) ? Nodes->FESpace() : NULL);
4880 }
4881 
4882 void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
4883 {
4884  space_dim = (space_dim == -1) ? spaceDim : space_dim;
4886  if (discont)
4887  {
4888  const int type = 1; // Gauss-Lobatto points
4889  nfec = new L2_FECollection(order, Dim, type);
4890  }
4891  else
4892  {
4893  nfec = new H1_FECollection(order, Dim);
4894  }
4895  FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
4896  ordering);
4897  SetNodalFESpace(nfes);
4898  Nodes->MakeOwner(nfec);
4899 }
4900 
4902 {
4903  MFEM_ASSERT(nodes != NULL, "");
4904  for (int i = 0; i < spaceDim; i++)
4905  {
4906  Vector vert_val;
4907  nodes->GetNodalValues(vert_val, i+1);
4908  for (int j = 0; j < NumOfVertices; j++)
4909  {
4910  vertices[j](i) = vert_val(j);
4911  }
4912  }
4913 }
4914 
4916 {
4917  switch (Dim)
4918  {
4919  case 1: return GetNV();
4920  case 2: return GetNEdges();
4921  case 3: return GetNFaces();
4922  }
4923  return 0;
4924 }
4925 
4926 static int CountFacesByType(const Mesh &mesh, const FaceType type)
4927 {
4928  int e1, e2;
4929  int inf1, inf2;
4930  int nf = 0;
4931  for (int f = 0; f < mesh.GetNumFaces(); ++f)
4932  {
4933  mesh.GetFaceElements(f, &e1, &e2);
4934  mesh.GetFaceInfos(f, &inf1, &inf2);
4935  if ((type==FaceType::Interior && (e2>=0 || (e2<0 && inf2>=0))) ||
4936  (type==FaceType::Boundary && e2<0 && inf2<0) ) { nf++; }
4937  }
4938  return nf;
4939 }
4940 
4942 {
4943  const bool isInt = type==FaceType::Interior;
4944  int &nf = isInt ? nbInteriorFaces : nbBoundaryFaces;
4945  if (nf<0) { nf = CountFacesByType(*this, type); }
4946  return nf;
4947 }
4948 
4949 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
4950 static const char *fixed_or_not[] = { "fixed", "NOT FIXED" };
4951 #endif
4952 
4954 {
4955  int i, j, k, wo = 0, fo = 0;
4956  double *v[4];
4957 
4958  if (Dim == 2 && spaceDim == 2)
4959  {
4960  DenseMatrix J(2, 2);
4961 
4962  for (i = 0; i < NumOfElements; i++)
4963  {
4964  int *vi = elements[i]->GetVertices();
4965  if (Nodes == NULL)
4966  {
4967  for (j = 0; j < 3; j++)
4968  {
4969  v[j] = vertices[vi[j]]();
4970  }
4971  for (j = 0; j < 2; j++)
4972  for (k = 0; k < 2; k++)
4973  {
4974  J(j, k) = v[j+1][k] - v[0][k];
4975  }
4976  }
4977  else
4978  {
4979  // only check the Jacobian at the center of the element
4980  GetElementJacobian(i, J);
4981  }
4982  if (J.Det() < 0.0)
4983  {
4984  if (fix_it)
4985  {
4986  switch (GetElementType(i))
4987  {
4988  case Element::TRIANGLE:
4989  mfem::Swap(vi[0], vi[1]);
4990  break;
4992  mfem::Swap(vi[1], vi[3]);
4993  break;
4994  default:
4995  MFEM_ABORT("Invalid 2D element type \""
4996  << GetElementType(i) << "\"");
4997  break;
4998  }
4999  fo++;
5000  }
5001  wo++;
5002  }
5003  }
5004  }
5005 
5006  if (Dim == 3)
5007  {
5008  DenseMatrix J(3, 3);
5009 
5010  for (i = 0; i < NumOfElements; i++)
5011  {
5012  int *vi = elements[i]->GetVertices();
5013  switch (GetElementType(i))
5014  {
5015  case Element::TETRAHEDRON:
5016  if (Nodes == NULL)
5017  {
5018  for (j = 0; j < 4; j++)
5019  {
5020  v[j] = vertices[vi[j]]();
5021  }
5022  for (j = 0; j < 3; j++)
5023  for (k = 0; k < 3; k++)
5024  {
5025  J(j, k) = v[j+1][k] - v[0][k];
5026  }
5027  }
5028  else
5029  {
5030  // only check the Jacobian at the center of the element
5031  GetElementJacobian(i, J);
5032  }
5033  if (J.Det() < 0.0)
5034  {
5035  wo++;
5036  if (fix_it)
5037  {
5038  mfem::Swap(vi[0], vi[1]);
5039  fo++;
5040  }
5041  }
5042  break;
5043 
5044  case Element::WEDGE:
5045  // only check the Jacobian at the center of the element
5046  GetElementJacobian(i, J);
5047  if (J.Det() < 0.0)
5048  {
5049  wo++;
5050  if (fix_it)
5051  {
5052  // how?
5053  }
5054  }
5055  break;
5056 
5057  case Element::HEXAHEDRON:
5058  // only check the Jacobian at the center of the element
5059  GetElementJacobian(i, J);
5060  if (J.Det() < 0.0)
5061  {
5062  wo++;
5063  if (fix_it)
5064  {
5065  // how?
5066  }
5067  }
5068  break;
5069 
5070  default:
5071  MFEM_ABORT("Invalid 3D element type \""
5072  << GetElementType(i) << "\"");
5073  break;
5074  }
5075  }
5076  }
5077 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5078  if (wo > 0)
5079  {
5080  mfem::out << "Elements with wrong orientation: " << wo << " / "
5081  << NumOfElements << " (" << fixed_or_not[(wo == fo) ? 0 : 1]
5082  << ")" << endl;
5083  }
5084 #endif
5085  return wo;
5086 }
5087 
5088 int Mesh::GetTriOrientation(const int *base, const int *test)
5089 {
5090  // Static method.
5091  // This function computes the index 'j' of the permutation that transforms
5092  // test into base: test[tri_orientation[j][i]]=base[i].
5093  // tri_orientation = Geometry::Constants<Geometry::TRIANGLE>::Orient
5094  int orient;
5095 
5096  if (test[0] == base[0])
5097  if (test[1] == base[1])
5098  {
5099  orient = 0; // (0, 1, 2)
5100  }
5101  else
5102  {
5103  orient = 5; // (0, 2, 1)
5104  }
5105  else if (test[0] == base[1])
5106  if (test[1] == base[0])
5107  {
5108  orient = 1; // (1, 0, 2)
5109  }
5110  else
5111  {
5112  orient = 2; // (1, 2, 0)
5113  }
5114  else // test[0] == base[2]
5115  if (test[1] == base[0])
5116  {
5117  orient = 4; // (2, 0, 1)
5118  }
5119  else
5120  {
5121  orient = 3; // (2, 1, 0)
5122  }
5123 
5124 #ifdef MFEM_DEBUG
5125  const int *aor = tri_t::Orient[orient];
5126  for (int j = 0; j < 3; j++)
5127  if (test[aor[j]] != base[j])
5128  {
5129  mfem_error("Mesh::GetTriOrientation(...)");
5130  }
5131 #endif
5132 
5133  return orient;
5134 }
5135 
5136 int Mesh::GetQuadOrientation(const int *base, const int *test)
5137 {
5138  int i;
5139 
5140  for (i = 0; i < 4; i++)
5141  if (test[i] == base[0])
5142  {
5143  break;
5144  }
5145 
5146 #ifdef MFEM_DEBUG
5147  int orient;
5148  if (test[(i+1)%4] == base[1])
5149  {
5150  orient = 2*i;
5151  }
5152  else
5153  {
5154  orient = 2*i+1;
5155  }
5156  const int *aor = quad_t::Orient[orient];
5157  for (int j = 0; j < 4; j++)
5158  if (test[aor[j]] != base[j])
5159  {
5160  mfem::err << "Mesh::GetQuadOrientation(...)" << endl;
5161  mfem::err << " base = [";
5162  for (int k = 0; k < 4; k++)
5163  {
5164  mfem::err << " " << base[k];
5165  }
5166  mfem::err << " ]\n test = [";
5167  for (int k = 0; k < 4; k++)
5168  {
5169  mfem::err << " " << test[k];
5170  }
5171  mfem::err << " ]" << endl;
5172  mfem_error();
5173  }
5174 #endif
5175 
5176  if (test[(i+1)%4] == base[1])
5177  {
5178  return 2*i;
5179  }
5180 
5181  return 2*i+1;
5182 }
5183 
5184 int Mesh::GetTetOrientation(const int *base, const int *test)
5185 {
5186  // Static method.
5187  // This function computes the index 'j' of the permutation that transforms
5188  // test into base: test[tet_orientation[j][i]]=base[i].
5189  // tet_orientation = Geometry::Constants<Geometry::TETRAHEDRON>::Orient
5190  int orient;
5191 
5192  if (test[0] == base[0])
5193  if (test[1] == base[1])
5194  if (test[2] == base[2])
5195  {
5196  orient = 0; // (0, 1, 2, 3)
5197  }
5198  else
5199  {
5200  orient = 1; // (0, 1, 3, 2)
5201  }
5202  else if (test[2] == base[1])
5203  if (test[3] == base[2])
5204  {
5205  orient = 2; // (0, 2, 3, 1)
5206  }
5207  else
5208  {
5209  orient = 3; // (0, 2, 1, 3)
5210  }
5211  else // test[3] == base[1]
5212  if (test[1] == base[2])
5213  {
5214  orient = 4; // (0, 3, 1, 2)
5215  }
5216  else
5217  {
5218  orient = 5; // (0, 3, 2, 1)
5219  }
5220  else if (test[1] == base[0])
5221  if (test[2] == base[1])
5222  if (test[0] == base[2])
5223  {
5224  orient = 6; // (1, 2, 0, 3)
5225  }
5226  else
5227  {
5228  orient = 7; // (1, 2, 3, 0)
5229  }
5230  else if (test[3] == base[1])
5231  if (test[2] == base[2])
5232  {
5233  orient = 8; // (1, 3, 2, 0)
5234  }
5235  else
5236  {
5237  orient = 9; // (1, 3, 0, 2)
5238  }
5239  else // test[0] == base[1]
5240  if (test[3] == base[2])
5241  {
5242  orient = 10; // (1, 0, 3, 2)
5243  }
5244  else
5245  {
5246  orient = 11; // (1, 0, 2, 3)
5247  }
5248  else if (test[2] == base[0])
5249  if (test[3] == base[1])
5250  if (test[0] == base[2])
5251  {
5252  orient = 12; // (2, 3, 0, 1)
5253  }
5254  else
5255  {
5256  orient = 13; // (2, 3, 1, 0)
5257  }
5258  else if (test[0] == base[1])
5259  if (test[1] == base[2])
5260  {
5261  orient = 14; // (2, 0, 1, 3)
5262  }
5263  else
5264  {
5265  orient = 15; // (2, 0, 3, 1)
5266  }
5267  else // test[1] == base[1]
5268  if (test[3] == base[2])
5269  {
5270  orient = 16; // (2, 1, 3, 0)
5271  }
5272  else
5273  {
5274  orient = 17; // (2, 1, 0, 3)
5275  }
5276  else // (test[3] == base[0])
5277  if (test[0] == base[1])
5278  if (test[2] == base[2])
5279  {
5280  orient = 18; // (3, 0, 2, 1)
5281  }
5282  else
5283  {
5284  orient = 19; // (3, 0, 1, 2)
5285  }
5286  else if (test[1] == base[1])
5287  if (test[0] == base[2])
5288  {
5289  orient = 20; // (3, 1, 0, 2)
5290  }
5291  else
5292  {
5293  orient = 21; // (3, 1, 2, 0)
5294  }
5295  else // test[2] == base[1]
5296  if (test[1] == base[2])
5297  {
5298  orient = 22; // (3, 2, 1, 0)
5299  }
5300  else
5301  {
5302  orient = 23; // (3, 2, 0, 1)
5303  }
5304 
5305 #ifdef MFEM_DEBUG
5306  const int *aor = tet_t::Orient[orient];
5307  for (int j = 0; j < 4; j++)
5308  if (test[aor[j]] != base[j])
5309  {
5310  mfem_error("Mesh::GetTetOrientation(...)");
5311  }
5312 #endif
5313 
5314  return orient;
5315 }
5316 
5318 {
5319  int wo = 0; // count wrong orientations
5320 
5321  if (Dim == 2)
5322  {
5323  if (el_to_edge == NULL) // edges were not generated
5324  {
5325  el_to_edge = new Table;
5327  GenerateFaces(); // 'Faces' in 2D refers to the edges
5328  }
5329  for (int i = 0; i < NumOfBdrElements; i++)
5330  {
5331  if (faces_info[be_to_edge[i]].Elem2No < 0) // boundary face
5332  {
5333  int *bv = boundary[i]->GetVertices();
5334  int *fv = faces[be_to_edge[i]]->GetVertices();
5335  if (bv[0] != fv[0])
5336  {
5337  if (fix_it)
5338  {
5339  mfem::Swap<int>(bv[0], bv[1]);
5340  }
5341  wo++;
5342  }
5343  }
5344  }
5345  }
5346 
5347  if (Dim == 3)
5348  {
5349  for (int i = 0; i < NumOfBdrElements; i++)
5350  {
5351  const int fi = be_to_face[i];
5352 
5353  if (faces_info[fi].Elem2No >= 0) { continue; }
5354 
5355  // boundary face
5356  int *bv = boundary[i]->GetVertices();
5357  // Make sure the 'faces' are generated:
5358  MFEM_ASSERT(fi < faces.Size(), "internal error");
5359  const int *fv = faces[fi]->GetVertices();
5360  int orientation; // orientation of the bdr. elem. w.r.t. the
5361  // corresponding face element (that's the base)
5362  const Element::Type bdr_type = GetBdrElementType(i);
5363  switch (bdr_type)
5364  {
5365  case Element::TRIANGLE:
5366  {
5367  orientation = GetTriOrientation(fv, bv);
5368  break;
5369  }
5371  {
5372  orientation = GetQuadOrientation(fv, bv);
5373  break;
5374  }
5375  default:
5376  MFEM_ABORT("Invalid 2D boundary element type \""
5377  << bdr_type << "\"");
5378  orientation = 0; // suppress a warning
5379  break;
5380  }
5381 
5382  if (orientation % 2 == 0) { continue; }
5383  wo++;
5384  if (!fix_it) { continue; }
5385 
5386  switch (bdr_type)
5387  {
5388  case Element::TRIANGLE:
5389  {
5390  // swap vertices 0 and 1 so that we don't change the marked edge:
5391  // (0,1,2) -> (1,0,2)
5392  mfem::Swap<int>(bv[0], bv[1]);
5393  if (bel_to_edge)
5394  {
5395  int *be = bel_to_edge->GetRow(i);
5396  mfem::Swap<int>(be[1], be[2]);
5397  }
5398  break;
5399  }
5401  {
5402  mfem::Swap<int>(bv[0], bv[2]);
5403  if (bel_to_edge)
5404  {
5405  int *be = bel_to_edge->GetRow(i);
5406  mfem::Swap<int>(be[0], be[1]);
5407  mfem::Swap<int>(be[2], be[3]);
5408  }
5409  break;
5410  }
5411  default: // unreachable
5412  break;
5413  }
5414  }
5415  }
5416  // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
5417 #ifdef MFEM_DEBUG
5418  if (wo > 0)
5419  {
5420  mfem::out << "Boundary elements with wrong orientation: " << wo << " / "
5421  << NumOfBdrElements << " (" << fixed_or_not[fix_it ? 0 : 1]
5422  << ")" << endl;
5423  }
5424 #endif
5425  return wo;
5426 }
5427 
5429 {
5430  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
5431  int num_geoms = 0;
5432  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
5433  {
5434  if (HasGeometry(Geometry::Type(g))) { num_geoms++; }
5435  }
5436  return num_geoms;
5437 }
5438 
5440 {
5441  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
5442  el_geoms.SetSize(0);
5443  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
5444  {
5445  if (HasGeometry(Geometry::Type(g)))
5446  {
5447  el_geoms.Append(Geometry::Type(g));
5448  }
5449  }
5450 }
5451 
5452 void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const
5453 {
5454  if (el_to_edge)
5455  {
5456  el_to_edge->GetRow(i, edges);
5457  }
5458  else
5459  {
5460  mfem_error("Mesh::GetElementEdges(...) element to edge table "
5461  "is not generated.");
5462  }
5463 
5464  const int *v = elements[i]->GetVertices();
5465  const int ne = elements[i]->GetNEdges();
5466  cor.SetSize(ne);
5467  for (int j = 0; j < ne; j++)
5468  {
5469  const int *e = elements[i]->GetEdgeVertices(j);
5470  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5471  }
5472 }
5473 
5474 void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const
5475 {
5476  if (Dim == 2)
5477  {
5478  edges.SetSize(1);
5479  cor.SetSize(1);
5480  edges[0] = be_to_edge[i];
5481  const int *v = boundary[i]->GetVertices();
5482  cor[0] = (v[0] < v[1]) ? (1) : (-1);
5483  }
5484  else if (Dim == 3)
5485  {
5486  if (bel_to_edge)
5487  {
5488  bel_to_edge->GetRow(i, edges);
5489  }
5490  else
5491  {
5492  mfem_error("Mesh::GetBdrElementEdges(...)");
5493  }
5494 
5495  const int *v = boundary[i]->GetVertices();
5496  const int ne = boundary[i]->GetNEdges();
5497  cor.SetSize(ne);
5498  for (int j = 0; j < ne; j++)
5499  {
5500  const int *e = boundary[i]->GetEdgeVertices(j);
5501  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5502  }
5503  }
5504 }
5505 
5506 void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const
5507 {
5508  if (Dim == 2)
5509  {
5510  edges.SetSize(1);
5511  edges[0] = i;
5512  o.SetSize(1);
5513  const int *v = faces[i]->GetVertices();
5514  o[0] = (v[0] < v[1]) ? (1) : (-1);
5515  }
5516 
5517  if (Dim != 3)
5518  {
5519  return;
5520  }
5521 
5522  GetFaceEdgeTable(); // generate face_edge Table (if not generated)
5523 
5524  face_edge->GetRow(i, edges);
5525 
5526  const int *v = faces[i]->GetVertices();
5527  const int ne = faces[i]->GetNEdges();
5528  o.SetSize(ne);
5529  for (int j = 0; j < ne; j++)
5530  {
5531  const int *e = faces[i]->GetEdgeVertices(j);
5532  o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
5533  }
5534 }
5535 
5536 void Mesh::GetEdgeVertices(int i, Array<int> &vert) const
5537 {
5538  // the two vertices are sorted: vert[0] < vert[1]
5539  // this is consistent with the global edge orientation
5540  // generate edge_vertex Table (if not generated)
5541  if (!edge_vertex) { GetEdgeVertexTable(); }
5542  edge_vertex->GetRow(i, vert);
5543 }
5544 
5546 {
5547  if (face_edge)
5548  {
5549  return face_edge;
5550  }
5551 
5552  if (Dim != 3)
5553  {
5554  return NULL;
5555  }
5556 
5557 #ifdef MFEM_DEBUG
5558  if (faces.Size() != NumOfFaces)
5559  {
5560  mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!");
5561  }
5562 #endif
5563 
5564  DSTable v_to_v(NumOfVertices);
5565  GetVertexToVertexTable(v_to_v);
5566 
5567  face_edge = new Table;
5569 
5570  return (face_edge);
5571 }
5572 
5574 {
5575  if (edge_vertex)
5576  {
5577  return edge_vertex;
5578  }
5579 
5580  DSTable v_to_v(NumOfVertices);
5581  GetVertexToVertexTable(v_to_v);
5582 
5583  int nedges = v_to_v.NumberOfEntries();
5584  edge_vertex = new Table(nedges, 2);
5585  for (int i = 0; i < NumOfVertices; i++)
5586  {
5587  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
5588  {
5589  int j = it.Index();
5590  edge_vertex->Push(j, i);
5591  edge_vertex->Push(j, it.Column());
5592  }
5593  }
5594  edge_vertex->Finalize();
5595 
5596  return edge_vertex;
5597 }
5598 
5600 {
5601  int i, j, nv, *v;
5602 
5603  Table *vert_elem = new Table;
5604 
5605  vert_elem->MakeI(NumOfVertices);
5606 
5607  for (i = 0; i < NumOfElements; i++)
5608  {
5609  nv = elements[i]->GetNVertices();
5610  v = elements[i]->GetVertices();
5611  for (j = 0; j < nv; j++)
5612  {
5613  vert_elem->AddAColumnInRow(v[j]);
5614  }
5615  }
5616 
5617  vert_elem->MakeJ();
5618 
5619  for (i = 0; i < NumOfElements; i++)
5620  {
5621  nv = elements[i]->GetNVertices();
5622  v = elements[i]->GetVertices();
5623  for (j = 0; j < nv; j++)
5624  {
5625  vert_elem->AddConnection(v[j], i);
5626  }
5627  }
5628 
5629  vert_elem->ShiftUpI();
5630 
5631  return vert_elem;
5632 }
5633 
5635 {
5636  Table *face_elem = new Table;
5637 
5638  face_elem->MakeI(faces_info.Size());
5639 
5640  for (int i = 0; i < faces_info.Size(); i++)
5641  {
5642  if (faces_info[i].Elem2No >= 0)
5643  {
5644  face_elem->AddColumnsInRow(i, 2);
5645  }
5646  else
5647  {
5648  face_elem->AddAColumnInRow(i);
5649  }
5650  }
5651 
5652  face_elem->MakeJ();
5653 
5654  for (int i = 0; i < faces_info.Size(); i++)
5655  {
5656  face_elem->AddConnection(i, faces_info[i].Elem1No);
5657  if (faces_info[i].Elem2No >= 0)
5658  {
5659  face_elem->AddConnection(i, faces_info[i].Elem2No);
5660  }
5661  }
5662 
5663  face_elem->ShiftUpI();
5664 
5665  return face_elem;
5666 }
5667 
5668 void Mesh::GetElementFaces(int i, Array<int> &faces, Array<int> &ori) const
5669 {
5670  MFEM_VERIFY(el_to_face != NULL, "el_to_face not generated");
5671 
5672  el_to_face->GetRow(i, faces);
5673 
5674  int n = faces.Size();
5675  ori.SetSize(n);
5676 
5677  for (int j = 0; j < n; j++)
5678  {
5679  if (faces_info[faces[j]].Elem1No == i)
5680  {
5681  ori[j] = faces_info[faces[j]].Elem1Inf % 64;
5682  }
5683  else
5684  {
5685  MFEM_ASSERT(faces_info[faces[j]].Elem2No == i, "internal error");
5686  ori[j] = faces_info[faces[j]].Elem2Inf % 64;
5687  }
5688  }
5689 }
5690 
5691 void Mesh::GetBdrElementFace(int i, int *f, int *o) const
5692 {
5693  const int *bv, *fv;
5694 
5695  *f = be_to_face[i];
5696  bv = boundary[i]->GetVertices();
5697  fv = faces[be_to_face[i]]->GetVertices();
5698 
5699  // find the orientation of the bdr. elem. w.r.t.
5700  // the corresponding face element (that's the base)
5701  switch (GetBdrElementType(i))
5702  {
5703  case Element::TRIANGLE:
5704  *o = GetTriOrientation(fv, bv);
5705  break;
5707  *o = GetQuadOrientation(fv, bv);
5708  break;
5709  default:
5710  MFEM_ABORT("invalid geometry");
5711  }
5712 }
5713 
5715 {
5716  switch (Dim)
5717  {
5718  case 1: return boundary[i]->GetVertices()[0];
5719  case 2: return be_to_edge[i];
5720  case 3: return be_to_face[i];
5721  default: MFEM_ABORT("invalid dimension!");
5722  }
5723  return -1;
5724 }
5725 
5726 void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
5727 {
5728  int fid = GetBdrElementEdgeIndex(bdr_el);
5729 
5730  const FaceInfo &fi = faces_info[fid];
5731  MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
5732 
5733  const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
5734  const int *bv = boundary[bdr_el]->GetVertices();
5735  int ori;
5736  switch (GetBdrElementGeometry(bdr_el))
5737  {
5738  case Geometry::POINT: ori = 0; break;
5739  case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
5740  case Geometry::TRIANGLE: ori = GetTriOrientation(fv, bv); break;
5741  case Geometry::SQUARE: ori = GetQuadOrientation(fv, bv); break;
5742  default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
5743  }
5744  el = fi.Elem1No;
5745  info = fi.Elem1Inf + ori;
5746 }
5747 
5749 {
5750  return elements[i]->GetType();
5751 }
5752 
5754 {
5755  return boundary[i]->GetType();
5756 }
5757 
5758 void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const
5759 {
5760  int k, j, nv;
5761  const int *v;
5762 
5763  v = elements[i]->GetVertices();
5764  nv = elements[i]->GetNVertices();
5765 
5766  pointmat.SetSize(spaceDim, nv);
5767  for (k = 0; k < spaceDim; k++)
5768  {
5769  for (j = 0; j < nv; j++)
5770  {
5771  pointmat(k, j) = vertices[v[j]](k);
5772  }
5773  }
5774 }
5775 
5776 void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const
5777 {
5778  int k, j, nv;
5779  const int *v;
5780 
5781  v = boundary[i]->GetVertices();
5782  nv = boundary[i]->GetNVertices();
5783 
5784  pointmat.SetSize(spaceDim, nv);
5785  for (k = 0; k < spaceDim; k++)
5786  for (j = 0; j < nv; j++)
5787  {
5788  pointmat(k, j) = vertices[v[j]](k);
5789  }
5790 }
5791 
5792 double Mesh::GetLength(int i, int j) const
5793 {
5794  const double *vi = vertices[i]();
5795  const double *vj = vertices[j]();
5796  double length = 0.;
5797 
5798  for (int k = 0; k < spaceDim; k++)
5799  {
5800  length += (vi[k]-vj[k])*(vi[k]-vj[k]);
5801  }
5802 
5803  return sqrt(length);
5804 }
5805 
5806 // static method
5808  const DSTable &v_to_v, Table &el_to_edge)
5809 {
5810  el_to_edge.MakeI(elem_array.Size());
5811  for (int i = 0; i < elem_array.Size(); i++)
5812  {
5813  el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges());
5814  }
5815  el_to_edge.MakeJ();
5816  for (int i = 0; i < elem_array.Size(); i++)
5817  {
5818  const int *v = elem_array[i]->GetVertices();
5819  const int ne = elem_array[i]->GetNEdges();
5820  for (int j = 0; j < ne; j++)
5821  {
5822  const int *e = elem_array[i]->GetEdgeVertices(j);
5823  el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]]));
5824  }
5825  }
5826  el_to_edge.ShiftUpI();
5827 }
5828 
5830 {
5831  if (edge_vertex)
5832  {
5833  for (int i = 0; i < edge_vertex->Size(); i++)
5834  {
5835  const int *v = edge_vertex->GetRow(i);
5836  v_to_v.Push(v[0], v[1]);
5837  }
5838  }
5839  else
5840  {
5841  for (int i = 0; i < NumOfElements; i++)
5842  {
5843  const int *v = elements[i]->GetVertices();
5844  const int ne = elements[i]->GetNEdges();
5845  for (int j = 0; j < ne; j++)
5846  {
5847  const int *e = elements[i]->GetEdgeVertices(j);
5848  v_to_v.Push(v[e[0]], v[e[1]]);
5849  }
5850  }
5851  }
5852 }
5853 
5855 {
5856  int i, NumberOfEdges;
5857 
5858  DSTable v_to_v(NumOfVertices);
5859  GetVertexToVertexTable(v_to_v);
5860 
5861  NumberOfEdges = v_to_v.NumberOfEntries();
5862 
5863  // Fill the element to edge table
5864  GetElementArrayEdgeTable(elements, v_to_v, e_to_f);
5865 
5866  if (Dim == 2)
5867  {
5868  // Initialize the indices for the boundary elements.
5869  be_to_f.SetSize(NumOfBdrElements);
5870  for (i = 0; i < NumOfBdrElements; i++)
5871  {
5872  const int *v = boundary[i]->GetVertices();
5873  be_to_f[i] = v_to_v(v[0], v[1]);
5874  }
5875  }
5876  else if (Dim == 3)
5877  {
5878  if (bel_to_edge == NULL)
5879  {
5880  bel_to_edge = new Table;
5881  }
5883  }
5884  else
5885  {
5886  mfem_error("1D GetElementToEdgeTable is not yet implemented.");
5887  }
5888 
5889  // Return the number of edges
5890  return NumberOfEdges;
5891 }
5892 
5894 {
5895  if (el_to_el)
5896  {
5897  return *el_to_el;
5898  }
5899 
5900  // Note that, for ParNCMeshes, faces_info will contain also the ghost faces
5901  MFEM_ASSERT(faces_info.Size() >= GetNumFaces(), "faces were not generated!");
5902 
5903  Array<Connection> conn;
5904  conn.Reserve(2*faces_info.Size());
5905 
5906  for (int i = 0; i < faces_info.Size(); i++)
5907  {
5908  const FaceInfo &fi = faces_info[i];
5909  if (fi.Elem2No >= 0)
5910  {
5911  conn.Append(Connection(fi.Elem1No, fi.Elem2No));
5912  conn.Append(Connection(fi.Elem2No, fi.Elem1No));
5913  }
5914  else if (fi.Elem2Inf >= 0)
5915  {
5916  int nbr_elem_idx = NumOfElements - 1 - fi.Elem2No;
5917  conn.Append(Connection(fi.Elem1No, nbr_elem_idx));
5918  conn.Append(Connection(nbr_elem_idx, fi.Elem1No));
5919  }
5920  }
5921 
5922  conn.Sort();
5923  conn.Unique();
5924  el_to_el = new Table(NumOfElements, conn);
5925 
5926  return *el_to_el;
5927 }
5928 
5930 {
5931  if (el_to_face == NULL)
5932  {
5933  mfem_error("Mesh::ElementToFaceTable()");
5934  }
5935  return *el_to_face;
5936 }
5937 
5939 {
5940  if (el_to_edge == NULL)
5941  {
5942  mfem_error("Mesh::ElementToEdgeTable()");
5943  }
5944  return *el_to_edge;
5945 }
5946 
5947 void Mesh::AddPointFaceElement(int lf, int gf, int el)
5948 {
5949  if (faces_info[gf].Elem1No == -1) // this will be elem1
5950  {
5951  // faces[gf] = new Point(&gf);
5952  faces_info[gf].Elem1No = el;
5953  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
5954  faces_info[gf].Elem2No = -1; // in case there's no other side
5955  faces_info[gf].Elem2Inf = -1; // face is not shared
5956  }
5957  else // this will be elem2
5958  {
5959  /* WARNING: Without the following check the mesh faces_info data structure
5960  may contain unreliable data. Normally, the order in which elements are
5961  processed could swap which elements appear as Elem1No and Elem2No. In
5962  branched meshes, where more than two elements can meet at a given node,
5963  the indices stored in Elem1No and Elem2No will be the first and last,
5964  respectively, elements found which touch a given node. This can lead to
5965  inconsistencies in any algorithms which rely on this data structure. To
5966  properly support branched meshes this data structure should be extended
5967  to support multiple elements per face. */
5968  /*
5969  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
5970  "Interior point found connecting 1D elements "
5971  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
5972  << " and " << el << ".");
5973  */
5974  faces_info[gf].Elem2No = el;
5975  faces_info[gf].Elem2Inf = 64 * lf + 1;
5976  }
5977 }
5978 
5979 void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
5980 {
5981  if (faces[gf] == NULL) // this will be elem1
5982  {
5983  faces[gf] = new Segment(v0, v1);
5984  faces_info[gf].Elem1No = el;
5985  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
5986  faces_info[gf].Elem2No = -1; // in case there's no other side
5987  faces_info[gf].Elem2Inf = -1; // face is not shared
5988  }
5989  else // this will be elem2
5990  {
5991  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
5992  "Interior edge found between 2D elements "
5993  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
5994  << " and " << el << ".");
5995  int *v = faces[gf]->GetVertices();
5996  faces_info[gf].Elem2No = el;
5997  if ( v[1] == v0 && v[0] == v1 )
5998  {
5999  faces_info[gf].Elem2Inf = 64 * lf + 1;
6000  }
6001  else if ( v[0] == v0 && v[1] == v1 )
6002  {
6003  // Temporarily allow even edge orientations: see the remark in
6004  // AddTriangleFaceElement().
6005  // Also, in a non-orientable surface mesh, the orientation will be even
6006  // for edges that connect elements with opposite orientations.
6007  faces_info[gf].Elem2Inf = 64 * lf;
6008  }
6009  else
6010  {
6011  MFEM_ABORT("internal error");
6012  }
6013  }
6014 }
6015 
6016 void Mesh::AddTriangleFaceElement(int lf, int gf, int el,
6017  int v0, int v1, int v2)
6018 {
6019  if (faces[gf] == NULL) // this will be elem1
6020  {
6021  faces[gf] = new Triangle(v0, v1, v2);
6022  faces_info[gf].Elem1No = el;
6023  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6024  faces_info[gf].Elem2No = -1; // in case there's no other side
6025  faces_info[gf].Elem2Inf = -1; // face is not shared
6026  }
6027  else // this will be elem2
6028  {
6029  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6030  "Interior triangular face found connecting elements "
6031  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6032  << " and " << el << ".");
6033  int orientation, vv[3] = { v0, v1, v2 };
6034  orientation = GetTriOrientation(faces[gf]->GetVertices(), vv);
6035  // In a valid mesh, we should have (orientation % 2 != 0), however, if
6036  // one of the adjacent elements has wrong orientation, both face
6037  // orientations can be even, until the element orientations are fixed.
6038  // MFEM_ASSERT(orientation % 2 != 0, "");
6039  faces_info[gf].Elem2No = el;
6040  faces_info[gf].Elem2Inf = 64 * lf + orientation;
6041  }
6042 }
6043 
6044 void Mesh::AddQuadFaceElement(int lf, int gf, int el,
6045  int v0, int v1, int v2, int v3)
6046 {
6047  if (faces_info[gf].Elem1No < 0) // this will be elem1
6048  {
6049  faces[gf] = new Quadrilateral(v0, v1, v2, v3);
6050  faces_info[gf].Elem1No = el;
6051  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
6052  faces_info[gf].Elem2No = -1; // in case there's no other side
6053  faces_info[gf].Elem2Inf = -1; // face is not shared
6054  }
6055  else // this will be elem2
6056  {
6057  MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
6058  "Interior quadrilateral face found connecting elements "
6059  << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
6060  << " and " << el << ".");
6061  int vv[4] = { v0, v1, v2, v3 };
6062  int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv);
6063  // Temporarily allow even face orientations: see the remark in
6064  // AddTriangleFaceElement().
6065  // MFEM_ASSERT(oo % 2 != 0, "");
6066  faces_info[gf].Elem2No = el;
6067  faces_info[gf].Elem2Inf = 64 * lf + oo;
6068  }
6069 }
6070 
6072 {
6073  int i, nfaces = GetNumFaces();
6074 
6075  for (i = 0; i < faces.Size(); i++)
6076  {
6077  FreeElement(faces[i]);
6078  }
6079 
6080  // (re)generate the interior faces and the info for them
6081  faces.SetSize(nfaces);
6082  faces_info.SetSize(nfaces);
6083  for (i = 0; i < nfaces; i++)
6084  {
6085  faces[i] = NULL;
6086  faces_info[i].Elem1No = -1;
6087  faces_info[i].NCFace = -1;
6088  }
6089  for (i = 0; i < NumOfElements; i++)
6090  {
6091  const int *v = elements[i]->GetVertices();
6092  const int *ef;
6093  if (Dim == 1)
6094  {
6095  AddPointFaceElement(0, v[0], i);
6096  AddPointFaceElement(1, v[1], i);
6097  }
6098  else if (Dim == 2)
6099  {
6100  ef = el_to_edge->GetRow(i);
6101  const int ne = elements[i]->GetNEdges();
6102  for (int j = 0; j < ne; j++)
6103  {
6104  const int *e = elements[i]->GetEdgeVertices(j);
6105  AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]);
6106  }
6107  }
6108  else
6109  {
6110  ef = el_to_face->GetRow(i);
6111  switch (GetElementType(i))
6112  {
6113  case Element::TETRAHEDRON:
6114  {
6115  for (int j = 0; j < 4; j++)
6116  {
6117  const int *fv = tet_t::FaceVert[j];
6118  AddTriangleFaceElement(j, ef[j], i,
6119  v[fv[0]], v[fv[1]], v[fv[2]]);
6120  }
6121  break;
6122  }
6123  case Element::WEDGE:
6124  {
6125  for (int j = 0; j < 2; j++)
6126  {
6127  const int *fv = pri_t::FaceVert[j];
6128  AddTriangleFaceElement(j, ef[j], i,
6129  v[fv[0]], v[fv[1]], v[fv[2]]);
6130  }
6131  for (int j = 2; j < 5; j++)
6132  {
6133  const int *fv = pri_t::FaceVert[j];
6134  AddQuadFaceElement(j, ef[j], i,
6135  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6136  }
6137  break;
6138  }
6139  case Element::HEXAHEDRON:
6140  {
6141  for (int j = 0; j < 6; j++)
6142  {
6143  const int *fv = hex_t::FaceVert[j];
6144  AddQuadFaceElement(j, ef[j], i,
6145  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6146  }
6147  break;
6148  }
6149  default:
6150  MFEM_ABORT("Unexpected type of Element.");
6151  }
6152  }
6153  }
6154 }
6155 
6157 {
6158  MFEM_VERIFY(ncmesh, "missing NCMesh.");
6159 
6160  for (int i = 0; i < faces_info.Size(); i++)
6161  {
6162  faces_info[i].NCFace = -1;
6163  }
6164 
6165  const NCMesh::NCList &list =
6166  (Dim == 2) ? ncmesh->GetEdgeList() : ncmesh->GetFaceList();
6167 
6168  nc_faces_info.SetSize(0);
6169  nc_faces_info.Reserve(list.masters.Size() + list.slaves.Size());
6170 
6171  int nfaces = GetNumFaces();
6172 
6173  // add records for master faces
6174  for (int i = 0; i < list.masters.Size(); i++)
6175  {
6176  const NCMesh::Master &master = list.masters[i];
6177  if (master.index >= nfaces) { continue; }
6178 
6179  faces_info[master.index].NCFace = nc_faces_info.Size();
6180  nc_faces_info.Append(NCFaceInfo(false, master.local, NULL));
6181  // NOTE: one of the unused members stores local face no. to be used below
6182  }
6183 
6184  // add records for slave faces
6185  for (int i = 0; i < list.slaves.Size(); i++)
6186  {
6187  const NCMesh::Slave &slave = list.slaves[i];
6188 
6189  if (slave.index < 0 || // degenerate slave face
6190  slave.index >= nfaces || // ghost slave
6191  slave.master >= nfaces) // has ghost master
6192  {
6193  continue;
6194  }
6195 
6196  FaceInfo &slave_fi = faces_info[slave.index];
6197  FaceInfo &master_fi = faces_info[slave.master];
6198  NCFaceInfo &master_nc = nc_faces_info[master_fi.NCFace];
6199 
6200  slave_fi.NCFace = nc_faces_info.Size();
6201  slave_fi.Elem2No = master_fi.Elem1No;
6202  slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
6203  // NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
6204  // matrix. In 2D, the point matrix has the orientation of the parent
6205  // edge, so its columns need to be flipped when applying it, see
6206  // ApplyLocalSlaveTransformation.
6207 
6208  nc_faces_info.Append(
6209  NCFaceInfo(true, slave.master,
6210  list.point_matrices[slave.geom][slave.matrix]));
6211  }
6212 }
6213 
6215 {
6216  STable3D *faces_tbl = new STable3D(NumOfVertices);
6217  for (int i = 0; i < NumOfElements; i++)
6218  {
6219  const int *v = elements[i]->GetVertices();
6220  switch (GetElementType(i))
6221  {
6222  case Element::TETRAHEDRON:
6223  {
6224  for (int j = 0; j < 4; j++)
6225  {
6226  const int *fv = tet_t::FaceVert[j];
6227  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6228  }
6229  break;
6230  }
6231  case Element::WEDGE:
6232  {
6233  for (int j = 0; j < 2; j++)
6234  {
6235  const int *fv = pri_t::FaceVert[j];
6236  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
6237  }
6238  for (int j = 2; j < 5; j++)
6239  {
6240  const int *fv = pri_t::FaceVert[j];
6241  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6242  }
6243  break;
6244  }
6245  case Element::HEXAHEDRON:
6246  {
6247  // find the face by the vertices with the smallest 3 numbers
6248  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
6249  for (int j = 0; j < 6; j++)
6250  {
6251  const int *fv = hex_t::FaceVert[j];
6252  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
6253  }
6254  break;
6255  }
6256  default:
6257  MFEM_ABORT("Unexpected type of Element.");
6258  }
6259  }
6260  return faces_tbl;
6261 }
6262 
6264 {
6265  int i, *v;
6266  STable3D *faces_tbl;
6267 
6268  if (el_to_face != NULL)
6269  {
6270  delete el_to_face;
6271  }
6272  el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra
6273  faces_tbl = new STable3D(NumOfVertices);
6274  for (i = 0; i < NumOfElements; i++)
6275  {
6276  v = elements[i]->GetVertices();
6277  switch (GetElementType(i))
6278  {
6279  case Element::TETRAHEDRON:
6280  {
6281  for (int j = 0; j < 4; j++)
6282  {
6283  const int *fv = tet_t::FaceVert[j];
6284  el_to_face->Push(
6285  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6286  }
6287  break;
6288  }
6289  case Element::WEDGE:
6290  {
6291  for (int j = 0; j < 2; j++)
6292  {
6293  const int *fv = pri_t::FaceVert[j];
6294  el_to_face->Push(
6295  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
6296  }
6297  for (int j = 2; j < 5; j++)
6298  {
6299  const int *fv = pri_t::FaceVert[j];
6300  el_to_face->Push(
6301  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6302  }
6303  break;
6304  }
6305  case Element::HEXAHEDRON:
6306  {
6307  // find the face by the vertices with the smallest 3 numbers
6308  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
6309  for (int j = 0; j < 6; j++)
6310  {
6311  const int *fv = hex_t::FaceVert[j];
6312  el_to_face->Push(
6313  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
6314  }
6315  break;
6316  }
6317  default:
6318  MFEM_ABORT("Unexpected type of Element.");
6319  }
6320  }
6321  el_to_face->Finalize();
6322  NumOfFaces = faces_tbl->NumberOfElements();
6324  for (i = 0; i < NumOfBdrElements; i++)
6325  {
6326  v = boundary[i]->GetVertices();
6327  switch (GetBdrElementType(i))
6328  {
6329  case Element::TRIANGLE:
6330  {
6331  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]);
6332  break;
6333  }
6335  {
6336  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
6337  break;
6338  }
6339  default:
6340  MFEM_ABORT("Unexpected type of boundary Element.");
6341  }
6342  }
6343 
6344  if (ret_ftbl)
6345  {
6346  return faces_tbl;
6347  }
6348  delete faces_tbl;
6349  return NULL;
6350 }
6351 
6352 // shift cyclically 3 integers so that the smallest is first
6353 static inline
6354 void Rotate3(int &a, int &b, int &c)
6355 {
6356  if (a < b)
6357  {
6358  if (a > c)
6359  {
6360  ShiftRight(a, b, c);
6361  }
6362  }
6363  else
6364  {
6365  if (b < c)
6366  {
6367  ShiftRight(c, b, a);
6368  }
6369  else
6370  {
6371  ShiftRight(a, b, c);
6372  }
6373  }
6374 }
6375 
6377 {
6378  if (Dim != 3 || !(meshgen & 1))
6379  {
6380  return;
6381  }
6382 
6383  ResetLazyData();
6384 
6385  DSTable *old_v_to_v = NULL;
6386  Table *old_elem_vert = NULL;
6387 
6388  if (Nodes)
6389  {
6390  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
6391  }
6392 
6393  for (int i = 0; i < NumOfElements; i++)
6394  {
6396  {
6397  int *v = elements[i]->GetVertices();
6398 
6399  Rotate3(v[0], v[1], v[2]);
6400  if (v[0] < v[3])
6401  {
6402  Rotate3(v[1], v[2], v[3]);
6403  }
6404  else
6405  {
6406  ShiftRight(v[0], v[1], v[3]);
6407  }
6408  }
6409  }
6410 
6411  for (int i = 0; i < NumOfBdrElements; i++)
6412  {
6414  {
6415  int *v = boundary[i]->GetVertices();
6416 
6417  Rotate3(v[0], v[1], v[2]);
6418  }
6419  }
6420 
6421  if (!Nodes)
6422  {
6424  GenerateFaces();
6425  if (el_to_edge)
6426  {
6428  }
6429  }
6430  else
6431  {
6432  DoNodeReorder(old_v_to_v, old_elem_vert);
6433  delete old_elem_vert;
6434  delete old_v_to_v;
6435  }
6436 }
6437 
6439 {
6440  int *partitioning;
6441  double pmin[3] = { infinity(), infinity(), infinity() };
6442  double pmax[3] = { -infinity(), -infinity(), -infinity() };
6443  // find a bounding box using the vertices
6444  for (int vi = 0; vi < NumOfVertices; vi++)
6445  {
6446  const double *p = vertices[vi]();
6447  for (int i = 0; i < spaceDim; i++)
6448  {
6449  if (p[i] < pmin[i]) { pmin[i] = p[i]; }
6450  if (p[i] > pmax[i]) { pmax[i] = p[i]; }
6451  }
6452  }
6453 
6454  partitioning = new int[NumOfElements];
6455 
6456  // determine the partitioning using the centers of the elements
6457  double ppt[3];
6458  Vector pt(ppt, spaceDim);
6459  for (int el = 0; el < NumOfElements; el++)
6460  {
6461  GetElementTransformation(el)->Transform(
6463  int part = 0;
6464  for (int i = spaceDim-1; i >= 0; i--)
6465  {
6466  int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i])));
6467  if (idx < 0) { idx = 0; }
6468  if (idx >= nxyz[i]) { idx = nxyz[i]-1; }
6469  part = part * nxyz[i] + idx;
6470  }
6471  partitioning[el] = part;
6472  }
6473 
6474  return partitioning;
6475 }
6476 
6477 int *Mesh::GeneratePartitioning(int nparts, int part_method)
6478 {
6479 #ifdef MFEM_USE_METIS
6480 
6481  int print_messages = 1;
6482  // If running in parallel, print messages only from rank 0.
6483 #ifdef MFEM_USE_MPI
6484  int init_flag, fin_flag;
6485  MPI_Initialized(&init_flag);
6486  MPI_Finalized(&fin_flag);
6487  if (init_flag && !fin_flag)
6488  {
6489  int rank;
6490  MPI_Comm_rank(GetGlobalMPI_Comm(), &rank);
6491  if (rank != 0) { print_messages = 0; }
6492  }
6493 #endif
6494 
6495  int i, *partitioning;
6496 
6498 
6499  partitioning = new int[NumOfElements];
6500 
6501  if (nparts == 1)
6502  {
6503  for (i = 0; i < NumOfElements; i++)
6504  {
6505  partitioning[i] = 0;
6506  }
6507  }
6508  else if (NumOfElements <= nparts)
6509  {
6510  for (i = 0; i < NumOfElements; i++)
6511  {
6512  partitioning[i] = i;
6513  }
6514  }
6515  else
6516  {
6517  idx_t *I, *J, n;
6518 #ifndef MFEM_USE_METIS_5
6519  idx_t wgtflag = 0;
6520  idx_t numflag = 0;
6521  idx_t options[5];
6522 #else
6523  idx_t ncon = 1;
6524  idx_t err;
6525  idx_t options[40];
6526 #endif
6527  idx_t edgecut;
6528 
6529  // In case METIS have been compiled with 64bit indices
6530  bool freedata = false;
6531  idx_t mparts = (idx_t) nparts;
6532  idx_t *mpartitioning;
6533 
6534  n = NumOfElements;
6535  if (sizeof(idx_t) == sizeof(int))
6536  {
6537  I = (idx_t*) el_to_el->GetI();
6538  J = (idx_t*) el_to_el->GetJ();
6539  mpartitioning = (idx_t*) partitioning;
6540  }
6541  else
6542  {
6543  int *iI = el_to_el->GetI();
6544  int *iJ = el_to_el->GetJ();
6545  int m = iI[n];
6546  I = new idx_t[n+1];
6547  J = new idx_t[m];
6548  for (int k = 0; k < n+1; k++) { I[k] = iI[k]; }
6549  for (int k = 0; k < m; k++) { J[k] = iJ[k]; }
6550  mpartitioning = new idx_t[n];
6551  freedata = true;
6552  }
6553 #ifndef MFEM_USE_METIS_5
6554  options[0] = 0;
6555 #else
6556  METIS_SetDefaultOptions(options);
6557  options[METIS_OPTION_CONTIG] = 1; // set METIS_OPTION_CONTIG
6558 #endif
6559 
6560  // Sort the neighbor lists
6561  if (part_method >= 0 && part_method <= 2)
6562  {
6563  for (i = 0; i < n; i++)
6564  {
6565  // Sort in increasing order.
6566  // std::sort(J+I[i], J+I[i+1]);
6567 
6568  // Sort in decreasing order, as in previous versions of MFEM.
6569  std::sort(J+I[i], J+I[i+1], std::greater<idx_t>());
6570  }
6571  }
6572 
6573  // This function should be used to partition a graph into a small
6574  // number of partitions (less than 8).
6575  if (part_method == 0 || part_method == 3)
6576  {
6577 #ifndef MFEM_USE_METIS_5
6579  I,
6580  J,
6581  NULL,
6582  NULL,
6583  &wgtflag,
6584  &numflag,
6585  &mparts,
6586  options,
6587  &edgecut,
6588  mpartitioning);
6589 #else
6590  err = METIS_PartGraphRecursive(&n,
6591  &ncon,
6592  I,
6593  J,
6594  NULL,
6595  NULL,
6596  NULL,
6597  &mparts,
6598  NULL,
6599  NULL,
6600  options,
6601  &edgecut,
6602  mpartitioning);
6603  if (err != 1)
6604  {
6605  mfem_error("Mesh::GeneratePartitioning: "
6606  " error in METIS_PartGraphRecursive!");
6607  }
6608 #endif
6609  }
6610 
6611  // This function should be used to partition a graph into a large
6612  // number of partitions (greater than 8).
6613  if (part_method == 1 || part_method == 4)
6614  {
6615 #ifndef MFEM_USE_METIS_5
6617  I,
6618  J,
6619  NULL,
6620  NULL,
6621  &wgtflag,
6622  &numflag,
6623  &mparts,
6624  options,
6625  &edgecut,
6626  mpartitioning);
6627 #else
6628  err = METIS_PartGraphKway(&n,
6629  &ncon,
6630  I,
6631  J,
6632  NULL,
6633  NULL,
6634  NULL,
6635  &mparts,
6636  NULL,
6637  NULL,
6638  options,
6639  &edgecut,
6640  mpartitioning);
6641  if (err != 1)
6642  {
6643  mfem_error("Mesh::GeneratePartitioning: "
6644  " error in METIS_PartGraphKway!");
6645  }
6646 #endif
6647  }
6648 
6649  // The objective of this partitioning is to minimize the total
6650  // communication volume
6651  if (part_method == 2 || part_method == 5)
6652  {
6653 #ifndef MFEM_USE_METIS_5
6655  I,
6656  J,
6657  NULL,
6658  NULL,
6659  &wgtflag,
6660  &numflag,
6661  &mparts,
6662  options,
6663  &edgecut,
6664  mpartitioning);
6665 #else
6666  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
6667  err = METIS_PartGraphKway(&n,
6668  &ncon,
6669  I,
6670  J,
6671  NULL,
6672  NULL,
6673  NULL,
6674  &mparts,
6675  NULL,
6676  NULL,
6677  options,
6678  &edgecut,
6679  mpartitioning);
6680  if (err != 1)
6681  {
6682  mfem_error("Mesh::GeneratePartitioning: "
6683  " error in METIS_PartGraphKway!");
6684  }
6685 #endif
6686  }
6687 
6688 #ifdef MFEM_DEBUG
6689  if (print_messages)
6690  {
6691  mfem::out << "Mesh::GeneratePartitioning(...): edgecut = "
6692  << edgecut << endl;
6693  }
6694 #endif
6695  nparts = (int) mparts;
6696  if (mpartitioning != (idx_t*)partitioning)
6697  {
6698  for (int k = 0; k<NumOfElements; k++)
6699  {
6700  partitioning[k] = mpartitioning[k];
6701  }
6702  }
6703  if (freedata)
6704  {
6705  delete[] I;
6706  delete[] J;
6707  delete[] mpartitioning;
6708  }
6709  }
6710 
6711  delete el_to_el;
6712  el_to_el = NULL;
6713 
6714  // Check for empty partitionings (a "feature" in METIS)
6715  if (nparts > 1 && NumOfElements > nparts)
6716  {
6717  Array< Pair<int,int> > psize(nparts);
6718  int empty_parts;
6719 
6720  // Count how many elements are in each partition, and store the result in
6721  // psize, where psize[i].one is the number of elements, and psize[i].two
6722  // is partition index. Keep track of the number of empty parts.
6723  auto count_partition_elements = [&]()
6724  {
6725  for (i = 0; i < nparts; i++)
6726  {
6727  psize[i].one = 0;
6728  psize[i].two = i;
6729  }
6730 
6731  for (i = 0; i < NumOfElements; i++)
6732  {
6733  psize[partitioning[i]].one++;
6734  }
6735 
6736  empty_parts = 0;
6737  for (i = 0; i < nparts; i++)
6738  {
6739  if (psize[i].one == 0) { empty_parts++; }
6740  }
6741  };
6742 
6743  count_partition_elements();
6744 
6745  // This code just split the largest partitionings in two.
6746  // Do we need to replace it with something better?
6747  while (empty_parts)
6748  {
6749  if (print_messages)
6750  {
6751  mfem::err << "Mesh::GeneratePartitioning(...): METIS returned "
6752  << empty_parts << " empty parts!"
6753  << " Applying a simple fix ..." << endl;
6754  }
6755 
6756  SortPairs<int,int>(psize, nparts);
6757 
6758  for (i = nparts-1; i > nparts-1-empty_parts; i--)
6759  {
6760  psize[i].one /= 2;
6761  }
6762 
6763  for (int j = 0; j < NumOfElements; j++)
6764  {
6765  for (i = nparts-1; i > nparts-1-empty_parts; i--)
6766  {
6767  if (psize[i].one == 0 || partitioning[j] != psize[i].two)
6768  {
6769  continue;
6770  }
6771  else
6772  {
6773  partitioning[j] = psize[nparts-1-i].two;
6774  psize[i].one--;
6775  }
6776  }
6777  }
6778 
6779  // Check for empty partitionings again
6780  count_partition_elements();
6781  }
6782  }
6783 
6784  return partitioning;
6785 
6786 #else
6787 
6788  mfem_error("Mesh::GeneratePartitioning(...): "
6789  "MFEM was compiled without Metis.");
6790 
6791  return NULL;
6792 
6793 #endif
6794 }
6795 
6796 /* required: 0 <= partitioning[i] < num_part */
6798  const Array<int> &partitioning,
6799  Array<int> &component,
6800  Array<int> &num_comp)
6801 {
6802  int i, j, k;
6803  int num_elem, *i_elem_elem, *j_elem_elem;
6804 
6805  num_elem = elem_elem.Size();
6806  i_elem_elem = elem_elem.GetI();
6807  j_elem_elem = elem_elem.GetJ();
6808 
6809  component.SetSize(num_elem);
6810 
6811  Array<int> elem_stack(num_elem);
6812  int stack_p, stack_top_p, elem;
6813  int num_part;
6814 
6815  num_part = -1;
6816  for (i = 0; i < num_elem; i++)
6817  {
6818  if (partitioning[i] > num_part)
6819  {
6820  num_part = partitioning[i];
6821  }
6822  component[i] = -1;
6823  }
6824  num_part++;
6825 
6826  num_comp.SetSize(num_part);
6827  for (i = 0; i < num_part; i++)
6828  {
6829  num_comp[i] = 0;
6830  }
6831 
6832  stack_p = 0;
6833  stack_top_p = 0; // points to the first unused element in the stack
6834  for (elem = 0; elem < num_elem; elem++)
6835  {
6836  if (component[elem] >= 0)
6837  {
6838  continue;
6839  }
6840 
6841  component[elem] = num_comp[partitioning[elem]]++;
6842 
6843  elem_stack[stack_top_p++] = elem;
6844 
6845  for ( ; stack_p < stack_top_p; stack_p++)
6846  {
6847  i = elem_stack[stack_p];
6848  for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++)
6849  {
6850  k = j_elem_elem[j];
6851  if (partitioning[k] == partitioning[i])
6852  {
6853  if (component[k] < 0)
6854  {
6855  component[k] = component[i];
6856  elem_stack[stack_top_p++] = k;
6857  }
6858  else if (component[k] != component[i])
6859  {
6860  mfem_error("FindPartitioningComponents");
6861  }
6862  }
6863  }
6864  }
6865  }
6866 }
6867 
6868 void Mesh::CheckPartitioning(int *partitioning_)
6869 {
6870  int i, n_empty, n_mcomp;
6871  Array<int> component, num_comp;
6872  const Array<int> partitioning(partitioning_, GetNE());
6873 
6875 
6876  FindPartitioningComponents(*el_to_el, partitioning, component, num_comp);
6877 
6878  n_empty = n_mcomp = 0;
6879  for (i = 0; i < num_comp.Size(); i++)
6880  if (num_comp[i] == 0)
6881  {
6882  n_empty++;
6883  }
6884  else if (num_comp[i] > 1)
6885  {
6886  n_mcomp++;
6887  }
6888 
6889  if (n_empty > 0)
6890  {
6891  mfem::out << "Mesh::CheckPartitioning(...) :\n"
6892  << "The following subdomains are empty :\n";
6893  for (i = 0; i < num_comp.Size(); i++)
6894  if (num_comp[i] == 0)
6895  {
6896  mfem::out << ' ' << i;
6897  }
6898  mfem::out << endl;
6899  }
6900  if (n_mcomp > 0)
6901  {
6902  mfem::out << "Mesh::CheckPartitioning(...) :\n"
6903  << "The following subdomains are NOT connected :\n";
6904  for (i = 0; i < num_comp.Size(); i++)
6905  if (num_comp[i] > 1)
6906  {
6907  mfem::out << ' ' << i;
6908  }
6909  mfem::out << endl;
6910  }
6911  if (n_empty == 0 && n_mcomp == 0)
6912  mfem::out << "Mesh::CheckPartitioning(...) : "
6913  "All subdomains are connected." << endl;
6914 
6915  if (el_to_el)
6916  {
6917  delete el_to_el;
6918  }
6919  el_to_el = NULL;
6920 }
6921 
6922 // compute the coefficients of the polynomial in t:
6923 // c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B)
6924 // where A, B are (d x d), d=2,3
6925 void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
6926 {
6927  const double *a = A.Data();
6928  const double *b = B.Data();
6929 
6930  c.SetSize(A.Width()+1);
6931  switch (A.Width())
6932  {
6933  case 2:
6934  {
6935  // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ |b0 b2|
6936  // |a1 a3| + \ |a1 b3| |b1 a3| / * t + |b1 b3| * t^2
6937  c(0) = a[0]*a[3]-a[1]*a[2];
6938  c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2];
6939  c(2) = b[0]*b[3]-b[1]*b[2];
6940  }
6941  break;
6942 
6943  case 3:
6944  {
6945  /* |a0 a3 a6|
6946  * det(A+t*B) = |a1 a4 a7| +
6947  * |a2 a5 a8|
6948 
6949  * / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \
6950  * + | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t +
6951  * \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| /
6952 
6953  * / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \
6954  * + | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 +
6955  * \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| /
6956 
6957  * |b0 b3 b6|
6958  * + |b1 b4 b7| * t^3
6959  * |b2 b5 b8| */
6960  c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) +
6961  a[1] * (a[5] * a[6] - a[3] * a[8]) +
6962  a[2] * (a[3] * a[7] - a[4] * a[6]));
6963 
6964  c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) +
6965  b[1] * (a[5] * a[6] - a[3] * a[8]) +
6966  b[2] * (a[3] * a[7] - a[4] * a[6]) +
6967 
6968  a[0] * (b[4] * a[8] - b[5] * a[7]) +
6969  a[1] * (b[5] * a[6] - b[3] * a[8]) +
6970  a[2] * (b[3] * a[7] - b[4] * a[6]) +
6971 
6972  a[0] * (a[4] * b[8] - a[5] * b[7]) +
6973  a[1] * (a[5] * b[6] - a[3] * b[8]) +
6974  a[2] * (a[3] * b[7] - a[4] * b[6]));
6975 
6976  c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) +
6977  a[1] * (b[5] * b[6] - b[3] * b[8]) +
6978  a[2] * (b[3] * b[7] - b[4] * b[6]) +
6979 
6980  b[0] * (a[4] * b[8] - a[5] * b[7]) +
6981  b[1] * (a[5] * b[6] - a[3] * b[8]) +
6982  b[2] * (a[3] * b[7] - a[4] * b[6]) +
6983 
6984  b[0] * (b[4] * a[8] - b[5] * a[7]) +
6985  b[1] * (b[5] * a[6] - b[3] * a[8]) +
6986  b[2] * (b[3] * a[7] - b[4] * a[6]));
6987 
6988  c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) +
6989  b[1] * (b[5] * b[6] - b[3] * b[8]) +
6990  b[2] * (b[3] * b[7] - b[4] * b[6]));
6991  }
6992  break;
6993 
6994  default:
6995  mfem_error("DetOfLinComb(...)");
6996  }
6997 }
6998 
6999 // compute the real roots of
7000 // z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3;
7001 // the roots are returned in x, sorted in increasing order;
7002 // it is assumed that x is at least of size d;
7003 // return the number of roots counting multiplicity;
7004 // return -1 if all z(i) are 0.
7005 int FindRoots(const Vector &z, Vector &x)
7006 {
7007  int d = z.Size()-1;
7008  if (d > 3 || d < 0)
7009  {
7010  mfem_error("FindRoots(...)");
7011  }
7012 
7013  while (z(d) == 0.0)
7014  {
7015  if (d == 0)
7016  {
7017  return (-1);
7018  }
7019  d--;
7020  }
7021  switch (d)
7022  {
7023  case 0:
7024  {
7025  return 0;
7026  }
7027 
7028  case 1:
7029  {
7030  x(0) = -z(0)/z(1);
7031  return 1;
7032  }
7033 
7034  case 2:
7035  {
7036  double a = z(2), b = z(1), c = z(0);
7037  double D = b*b-4*a*c;
7038  if (D < 0.0)
7039  {
7040  return 0;
7041  }
7042  if (D == 0.0)
7043  {
7044  x(0) = x(1) = -0.5 * b / a;
7045  return 2; // root with multiplicity 2
7046  }
7047  if (b == 0.0)
7048  {
7049  x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a));
7050  return 2;
7051  }
7052  else
7053  {
7054  double t;
7055  if (b > 0.0)
7056  {
7057  t = -0.5 * (b + sqrt(D));
7058  }
7059  else
7060  {
7061  t = -0.5 * (b - sqrt(D));
7062  }
7063  x(0) = t / a;
7064  x(1) = c / t;
7065  if (x(0) > x(1))
7066  {
7067  Swap<double>(x(0), x(1));
7068  }
7069  return 2;
7070  }
7071  }
7072 
7073  case 3:
7074  {
7075  double a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3);
7076 
7077  // find the real roots of x^3 + a x^2 + b x + c = 0
7078  double Q = (a * a - 3 * b) / 9;
7079  double R = (2 * a * a * a - 9 * a * b + 27 * c) / 54;
7080  double Q3 = Q * Q * Q;
7081  double R2 = R * R;
7082 
7083  if (R2 == Q3)
7084  {
7085  if (Q == 0)
7086  {
7087  x(0) = x(1) = x(2) = - a / 3;
7088  }
7089  else
7090  {
7091  double sqrtQ = sqrt(Q);
7092 
7093  if (R > 0)
7094  {
7095  x(0) = -2 * sqrtQ - a / 3;
7096  x(1) = x(2) = sqrtQ - a / 3;
7097  }
7098  else
7099  {
7100  x(0) = x(1) = - sqrtQ - a / 3;
7101  x(2) = 2 * sqrtQ - a / 3;
7102  }
7103  }
7104  return 3;
7105  }
7106  else if (R2 < Q3)
7107  {
7108  double theta = acos(R / sqrt(Q3));
7109  double A = -2 * sqrt(Q);
7110  double x0, x1, x2;
7111  x0 = A * cos(theta / 3) - a / 3;
7112  x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3;
7113  x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3;
7114 
7115  /* Sort x0, x1, x2 */
7116  if (x0 > x1)
7117  {
7118  Swap<double>(x0, x1);
7119  }
7120  if (x1 > x2)
7121  {
7122  Swap<double>(x1, x2);
7123  if (x0 > x1)
7124  {
7125  Swap<double>(x0, x1);
7126  }
7127  }
7128  x(0) = x0;
7129  x(1) = x1;
7130  x(2) = x2;
7131  return 3;
7132  }
7133  else
7134  {
7135  double A;
7136  if (R >= 0.0)
7137  {
7138  A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0);
7139  }
7140  else
7141  {
7142  A = pow(sqrt(R2 - Q3) - R, 1.0/3.0);
7143  }
7144  x(0) = A + Q / A - a / 3;
7145  return 1;
7146  }
7147  }
7148  }
7149  return 0;
7150 }
7151 
7152 void FindTMax(Vector &c, Vector &x, double &tmax,
7153  const double factor, const int Dim)
7154 {
7155  const double c0 = c(0);
7156  c(0) = c0 * (1.0 - pow(factor, -Dim));
7157  int nr = FindRoots(c, x);
7158  for (int j = 0; j < nr; j++)
7159  {
7160  if (x(j) > tmax)
7161  {
7162  break;
7163  }
7164  if (x(j) >= 0.0)
7165  {
7166  tmax = x(j);
7167  break;
7168  }
7169  }
7170  c(0) = c0 * (1.0 - pow(factor, Dim));
7171  nr = FindRoots(c, x);
7172  for (int j = 0; j < nr; j++)
7173  {
7174  if (x(j) > tmax)
7175  {
7176  break;
7177  }
7178  if (x(j) >= 0.0)
7179  {
7180  tmax = x(j);
7181  break;
7182  }
7183  }
7184 }
7185 
7186 void Mesh::CheckDisplacements(const Vector &displacements, double &tmax)
7187 {
7188  int nvs = vertices.Size();
7189  DenseMatrix P, V, DS, PDS(spaceDim), VDS(spaceDim);
7190  Vector c(spaceDim+1), x(spaceDim);
7191  const double factor = 2.0;
7192 
7193  // check for tangling assuming constant speed
7194  if (tmax < 1.0)
7195  {
7196  tmax = 1.0;
7197  }
7198  for (int i = 0; i < NumOfElements; i++)
7199  {
7200  Element *el = elements[i];
7201  int nv = el->GetNVertices();
7202  int *v = el->GetVertices();
7203  P.SetSize(spaceDim, nv);
7204  V.SetSize(spaceDim, nv);
7205  for (int j = 0; j < spaceDim; j++)
7206  for (int k = 0; k < nv; k++)
7207  {
7208  P(j, k) = vertices[v[k]](j);
7209  V(j, k) = displacements(v[k]+j*nvs);
7210  }
7211  DS.SetSize(nv, spaceDim);
7212  const FiniteElement *fe =
7214  // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1
7215  switch (el->GetType())
7216  {
7217  case Element::TRIANGLE:
7218  case Element::TETRAHEDRON:
7219  {
7220  // DS is constant
7221  fe->CalcDShape(Geometries.GetCenter(fe->GetGeomType()), DS);
7222  Mult(P, DS, PDS);
7223  Mult(V, DS, VDS);
7224  DetOfLinComb(PDS, VDS, c);
7225  if (c(0) <= 0.0)
7226  {
7227  tmax = 0.0;
7228  }
7229  else
7230  {
7231  FindTMax(c, x, tmax, factor, Dim);
7232  }
7233  }
7234  break;
7235 
7237  {
7238  const IntegrationRule &ir = fe->GetNodes();
7239  for (int j = 0; j < nv; j++)
7240  {
7241  fe->CalcDShape(ir.IntPoint(j), DS);
7242  Mult(P, DS, PDS);
7243  Mult(V, DS, VDS);
7244  DetOfLinComb(PDS, VDS, c);
7245  if (c(0) <= 0.0)
7246  {
7247  tmax = 0.0;
7248  }
7249  else
7250  {
7251  FindTMax(c, x, tmax, factor, Dim);
7252  }
7253  }
7254  }
7255  break;
7256 
7257  default:
7258  mfem_error("Mesh::CheckDisplacements(...)");
7259  }
7260  }
7261 }
7262 
7263 void Mesh::MoveVertices(const Vector &displacements)
7264 {
7265  for (int i = 0, nv = vertices.Size(); i < nv; i++)
7266  for (int j = 0; j < spaceDim; j++)
7267  {
7268  vertices[i](j) += displacements(j*nv+i);
7269  }
7270 }
7271 
7272 void Mesh::GetVertices(Vector &vert_coord) const
7273 {
7274  int nv = vertices.Size();
7275  vert_coord.SetSize(nv*spaceDim);
7276  for (int i = 0; i < nv; i++)
7277  for (int j = 0; j < spaceDim; j++)
7278  {
7279  vert_coord(j*nv+i) = vertices[i](j);
7280  }
7281 }
7282 
7283 void Mesh::SetVertices(const Vector &vert_coord)
7284 {
7285  for (int i = 0, nv = vertices.Size(); i < nv; i++)
7286  for (int j = 0; j < spaceDim; j++)
7287  {
7288  vertices[i](j) = vert_coord(j*nv+i);
7289  }
7290 }
7291 
7292 void Mesh::GetNode(int i, double *coord) const
7293 {
7294  if (Nodes)
7295  {
7296  FiniteElementSpace *fes = Nodes->FESpace();
7297  for (int j = 0; j < spaceDim; j++)
7298  {
7299  coord[j] = (*Nodes)(fes->DofToVDof(i, j));
7300  }
7301  }
7302  else
7303  {
7304  for (int j = 0; j < spaceDim; j++)
7305  {
7306  coord[j] = vertices[i](j);
7307  }
7308  }
7309 }
7310 
7311 void Mesh::SetNode(int i, const double *coord)
7312 {
7313  if (Nodes)
7314  {
7315  FiniteElementSpace *fes = Nodes->FESpace();
7316  for (int j = 0; j < spaceDim; j++)
7317  {
7318  (*Nodes)(fes->DofToVDof(i, j)) = coord[j];
7319  }
7320  }
7321  else
7322  {
7323  for (int j = 0; j < spaceDim; j++)
7324  {
7325  vertices[i](j) = coord[j];
7326  }
7327 
7328  }
7329 }
7330 
7331 void Mesh::MoveNodes(const Vector &displacements)
7332 {
7333  if (Nodes)
7334  {
7335  (*Nodes) += displacements;
7336  }
7337  else
7338  {
7339  MoveVertices(displacements);
7340  }
7341 }
7342 
7343 void Mesh::GetNodes(Vector &node_coord) const
7344 {
7345  if (Nodes)
7346  {
7347  node_coord = (*Nodes);
7348  }
7349  else
7350  {
7351  GetVertices(node_coord);
7352  }
7353 }
7354 
7355 void Mesh::SetNodes(const Vector &node_coord)
7356 {
7357  if (Nodes)
7358  {
7359  (*Nodes) = node_coord;
7360  }
7361  else
7362  {
7363  SetVertices(node_coord);
7364  }
7365 }
7366 
7367 void Mesh::NewNodes(GridFunction &nodes, bool make_owner)
7368 {
7369  if (own_nodes) { delete Nodes; }
7370  Nodes = &nodes;
7371  spaceDim = Nodes->FESpace()->GetVDim();
7372  own_nodes = (int)make_owner;
7373 
7374  if (NURBSext != nodes.FESpace()->GetNURBSext())
7375  {
7376  delete NURBSext;
7377  NURBSext = nodes.FESpace()->StealNURBSext();
7378  }
7379 
7380  if (ncmesh)
7381  {
7383  }
7384 }
7385 
7386 void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_)
7387 {
7388  mfem::Swap<GridFunction*>(Nodes, nodes);
7389  mfem::Swap<int>(own_nodes, own_nodes_);
7390  // TODO:
7391  // if (nodes)
7392  // nodes->FESpace()->MakeNURBSextOwner();
7393  // NURBSext = (Nodes) ? Nodes->FESpace()->StealNURBSext() : NULL;
7394 }
7395 
7396 void Mesh::AverageVertices(const int *indexes, int n, int result)
7397 {
7398  int j, k;
7399 
7400  for (k = 0; k < spaceDim; k++)
7401  {
7402  vertices[result](k) = vertices[indexes[0]](k);
7403  }
7404 
7405  for (j = 1; j < n; j++)
7406  for (k = 0; k < spaceDim; k++)
7407  {
7408  vertices[result](k) += vertices[indexes[j]](k);
7409  }
7410 
7411  for (k = 0; k < spaceDim; k++)
7412  {
7413  vertices[result](k) *= (1.0 / n);
7414  }
7415 }
7416 
7418 {
7419  if (Nodes)
7420  {
7421  Nodes->FESpace()->Update();
7422  Nodes->Update();
7423 
7424  // update vertex coordinates for compatibility (e.g., GetVertex())
7426  }
7427 }
7428 
7429 void Mesh::UniformRefinement2D_base(bool update_nodes)
7430 {
7431  ResetLazyData();
7432 
7433  if (el_to_edge == NULL)
7434  {
7435  el_to_edge = new Table;
7437  }
7438 
7439  int quad_counter = 0;
7440  for (int i = 0; i < NumOfElements; i++)
7441  {
7442  if (elements[i]->GetType() == Element::QUADRILATERAL)
7443  {
7444  quad_counter++;
7445  }
7446  }
7447 
7448  const int oedge = NumOfVertices;
7449  const int oelem = oedge + NumOfEdges;
7450 
7451  Array<Element*> new_elements;
7452  Array<Element*> new_boundary;
7453 
7454  vertices.SetSize(oelem + quad_counter);
7455  new_elements.SetSize(4 * NumOfElements);
7456  quad_counter = 0;
7457 
7458  for (int i = 0, j = 0; i < NumOfElements; i++)
7459  {
7460  const Element::Type el_type = elements[i]->GetType();
7461  const int attr = elements[i]->GetAttribute();
7462  int *v = elements[i]->GetVertices();
7463  const int *e = el_to_edge->GetRow(i);
7464  int vv[2];
7465 
7466  if (el_type == Element::TRIANGLE)
7467  {
7468  for (int ei = 0; ei < 3; ei++)
7469  {
7470  for (int k = 0; k < 2; k++)
7471  {
7472  vv[k] = v[tri_t::Edges[ei][k]];
7473  }
7474  AverageVertices(vv, 2, oedge+e[ei]);
7475  }
7476 
7477  new_elements[j++] =
7478  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
7479  new_elements[j++] =
7480  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
7481  new_elements[j++] =
7482  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
7483  new_elements[j++] =
7484  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
7485  }
7486  else if (el_type == Element::QUADRILATERAL)
7487  {
7488  const int qe = quad_counter;
7489  quad_counter++;
7490  AverageVertices(v, 4, oelem+qe);
7491 
7492  for (int ei = 0; ei < 4; ei++)
7493  {
7494  for (int k = 0; k < 2; k++)
7495  {
7496  vv[k] = v[quad_t::Edges[ei][k]];
7497  }
7498  AverageVertices(vv, 2, oedge+e[ei]);
7499  }
7500 
7501  new_elements[j++] =
7502  new Quadrilateral(v[0], oedge+e[0], oelem+qe, oedge+e[3], attr);
7503  new_elements[j++] =
7504  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oelem+qe, attr);
7505  new_elements[j++] =
7506  new Quadrilateral(oelem+qe, oedge+e[1], v[2], oedge+e[2], attr);
7507  new_elements[j++] =
7508  new Quadrilateral(oedge+e[3], oelem+qe, oedge+e[2], v[3], attr);
7509  }
7510  else
7511  {
7512  MFEM_ABORT("unknown element type: " << el_type);
7513  }
7514  FreeElement(elements[i]);
7515  }
7516  mfem::Swap(elements, new_elements);
7517 
7518  // refine boundary elements
7519  new_boundary.SetSize(2 * NumOfBdrElements);
7520  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
7521  {
7522  const int attr = boundary[i]->GetAttribute();
7523  int *v = boundary[i]->GetVertices();
7524 
7525  new_boundary[j++] = new Segment(v[0], oedge+be_to_edge[i], attr);
7526  new_boundary[j++] = new Segment(oedge+be_to_edge[i], v[1], attr);
7527 
7528  FreeElement(boundary[i]);
7529  }
7530  mfem::Swap(boundary, new_boundary);
7531 
7532  static const double A = 0.0, B = 0.5, C = 1.0;
7533  static double tri_children[2*3*4] =
7534  {
7535  A,A, B,A, A,B,
7536  B,B, A,B, B,A,
7537  B,A, C,A, B,B,
7538  A,B, B,B, A,C
7539  };
7540  static double quad_children[2*4*4] =
7541  {
7542  A,A, B,A, B,B, A,B, // lower-left
7543  B,A, C,A, C,B, B,B, // lower-right
7544  B,B, C,B, C,C, B,C, // upper-right
7545  A,B, B,B, B,C, A,C // upper-left
7546  };
7547 
7549  .UseExternalData(tri_children, 2, 3, 4);
7551  .UseExternalData(quad_children, 2, 4, 4);
7552  CoarseFineTr.embeddings.SetSize(elements.Size());
7553 
7554  for (int i = 0; i < elements.Size(); i++)
7555  {
7556  Embedding &emb = CoarseFineTr.embeddings[i];
7557  emb.parent = i / 4;
7558  emb.matrix = i % 4;
7559  }
7560 
7561  NumOfVertices = vertices.Size();
7562  NumOfElements = 4 * NumOfElements;
7563  NumOfBdrElements = 2 * NumOfBdrElements;
7564  NumOfFaces = 0;
7565 
7567  GenerateFaces();
7568 
7570  sequence++;
7571 
7572  if (update_nodes) { UpdateNodes(); }
7573 
7574 #ifdef MFEM_DEBUG
7575  if (!Nodes || update_nodes)
7576  {
7577  CheckElementOrientation(false);
7578  }
7580 #endif
7581 }
7582 
7583 static inline double sqr(const double &x)
7584 {
7585  return x*x;
7586 }
7587 
7589  bool update_nodes)
7590 {
7591  ResetLazyData();
7592 
7593  if (el_to_edge == NULL)
7594  {
7595  el_to_edge = new Table;
7597  }
7598 
7599  if (el_to_face == NULL)
7600  {
7602  }
7603 
7604  Array<int> f2qf_loc;
7605  Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
7606  f2qf.SetSize(0);
7607 
7608  int NumOfQuadFaces = 0;
7610  {
7612  {
7613  f2qf.SetSize(faces.Size());
7614  for (int i = 0; i < faces.Size(); i++)
7615  {
7616  if (faces[i]->GetType() == Element::QUADRILATERAL)
7617  {
7618  f2qf[i] = NumOfQuadFaces;
7619  NumOfQuadFaces++;
7620  }
7621  }
7622  }
7623  else
7624  {
7625  NumOfQuadFaces = faces.Size();
7626  }
7627  }
7628 
7629  int hex_counter = 0;
7631  {
7632  for (int i = 0; i < elements.Size(); i++)
7633  {
7634  if (elements[i]->GetType() == Element::HEXAHEDRON)
7635  {
7636  hex_counter++;
7637  }
7638  }
7639  }
7640 
7641  // Map from edge-index to vertex-index, needed for ReorientTetMesh() for
7642  // parallel meshes.
7643  Array<int> e2v;
7645  {
7646  e2v.SetSize(NumOfEdges);
7647 
7648  DSTable *v_to_v_ptr = v_to_v_p;
7649  if (!v_to_v_p)
7650  {
7651  v_to_v_ptr = new DSTable(NumOfVertices);
7652  GetVertexToVertexTable(*v_to_v_ptr);
7653  }
7654 
7655  Array<Pair<int,int> > J_v2v(NumOfEdges); // (second vertex id, edge id)
7656  J_v2v.SetSize(0);
7657  for (int i = 0; i < NumOfVertices; i++)
7658  {
7659  Pair<int,int> *row_start = J_v2v.end();
7660  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
7661  {
7662  J_v2v.Append(Pair<int,int>(it.Column(), it.Index()));
7663  }
7664  std::sort(row_start, J_v2v.end());
7665  }
7666 
7667  for (int i = 0; i < J_v2v.Size(); i++)
7668  {
7669  e2v[J_v2v[i].two] = i;
7670  }
7671 
7672  if (!v_to_v_p)
7673  {
7674  delete v_to_v_ptr;
7675  }
7676  else
7677  {
7678  for (int i = 0; i < NumOfVertices; i++)
7679  {
7680  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
7681  {
7682  it.SetIndex(e2v[it.Index()]);
7683  }
7684  }
7685  }
7686  }
7687 
7688  // Offsets for new vertices from edges, faces (quads only), and elements
7689  // (hexes only); each of these entities generates one new vertex.
7690  const int oedge = NumOfVertices;
7691  const int oface = oedge + NumOfEdges;
7692  const int oelem = oface + NumOfQuadFaces;
7693 
7694  Array<Element*> new_elements;
7695  Array<Element*> new_boundary;
7696 
7697  vertices.SetSize(oelem + hex_counter);
7698  new_elements.SetSize(8 * NumOfElements);
7699  CoarseFineTr.embeddings.SetSize(new_elements.Size());
7700 
7701  hex_counter = 0;
7702  for (int i = 0, j = 0; i < NumOfElements; i++)
7703  {
7704  const Element::Type el_type = elements[i]->GetType();
7705  const int attr = elements[i]->GetAttribute();
7706  int *v = elements[i]->GetVertices();
7707  const int *e = el_to_edge->GetRow(i);
7708  int vv[4], ev[12];
7709 
7710  if (e2v.Size())
7711  {
7712  const int ne = el_to_edge->RowSize(i);
7713  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
7714  e = ev;
7715  }
7716 
7717  switch (el_type)
7718  {
7719  case Element::TETRAHEDRON:
7720  {
7721  for (int ei = 0; ei < 6; ei++)
7722  {
7723  for (int k = 0; k < 2; k++)
7724  {
7725  vv[k] = v[tet_t::Edges[ei][k]];
7726  }
7727  AverageVertices(vv, 2, oedge+e[ei]);
7728  }
7729 
7730  // Algorithm for choosing refinement type:
7731  // 0: smallest octahedron diagonal
7732  // 1: best aspect ratio
7733  const int rt_algo = 1;
7734  // Refinement type:
7735  // 0: (v0,v1)-(v2,v3), 1: (v0,v2)-(v1,v3), 2: (v0,v3)-(v1,v2)
7736  // 0: e0-e5, 1: e1-e4, 2: e2-e3
7737  int rt;
7740  const DenseMatrix &J = T->Jacobian();
7741  if (rt_algo == 0)
7742  {
7743  // smallest octahedron diagonal
7744  double len_sqr, min_len;
7745 
7746  min_len = sqr(J(0,0)-J(0,1)-J(0,2)) +
7747  sqr(J(1,0)-J(1,1)-J(1,2)) +
7748  sqr(J(2,0)-J(2,1)-J(2,2));
7749  rt = 0;
7750 
7751  len_sqr = sqr(J(0,1)-J(0,0)-J(0,2)) +
7752  sqr(J(1,1)-J(1,0)-J(1,2)) +
7753  sqr(J(2,1)-J(2,0)-J(2,2));
7754  if (len_sqr < min_len) { min_len = len_sqr; rt = 1; }
7755 
7756  len_sqr = sqr(J(0,2)-J(0,0)-J(0,1)) +
7757  sqr(J(1,2)-J(1,0)-J(1,1)) +
7758  sqr(J(2,2)-J(2,0)-J(2,1));
7759  if (len_sqr < min_len) { rt = 2; }
7760  }
7761  else
7762  {
7763  // best aspect ratio
7764  double Em_data[18], Js_data[9], Jp_data[9];
7765  DenseMatrix Em(Em_data, 3, 6);
7766  DenseMatrix Js(Js_data, 3, 3), Jp(Jp_data, 3, 3);
7767  double ar1, ar2, kappa, kappa_min;
7768 
7769  for (int s = 0; s < 3; s++)
7770  {
7771  for (int t = 0; t < 3; t++)
7772  {
7773  Em(t,s) = 0.5*J(t,s);
7774  }
7775  }
7776  for (int t = 0; t < 3; t++)
7777  {
7778  Em(t,3) = 0.5*(J(t,0)+J(t,1));
7779  Em(t,4) = 0.5*(J(t,0)+J(t,2));
7780  Em(t,5) = 0.5*(J(t,1)+J(t,2));
7781  }
7782 
7783  // rt = 0; Em: {0,5,1,2}, {0,5,2,4}
7784  for (int t = 0; t < 3; t++)
7785  {
7786  Js(t,0) = Em(t,5)-Em(t,0);
7787  Js(t,1) = Em(t,1)-Em(t,0);
7788  Js(t,2) = Em(t,2)-Em(t,0);
7789  }
7791  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7792  for (int t = 0; t < 3; t++)
7793  {
7794  Js(t,0) = Em(t,5)-Em(t,0);
7795  Js(t,1) = Em(t,2)-Em(t,0);
7796  Js(t,2) = Em(t,4)-Em(t,0);
7797  }
7799  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7800  kappa_min = std::max(ar1, ar2);
7801  rt = 0;
7802 
7803  // rt = 1; Em: {1,0,4,2}, {1,2,4,5}
7804  for (int t = 0; t < 3; t++)
7805  {
7806  Js(t,0) = Em(t,0)-Em(t,1);
7807  Js(t,1) = Em(t,4)-Em(t,1);
7808  Js(t,2) = Em(t,2)-Em(t,1);
7809  }
7811  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7812  for (int t = 0; t < 3; t++)
7813  {
7814  Js(t,0) = Em(t,2)-Em(t,1);
7815  Js(t,1) = Em(t,4)-Em(t,1);
7816  Js(t,2) = Em(t,5)-Em(t,1);
7817  }
7819  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7820  kappa = std::max(ar1, ar2);
7821  if (kappa < kappa_min) { kappa_min = kappa; rt = 1; }
7822 
7823  // rt = 2; Em: {2,0,1,3}, {2,1,5,3}
7824  for (int t = 0; t < 3; t++)
7825  {
7826  Js(t,0) = Em(t,0)-Em(t,2);
7827  Js(t,1) = Em(t,1)-Em(t,2);
7828  Js(t,2) = Em(t,3)-Em(t,2);
7829  }
7831  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7832  for (int t = 0; t < 3; t++)
7833  {
7834  Js(t,0) = Em(t,1)-Em(t,2);
7835  Js(t,1) = Em(t,5)-Em(t,2);
7836  Js(t,2) = Em(t,3)-Em(t,2);
7837  }
7839  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7840  kappa = std::max(ar1, ar2);
7841  if (kappa < kappa_min) { rt = 2; }
7842  }
7843 
7844  static const int mv_all[3][4][4] =
7845  {
7846  { {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1} }, // rt = 0
7847  { {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0} }, // rt = 1
7848  { {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3} } // rt = 2
7849  };
7850  const int (&mv)[4][4] = mv_all[rt];
7851 
7852 #ifndef MFEM_USE_MEMALLOC
7853  new_elements[j+0] =
7854  new Tetrahedron(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
7855  new_elements[j+1] =
7856  new Tetrahedron(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
7857  new_elements[j+2] =
7858  new Tetrahedron(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
7859  new_elements[j+3] =
7860  new Tetrahedron(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
7861 
7862  for (int k = 0; k < 4; k++)
7863  {
7864  new_elements[j+4+k] =
7865  new Tetrahedron(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
7866  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
7867  }
7868 #else
7869  Tetrahedron *tet;
7870  new_elements[j+0] = tet = TetMemory.Alloc();
7871  tet->Init(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
7872 
7873  new_elements[j+1] = tet = TetMemory.Alloc();
7874  tet->Init(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
7875 
7876  new_elements[j+2] = tet = TetMemory.Alloc();
7877  tet->Init(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
7878 
7879  new_elements[j+3] = tet = TetMemory.Alloc();
7880  tet->Init(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
7881 
7882  for (int k = 0; k < 4; k++)
7883  {
7884  new_elements[j+4+k] = tet = TetMemory.Alloc();
7885  tet->Init(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
7886  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
7887  }
7888 #endif
7889  for (int k = 0; k < 4; k++)
7890  {
7891  CoarseFineTr.embeddings[j+k].parent = i;
7892  CoarseFineTr.embeddings[j+k].matrix = k;
7893  }
7894  for (int k = 0; k < 4; k++)
7895  {
7896  CoarseFineTr.embeddings[j+4+k].parent = i;
7897  CoarseFineTr.embeddings[j+4+k].matrix = 4*(rt+1)+k;
7898  }
7899 
7900  j += 8;
7901  }
7902  break;
7903 
7904  case Element::WEDGE:
7905  {
7906  const int *f = el_to_face->GetRow(i);
7907 
7908  for (int fi = 2; fi < 5; fi++)
7909  {
7910  for (int k = 0; k < 4; k++)
7911  {
7912  vv[k] = v[pri_t::FaceVert[fi][k]];
7913  }
7914  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
7915  }
7916 
7917  for (int ei = 0; ei < 9; ei++)
7918  {
7919  for (int k = 0; k < 2; k++)
7920  {
7921  vv[k] = v[pri_t::Edges[ei][k]];
7922  }
7923  AverageVertices(vv, 2, oedge+e[ei]);
7924  }
7925 
7926  const int qf2 = f2qf[f[2]];
7927  const int qf3 = f2qf[f[3]];
7928  const int qf4 = f2qf[f[4]];
7929 
7930  new_elements[j++] =
7931  new Wedge(v[0], oedge+e[0], oedge+e[2],
7932  oedge+e[6], oface+qf2, oface+qf4, attr);
7933 
7934  new_elements[j++] =
7935  new Wedge(oedge+e[1], oedge+e[2], oedge+e[0],
7936  oface+qf3, oface+qf4, oface+qf2, attr);
7937 
7938  new_elements[j++] =
7939  new Wedge(oedge+e[0], v[1], oedge+e[1],
7940  oface+qf2, oedge+e[7], oface+qf3, attr);
7941 
7942  new_elements[j++] =
7943  new Wedge(oedge+e[2], oedge+e[1], v[2],
7944  oface+qf4, oface+qf3, oedge+e[8], attr);
7945 
7946  new_elements[j++] =
7947  new Wedge(oedge+e[6], oface+qf2, oface+qf4,
7948  v[3], oedge+e[3], oedge+e[5], attr);
7949 
7950  new_elements[j++] =
7951  new Wedge(oface+qf3, oface+qf4, oface+qf2,
7952  oedge+e[4], oedge+e[5], oedge+e[3], attr);
7953 
7954  new_elements[j++] =
7955  new Wedge(oface+qf2, oedge+e[7], oface+qf3,
7956  oedge+e[3], v[4], oedge+e[4], attr);
7957 
7958  new_elements[j++] =
7959  new Wedge(oface+qf4, oface+qf3, oedge+e[8],
7960  oedge+e[5], oedge+e[4], v[5], attr);
7961  }
7962  break;
7963 
7964  case Element::HEXAHEDRON:
7965  {
7966  const int *f = el_to_face->GetRow(i);
7967  const int he = hex_counter;
7968  hex_counter++;
7969 
7970  const int *qf;
7971  int qf_data[6];
7972  if (f2qf.Size() == 0)
7973  {
7974  qf = f;
7975  }
7976  else
7977  {
7978  for (int k = 0; k < 6; k++) { qf_data[k] = f2qf[f[k]]; }
7979  qf = qf_data;
7980  }
7981 
7982  AverageVertices(v, 8, oelem+he);
7983 
7984  for (int fi = 0; fi < 6; fi++)
7985  {
7986  for (int k = 0; k < 4; k++)
7987  {
7988  vv[k] = v[hex_t::FaceVert[fi][k]];
7989  }
7990  AverageVertices(vv, 4, oface + qf[fi]);
7991  }
7992 
7993  for (int ei = 0; ei < 12; ei++)
7994  {
7995  for (int k = 0; k < 2; k++)
7996  {
7997  vv[k] = v[hex_t::Edges[ei][k]];
7998  }
7999  AverageVertices(vv, 2, oedge+e[ei]);
8000  }
8001 
8002  new_elements[j++] =
8003  new Hexahedron(v[0], oedge+e[0], oface+qf[0],
8004  oedge+e[3], oedge+e[8], oface+qf[1],
8005  oelem+he, oface+qf[4], attr);
8006  new_elements[j++] =
8007  new Hexahedron(oedge+e[0], v[1], oedge+e[1],
8008  oface+qf[0], oface+qf[1], oedge+e[9],
8009  oface+qf[2], oelem+he, attr);
8010  new_elements[j++] =
8011  new Hexahedron(oface+qf[0], oedge+e[1], v[2],
8012  oedge+e[2], oelem+he, oface+qf[2],
8013  oedge+e[10], oface+qf[3], attr);
8014  new_elements[j++] =
8015  new Hexahedron(oedge+e[3], oface+qf[0], oedge+e[2],
8016  v[3], oface+qf[4], oelem+he,
8017  oface+qf[3], oedge+e[11], attr);
8018  new_elements[j++] =
8019  new Hexahedron(oedge+e[8], oface+qf[1], oelem+he,
8020  oface+qf[4], v[4], oedge+e[4],
8021  oface+qf[5], oedge+e[7], attr);
8022  new_elements[j++] =
8023  new Hexahedron(oface+qf[1], oedge+e[9], oface+qf[2],
8024  oelem+he, oedge+e[4], v[5],
8025  oedge+e[5], oface+qf[5], attr);
8026  new_elements[j++] =
8027  new Hexahedron(oelem+he, oface+qf[2], oedge+e[10],
8028  oface+qf[3], oface+qf[5], oedge+e[5],
8029  v[6], oedge+e[6], attr);
8030  new_elements[j++] =
8031  new Hexahedron(oface+qf[4], oelem+he, oface+qf[3],
8032  oedge+e[11], oedge+e[7], oface+qf[5],
8033  oedge+e[6], v[7], attr);
8034  }
8035  break;
8036 
8037  default:
8038  MFEM_ABORT("Unknown 3D element type \"" << el_type << "\"");
8039  break;
8040  }
8041  FreeElement(elements[i]);
8042  }
8043  mfem::Swap(elements, new_elements);
8044 
8045  // refine boundary elements
8046  new_boundary.SetSize(4 * NumOfBdrElements);
8047  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
8048  {
8049  const Element::Type bdr_el_type = boundary[i]->GetType();
8050  const int attr = boundary[i]->GetAttribute();
8051  int *v = boundary[i]->GetVertices();
8052  const int *e = bel_to_edge->GetRow(i);
8053  int ev[4];
8054 
8055  if (e2v.Size())
8056  {
8057  const int ne = bel_to_edge->RowSize(i);
8058  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
8059  e = ev;
8060  }
8061 
8062  if (bdr_el_type == Element::TRIANGLE)
8063  {
8064  new_boundary[j++] =
8065  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
8066  new_boundary[j++] =
8067  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
8068  new_boundary[j++] =
8069  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
8070  new_boundary[j++] =
8071  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
8072  }
8073  else if (bdr_el_type == Element::QUADRILATERAL)
8074  {
8075  const int qf =
8076  (f2qf.Size() == 0) ? be_to_face[i] : f2qf[be_to_face[i]];
8077 
8078  new_boundary[j++] =
8079  new Quadrilateral(v[0], oedge+e[0], oface+qf, oedge+e[3], attr);
8080  new_boundary[j++] =
8081  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oface+qf, attr);
8082  new_boundary[j++] =
8083  new Quadrilateral(oface+qf, oedge+e[1], v[2], oedge+e[2], attr);
8084  new_boundary[j++] =
8085  new Quadrilateral(oedge+e[3], oface+qf, oedge+e[2], v[3], attr);
8086  }
8087  else
8088  {
8089  MFEM_ABORT("boundary Element is not a triangle or a quad!");
8090  }
8091  FreeElement(boundary[i]);
8092  }
8093  mfem::Swap(boundary, new_boundary);
8094 
8095  static const double A = 0.0, B = 0.5, C = 1.0;
8096  static double tet_children[3*4*16] =
8097  {
8098  A,A,A, B,A,A, A,B,A, A,A,B,
8099  B,A,A, C,A,A, B,B,A, B,A,B,
8100  A,B,A, B,B,A, A,C,A, A,B,B,
8101  A,A,B, B,A,B, A,B,B, A,A,C,
8102  // edge coordinates:
8103  // 0 -> B,A,A 1 -> A,B,A 2 -> A,A,B
8104  // 3 -> B,B,A 4 -> B,A,B 5 -> A,B,B
8105  // rt = 0: {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1}
8106  B,A,A, A,B,B, A,B,A, A,A,B,
8107  B,A,A, A,B,B, A,A,B, B,A,B,
8108  B,A,A, A,B,B, B,A,B, B,B,A,
8109  B,A,A, A,B,B, B,B,A, A,B,A,
8110  // rt = 1: {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0}
8111  A,B,A, B,A,A, B,A,B, A,A,B,
8112  A,B,A, A,A,B, B,A,B, A,B,B,
8113  A,B,A, A,B,B, B,A,B, B,B,A,
8114  A,B,A, B,B,A, B,A,B, B,A,A,
8115  // rt = 2: {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3}
8116  A,A,B, B,A,A, A,B,A, B,B,A,
8117  A,A,B, A,B,A, A,B,B, B,B,A,
8118  A,A,B, A,B,B, B,A,B, B,B,A,
8119  A,A,B, B,A,B, B,A,A, B,B,A
8120  };
8121  static double pri_children[3*6*8] =
8122  {
8123  A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
8124  B,B,A, A,B,A, B,A,A, B,B,B, A,B,B, B,A,B,
8125  B,A,A, C,A,A, B,B,A, B,A,B, C,A,B, B,B,B,
8126  A,B,A, B,B,A, A,C,A, A,B,B, B,B,B, A,C,B,
8127  A,A,B, B,A,B, A,B,B, A,A,C, B,A,C, A,B,C,
8128  B,B,B, A,B,B, B,A,B, B,B,C, A,B,C, B,A,C,
8129  B,A,B, C,A,B, B,B,B, B,A,C, C,A,C, B,B,C,
8130  A,B,B, B,B,B, A,C,B, A,B,C, B,B,C, A,C,C
8131  };
8132  static double hex_children[3*8*8] =
8133  {
8134  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B, B,A,B, B,B,B, A,B,B,
8135  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B, C,A,B, C,B,B, B,B,B,
8136  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B, C,B,B, C,C,B, B,C,B,
8137  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B, B,B,B, B,C,B, A,C,B,
8138  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C, B,A,C, B,B,C, A,B,C,
8139  B,A,B, C,A,B, C,B,B, B,B,B, B,A,C, C,A,C, C,B,C, B,B,C,
8140  B,B,B, C,B,B, C,C,B, B,C,B, B,B,C, C,B,C, C,C,C, B,C,C,
8141  A,B,B, B,B,B, B,C,B, A,C,B, A,B,C, B,B,C, B,C,C, A,C,C
8142  };
8143 
8145  .UseExternalData(tet_children, 3, 4, 16);
8147  .UseExternalData(pri_children, 3, 6, 8);
8149  .UseExternalData(hex_children, 3, 8, 8);
8150 
8151  for (int i = 0; i < elements.Size(); i++)
8152  {
8153  // tetrahedron elements are handled above:
8154  if (elements[i]->GetType() == Element::TETRAHEDRON) { continue; }
8155 
8156  Embedding &emb = CoarseFineTr.embeddings[i];
8157  emb.parent = i / 8;
8158  emb.matrix = i % 8;
8159  }
8160 
8161  NumOfVertices = vertices.Size();
8162  NumOfElements = 8 * NumOfElements;
8163  NumOfBdrElements = 4 * NumOfBdrElements;
8164 
8166  GenerateFaces();
8167 
8168 #ifdef MFEM_DEBUG
8170 #endif
8171 
8173 
8175  sequence++;
8176 
8177  if (update_nodes) { UpdateNodes(); }
8178 }
8179 
8180 void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
8181 {
8182  int i, j, ind, nedges;
8183  Array<int> v;
8184 
8185  ResetLazyData();
8186 
8187  if (ncmesh)
8188  {
8189  MFEM_ABORT("Local and nonconforming refinements cannot be mixed.");
8190  }
8191 
8193 
8194  if (Dim == 1) // --------------------------------------------------------
8195  {
8196  int cne = NumOfElements, cnv = NumOfVertices;
8197  NumOfVertices += marked_el.Size();
8198  NumOfElements += marked_el.Size();
8199  vertices.SetSize(NumOfVertices);
8200  elements.SetSize(NumOfElements);
8202 
8203  for (j = 0; j < marked_el.Size(); j++)
8204  {
8205  i = marked_el[j];
8206  Segment *c_seg = (Segment *)elements[i];
8207  int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
8208  int new_v = cnv + j, new_e = cne + j;
8209  AverageVertices(vert, 2, new_v);
8210  elements[new_e] = new Segment(new_v, vert[1], attr);
8211  vert[1] = new_v;
8212 
8213  CoarseFineTr.embeddings[i] = Embedding(i, 1);
8214  CoarseFineTr.embeddings[new_e] = Embedding(i, 2);
8215  }
8216 
8217  static double seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
8219  UseExternalData(seg_children, 1, 2, 3);
8220 
8221  GenerateFaces();
8222 
8223  } // end of 'if (Dim == 1)'
8224  else if (Dim == 2) // ---------------------------------------------------
8225  {
8226  // 1. Get table of vertex to vertex connections.
8227  DSTable v_to_v(NumOfVertices);
8228  GetVertexToVertexTable(v_to_v);
8229 
8230  // 2. Get edge to element connections in arrays edge1 and edge2
8231  nedges = v_to_v.NumberOfEntries();
8232  int *edge1 = new int[nedges];
8233  int *edge2 = new int[nedges];
8234  int *middle = new int[nedges];
8235 
8236  for (i = 0; i < nedges; i++)
8237  {
8238  edge1[i] = edge2[i] = middle[i] = -1;
8239  }
8240 
8241  for (i = 0; i < NumOfElements; i++)
8242  {
8243  elements[i]->GetVertices(v);
8244  for (j = 1; j < v.Size(); j++)
8245  {
8246  ind = v_to_v(v[j-1], v[j]);
8247  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
8248  }
8249  ind = v_to_v(v[0], v[v.Size()-1]);
8250  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
8251  }
8252 
8253  // 3. Do the red refinement.
8254  for (i = 0; i < marked_el.Size(); i++)
8255  {
8256  RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
8257  }
8258 
8259  // 4. Do the green refinement (to get conforming mesh).
8260  int need_refinement;
8261  do
8262  {
8263  need_refinement = 0;
8264  for (i = 0; i < nedges; i++)
8265  {
8266  if (middle[i] != -1 && edge1[i] != -1)
8267  {
8268  need_refinement = 1;
8269  GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
8270  }
8271  }
8272  }
8273  while (need_refinement == 1);
8274 
8275  // 5. Update the boundary elements.
8276  int v1[2], v2[2], bisect, temp;
8277  temp = NumOfBdrElements;
8278  for (i = 0; i < temp; i++)
8279  {
8280  boundary[i]->GetVertices(v);
8281  bisect = v_to_v(v[0], v[1]);
8282  if (middle[bisect] != -1) // the element was refined (needs updating)
8283  {
8284  if (boundary[i]->GetType() == Element::SEGMENT)
8285  {
8286  v1[0] = v[0]; v1[1] = middle[bisect];
8287  v2[0] = middle[bisect]; v2[1] = v[1];
8288 
8289  boundary[i]->SetVertices(v1);
8290  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
8291  }
8292  else
8293  mfem_error("Only bisection of segment is implemented"
8294  " for bdr elem.");
8295  }
8296  }
8297  NumOfBdrElements = boundary.Size();
8298 
8299  // 6. Free the allocated memory.
8300  delete [] edge1;
8301  delete [] edge2;
8302  delete [] middle;
8303 
8304  if (el_to_edge != NULL)
8305  {
8307  GenerateFaces();
8308  }
8309 
8310  }
8311  else if (Dim == 3) // ---------------------------------------------------
8312  {
8313  // 1. Hash table of vertex to vertex connections corresponding to refined
8314  // edges.
8315  HashTable<Hashed2> v_to_v;
8316 
8317  MFEM_VERIFY(GetNE() == 0 ||
8318  ((Tetrahedron*)elements[0])->GetRefinementFlag() != 0,
8319  "tetrahedral mesh is not marked for refinement:"
8320  " call Finalize(true)");
8321 
8322  // 2. Do the red refinement.
8323  int ii;
8324  switch (type)
8325  {
8326  case 1:
8327  for (i = 0; i < marked_el.Size(); i++)
8328  {
8329  Bisection(marked_el[i], v_to_v);
8330  }
8331  break;
8332  case 2:
8333  for (i = 0; i < marked_el.Size(); i++)
8334  {
8335  Bisection(marked_el[i], v_to_v);
8336 
8337  Bisection(NumOfElements - 1, v_to_v);
8338  Bisection(marked_el[i], v_to_v);
8339  }
8340  break;
8341  case 3:
8342  for (i = 0; i < marked_el.Size(); i++)
8343  {
8344  Bisection(marked_el[i], v_to_v);
8345 
8346  ii = NumOfElements - 1;
8347  Bisection(ii, v_to_v);
8348  Bisection(NumOfElements - 1, v_to_v);
8349  Bisection(ii, v_to_v);
8350 
8351  Bisection(marked_el[i], v_to_v);
8352  Bisection(NumOfElements-1, v_to_v);
8353  Bisection(marked_el[i], v_to_v);
8354  }
8355  break;
8356  }
8357 
8358  // 3. Do the green refinement (to get conforming mesh).
8359  int need_refinement;
8360  // int need_refinement, onoe, max_gen = 0;
8361  do
8362  {
8363  // int redges[2], type, flag;
8364  need_refinement = 0;
8365  // onoe = NumOfElements;
8366  // for (i = 0; i < onoe; i++)
8367  for (i = 0; i < NumOfElements; i++)
8368  {
8369  // ((Tetrahedron *)elements[i])->
8370  // ParseRefinementFlag(redges, type, flag);
8371  // if (flag > max_gen) max_gen = flag;
8372  if (elements[i]->NeedRefinement(v_to_v))
8373  {
8374  need_refinement = 1;
8375  Bisection(i, v_to_v);
8376  }
8377  }
8378  }
8379  while (need_refinement == 1);
8380 
8381  // mfem::out << "Maximum generation: " << max_gen << endl;
8382 
8383  // 4. Update the boundary elements.
8384  do
8385  {
8386  need_refinement = 0;
8387  for (i = 0; i < NumOfBdrElements; i++)
8388  if (boundary[i]->NeedRefinement(v_to_v))
8389  {
8390  need_refinement = 1;
8391  BdrBisection(i, v_to_v);
8392  }
8393  }
8394  while (need_refinement == 1);
8395 
8396  NumOfVertices = vertices.Size();
8397  NumOfBdrElements = boundary.Size();
8398 
8399  // 5. Update element-to-edge and element-to-face relations.
8400  if (el_to_edge != NULL)
8401  {
8403  }
8404  if (el_to_face != NULL)
8405  {
8407  GenerateFaces();
8408  }
8409 
8410  } // end 'if (Dim == 3)'
8411 
8413  sequence++;
8414 
8415  UpdateNodes();
8416 
8417 #ifdef MFEM_DEBUG
8418  CheckElementOrientation(false);
8419 #endif
8420 }
8421 
8423  int nc_limit)
8424 {
8425  MFEM_VERIFY(!NURBSext, "Nonconforming refinement of NURBS meshes is "
8426  "not supported. Project the NURBS to Nodes first.");
8427 
8428  ResetLazyData();
8429 
8430  if (!ncmesh)
8431  {
8432  // start tracking refinement hierarchy
8433  ncmesh = new NCMesh(this);
8434  }
8435 
8436  if (!refinements.Size())
8437  {
8439  return;
8440  }
8441 
8442  // do the refinements
8444  ncmesh->Refine(refinements);
8445 
8446  if (nc_limit > 0)
8447  {
8448  ncmesh->LimitNCLevel(nc_limit);
8449  }
8450 
8451  // create a second mesh containing the finest elements from 'ncmesh'
8452  Mesh* mesh2 = new Mesh(*ncmesh);
8453  ncmesh->OnMeshUpdated(mesh2);
8454 
8455  // now swap the meshes, the second mesh will become the old coarse mesh
8456  // and this mesh will be the new fine mesh
8457  Swap(*mesh2, false);
8458  delete mesh2;
8459 
8461 
8463  sequence++;
8464 
8465  if (Nodes) // update/interpolate curved mesh
8466  {
8467  Nodes->FESpace()->Update();
8468  Nodes->Update();
8469  }
8470 }
8471 
8472 double Mesh::AggregateError(const Array<double> &elem_error,
8473  const int *fine, int nfine, int op)
8474 {
8475  double error = 0.0;
8476  for (int i = 0; i < nfine; i++)
8477  {
8478  MFEM_VERIFY(fine[i] < elem_error.Size(), "");
8479 
8480  double err_fine = elem_error[fine[i]];
8481  switch (op)
8482  {
8483  case 0: error = std::min(error, err_fine); break;
8484  case 1: error += err_fine; break;
8485  case 2: error = std::max(error, err_fine); break;
8486  }
8487  }
8488  return error;
8489 }
8490 
8492  double threshold, int nc_limit, int op)
8493 {
8494  MFEM_VERIFY(ncmesh, "Only supported for non-conforming meshes.");
8495  MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. "
8496  "Project the NURBS to Nodes first.");
8497 
8498  ResetLazyData();
8499 
8500  const Table &dt = ncmesh->GetDerefinementTable();
8501 
8502  Array<int> level_ok;
8503  if (nc_limit > 0)
8504  {
8505  ncmesh->CheckDerefinementNCLevel(dt, level_ok, nc_limit);
8506  }
8507 
8508  Array<int> derefs;
8509  for (int i = 0; i < dt.Size(); i++)
8510  {
8511  if (nc_limit > 0 && !level_ok[i]) { continue; }
8512 
8513  double error =
8514  AggregateError(elem_error, dt.GetRow(i), dt.RowSize(i), op);
8515 
8516  if (error < threshold) { derefs.Append(i); }
8517  }
8518 
8519  if (!derefs.Size()) { return false; }
8520 
8521  ncmesh->Derefine(derefs);
8522 
8523  Mesh* mesh2 = new Mesh(*ncmesh);
8524  ncmesh->OnMeshUpdated(mesh2);
8525 
8526  Swap(*mesh2, false);
8527  delete mesh2;
8528 
8530 
8532  sequence++;
8533 
8534  UpdateNodes();
8535 
8536  return true;
8537 }
8538 
8539 bool Mesh::DerefineByError(Array<double> &elem_error, double threshold,
8540  int nc_limit, int op)
8541 {
8542  // NOTE: the error array is not const because it will be expanded in parallel
8543  // by ghost element errors
8544  if (Nonconforming())
8545  {
8546  return NonconformingDerefinement(elem_error, threshold, nc_limit, op);
8547  }
8548  else
8549  {
8550  MFEM_ABORT("Derefinement is currently supported for non-conforming "
8551  "meshes only.");
8552  return false;
8553  }
8554 }
8555 
8556 bool Mesh::DerefineByError(const Vector &elem_error, double threshold,
8557  int nc_limit, int op)
8558 {
8559  Array<double> tmp(elem_error.Size());
8560  for (int i = 0; i < tmp.Size(); i++)
8561  {
8562  tmp[i] = elem_error(i);
8563  }
8564  return DerefineByError(tmp, threshold, nc_limit, op);
8565 }
8566 
8567 
8568 void Mesh::InitFromNCMesh(const NCMesh &ncmesh)
8569 {
8570  Dim = ncmesh.Dimension();
8571  spaceDim = ncmesh.SpaceDimension();
8572 
8573  DeleteTables();
8574 
8575  ncmesh.GetMeshComponents(*this);
8576 
8577  NumOfVertices = vertices.Size();
8578  NumOfElements = elements.Size();
8579  NumOfBdrElements = boundary.Size();
8580 
8581  SetMeshGen(); // set the mesh type: 'meshgen', ...
8582 
8583  NumOfEdges = NumOfFaces = 0;
8585 
8586  if (Dim > 1)
8587  {
8588  el_to_edge = new Table;
8590  }
8591  if (Dim > 2)
8592  {
8594  }
8595  GenerateFaces();
8596 #ifdef MFEM_DEBUG
8598 #endif
8599 
8600  // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
8601  // outside after this method.
8602 }
8603 
8604 Mesh::Mesh(const NCMesh &ncmesh)
8605 {
8606  Init();
8607  InitTables();
8608  InitFromNCMesh(ncmesh);
8609  SetAttributes();
8610 }
8611 
8612 void Mesh::Swap(Mesh& other, bool non_geometry)
8613 {
8614  mfem::Swap(Dim, other.Dim);
8615  mfem::Swap(spaceDim, other.spaceDim);
8616 
8622 
8623  mfem::Swap(meshgen, other.meshgen);
8625 
8626  mfem::Swap(elements, other.elements);
8627  mfem::Swap(vertices, other.vertices);
8628  mfem::Swap(boundary, other.boundary);
8629  mfem::Swap(faces, other.faces);
8632 
8635  mfem::Swap(el_to_el, other.el_to_el);
8639  mfem::Swap(face_edge, other.face_edge);
8641 
8644 
8646 
8647 #ifdef MFEM_USE_MEMALLOC
8648  TetMemory.Swap(other.TetMemory);
8649 #endif
8650 
8651  if (non_geometry)
8652  {
8653  mfem::Swap(NURBSext, other.NURBSext);
8654  mfem::Swap(ncmesh, other.ncmesh);
8655 
8656  mfem::Swap(Nodes, other.Nodes);
8657  if (Nodes) { Nodes->FESpace()->UpdateMeshPointer(this); }
8658  if (other.Nodes) { other.Nodes->FESpace()->UpdateMeshPointer(&other); }
8659  mfem::Swap(own_nodes, other.own_nodes);
8660 
8662 
8663  mfem::Swap(sequence, other.sequence);
8665  }
8666 }
8667 
8668 void Mesh::GetElementData(const Array<Element*> &elem_array, int geom,
8669  Array<int> &elem_vtx, Array<int> &attr) const
8670 {
8671  // protected method
8672  const int nv = Geometry::NumVerts[geom];
8673  int num_elems = 0;
8674  for (int i = 0; i < elem_array.Size(); i++)
8675  {
8676  if (elem_array[i]->GetGeometryType() == geom)
8677  {
8678  num_elems++;
8679  }
8680  }
8681  elem_vtx.SetSize(nv*num_elems);
8682  attr.SetSize(num_elems);
8683  elem_vtx.SetSize(0);
8684  attr.SetSize(0);
8685  for (int i = 0; i < elem_array.Size(); i++)
8686  {
8687  Element *el = elem_array[i];
8688  if (el->GetGeometryType() != geom) { continue; }
8689 
8690  Array<int> loc_vtx(el->GetVertices(), nv);
8691  elem_vtx.Append(loc_vtx);
8692  attr.Append(el->GetAttribute());
8693  }
8694 }
8695 
8696 static Array<int>& AllElements(Array<int> &list, int nelem)
8697 {
8698  list.SetSize(nelem);
8699  for (int i = 0; i < nelem; i++) { list[i] = i; }
8700  return list;
8701 }
8702 
8703 void Mesh::UniformRefinement(int ref_algo)
8704 {
8705  Array<int> list;
8706 
8707  if (NURBSext)
8708  {
8710  }
8711  else if (ncmesh)
8712  {
8713  GeneralRefinement(AllElements(list, GetNE()));
8714  }
8715  else if (ref_algo == 1 && meshgen == 1 && Dim == 3)
8716  {
8717  // algorithm "B" for an all-tet mesh
8718  LocalRefinement(AllElements(list, GetNE()));
8719  }
8720  else
8721  {
8722  switch (Dim)
8723  {
8724  case 1: LocalRefinement(AllElements(list, GetNE())); break;
8725  case 2: UniformRefinement2D(); break;
8726  case 3: UniformRefinement3D(); break;
8727  default: MFEM_ABORT("internal error");
8728  }
8729  }
8730 }
8731 
8733  int nonconforming, int nc_limit)
8734 {
8735  if (ncmesh)
8736  {
8737  nonconforming = 1;
8738  }
8739  else if (Dim == 1 || (Dim == 3 && (meshgen & 1)))
8740  {
8741  nonconforming = 0;
8742  }
8743  else if (nonconforming < 0)
8744  {
8745  // determine if nonconforming refinement is suitable
8746  if ((meshgen & 2) || (meshgen & 4))
8747  {
8748  nonconforming = 1; // tensor product elements and wedges
8749  }
8750  else
8751  {
8752  nonconforming = 0; // simplices
8753  }
8754  }
8755 
8756  if (nonconforming)
8757  {
8758  // non-conforming refinement (hanging nodes)
8759  NonconformingRefinement(refinements, nc_limit);
8760  }
8761  else
8762  {
8763  Array<int> el_to_refine(refinements.Size());
8764  for (int i = 0; i < refinements.Size(); i++)
8765  {
8766  el_to_refine[i] = refinements[i].index;
8767  }
8768 
8769  // infer 'type' of local refinement from first element's 'ref_type'
8770  int type, rt = (refinements.Size() ? refinements[0].ref_type : 7);
8771  if (rt == 1 || rt == 2 || rt == 4)
8772  {
8773  type = 1; // bisection
8774  }
8775  else if (rt == 3 || rt == 5 || rt == 6)
8776  {
8777  type = 2; // quadrisection
8778  }
8779  else
8780  {
8781  type = 3; // octasection
8782  }
8783 
8784  // red-green refinement and bisection, no hanging nodes
8785  LocalRefinement(el_to_refine, type);
8786  }
8787 }
8788 
8789 void Mesh::GeneralRefinement(const Array<int> &el_to_refine, int nonconforming,
8790  int nc_limit)
8791 {
8792  Array<Refinement> refinements(el_to_refine.Size());
8793  for (int i = 0; i < el_to_refine.Size(); i++)
8794  {
8795  refinements[i] = Refinement(el_to_refine[i]);
8796  }
8797  GeneralRefinement(refinements, nonconforming, nc_limit);
8798 }
8799 
8800 void Mesh::EnsureNCMesh(bool simplices_nonconforming)
8801 {
8802  MFEM_VERIFY(!NURBSext, "Cannot convert a NURBS mesh to an NC mesh. "
8803  "Please project the NURBS to Nodes first, with SetCurvature().");
8804 
8805 #ifdef MFEM_USE_MPI
8806  MFEM_VERIFY(ncmesh != NULL || dynamic_cast<const ParMesh*>(this) == NULL,
8807  "Sorry, converting a conforming ParMesh to an NC mesh is "
8808  "not possible.");
8809 #endif
8810 
8811  if (!ncmesh)
8812  {
8813  if ((meshgen & 0x2) /* quads/hexes */ ||
8814  (meshgen & 0x4) /* wedges */ ||
8815  (simplices_nonconforming && (meshgen & 0x1)) /* simplices */)
8816  {
8817  ncmesh = new NCMesh(this);
8818  ncmesh->OnMeshUpdated(this);
8820  }
8821  }
8822 }
8823 
8824 void Mesh::RandomRefinement(double prob, bool aniso, int nonconforming,
8825  int nc_limit)
8826 {
8827  Array<Refinement> refs;
8828  for (int i = 0; i < GetNE(); i++)
8829  {
8830  if ((double) rand() / RAND_MAX < prob)
8831  {
8832  int type = 7;
8833  if (aniso)
8834  {
8835  type = (Dim == 3) ? (rand() % 7 + 1) : (rand() % 3 + 1);
8836  }
8837  refs.Append(Refinement(i, type));
8838  }
8839  }
8840  GeneralRefinement(refs, nonconforming, nc_limit);
8841 }
8842 
8843 void Mesh::RefineAtVertex(const Vertex& vert, double eps, int nonconforming)
8844 {
8845  Array<int> v;
8846  Array<Refinement> refs;
8847  for (int i = 0; i < GetNE(); i++)
8848  {
8849  GetElementVertices(i, v);
8850  bool refine = false;
8851  for (int j = 0; j < v.Size(); j++)
8852  {
8853  double dist = 0.0;
8854  for (int l = 0; l < spaceDim; l++)
8855  {
8856  double d = vert(l) - vertices[v[j]](l);
8857  dist += d*d;
8858  }
8859  if (dist <= eps*eps) { refine = true; break; }
8860  }
8861  if (refine)
8862  {
8863  refs.Append(Refinement(i));
8864  }
8865  }
8866  GeneralRefinement(refs, nonconforming);
8867 }
8868 
8869 bool Mesh::RefineByError(const Array<double> &elem_error, double threshold,
8870  int nonconforming, int nc_limit)
8871 {
8872  MFEM_VERIFY(elem_error.Size() == GetNE(), "");
8873  Array<Refinement> refs;
8874  for (int i = 0; i < GetNE(); i++)
8875  {
8876  if (elem_error[i] > threshold)
8877  {
8878  refs.Append(Refinement(i));
8879  }
8880  }
8881  if (ReduceInt(refs.Size()))
8882  {
8883  GeneralRefinement(refs, nonconforming, nc_limit);
8884  return true;
8885  }
8886  return false;
8887 }
8888 
8889 bool Mesh::RefineByError(const Vector &elem_error, double threshold,
8890  int nonconforming, int nc_limit)
8891 {
8892  Array<double> tmp(const_cast<double*>(elem_error.GetData()),
8893  elem_error.Size());
8894  return RefineByError(tmp, threshold, nonconforming, nc_limit);
8895 }
8896 
8897 
8898 void Mesh::Bisection(int i, const DSTable &v_to_v,
8899  int *edge1, int *edge2, int *middle)
8900 {
8901  int *vert;
8902  int v[2][4], v_new, bisect, t;
8903  Element *el = elements[i];
8904  Vertex V;
8905 
8906  t = el->GetType();
8907  if (t == Element::TRIANGLE)
8908  {
8909  Triangle *tri = (Triangle *) el;
8910 
8911  vert = tri->GetVertices();
8912 
8913  // 1. Get the index for the new vertex in v_new.
8914  bisect = v_to_v(vert[0], vert[1]);
8915  MFEM_ASSERT(bisect >= 0, "");
8916 
8917  if (middle[bisect] == -1)
8918  {
8919  v_new = NumOfVertices++;
8920  for (int d = 0; d < spaceDim; d++)
8921  {
8922  V(d) = 0.5 * (vertices[vert[0]](d) + vertices[vert[1]](d));
8923  }
8924  vertices.Append(V);
8925 
8926  // Put the element that may need refinement (because of this
8927  // bisection) in edge1, or -1 if no more refinement is needed.
8928  if (edge1[bisect] == i)
8929  {
8930  edge1[bisect] = edge2[bisect];
8931  }
8932 
8933  middle[bisect] = v_new;
8934  }
8935  else
8936  {
8937  v_new = middle[bisect];
8938 
8939  // This edge will require no more refinement.
8940  edge1[bisect] = -1;
8941  }
8942 
8943  // 2. Set the node indices for the new elements in v[0] and v[1] so that
8944  // the edge marked for refinement is between the first two nodes.
8945  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
8946  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
8947 
8948  tri->SetVertices(v[0]); // changes vert[0..2] !!!
8949 
8950  Triangle* tri_new = new Triangle(v[1], tri->GetAttribute());
8951  elements.Append(tri_new);
8952 
8953  int tr = tri->GetTransform();
8954  tri_new->ResetTransform(tr);
8955 
8956  // record the sequence of refinements
8957  tri->PushTransform(4);
8958  tri_new->PushTransform(5);
8959 
8960  int coarse = FindCoarseElement(i);
8961  CoarseFineTr.embeddings[i].parent = coarse;
8962  CoarseFineTr.embeddings.Append(Embedding(coarse));
8963 
8964  // 3. edge1 and edge2 may have to be changed for the second triangle.
8965  if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
8966  {
8967  bisect = v_to_v(v[1][0], v[1][1]);
8968  MFEM_ASSERT(bisect >= 0, "");
8969 
8970  if (edge1[bisect] == i)
8971  {
8972  edge1[bisect] = NumOfElements;
8973  }
8974  else if (edge2[bisect] == i)
8975  {
8976  edge2[bisect] = NumOfElements;
8977  }
8978  }
8979  NumOfElements++;
8980  }
8981  else
8982  {
8983  MFEM_ABORT("Bisection for now works only for triangles.");
8984  }
8985 }
8986 
8988 {
8989  int *vert;
8990  int v[2][4], v_new, bisect, t;
8991  Element *el = elements[i];
8992  Vertex V;
8993 
8994  t = el->GetType();
8995  if (t == Element::TETRAHEDRON)
8996  {
8997  int j, type, new_type, old_redges[2], new_redges[2][2], flag;
8998  Tetrahedron *tet = (Tetrahedron *) el;
8999 
9000  MFEM_VERIFY(tet->GetRefinementFlag() != 0,
9001  "TETRAHEDRON element is not marked for refinement.");
9002 
9003  vert = tet->GetVertices();
9004 
9005  // 1. Get the index for the new vertex in v_new.
9006  bisect = v_to_v.FindId(vert[0], vert[1]);
9007  if (bisect == -1)
9008  {
9009  v_new = NumOfVertices + v_to_v.GetId(vert[0],vert[1]);
9010  for (j = 0; j < 3; j++)
9011  {
9012  V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j));
9013  }
9014  vertices.Append(V);
9015  }
9016  else
9017  {
9018  v_new = NumOfVertices + bisect;
9019  }
9020 
9021  // 2. Set the node indices for the new elements in v[2][4] so that
9022  // the edge marked for refinement is between the first two nodes.
9023  tet->ParseRefinementFlag(old_redges, type, flag);
9024 
9025  v[0][3] = v_new;
9026  v[1][3] = v_new;
9027  new_redges[0][0] = 2;
9028  new_redges[0][1] = 1;
9029  new_redges[1][0] = 2;
9030  new_redges[1][1] = 1;
9031  int tr1 = -1, tr2 = -1;
9032  switch (old_redges[0])
9033  {
9034  case 2:
9035  v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3];
9036  if (type == Tetrahedron::TYPE_PF) { new_redges[0][1] = 4; }
9037  tr1 = 0;
9038  break;
9039  case 3:
9040  v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2];
9041  tr1 = 2;
9042  break;
9043  case 5:
9044  v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0];
9045  tr1 = 4;
9046  }
9047  switch (old_redges[1])
9048  {
9049  case 1:
9050  v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3];
9051  if (type == Tetrahedron::TYPE_PF) { new_redges[1][0] = 3; }
9052  tr2 = 1;
9053  break;
9054  case 4:
9055  v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2];
9056  tr2 = 3;
9057  break;
9058  case 5:
9059  v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1];
9060  tr2 = 5;
9061  }
9062 
9063  int attr = tet->GetAttribute();
9064  tet->SetVertices(v[0]);
9065 
9066 #ifdef MFEM_USE_MEMALLOC
9067  Tetrahedron *tet2 = TetMemory.Alloc();
9068  tet2->SetVertices(v[1]);
9069  tet2->SetAttribute(attr);
9070 #else
9071  Tetrahedron *tet2 = new Tetrahedron(v[1], attr);
9072 #endif
9073  tet2->ResetTransform(tet->GetTransform());
9074  elements.Append(tet2);
9075 
9076  // record the sequence of refinements
9077  tet->PushTransform(tr1);
9078  tet2->PushTransform(tr2);
9079 
9080  int coarse = FindCoarseElement(i);
9081  CoarseFineTr.embeddings[i].parent = coarse;
9082  CoarseFineTr.embeddings.Append(Embedding(coarse));
9083 
9084  // 3. Set the bisection flag
9085  switch (type)
9086  {
9087  case Tetrahedron::TYPE_PU:
9088  new_type = Tetrahedron::TYPE_PF; break;
9089  case Tetrahedron::TYPE_PF:
9090  new_type = Tetrahedron::TYPE_A; break;
9091  default:
9092  new_type = Tetrahedron::TYPE_PU;
9093  }
9094 
9095  tet->CreateRefinementFlag(new_redges[0], new_type, flag+1);
9096  tet2->CreateRefinementFlag(new_redges[1], new_type, flag+1);
9097 
9098  NumOfElements++;
9099  }
9100  else
9101  {
9102  MFEM_ABORT("Bisection with HashTable for now works only for tetrahedra.");
9103  }
9104 }
9105 
9106 void Mesh::BdrBisection(int i, const HashTable<Hashed2> &v_to_v)
9107 {
9108  int *vert;
9109  int v[2][3], v_new, bisect, t;
9110  Element *bdr_el = boundary[i];
9111 
9112  t = bdr_el->GetType();
9113  if (t == Element::TRIANGLE)
9114  {
9115  Triangle *tri = (Triangle *) bdr_el;
9116 
9117  vert = tri->GetVertices();
9118 
9119  // 1. Get the index for the new vertex in v_new.
9120  bisect = v_to_v.FindId(vert[0], vert[1]);
9121  MFEM_ASSERT(bisect >= 0, "");
9122  v_new = NumOfVertices + bisect;
9123  MFEM_ASSERT(v_new != -1, "");
9124 
9125  // 2. Set the node indices for the new elements in v[0] and v[1] so that
9126  // the edge marked for refinement is between the first two nodes.
9127  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
9128  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
9129 
9130  tri->SetVertices(v[0]);
9131 
9132  boundary.Append(new Triangle(v[1], tri->GetAttribute()));
9133 
9134  NumOfBdrElements++;
9135  }
9136  else
9137  {
9138  MFEM_ABORT("Bisection of boundary elements with HashTable works only for"
9139  " triangles!");
9140  }
9141 }
9142 
9143 void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
9144  int *edge1, int *edge2, int *middle)
9145 {
9146  Array<int> v;
9147  int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3];
9148  Vertex V;
9149 
9150  if (elements[i]->GetType() == Element::TRIANGLE)
9151  {
9152  Triangle *tri0 = (Triangle*) elements[i];
9153  tri0->GetVertices(v);
9154 
9155  // 1. Get the indeces for the new vertices in array v_new
9156  bisect[0] = v_to_v(v[0],v[1]);
9157  bisect[1] = v_to_v(v[1],v[2]);
9158  bisect[2] = v_to_v(v[0],v[2]);
9159  MFEM_ASSERT(bisect[0] >= 0 && bisect[1] >= 0 && bisect[2] >= 0, "");
9160 
9161  for (j = 0; j < 3; j++) // for the 3 edges fix v_new
9162  {
9163  if (middle[bisect[j]] == -1)
9164  {
9165  v_new[j] = NumOfVertices++;
9166  for (int d = 0; d < spaceDim; d++)
9167  {
9168  V(d) = (vertices[v[j]](d) + vertices[v[(j+1)%3]](d))/2.;
9169  }
9170  vertices.Append(V);
9171 
9172  // Put the element that may need refinement (because of this
9173  // bisection) in edge1, or -1 if no more refinement is needed.
9174  if (edge1[bisect[j]] == i)
9175  {
9176  edge1[bisect[j]] = edge2[bisect[j]];
9177  }
9178 
9179  middle[bisect[j]] = v_new[j];
9180  }
9181  else
9182  {
9183  v_new[j] = middle[bisect[j]];
9184 
9185  // This edge will require no more refinement.
9186  edge1[bisect[j]] = -1;
9187  }
9188  }
9189 
9190  // 2. Set the node indeces for the new elements in v1, v2, v3 & v4 so that
9191  // the edges marked for refinement be between the first two nodes.
9192  v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2];
9193  v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1];
9194  v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2];
9195  v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0];
9196 
9197  Triangle* tri1 = new Triangle(v1, tri0->GetAttribute());
9198  Triangle* tri2 = new Triangle(v2, tri0->GetAttribute());
9199  Triangle* tri3 = new Triangle(v3, tri0->GetAttribute());
9200 
9201  elements.Append(tri1);
9202  elements.Append(tri2);
9203  elements.Append(tri3);
9204 
9205  tri0->SetVertices(v4);
9206 
9207  // record the sequence of refinements
9208  unsigned code = tri0->GetTransform();
9209  tri1->ResetTransform(code);
9210  tri2->ResetTransform(code);
9211  tri3->ResetTransform(code);
9212 
9213  tri0->PushTransform(3);
9214  tri1->PushTransform(0);
9215  tri2->PushTransform(1);
9216  tri3->PushTransform(2);
9217 
9218  // set parent indices
9219  int coarse = FindCoarseElement(i);
9220  CoarseFineTr.embeddings[i] = Embedding(coarse);
9221  CoarseFineTr.embeddings.Append(Embedding(coarse));
9222  CoarseFineTr.embeddings.Append(Embedding(coarse));
9223  CoarseFineTr.embeddings.Append(Embedding(coarse));
9224 
9225  NumOfElements += 3;
9226  }
9227  else
9228  {
9229  MFEM_ABORT("Uniform refinement for now works only for triangles.");
9230  }
9231 }
9232 
9234 {
9235  // initialize CoarseFineTr
9236  CoarseFineTr.Clear();
9238  for (int i = 0; i < NumOfElements; i++)
9239  {
9240  elements[i]->ResetTransform(0);
9242  }
9243 }
9244 
9246 {
9247  int coarse;
9248  while ((coarse = CoarseFineTr.embeddings[i].parent) != i)
9249  {
9250  i = coarse;
9251  }
9252  return coarse;
9253 }
9254 
9256 {
9257  MFEM_VERIFY(GetLastOperation() == Mesh::REFINE, "");
9258 
9259  if (ncmesh)
9260  {
9261  return ncmesh->GetRefinementTransforms();
9262  }
9263 
9264  Mesh::GeometryList elem_geoms(*this);
9265  for (int i = 0; i < elem_geoms.Size(); i++)
9266  {
9267  const Geometry::Type geom = elem_geoms[i];
9268  if (CoarseFineTr.point_matrices[geom].SizeK()) { continue; }
9269 
9270  if (geom == Geometry::TRIANGLE ||
9271  geom == Geometry::TETRAHEDRON)
9272  {
9273  std::map<unsigned, int> mat_no;
9274  mat_no[0] = 1; // identity
9275 
9276  // assign matrix indices to element transformations
9277  for (int i = 0; i < elements.Size(); i++)
9278  {
9279  int index = 0;
9280  unsigned code = elements[i]->GetTransform();
9281  if (code)
9282  {
9283  int &matrix = mat_no[code];
9284  if (!matrix) { matrix = mat_no.size(); }
9285  index = matrix-1;
9286  }
9287  CoarseFineTr.embeddings[i].matrix = index;
9288  }
9289 
9291  pmats.SetSize(Dim, Dim+1, mat_no.size());
9292 
9293  // calculate the point matrices used
9294  std::map<unsigned, int>::iterator it;
9295  for (it = mat_no.begin(); it != mat_no.end(); ++it)
9296  {
9297  if (geom == Geometry::TRIANGLE)
9298  {
9299  Triangle::GetPointMatrix(it->first, pmats(it->second-1));
9300  }
9301  else
9302  {
9303  Tetrahedron::GetPointMatrix(it->first, pmats(it->second-1));
9304  }
9305  }
9306  }
9307  else
9308  {
9309  MFEM_ABORT("Don't know how to construct CoarseFineTransformations for"
9310  " geom = " << geom);
9311  }
9312  }
9313 
9314  // NOTE: quads and hexes already have trivial transformations ready
9315  return CoarseFineTr;
9316 }
9317 
9318 void Mesh::PrintXG(std::ostream &out) const
9319 {
9320  MFEM_ASSERT(Dim==spaceDim, "2D Manifold meshes not supported");
9321  int i, j;
9322  Array<int> v;
9323 
9324  if (Dim == 2)
9325  {
9326  // Print the type of the mesh.
9327  if (Nodes == NULL)
9328  {
9329  out << "areamesh2\n\n";
9330  }
9331  else
9332  {
9333  out << "curved_areamesh2\n\n";
9334  }
9335 
9336  // Print the boundary elements.
9337  out << NumOfBdrElements << '\n';
9338  for (i = 0; i < NumOfBdrElements; i++)
9339  {
9340  boundary[i]->GetVertices(v);
9341 
9342  out << boundary[i]->GetAttribute();
9343  for (j = 0; j < v.Size(); j++)
9344  {
9345  out << ' ' << v[j] + 1;
9346  }
9347  out << '\n';
9348  }
9349 
9350  // Print the elements.
9351  out << NumOfElements << '\n';
9352  for (i = 0; i < NumOfElements; i++)
9353  {
9354  elements[i]->GetVertices(v);
9355 
9356  out << elements[i]->GetAttribute() << ' ' << v.Size();
9357  for (j = 0; j < v.Size(); j++)
9358  {
9359  out << ' ' << v[j] + 1;
9360  }
9361  out << '\n';
9362  }
9363 
9364  if (Nodes == NULL)
9365  {
9366  // Print the vertices.
9367  out << NumOfVertices << '\n';
9368  for (i = 0; i < NumOfVertices; i++)
9369  {
9370  out << vertices[i](0);
9371  for (j = 1; j < Dim; j++)
9372  {
9373  out << ' ' << vertices[i](j);
9374  }
9375  out << '\n';
9376  }
9377  }
9378  else
9379  {
9380  out << NumOfVertices << '\n';
9381  Nodes->Save(out);
9382  }
9383  }
9384  else // ===== Dim != 2 =====
9385  {
9386  if (Nodes)
9387  {
9388  mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D");
9389  }
9390 
9391  if (meshgen == 1)
9392  {
9393  int nv;
9394  const int *ind;
9395 
9396  out << "NETGEN_Neutral_Format\n";
9397  // print the vertices
9398  out << NumOfVertices << '\n';
9399  for (i = 0; i < NumOfVertices; i++)
9400  {
9401  for (j = 0; j < Dim; j++)
9402  {
9403  out << ' ' << vertices[i](j);
9404  }
9405  out << '\n';
9406  }
9407 
9408  // print the elements
9409  out << NumOfElements << '\n';
9410  for (i = 0; i < NumOfElements; i++)
9411  {
9412  nv = elements[i]->GetNVertices();
9413  ind = elements[i]->GetVertices();
9414  out << elements[i]->GetAttribute();
9415  for (j = 0; j < nv; j++)
9416  {
9417  out << ' ' << ind[j]+1;
9418  }
9419  out << '\n';
9420  }
9421 
9422  // print the boundary information.
9423  out << NumOfBdrElements << '\n';
9424  for (i = 0; i < NumOfBdrElements; i++)
9425  {
9426  nv = boundary[i]->GetNVertices();
9427  ind = boundary[i]->GetVertices();
9428  out << boundary[i]->GetAttribute();
9429  for (j = 0; j < nv; j++)
9430  {
9431  out << ' ' << ind[j]+1;
9432  }
9433  out << '\n';
9434  }
9435  }
9436  else if (meshgen == 2) // TrueGrid
9437  {
9438  int nv;
9439  const int *ind;
9440 
9441  out << "TrueGrid\n"
9442  << "1 " << NumOfVertices << " " << NumOfElements
9443  << " 0 0 0 0 0 0 0\n"
9444  << "0 0 0 1 0 0 0 0 0 0 0\n"
9445  << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
9446  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
9447  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
9448 
9449  for (i = 0; i < NumOfVertices; i++)
9450  out << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1)
9451  << ' ' << vertices[i](2) << " 0.0\n";
9452 
9453  for (i = 0; i < NumOfElements; i++)
9454  {
9455  nv = elements[i]->GetNVertices();
9456  ind = elements[i]->GetVertices();
9457  out << i+1 << ' ' << elements[i]->GetAttribute();
9458  for (j = 0; j < nv; j++)
9459  {
9460  out << ' ' << ind[j]+1;
9461  }
9462  out << '\n';
9463  }
9464 
9465  for (i = 0; i < NumOfBdrElements; i++)
9466  {
9467  nv = boundary[i]->GetNVertices();
9468  ind = boundary[i]->GetVertices();
9469  out << boundary[i]->GetAttribute();
9470  for (j = 0; j < nv; j++)
9471  {
9472  out << ' ' << ind[j]+1;
9473  }
9474  out << " 1.0 1.0 1.0 1.0\n";
9475  }
9476  }
9477  }
9478 
9479  out << flush;
9480 }
9481 
9482 void Mesh::Printer(std::ostream &out, std::string section_delimiter) const
9483 {
9484  int i, j;
9485 
9486  if (NURBSext)
9487  {
9488  // general format
9489  NURBSext->Print(out);
9490  out << '\n';
9491  Nodes->Save(out);
9492 
9493  // patch-wise format
9494  // NURBSext->ConvertToPatches(*Nodes);
9495  // NURBSext->Print(out);
9496 
9497  return;
9498  }
9499 
9500  if (Nonconforming())
9501  {
9502  // nonconforming mesh format
9503  ncmesh->Print(out);
9504 
9505  if (Nodes)
9506  {
9507  out << "\n# mesh curvature GridFunction";
9508  out << "\nnodes\n";
9509  Nodes->Save(out);
9510  }
9511 
9512  out << "\nmfem_mesh_end" << endl;
9513  return;
9514  }
9515 
9516  // serial/parallel conforming mesh format
9517  out << (section_delimiter.empty()
9518  ? "MFEM mesh v1.0\n" : "MFEM mesh v1.2\n");
9519 
9520  // optional
9521  out <<
9522  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
9523  "# POINT = 0\n"
9524  "# SEGMENT = 1\n"
9525  "# TRIANGLE = 2\n"
9526  "# SQUARE = 3\n"
9527  "# TETRAHEDRON = 4\n"
9528  "# CUBE = 5\n"
9529  "# PRISM = 6\n"
9530  "#\n";
9531 
9532  out << "\ndimension\n" << Dim;
9533 
9534  out << "\n\nelements\n" << NumOfElements << '\n';
9535  for (i = 0; i < NumOfElements; i++)
9536  {
9537  PrintElement(elements[i], out);
9538  }
9539 
9540  out << "\nboundary\n" << NumOfBdrElements << '\n';
9541  for (i = 0; i < NumOfBdrElements; i++)
9542  {
9543  PrintElement(boundary[i], out);
9544  }
9545 
9546  out << "\nvertices\n" << NumOfVertices << '\n';
9547  if (Nodes == NULL)
9548  {
9549  out << spaceDim << '\n';
9550  for (i = 0; i < NumOfVertices; i++)
9551  {
9552  out << vertices[i](0);
9553  for (j = 1; j < spaceDim; j++)
9554  {
9555  out << ' ' << vertices[i](j);
9556  }
9557  out << '\n';
9558  }
9559  out.flush();
9560  }
9561  else
9562  {
9563  out << "\nnodes\n";
9564  Nodes->Save(out);
9565  }
9566 
9567  if (!section_delimiter.empty())
9568  {
9569  out << section_delimiter << endl; // only with format v1.2
9570  }
9571 }
9572 
9573 void Mesh::PrintTopo(std::ostream &out,const Array<int> &e_to_k) const
9574 {
9575  int i;
9576  Array<int> vert;
9577 
9578  out << "MFEM NURBS mesh v1.0\n";
9579 
9580  // optional
9581  out <<
9582  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
9583  "# SEGMENT = 1\n"
9584  "# SQUARE = 3\n"
9585  "# CUBE = 5\n"
9586  "#\n";
9587 
9588  out << "\ndimension\n" << Dim
9589  << "\n\nelements\n" << NumOfElements << '\n';
9590  for (i = 0; i < NumOfElements; i++)
9591  {
9592  PrintElement(elements[i], out);
9593  }
9594 
9595  out << "\nboundary\n" << NumOfBdrElements << '\n';
9596  for (i = 0; i < NumOfBdrElements; i++)
9597  {
9598  PrintElement(boundary[i], out);
9599  }
9600 
9601  out << "\nedges\n" << NumOfEdges << '\n';
9602  for (i = 0; i < NumOfEdges; i++)
9603  {
9604  edge_vertex->GetRow(i, vert);
9605  int ki = e_to_k[i];
9606  if (ki < 0)
9607  {
9608  ki = -1 - ki;
9609  }
9610  out << ki << ' ' << vert[0] << ' ' << vert[1] << '\n';
9611  }
9612  out << "\nvertices\n" << NumOfVertices << '\n';
9613 }
9614 
9615 void Mesh::Save(const char *fname, int precision) const
9616 {
9617  ofstream ofs(fname);
9618  ofs.precision(precision);
9619  Print(ofs);
9620 }
9621 
9622 #ifdef MFEM_USE_ADIOS2
9624 {
9625  out.Print(*this);
9626 }
9627 #endif
9628 
9629 void Mesh::PrintVTK(std::ostream &out)
9630 {
9631  out <<
9632  "# vtk DataFile Version 3.0\n"
9633  "Generated by MFEM\n"
9634  "ASCII\n"
9635  "DATASET UNSTRUCTURED_GRID\n";
9636 
9637  if (Nodes == NULL)
9638  {
9639  out << "POINTS " << NumOfVertices << " double\n";
9640  for (int i = 0; i < NumOfVertices; i++)
9641  {
9642  out << vertices[i](0);
9643  int j;
9644  for (j = 1; j < spaceDim; j++)
9645  {
9646  out << ' ' << vertices[i](j);
9647  }
9648  for ( ; j < 3; j++)
9649  {
9650  out << ' ' << 0.0;
9651  }
9652  out << '\n';
9653  }
9654  }
9655  else
9656  {
9657  Array<int> vdofs(3);
9658  out << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n";
9659  for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++)
9660  {
9661  vdofs.SetSize(1);
9662  vdofs[0] = i;
9663  Nodes->FESpace()->DofsToVDofs(vdofs);
9664  out << (*Nodes)(vdofs[0]);
9665  int j;
9666  for (j = 1; j < spaceDim; j++)
9667  {
9668  out << ' ' << (*Nodes)(vdofs[j]);
9669  }
9670  for ( ; j < 3; j++)
9671  {
9672  out << ' ' << 0.0;
9673  }
9674  out << '\n';
9675  }
9676  }
9677 
9678  int order = -1;
9679  if (Nodes == NULL)
9680  {
9681  int size = 0;
9682  for (int i = 0; i < NumOfElements; i++)
9683  {
9684  size += elements[i]->GetNVertices() + 1;
9685  }
9686  out << "CELLS " << NumOfElements << ' ' << size << '\n';
9687  for (int i = 0; i < NumOfElements; i++)
9688  {
9689  const int *v = elements[i]->GetVertices();
9690  const int nv = elements[i]->GetNVertices();
9691  out << nv;
9692  Geometry::Type geom = elements[i]->GetGeometryType();
9693  const int *perm = VTKGeometry::VertexPermutation[geom];
9694  for (int j = 0; j < nv; j++)
9695  {
9696  out << ' ' << v[perm ? perm[j] : j];
9697  }
9698  out << '\n';
9699  }
9700  order = 1;
9701  }
9702  else
9703  {
9704  Array<int> dofs;
9705  int size = 0;
9706  for (int i = 0; i < NumOfElements; i++)
9707  {
9708  Nodes->FESpace()->GetElementDofs(i, dofs);
9709  MFEM_ASSERT(Dim != 0 || dofs.Size() == 1,
9710  "Point meshes should have a single dof per element");
9711  size += dofs.Size() + 1;
9712  }
9713  out << "CELLS " << NumOfElements << ' ' << size << '\n';
9714  const char *fec_name = Nodes->FESpace()->FEColl()->Name();
9715 
9716  if (!strcmp(fec_name, "Linear") ||
9717  !strcmp(fec_name, "H1_0D_P1") ||
9718  !strcmp(fec_name, "H1_1D_P1") ||
9719  !strcmp(fec_name, "H1_2D_P1") ||
9720  !strcmp(fec_name, "H1_3D_P1"))
9721  {
9722  order = 1;
9723  }
9724  else if (!strcmp(fec_name, "Quadratic") ||
9725  !strcmp(fec_name, "H1_1D_P2") ||
9726  !strcmp(fec_name, "H1_2D_P2") ||
9727  !strcmp(fec_name, "H1_3D_P2"))
9728  {
9729  order = 2;
9730  }
9731  if (order == -1)
9732  {
9733  mfem::err << "Mesh::PrintVTK : can not save '"
9734  << fec_name << "' elements!" << endl;
9735  mfem_error();
9736  }
9737  for (int i = 0; i < NumOfElements; i++)
9738  {
9739  Nodes->FESpace()->GetElementDofs(i, dofs);
9740  out << dofs.Size();
9741  if (order == 1)
9742  {
9743  for (int j = 0; j < dofs.Size(); j++)
9744  {
9745  out << ' ' << dofs[j];
9746  }
9747  }
9748  else if (order == 2)
9749  {
9750  const int *vtk_mfem;
9751  switch (elements[i]->GetGeometryType())
9752  {
9753  case Geometry::SEGMENT:
9754  case Geometry::TRIANGLE:
9755  case Geometry::SQUARE:
9756  vtk_mfem = vtk_quadratic_hex; break; // identity map
9757  case Geometry::TETRAHEDRON:
9758  vtk_mfem = vtk_quadratic_tet; break;
9759  case Geometry::PRISM:
9760  vtk_mfem = vtk_quadratic_wedge; break;
9761  case Geometry::CUBE:
9762  default:
9763  vtk_mfem = vtk_quadratic_hex; break;
9764  }
9765  for (int j = 0; j < dofs.Size(); j++)
9766  {
9767  out << ' ' << dofs[vtk_mfem[j]];
9768  }
9769  }
9770  out << '\n';
9771  }
9772  }
9773 
9774  out << "CELL_TYPES " << NumOfElements << '\n';
9775  for (int i = 0; i < NumOfElements; i++)
9776  {
9777  int vtk_cell_type = 5;
9779  if (order == 1) { vtk_cell_type = VTKGeometry::Map[geom]; }
9780  else if (order == 2) { vtk_cell_type = VTKGeometry::QuadraticMap[geom]; }
9781  out << vtk_cell_type << '\n';
9782  }
9783 
9784  // write attributes
9785  out << "CELL_DATA " << NumOfElements << '\n'
9786  << "SCALARS material int\n"
9787  << "LOOKUP_TABLE default\n";
9788  for (int i = 0; i < NumOfElements; i++)
9789  {
9790  out << elements[i]->GetAttribute() << '\n';
9791  }
9792  out.flush();
9793 }
9794 
9795 void Mesh::PrintVTU(std::string fname,
9796  VTKFormat format,
9797  bool high_order_output,
9798  int compression_level,
9799  bool bdr)
9800 {
9801  int ref = (high_order_output && Nodes)
9802  ? Nodes->FESpace()->GetElementOrder(0) : 1;
9803 
9804  fname = fname + ".vtu";
9805  std::fstream out(fname.c_str(),std::ios::out);
9806  out << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"";
9807  if (compression_level != 0)
9808  {
9809  out << " compressor=\"vtkZLibDataCompressor\"";
9810  }
9811  out << " byte_order=\"" << VTKByteOrder() << "\">\n";
9812  out << "<UnstructuredGrid>\n";
9813  PrintVTU(out, ref, format, high_order_output, compression_level, bdr);
9814  out << "</Piece>\n"; // need to close the piece open in the PrintVTU method
9815  out << "</UnstructuredGrid>\n";
9816  out << "</VTKFile>" << std::endl;
9817 
9818  out.close();
9819 }
9820 
9821 void Mesh::PrintBdrVTU(std::string fname,
9822  VTKFormat format,
9823  bool high_order_output,
9824  int compression_level)
9825 {
9826  PrintVTU(fname, format, high_order_output, compression_level, true);
9827 }
9828 
9829 template <typename T>
9830 void WriteBinaryOrASCII(std::ostream &out, std::vector<char> &buf, const T &val,
9831  const char *suffix, VTKFormat format)
9832 {
9833  if (format == VTKFormat::ASCII) { out << val << suffix; }
9834  else { bin_io::AppendBytes(buf, val); }
9835 }
9836 
9837 // Ensure ASCII output of uint8_t to stream is integer rather than character
9838 template <>
9839 void WriteBinaryOrASCII<uint8_t>(std::ostream &out, std::vector<char> &buf,
9840  const uint8_t &val, const char *suffix,
9841  VTKFormat format)
9842 {
9843  if (format == VTKFormat::ASCII) { out << static_cast<int>(val) << suffix; }
9844  else { bin_io::AppendBytes(buf, val); }
9845 }
9846 
9847 template <>
9848 void WriteBinaryOrASCII<double>(std::ostream &out, std::vector<char> &buf,
9849  const double &val, const char *suffix,
9850  VTKFormat format)
9851 {
9852  if (format == VTKFormat::BINARY32)
9853  {
9854  bin_io::AppendBytes<float>(buf, float(val));
9855  }
9856  else if (format == VTKFormat::BINARY)
9857  {
9858  bin_io::AppendBytes(buf, val);
9859  }
9860  else
9861  {
9862  out << val << suffix;
9863  }
9864 }
9865 
9866 template <>
9867 void WriteBinaryOrASCII<float>(std::ostream &out, std::vector<char> &buf,
9868  const float &val, const char *suffix,
9869  VTKFormat format)
9870 {
9871  if (format == VTKFormat::BINARY) { bin_io::AppendBytes<double>(buf, val); }
9872  else if (format == VTKFormat::BINARY32) { bin_io::AppendBytes(buf, val); }
9873  else { out << val << suffix; }
9874 }
9875 
9876 void WriteBase64WithSizeAndClear(std::ostream &out, std::vector<char> &buf,
9877  int compression_level)
9878 {
9879  WriteVTKEncodedCompressed(out, buf.data(), buf.size(), compression_level);
9880  out << '\n';
9881  buf.clear();
9882 }
9883 
9884 void Mesh::PrintVTU(std::ostream &out, int ref, VTKFormat format,
9885  bool high_order_output, int compression_level,
9886  bool bdr_elements)
9887 {
9888  RefinedGeometry *RefG;
9889  DenseMatrix pmat;
9890 
9891  const char *fmt_str = (format == VTKFormat::ASCII) ? "ascii" : "binary";
9892  const char *type_str = (format != VTKFormat::BINARY32) ? "Float64" : "Float32";
9893  std::vector<char> buf;
9894 
9895  auto get_geom = [&](int i)
9896  {
9897  if (bdr_elements) { return GetBdrElementBaseGeometry(i); }
9898  else { return GetElementBaseGeometry(i); }
9899  };
9900 
9901  int ne = bdr_elements ? GetNBE() : GetNE();
9902  // count the points, cells, size
9903  int np = 0, nc_ref = 0, size = 0;
9904  for (int i = 0; i < ne; i++)
9905  {
9906  Geometry::Type geom = get_geom(i);
9907  int nv = Geometries.GetVertices(geom)->GetNPoints();
9908  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9909  np += RefG->RefPts.GetNPoints();
9910  nc_ref += RefG->RefGeoms.Size() / nv;
9911  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
9912  }
9913 
9914  out << "<Piece NumberOfPoints=\"" << np << "\" NumberOfCells=\""
9915  << (high_order_output ? ne : nc_ref) << "\">\n";
9916 
9917  // print out the points
9918  out << "<Points>\n";
9919  out << "<DataArray type=\"" << type_str
9920  << "\" NumberOfComponents=\"3\" format=\"" << fmt_str << "\">\n";
9921  for (int i = 0; i < ne; i++)
9922  {
9923  RefG = GlobGeometryRefiner.Refine(get_geom(i), ref, 1);
9924 
9925  if (bdr_elements)
9926  {
9927  GetBdrElementTransformation(i)->Transform(RefG->RefPts, pmat);
9928  }
9929  else
9930  {
9931  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
9932  }
9933 
9934  for (int j = 0; j < pmat.Width(); j++)
9935  {
9936  WriteBinaryOrASCII(out, buf, pmat(0,j), " ", format);
9937  if (pmat.Height() > 1)
9938  {
9939  WriteBinaryOrASCII(out, buf, pmat(1,j), " ", format);
9940  }
9941  else
9942  {
9943  WriteBinaryOrASCII(out, buf, 0.0, " ", format);
9944  }
9945  if (pmat.Height() > 2)
9946  {
9947  WriteBinaryOrASCII(out, buf, pmat(2,j), "", format);
9948  }
9949  else
9950  {
9951  WriteBinaryOrASCII(out, buf, 0.0, "", format);
9952  }
9953  if (format == VTKFormat::ASCII) { out << '\n'; }
9954  }
9955  }
9956  if (format != VTKFormat::ASCII)
9957  {
9958  WriteBase64WithSizeAndClear(out, buf, compression_level);
9959  }
9960  out << "</DataArray>" << std::endl;
9961  out << "</Points>" << std::endl;
9962 
9963  out << "<Cells>" << std::endl;
9964  out << "<DataArray type=\"Int32\" Name=\"connectivity\" format=\""
9965  << fmt_str << "\">" << std::endl;
9966  // connectivity
9967  std::vector<int> offset;
9968 
9969  np = 0;
9970  if (high_order_output)
9971  {
9972  Array<int> local_connectivity;
9973  for (int iel = 0; iel < ne; iel++)
9974  {
9975  Geometry::Type geom = get_geom(iel);
9976  CreateVTKElementConnectivity(local_connectivity, geom, ref);
9977  int nnodes = local_connectivity.Size();
9978  for (int i=0; i<nnodes; ++i)
9979  {
9980  WriteBinaryOrASCII(out, buf, np+local_connectivity[i], " ", format);
9981  }
9982  if (format == VTKFormat::ASCII) { out << '\n'; }
9983  np += nnodes;
9984  offset.push_back(np);
9985  }
9986  }
9987  else
9988  {
9989  int coff = 0;
9990  for (int i = 0; i < ne; i++)
9991  {
9992  Geometry::Type geom = get_geom(i);
9993  int nv = Geometries.GetVertices(geom)->GetNPoints();
9994  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9995  Array<int> &RG = RefG->RefGeoms;
9996  for (int j = 0; j < RG.Size(); )
9997  {
9998  coff = coff+nv;
9999  offset.push_back(coff);
10000  const int *p = VTKGeometry::VertexPermutation[geom];
10001  for (int k = 0; k < nv; k++, j++)
10002  {
10003  WriteBinaryOrASCII(out, buf, np + RG[p ? p[j] : j], " ", format);
10004  }
10005  if (format == VTKFormat::ASCII) { out << '\n'; }
10006  }
10007  np += RefG->RefPts.GetNPoints();
10008  }
10009  }
10010  if (format != VTKFormat::ASCII)
10011  {
10012  WriteBase64WithSizeAndClear(out, buf, compression_level);
10013  }
10014  out << "</DataArray>" << std::endl;
10015 
10016  out << "<DataArray type=\"Int32\" Name=\"offsets\" format=\""
10017  << fmt_str << "\">" << std::endl;
10018  // offsets
10019  for (size_t ii=0; ii<offset.size(); ii++)
10020  {
10021  WriteBinaryOrASCII(out, buf, offset[ii], "\n", format);
10022  }
10023  if (format != VTKFormat::ASCII)
10024  {
10025  WriteBase64WithSizeAndClear(out, buf, compression_level);
10026  }
10027  out << "</DataArray>" << std::endl;
10028  out << "<DataArray type=\"UInt8\" Name=\"types\" format=\""
10029  << fmt_str << "\">" << std::endl;
10030  // cell types
10031  const int *vtk_geom_map =
10032  high_order_output ? VTKGeometry::HighOrderMap : VTKGeometry::Map;
10033  for (int i = 0; i < ne; i++)
10034  {
10035  Geometry::Type geom = get_geom(i);
10036  uint8_t vtk_cell_type = 5;
10037 
10038  vtk_cell_type = vtk_geom_map[geom];
10039 
10040  if (high_order_output)
10041  {
10042  WriteBinaryOrASCII(out, buf, vtk_cell_type, "\n", format);
10043  }
10044  else
10045  {
10046  int nv = Geometries.GetVertices(geom)->GetNPoints();
10047  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10048  Array<int> &RG = RefG->RefGeoms;
10049  for (int j = 0; j < RG.Size(); j += nv)
10050  {
10051  WriteBinaryOrASCII(out, buf, vtk_cell_type, "\n", format);
10052  }
10053  }
10054  }
10055  if (format != VTKFormat::ASCII)
10056  {
10057  WriteBase64WithSizeAndClear(out, buf, compression_level);
10058  }
10059  out << "</DataArray>" << std::endl;
10060  out << "</Cells>" << std::endl;
10061 
10062  out << "<CellData Scalars=\"attribute\">" << std::endl;
10063  out << "<DataArray type=\"Int32\" Name=\"attribute\" format=\""
10064  << fmt_str << "\">" << std::endl;
10065  for (int i = 0; i < ne; i++)
10066  {
10067  int attr = bdr_elements ? GetBdrAttribute(i) : GetAttribute(i);
10068  if (high_order_output)
10069  {
10070  WriteBinaryOrASCII(out, buf, attr, "\n", format);
10071  }
10072  else
10073  {
10074  Geometry::Type geom = get_geom(i);
10075  int nv = Geometries.GetVertices(geom)->GetNPoints();
10076  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10077  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10078  {
10079  WriteBinaryOrASCII(out, buf, attr, "\n", format);
10080  }
10081  }
10082  }
10083  if (format != VTKFormat::ASCII)
10084  {
10085  WriteBase64WithSizeAndClear(out, buf, compression_level);
10086  }
10087  out << "</DataArray>" << std::endl;
10088  out << "</CellData>" << std::endl;
10089 }
10090 
10091 
10092 void Mesh::PrintVTK(std::ostream &out, int ref, int field_data)
10093 {
10094  int np, nc, size;
10095  RefinedGeometry *RefG;
10096  DenseMatrix pmat;
10097 
10098  out <<
10099  "# vtk DataFile Version 3.0\n"
10100  "Generated by MFEM\n"
10101  "ASCII\n"
10102  "DATASET UNSTRUCTURED_GRID\n";
10103 
10104  // additional dataset information
10105  if (field_data)
10106  {
10107  out << "FIELD FieldData 1\n"
10108  << "MaterialIds " << 1 << " " << attributes.Size() << " int\n";
10109  for (int i = 0; i < attributes.Size(); i++)
10110  {
10111  out << ' ' << attributes[i];
10112  }
10113  out << '\n';
10114  }
10115 
10116  // count the points, cells, size
10117  np = nc = size = 0;
10118  for (int i = 0; i < GetNE(); i++)
10119  {
10121  int nv = Geometries.GetVertices(geom)->GetNPoints();
10122  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10123  np += RefG->RefPts.GetNPoints();
10124  nc += RefG->RefGeoms.Size() / nv;
10125  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
10126  }
10127  out << "POINTS " << np << " double\n";
10128  // write the points
10129  for (int i = 0; i < GetNE(); i++)
10130  {
10131  RefG = GlobGeometryRefiner.Refine(
10132  GetElementBaseGeometry(i), ref, 1);
10133 
10134  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
10135 
10136  for (int j = 0; j < pmat.Width(); j++)
10137  {
10138  out << pmat(0, j) << ' ';
10139  if (pmat.Height() > 1)
10140  {
10141  out << pmat(1, j) << ' ';
10142  if (pmat.Height() > 2)
10143  {
10144  out << pmat(2, j);
10145  }
10146  else
10147  {
10148  out << 0.0;
10149  }
10150  }
10151  else
10152  {
10153  out << 0.0 << ' ' << 0.0;
10154  }
10155  out << '\n';
10156  }
10157  }
10158 
10159  // write the cells
10160  out << "CELLS " << nc << ' ' << size << '\n';
10161  np = 0;
10162  for (int i = 0; i < GetNE(); i++)
10163  {
10165  int nv = Geometries.GetVertices(geom)->GetNPoints();
10166  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10167  Array<int> &RG = RefG->RefGeoms;
10168 
10169  for (int j = 0; j < RG.Size(); )
10170  {
10171  out << nv;
10172  for (int k = 0; k < nv; k++, j++)
10173  {
10174  out << ' ' << np + RG[j];
10175  }
10176  out << '\n';
10177  }
10178  np += RefG->RefPts.GetNPoints();
10179  }
10180  out << "CELL_TYPES " << nc << '\n';
10181  for (int i = 0; i < GetNE(); i++)
10182  {
10184  int nv = Geometries.GetVertices(geom)->GetNPoints();
10185  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10186  Array<int> &RG = RefG->RefGeoms;
10187  int vtk_cell_type = VTKGeometry::Map[geom];
10188 
10189  for (int j = 0; j < RG.Size(); j += nv)
10190  {
10191  out << vtk_cell_type << '\n';
10192  }
10193  }
10194  // write attributes (materials)
10195  out << "CELL_DATA " << nc << '\n'
10196  << "SCALARS material int\n"
10197  << "LOOKUP_TABLE default\n";
10198  for (int i = 0; i < GetNE(); i++)
10199  {
10201  int nv = Geometries.GetVertices(geom)->GetNPoints();
10202  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10203  int attr = GetAttribute(i);
10204  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10205  {
10206  out << attr << '\n';
10207  }
10208  }
10209 
10210  if (Dim > 1)
10211  {
10212  Array<int> coloring;
10213  srand((unsigned)time(0));
10214  double a = double(rand()) / (double(RAND_MAX) + 1.);
10215  int el0 = (int)floor(a * GetNE());
10216  GetElementColoring(coloring, el0);
10217  out << "SCALARS element_coloring int\n"
10218  << "LOOKUP_TABLE default\n";
10219  for (int i = 0; i < GetNE(); i++)
10220  {
10222  int nv = Geometries.GetVertices(geom)->GetNPoints();
10223  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
10224  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
10225  {
10226  out << coloring[i] + 1 << '\n';
10227  }
10228  }
10229  }
10230 
10231  // prepare to write data
10232  out << "POINT_DATA " << np << '\n' << flush;
10233 }
10234 
10235 void Mesh::GetElementColoring(Array<int> &colors, int el0)
10236 {
10237  int delete_el_to_el = (el_to_el) ? (0) : (1);
10238  const Table &el_el = ElementToElementTable();
10239  int num_el = GetNE(), stack_p, stack_top_p, max_num_col;
10240  Array<int> el_stack(num_el);
10241 
10242  const int *i_el_el = el_el.GetI();
10243  const int *j_el_el = el_el.GetJ();
10244 
10245  colors.SetSize(num_el);
10246  colors = -2;
10247  max_num_col = 1;
10248  stack_p = stack_top_p = 0;
10249  for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el)
10250  {
10251  if (colors[el] != -2)
10252  {
10253  continue;
10254  }
10255 
10256  colors[el] = -1;
10257  el_stack[stack_top_p++] = el;
10258 
10259  for ( ; stack_p < stack_top_p; stack_p++)
10260  {
10261  int i = el_stack[stack_p];
10262  int num_nb = i_el_el[i+1] - i_el_el[i];
10263  if (max_num_col < num_nb + 1)
10264  {
10265  max_num_col = num_nb + 1;
10266  }
10267  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
10268  {
10269  int k = j_el_el[j];
10270  if (colors[k] == -2)
10271  {
10272  colors[k] = -1;
10273  el_stack[stack_top_p++] = k;
10274  }
10275  }
10276  }
10277  }
10278 
10279  Array<int> col_marker(max_num_col);
10280 
10281  for (stack_p = 0; stack_p < stack_top_p; stack_p++)
10282  {
10283  int i = el_stack[stack_p], col;
10284  col_marker = 0;
10285  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
10286  {
10287  col = colors[j_el_el[j]];
10288  if (col != -1)
10289  {
10290  col_marker[col] = 1;
10291  }
10292  }
10293 
10294  for (col = 0; col < max_num_col; col++)
10295  if (col_marker[col] == 0)
10296  {
10297  break;
10298  }
10299 
10300  colors[i] = col;
10301  }
10302 
10303  if (delete_el_to_el)
10304  {
10305  delete el_to_el;
10306  el_to_el = NULL;
10307  }
10308 }
10309 
10310 void Mesh::PrintWithPartitioning(int *partitioning, std::ostream &out,
10311  int elem_attr) const
10312 {
10313  if (Dim != 3 && Dim != 2) { return; }
10314 
10315  int i, j, k, l, nv, nbe, *v;
10316 
10317  out << "MFEM mesh v1.0\n";
10318 
10319  // optional
10320  out <<
10321  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10322  "# POINT = 0\n"
10323  "# SEGMENT = 1\n"
10324  "# TRIANGLE = 2\n"
10325  "# SQUARE = 3\n"
10326  "# TETRAHEDRON = 4\n"
10327  "# CUBE = 5\n"
10328  "# PRISM = 6\n"
10329  "#\n";
10330 
10331  out << "\ndimension\n" << Dim
10332  << "\n\nelements\n" << NumOfElements << '\n';
10333  for (i = 0; i < NumOfElements; i++)
10334  {
10335  out << int((elem_attr) ? partitioning[i]+1 : elements[i]->GetAttribute())
10336  << ' ' << elements[i]->GetGeometryType();
10337  nv = elements[i]->GetNVertices();
10338  v = elements[i]->GetVertices();
10339  for (j = 0; j < nv; j++)
10340  {
10341  out << ' ' << v[j];
10342  }
10343  out << '\n';
10344  }
10345  nbe = 0;
10346  for (i = 0; i < faces_info.Size(); i++)
10347  {
10348  if ((l = faces_info[i].Elem2No) >= 0)
10349  {
10350  k = partitioning[faces_info[i].Elem1No];
10351  l = partitioning[l];
10352  if (k != l)
10353  {
10354  nbe++;
10355  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
10356  {
10357  nbe++;
10358  }
10359  }
10360  }
10361  else
10362  {
10363  nbe++;
10364  }
10365  }
10366  out << "\nboundary\n" << nbe << '\n';
10367  for (i = 0; i < faces_info.Size(); i++)
10368  {
10369  if ((l = faces_info[i].Elem2No) >= 0)
10370  {
10371  k = partitioning[faces_info[i].Elem1No];
10372  l = partitioning[l];
10373  if (k != l)
10374  {
10375  nv = faces[i]->GetNVertices();
10376  v = faces[i]->GetVertices();
10377  out << k+1 << ' ' << faces[i]->GetGeometryType();
10378  for (j = 0; j < nv; j++)
10379  {
10380  out << ' ' << v[j];
10381  }
10382  out << '\n';
10383  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
10384  {
10385  out << l+1 << ' ' << faces[i]->GetGeometryType();
10386  for (j = nv-1; j >= 0; j--)
10387  {
10388  out << ' ' << v[j];
10389  }
10390  out << '\n';
10391  }
10392  }
10393  }
10394  else
10395  {
10396  k = partitioning[faces_info[i].Elem1No];
10397  nv = faces[i]->GetNVertices();
10398  v = faces[i]->GetVertices();
10399  out << k+1 << ' ' << faces[i]->GetGeometryType();
10400  for (j = 0; j < nv; j++)
10401  {
10402  out << ' ' << v[j];
10403  }
10404  out << '\n';
10405  }
10406  }
10407  out << "\nvertices\n" << NumOfVertices << '\n';
10408  if (Nodes == NULL)
10409  {
10410  out << spaceDim << '\n';
10411  for (i = 0; i < NumOfVertices; i++)
10412  {
10413  out << vertices[i](0);
10414  for (j = 1; j < spaceDim; j++)
10415  {
10416  out << ' ' << vertices[i](j);
10417  }
10418  out << '\n';
10419  }
10420  out.flush();
10421  }
10422  else
10423  {
10424  out << "\nnodes\n";
10425  Nodes->Save(out);
10426  }
10427 }
10428 
10430  std::ostream &out,
10431  int interior_faces)
10432 {
10433  MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported\n");
10434  if (Dim != 3 && Dim != 2) { return; }
10435 
10436  int i, j, k, l, s;
10437 
10438  int nv;
10439  const int *ind;
10440 
10441  int *vcount = new int[NumOfVertices];
10442  for (i = 0; i < NumOfVertices; i++)
10443  {
10444  vcount[i] = 0;
10445  }
10446  for (i = 0; i < NumOfElements; i++)
10447  {
10448  nv = elements[i]->GetNVertices();
10449  ind = elements[i]->GetVertices();
10450  for (j = 0; j < nv; j++)
10451  {
10452  vcount[ind[j]]++;
10453  }
10454  }
10455 
10456  int *voff = new int[NumOfVertices+1];
10457  voff[0] = 0;
10458  for (i = 1; i <= NumOfVertices; i++)
10459  {
10460  voff[i] = vcount[i-1] + voff[i-1];
10461  }
10462 
10463  int **vown = new int*[NumOfVertices];
10464  for (i = 0; i < NumOfVertices; i++)
10465  {
10466  vown[i] = new int[vcount[i]];
10467  }
10468 
10469  // 2D
10470  if (Dim == 2)
10471  {
10472  int nv, nbe;
10473  int *ind;
10474 
10475  Table edge_el;
10476  Transpose(ElementToEdgeTable(), edge_el);
10477 
10478  // Fake printing of the elements.
10479  for (i = 0; i < NumOfElements; i++)
10480  {
10481  nv = elements[i]->GetNVertices();
10482  ind = elements[i]->GetVertices();
10483  for (j = 0; j < nv; j++)
10484  {
10485  vcount[ind[j]]--;
10486  vown[ind[j]][vcount[ind[j]]] = i;
10487  }
10488  }
10489 
10490  for (i = 0; i < NumOfVertices; i++)
10491  {
10492  vcount[i] = voff[i+1] - voff[i];
10493  }
10494 
10495  nbe = 0;
10496  for (i = 0; i < edge_el.Size(); i++)
10497  {
10498  const int *el = edge_el.GetRow(i);
10499  if (edge_el.RowSize(i) > 1)
10500  {
10501  k = partitioning[el[0]];
10502  l = partitioning[el[1]];
10503  if (interior_faces || k != l)
10504  {
10505  nbe += 2;
10506  }
10507  }
10508  else
10509  {
10510  nbe++;
10511  }
10512  }
10513 
10514  // Print the type of the mesh and the boundary elements.
10515  out << "areamesh2\n\n" << nbe << '\n';
10516 
10517  for (i = 0; i < edge_el.Size(); i++)
10518  {
10519  const int *el = edge_el.GetRow(i);
10520  if (edge_el.RowSize(i) > 1)
10521  {
10522  k = partitioning[el[0]];
10523  l = partitioning[el[1]];
10524  if (interior_faces || k != l)
10525  {
10526  Array<int> ev;
10527  GetEdgeVertices(i,ev);
10528  out << k+1; // attribute
10529  for (j = 0; j < 2; j++)
10530  for (s = 0; s < vcount[ev[j]]; s++)
10531  if (vown[ev[j]][s] == el[0])
10532  {
10533  out << ' ' << voff[ev[j]]+s+1;
10534  }
10535  out << '\n';
10536  out << l+1; // attribute
10537  for (j = 1; j >= 0; j--)
10538  for (s = 0; s < vcount[ev[j]]; s++)
10539  if (vown[ev[j]][s] == el[1])
10540  {
10541  out << ' ' << voff[ev[j]]+s+1;
10542  }
10543  out << '\n';
10544  }
10545  }
10546  else
10547  {
10548  k = partitioning[el[0]];
10549  Array<int> ev;
10550  GetEdgeVertices(i,ev);
10551  out << k+1; // attribute
10552  for (j = 0; j < 2; j++)
10553  for (s = 0; s < vcount[ev[j]]; s++)
10554  if (vown[ev[j]][s] == el[0])
10555  {
10556  out << ' ' << voff[ev[j]]+s+1;
10557  }
10558  out << '\n';
10559  }
10560  }
10561 
10562  // Print the elements.
10563  out << NumOfElements << '\n';
10564  for (i = 0; i < NumOfElements; i++)
10565  {
10566  nv = elements[i]->GetNVertices();
10567  ind = elements[i]->GetVertices();
10568  out << partitioning[i]+1 << ' '; // use subdomain number as attribute
10569  out << nv << ' ';
10570  for (j = 0; j < nv; j++)
10571  {
10572  out << ' ' << voff[ind[j]]+vcount[ind[j]]--;
10573  vown[ind[j]][vcount[ind[j]]] = i;
10574  }
10575  out << '\n';
10576  }
10577 
10578  for (i = 0; i < NumOfVertices; i++)
10579  {
10580  vcount[i] = voff[i+1] - voff[i];
10581  }
10582 
10583  // Print the vertices.
10584  out << voff[NumOfVertices] << '\n';
10585  for (i = 0; i < NumOfVertices; i++)
10586  for (k = 0; k < vcount[i]; k++)
10587  {
10588  for (j = 0; j < Dim; j++)
10589  {
10590  out << vertices[i](j) << ' ';
10591  }
10592  out << '\n';
10593  }
10594  }
10595  // Dim is 3
10596  else if (meshgen == 1)
10597  {
10598  out << "NETGEN_Neutral_Format\n";
10599  // print the vertices
10600  out << voff[NumOfVertices] << '\n';
10601  for (i = 0; i < NumOfVertices; i++)
10602  for (k = 0; k < vcount[i]; k++)
10603  {
10604  for (j = 0; j < Dim; j++)
10605  {
10606  out << ' ' << vertices[i](j);
10607  }
10608  out << '\n';
10609  }
10610 
10611  // print the elements
10612  out << NumOfElements << '\n';
10613  for (i = 0; i < NumOfElements; i++)
10614  {
10615  nv = elements[i]->GetNVertices();
10616  ind = elements[i]->GetVertices();
10617  out << partitioning[i]+1; // use subdomain number as attribute
10618  for (j = 0; j < nv; j++)
10619  {
10620  out << ' ' << voff[ind[j]]+vcount[ind[j]]--;
10621  vown[ind[j]][vcount[ind[j]]] = i;
10622  }
10623  out << '\n';
10624  }
10625 
10626  for (i = 0; i < NumOfVertices; i++)
10627  {
10628  vcount[i] = voff[i+1] - voff[i];
10629  }
10630 
10631  // print the boundary information.
10632  int k, l, nbe;
10633  nbe = 0;
10634  for (i = 0; i < NumOfFaces; i++)
10635  if ((l = faces_info[i].Elem2No) >= 0)
10636  {
10637  k = partitioning[faces_info[i].Elem1No];
10638  l = partitioning[l];
10639  if (interior_faces || k != l)
10640  {
10641  nbe += 2;
10642  }
10643  }
10644  else
10645  {
10646  nbe++;
10647  }
10648 
10649  out << nbe << '\n';
10650  for (i = 0; i < NumOfFaces; i++)
10651  if ((l = faces_info[i].Elem2No) >= 0)
10652  {
10653  k = partitioning[faces_info[i].Elem1No];
10654  l = partitioning[l];
10655  if (interior_faces || k != l)
10656  {
10657  nv = faces[i]->GetNVertices();
10658  ind = faces[i]->GetVertices();
10659  out << k+1; // attribute
10660  for (j = 0; j < nv; j++)
10661  for (s = 0; s < vcount[ind[j]]; s++)
10662  if (vown[ind[j]][s] == faces_info[i].Elem1No)
10663  {
10664  out << ' ' << voff[ind[j]]+s+1;
10665  }
10666  out << '\n';
10667  out << l+1; // attribute
10668  for (j = nv-1; j >= 0; j--)
10669  for (s = 0; s < vcount[ind[j]]; s++)
10670  if (vown[ind[j]][s] == faces_info[i].Elem2No)
10671  {
10672  out << ' ' << voff[ind[j]]+s+1;
10673  }
10674  out << '\n';
10675  }
10676  }
10677  else
10678  {
10679  k = partitioning[faces_info[i].Elem1No];
10680  nv = faces[i]->GetNVertices();
10681  ind = faces[i]->GetVertices();
10682  out << k+1; // attribute
10683  for (j = 0; j < nv; j++)
10684  for (s = 0; s < vcount[ind[j]]; s++)
10685  if (vown[ind[j]][s] == faces_info[i].Elem1No)
10686  {
10687  out << ' ' << voff[ind[j]]+s+1;
10688  }
10689  out << '\n';
10690  }
10691  }
10692  // Dim is 3
10693  else if (meshgen == 2) // TrueGrid
10694  {
10695  // count the number of the boundary elements.
10696  int k, l, nbe;
10697  nbe = 0;
10698  for (i = 0; i < NumOfFaces; i++)
10699  if ((l = faces_info[i].Elem2No) >= 0)
10700  {
10701  k = partitioning[faces_info[i].Elem1No];
10702  l = partitioning[l];
10703  if (interior_faces || k != l)
10704  {
10705  nbe += 2;
10706  }
10707  }
10708  else
10709  {
10710  nbe++;
10711  }
10712 
10713 
10714  out << "TrueGrid\n"
10715  << "1 " << voff[NumOfVertices] << " " << NumOfElements
10716  << " 0 0 0 0 0 0 0\n"
10717  << "0 0 0 1 0 0 0 0 0 0 0\n"
10718  << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
10719  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
10720  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
10721 
10722  for (i = 0; i < NumOfVertices; i++)
10723  for (k = 0; k < vcount[i]; k++)
10724  out << voff[i]+k << " 0.0 " << vertices[i](0) << ' '
10725  << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n";
10726 
10727  for (i = 0; i < NumOfElements; i++)
10728  {
10729  nv = elements[i]->GetNVertices();
10730  ind = elements[i]->GetVertices();
10731  out << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute
10732  for (j = 0; j < nv; j++)
10733  {
10734  out << ' ' << voff[ind[j]]+vcount[ind[j]]--;
10735  vown[ind[j]][vcount[ind[j]]] = i;
10736  }
10737  out << '\n';
10738  }
10739 
10740  for (i = 0; i < NumOfVertices; i++)
10741  {
10742  vcount[i] = voff[i+1] - voff[i];
10743  }
10744 
10745  // boundary elements
10746  for (i = 0; i < NumOfFaces; i++)
10747  if ((l = faces_info[i].Elem2No) >= 0)
10748  {
10749  k = partitioning[faces_info[i].Elem1No];
10750  l = partitioning[l];
10751  if (interior_faces || k != l)
10752  {
10753  nv = faces[i]->GetNVertices();
10754  ind = faces[i]->GetVertices();
10755  out << k+1; // attribute
10756  for (j = 0; j < nv; j++)
10757  for (s = 0; s < vcount[ind[j]]; s++)
10758  if (vown[ind[j]][s] == faces_info[i].Elem1No)
10759  {
10760  out << ' ' << voff[ind[j]]+s+1;
10761  }
10762  out << " 1.0 1.0 1.0 1.0\n";
10763  out << l+1; // attribute
10764  for (j = nv-1; j >= 0; j--)
10765  for (s = 0; s < vcount[ind[j]]; s++)
10766  if (vown[ind[j]][s] == faces_info[i].Elem2No)
10767  {
10768  out << ' ' << voff[ind[j]]+s+1;
10769  }
10770  out << " 1.0 1.0 1.0 1.0\n";
10771  }
10772  }
10773  else
10774  {
10775  k = partitioning[faces_info[i].Elem1No];
10776  nv = faces[i]->GetNVertices();
10777  ind = faces[i]->GetVertices();
10778  out << k+1; // attribute
10779  for (j = 0; j < nv; j++)
10780  for (s = 0; s < vcount[ind[j]]; s++)
10781  if (vown[ind[j]][s] == faces_info[i].Elem1No)
10782  {
10783  out << ' ' << voff[ind[j]]+s+1;
10784  }
10785  out << " 1.0 1.0 1.0 1.0\n";
10786  }
10787  }
10788 
10789  out << flush;
10790 
10791  for (i = 0; i < NumOfVertices; i++)
10792  {
10793  delete [] vown[i];
10794  }
10795 
10796  delete [] vcount;
10797  delete [] voff;
10798  delete [] vown;
10799 }
10800 
10801 void Mesh::PrintSurfaces(const Table & Aface_face, std::ostream &out) const
10802 {
10803  int i, j;
10804 
10805  if (NURBSext)
10806  {
10807  mfem_error("Mesh::PrintSurfaces"
10808  " NURBS mesh is not supported!");
10809  return;
10810  }
10811 
10812  out << "MFEM mesh v1.0\n";
10813 
10814  // optional
10815  out <<
10816  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10817  "# POINT = 0\n"
10818  "# SEGMENT = 1\n"
10819  "# TRIANGLE = 2\n"
10820  "# SQUARE = 3\n"
10821  "# TETRAHEDRON = 4\n"
10822  "# CUBE = 5\n"
10823  "# PRISM = 6\n"
10824  "#\n";
10825 
10826  out << "\ndimension\n" << Dim
10827  << "\n\nelements\n" << NumOfElements << '\n';
10828  for (i = 0; i < NumOfElements; i++)
10829  {
10830  PrintElement(elements[i], out);
10831  }
10832 
10833  out << "\nboundary\n" << Aface_face.Size_of_connections() << '\n';
10834  const int * const i_AF_f = Aface_face.GetI();
10835  const int * const j_AF_f = Aface_face.GetJ();
10836 
10837  for (int iAF=0; iAF < Aface_face.Size(); ++iAF)
10838  for (const int * iface = j_AF_f + i_AF_f[iAF];
10839  iface < j_AF_f + i_AF_f[iAF+1];
10840  ++iface)
10841  {
10842  out << iAF+1 << ' ';
10843  PrintElementWithoutAttr(faces[*iface],out);
10844  }
10845 
10846  out << "\nvertices\n" << NumOfVertices << '\n';
10847  if (Nodes == NULL)
10848  {
10849  out << spaceDim << '\n';
10850  for (i = 0; i < NumOfVertices; i++)
10851  {
10852  out << vertices[i](0);
10853  for (j = 1; j < spaceDim; j++)
10854  {
10855  out << ' ' << vertices[i](j);
10856  }
10857  out << '\n';
10858  }
10859  out.flush();
10860  }
10861  else
10862  {
10863  out << "\nnodes\n";
10864  Nodes->Save(out);
10865  }
10866 }
10867 
10868 void Mesh::ScaleSubdomains(double sf)
10869 {
10870  int i,j,k;
10871  Array<int> vert;
10872  DenseMatrix pointmat;
10873  int na = attributes.Size();
10874  double *cg = new double[na*spaceDim];
10875  int *nbea = new int[na];
10876 
10877  int *vn = new int[NumOfVertices];
10878  for (i = 0; i < NumOfVertices; i++)
10879  {
10880  vn[i] = 0;
10881  }
10882  for (i = 0; i < na; i++)
10883  {
10884  for (j = 0; j < spaceDim; j++)
10885  {
10886  cg[i*spaceDim+j] = 0.0;
10887  }
10888  nbea[i] = 0;
10889  }
10890 
10891  for (i = 0; i < NumOfElements; i++)
10892  {
10893  GetElementVertices(i, vert);
10894  for (k = 0; k < vert.Size(); k++)
10895  {
10896  vn[vert[k]] = 1;
10897  }
10898  }
10899 
10900  for (i = 0; i < NumOfElements; i++)
10901  {
10902  int bea = GetAttribute(i)-1;
10903  GetPointMatrix(i, pointmat);
10904  GetElementVertices(i, vert);
10905 
10906  for (k = 0; k < vert.Size(); k++)
10907  if (vn[vert[k]] == 1)
10908  {
10909  nbea[bea]++;
10910  for (j = 0; j < spaceDim; j++)
10911  {
10912  cg[bea*spaceDim+j] += pointmat(j,k);
10913  }
10914  vn[vert[k]] = 2;
10915  }
10916  }
10917 
10918  for (i = 0; i < NumOfElements; i++)
10919  {
10920  int bea = GetAttribute(i)-1;
10921  GetElementVertices (i, vert);
10922 
10923  for (k = 0; k < vert.Size(); k++)
10924  if (vn[vert[k]])
10925  {
10926  for (j = 0; j < spaceDim; j++)
10927  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
10928  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
10929  vn[vert[k]] = 0;
10930  }
10931  }
10932 
10933  delete [] cg;
10934  delete [] nbea;
10935  delete [] vn;
10936 }
10937 
10938 void Mesh::ScaleElements(double sf)
10939 {
10940  int i,j,k;
10941  Array<int> vert;
10942  DenseMatrix pointmat;
10943  int na = NumOfElements;
10944  double *cg = new double[na*spaceDim];
10945  int *nbea = new int[na];
10946 
10947  int *vn = new int[NumOfVertices];
10948  for (i = 0; i < NumOfVertices; i++)
10949  {
10950  vn[i] = 0;
10951  }
10952  for (i = 0; i < na; i++)
10953  {
10954  for (j = 0; j < spaceDim; j++)
10955  {
10956  cg[i*spaceDim+j] = 0.0;
10957  }
10958  nbea[i] = 0;
10959  }
10960 
10961  for (i = 0; i < NumOfElements; i++)
10962  {
10963  GetElementVertices(i, vert);
10964  for (k = 0; k < vert.Size(); k++)
10965  {
10966  vn[vert[k]] = 1;
10967  }
10968  }
10969 
10970  for (i = 0; i < NumOfElements; i++)
10971  {
10972  int bea = i;
10973  GetPointMatrix(i, pointmat);
10974  GetElementVertices(i, vert);
10975 
10976  for (k = 0; k < vert.Size(); k++)
10977  if (vn[vert[k]] == 1)
10978  {
10979  nbea[bea]++;
10980  for (j = 0; j < spaceDim; j++)
10981  {
10982  cg[bea*spaceDim+j] += pointmat(j,k);
10983  }
10984  vn[vert[k]] = 2;
10985  }
10986  }
10987 
10988  for (i = 0; i < NumOfElements; i++)
10989  {
10990  int bea = i;
10991  GetElementVertices(i, vert);
10992 
10993  for (k = 0; k < vert.Size(); k++)
10994  if (vn[vert[k]])
10995  {
10996  for (j = 0; j < spaceDim; j++)
10997  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
10998  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
10999  vn[vert[k]] = 0;
11000  }
11001  }
11002 
11003  delete [] cg;
11004  delete [] nbea;
11005  delete [] vn;
11006 }
11007 
11008 void Mesh::Transform(void (*f)(const Vector&, Vector&))
11009 {
11010  // TODO: support for different new spaceDim.
11011  if (Nodes == NULL)
11012  {
11013  Vector vold(spaceDim), vnew(NULL, spaceDim);
11014  for (int i = 0; i < vertices.Size(); i++)
11015  {
11016  for (int j = 0; j < spaceDim; j++)
11017  {
11018  vold(j) = vertices[i](j);
11019  }
11020  vnew.SetData(vertices[i]());
11021  (*f)(vold, vnew);
11022  }
11023  }
11024  else
11025  {
11026  GridFunction xnew(Nodes->FESpace());
11028  xnew.ProjectCoefficient(f_pert);
11029  *Nodes = xnew;
11030  }
11031 }
11032 
11034 {
11035  MFEM_VERIFY(spaceDim == deformation.GetVDim(),
11036  "incompatible vector dimensions");
11037  if (Nodes == NULL)
11038  {
11039  LinearFECollection fec;
11040  FiniteElementSpace fes(this, &fec, spaceDim, Ordering::byVDIM);
11041  GridFunction xnew(&fes);
11042  xnew.ProjectCoefficient(deformation);
11043  for (int i = 0; i < NumOfVertices; i++)
11044  for (int d = 0; d < spaceDim; d++)
11045  {
11046  vertices[i](d) = xnew(d + spaceDim*i);
11047  }
11048  }
11049  else
11050  {
11051  GridFunction xnew(Nodes->FESpace());
11052  xnew.ProjectCoefficient(deformation);
11053  *Nodes = xnew;
11054  }
11055 }
11056 
11058 {
11059  if (NURBSext || ncmesh) { return; }
11060 
11061  Array<int> v2v(GetNV());
11062  v2v = -1;
11063  for (int i = 0; i < GetNE(); i++)
11064  {
11065  Element *el = GetElement(i);
11066  int nv = el->GetNVertices();
11067  int *v = el->GetVertices();
11068  for (int j = 0; j < nv; j++)
11069  {
11070  v2v[v[j]] = 0;
11071  }
11072  }
11073  for (int i = 0; i < GetNBE(); i++)
11074  {
11075  Element *el = GetBdrElement(i);
11076  int *v = el->GetVertices();
11077  int nv = el->GetNVertices();
11078  for (int j = 0; j < nv; j++)
11079  {
11080  v2v[v[j]] = 0;
11081  }
11082  }
11083  int num_vert = 0;
11084  for (int i = 0; i < v2v.Size(); i++)
11085  {
11086  if (v2v[i] == 0)
11087  {
11088  vertices[num_vert] = vertices[i];
11089  v2v[i] = num_vert++;
11090  }
11091  }
11092 
11093  if (num_vert == v2v.Size()) { return; }
11094 
11095  Vector nodes_by_element;
11096  Array<int> vdofs;
11097  if (Nodes)
11098  {
11099  int s = 0;
11100  for (int i = 0; i < GetNE(); i++)
11101  {
11102  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11103  s += vdofs.Size();
11104  }
11105  nodes_by_element.SetSize(s);
11106  s = 0;
11107  for (int i = 0; i < GetNE(); i++)
11108  {
11109  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11110  Nodes->GetSubVector(vdofs, &nodes_by_element(s));
11111  s += vdofs.Size();
11112  }
11113  }
11114  vertices.SetSize(num_vert);
11115  NumOfVertices = num_vert;
11116  for (int i = 0; i < GetNE(); i++)
11117  {
11118  Element *el = GetElement(i);
11119  int *v = el->GetVertices();
11120  int nv = el->GetNVertices();
11121  for (int j = 0; j < nv; j++)
11122  {
11123  v[j] = v2v[v[j]];
11124  }
11125  }
11126  for (int i = 0; i < GetNBE(); i++)
11127  {
11128  Element *el = GetBdrElement(i);
11129  int *v = el->GetVertices();
11130  int nv = el->GetNVertices();
11131  for (int j = 0; j < nv; j++)
11132  {
11133  v[j] = v2v[v[j]];
11134  }
11135  }
11136  DeleteTables();
11137  if (Dim > 1)
11138  {
11139  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
11140  el_to_edge = new Table;
11142  }
11143  if (Dim > 2)
11144  {
11145  // generate el_to_face, be_to_face
11147  }
11148  // Update faces and faces_info
11149  GenerateFaces();
11150  if (Nodes)
11151  {
11152  Nodes->FESpace()->Update();
11153  Nodes->Update();
11154  int s = 0;
11155  for (int i = 0; i < GetNE(); i++)
11156  {
11157  Nodes->FESpace()->GetElementVDofs(i, vdofs);
11158  Nodes->SetSubVector(vdofs, &nodes_by_element(s));
11159  s += vdofs.Size();
11160  }
11161  }
11162 }
11163 
11165 {
11166  if (NURBSext || ncmesh) { return; }
11167 
11168  int num_bdr_elem = 0;
11169  int new_bel_to_edge_nnz = 0;
11170  for (int i = 0; i < GetNBE(); i++)
11171  {
11173  {
11174  FreeElement(boundary[i]);
11175  }
11176  else
11177  {
11178  num_bdr_elem++;
11179  if (Dim == 3)
11180  {
11181  new_bel_to_edge_nnz += bel_to_edge->RowSize(i);
11182  }
11183  }
11184  }
11185 
11186  if (num_bdr_elem == GetNBE()) { return; }
11187 
11188  Array<Element *> new_boundary(num_bdr_elem);
11189  Array<int> new_be_to_edge, new_be_to_face;
11190  Table *new_bel_to_edge = NULL;
11191  new_boundary.SetSize(0);
11192  if (Dim == 2)
11193  {
11194  new_be_to_edge.Reserve(num_bdr_elem);
11195  }
11196  else if (Dim == 3)
11197  {
11198  new_be_to_face.Reserve(num_bdr_elem);
11199  new_bel_to_edge = new Table;
11200  new_bel_to_edge->SetDims(num_bdr_elem, new_bel_to_edge_nnz);
11201  }
11202  for (int i = 0; i < GetNBE(); i++)
11203  {
11205  {
11206  new_boundary.Append(boundary[i]);
11207  if (Dim == 2)
11208  {
11209  new_be_to_edge.Append(be_to_edge[i]);
11210  }
11211  else if (Dim == 3)
11212  {
11213  int row = new_be_to_face.Size();
11214  new_be_to_face.Append(be_to_face[i]);
11215  int *e = bel_to_edge->GetRow(i);
11216  int ne = bel_to_edge->RowSize(i);
11217  int *new_e = new_bel_to_edge->GetRow(row);
11218  for (int j = 0; j < ne; j++)
11219  {
11220  new_e[j] = e[j];
11221  }
11222  new_bel_to_edge->GetI()[row+1] = new_bel_to_edge->GetI()[row] + ne;
11223  }
11224  }
11225  }
11226 
11227  NumOfBdrElements = new_boundary.Size();
11228  mfem::Swap(boundary, new_boundary);
11229 
11230  if (Dim == 2)
11231  {
11232  mfem::Swap(be_to_edge, new_be_to_edge);
11233  }
11234  else if (Dim == 3)
11235  {
11236  mfem::Swap(be_to_face, new_be_to_face);
11237  delete bel_to_edge;
11238  bel_to_edge = new_bel_to_edge;
11239  }
11240 
11241  Array<int> attribs(num_bdr_elem);
11242  for (int i = 0; i < attribs.Size(); i++)
11243  {
11244  attribs[i] = GetBdrAttribute(i);
11245  }
11246  attribs.Sort();
11247  attribs.Unique();
11249  attribs.Copy(bdr_attributes);
11250 }
11251 
11253 {
11254 #ifdef MFEM_USE_MEMALLOC
11255  if (E)
11256  {
11257  if (E->GetType() == Element::TETRAHEDRON)
11258  {
11259  TetMemory.Free((Tetrahedron*) E);
11260  }
11261  else
11262  {
11263  delete E;
11264  }
11265  }
11266 #else
11267  delete E;
11268 #endif
11269 }
11270 
11271 std::ostream &operator<<(std::ostream &out, const Mesh &mesh)
11272 {
11273  mesh.Print(out);
11274  return out;
11275 }
11276 
11277 int Mesh::FindPoints(DenseMatrix &point_mat, Array<int>& elem_ids,
11278  Array<IntegrationPoint>& ips, bool warn,
11279  InverseElementTransformation *inv_trans)
11280 {
11281  const int npts = point_mat.Width();
11282  if (!npts) { return 0; }
11283  MFEM_VERIFY(point_mat.Height() == spaceDim,"Invalid points matrix");
11284  elem_ids.SetSize(npts);
11285  ips.SetSize(npts);
11286  elem_ids = -1;
11287  if (!GetNE()) { return 0; }
11288 
11289  double *data = point_mat.GetData();
11290  InverseElementTransformation *inv_tr = inv_trans;
11291  inv_tr = inv_tr ? inv_tr : new InverseElementTransformation;
11292 
11293  // For each point in 'point_mat', find the element whose center is closest.
11294  Vector min_dist(npts);
11295  Array<int> e_idx(npts);
11296  min_dist = std::numeric_limits<double>::max();
11297  e_idx = -1;
11298 
11299  Vector pt(spaceDim);
11300  for (int i = 0; i < GetNE(); i++)
11301  {
11302  GetElementTransformation(i)->Transform(
11304  for (int k = 0; k < npts; k++)
11305  {
11306  double dist = pt.DistanceTo(data+k*spaceDim);
11307  if (dist < min_dist(k))
11308  {
11309  min_dist(k) = dist;
11310  e_idx[k] = i;
11311  }
11312  }
11313  }
11314 
11315  // Checks if the points lie in the closest element
11316  int pts_found = 0;
11317  pt.NewDataAndSize(NULL, spaceDim);
11318  for (int k = 0; k < npts; k++)
11319  {
11320  pt.SetData(data+k*spaceDim);
11321  inv_tr->SetTransformation(*GetElementTransformation(e_idx[k]));
11322  int res = inv_tr->Transform(pt, ips[k]);
11324  {
11325  elem_ids[k] = e_idx[k];
11326  pts_found++;
11327  }
11328  }
11329  if (pts_found != npts)
11330  {
11332  Table *vtoel = GetVertexToElementTable();
11333  for (int k = 0; k < npts; k++)
11334  {
11335  if (elem_ids[k] != -1) { continue; }
11336  // Try all vertex-neighbors of element e_idx[k]
11337  pt.SetData(data+k*spaceDim);
11338  GetElementVertices(e_idx[k], vertices);
11339  for (int v = 0; v < vertices.Size(); v++)
11340  {
11341  int vv = vertices[v];
11342  int ne = vtoel->RowSize(vv);
11343  const int* els = vtoel->GetRow(vv);
11344  for (int e = 0; e < ne; e++)
11345  {
11346  if (els[e] == e_idx[k]) { continue; }
11347  inv_tr->SetTransformation(*GetElementTransformation(els[e]));
11348  int res = inv_tr->Transform(pt, ips[k]);
11350  {
11351  elem_ids[k] = els[e];
11352  pts_found++;
11353  goto next_point;
11354  }
11355  }
11356  }
11357  // Try neighbors for non-conforming meshes
11358  if (ncmesh)
11359  {
11360  Array<int> neigh;
11361  int le = ncmesh->leaf_elements[e_idx[k]];
11362  ncmesh->FindNeighbors(le,neigh);
11363  for (int e = 0; e < neigh.Size(); e++)
11364  {
11365  int nn = neigh[e];
11366  if (ncmesh->IsGhost(ncmesh->elements[nn])) { continue; }
11367  int el = ncmesh->elements[nn].index;
11369  int res = inv_tr->Transform(pt, ips[k]);
11371  {
11372  elem_ids[k] = el;
11373  pts_found++;
11374  goto next_point;
11375  }
11376  }
11377  }
11378  next_point: ;
11379  }
11380  delete vtoel;
11381  }
11382  if (inv_trans == NULL) { delete inv_tr; }
11383 
11384  if (warn && pts_found != npts)
11385  {
11386  MFEM_WARNING((npts-pts_found) << " points were not found");
11387  }
11388  return pts_found;
11389 }
11390 
11391 
11393  int flags, MemoryType d_mt)
11394 {
11395  this->mesh = mesh;
11396  IntRule = &ir;
11397  computed_factors = flags;
11398 
11399  MFEM_ASSERT(mesh->GetNumGeometries(mesh->Dimension()) <= 1,
11400  "mixed meshes are not supported!");
11401  MFEM_ASSERT(mesh->GetNodes(), "meshes without nodes are not supported!");
11402 
11403  Compute(*mesh->GetNodes(), d_mt);
11404 }
11405 
11407  const IntegrationRule &ir,
11408  int flags, MemoryType d_mt)
11409 {
11410  this->mesh = nodes.FESpace()->GetMesh();
11411  IntRule = &ir;
11412  computed_factors = flags;
11413 
11414  Compute(nodes, d_mt);
11415 }
11416 
11417 void GeometricFactors::Compute(const GridFunction &nodes,
11418  MemoryType d_mt)
11419 {
11420 
11421  const FiniteElementSpace *fespace = nodes.FESpace();
11422  const FiniteElement *fe = fespace->GetFE(0);
11423  const int dim = fe->GetDim();
11424  const int vdim = fespace->GetVDim();
11425  const int NE = fespace->GetNE();
11426  const int ND = fe->GetDof();
11427  const int NQ = IntRule->GetNPoints();
11428 
11429  unsigned eval_flags = 0;
11430  MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
11433  {
11434  X.SetSize(vdim*NQ*NE, my_d_mt); // NQ x SDIM x NE
11435  eval_flags |= QuadratureInterpolator::VALUES;
11436  }
11438  {
11439  J.SetSize(dim*vdim*NQ*NE, my_d_mt); // NQ x SDIM x DIM x NE
11441  }
11443  {
11444  detJ.SetSize(NQ*NE, my_d_mt); // NQ x NE
11446  }
11447 
11448  const QuadratureInterpolator *qi = fespace->GetQuadratureInterpolator(*IntRule);
11449  // All X, J, and detJ use this layout:
11451 
11452  const bool use_tensor_products = UsesTensorBasis(*fespace);
11453 
11454  qi->DisableTensorProducts(!use_tensor_products);
11455  const ElementDofOrdering e_ordering = use_tensor_products ?
11458  const Operator *elem_restr = fespace->GetElementRestriction(e_ordering);
11459 
11460  if (elem_restr) // Always true as of 2021-04-27
11461  {
11462  Vector Enodes(vdim*ND*NE, my_d_mt);
11463  elem_restr->Mult(nodes, Enodes);
11464  qi->Mult(Enodes, eval_flags, X, J, detJ);
11465  }
11466  else
11467  {
11468  qi->Mult(nodes, eval_flags, X, J, detJ);
11469  }
11470 }
11471 
11473  const IntegrationRule &ir,
11474  int flags, FaceType type)
11475  : type(type)
11476 {
11477  this->mesh = mesh;
11478  IntRule = &ir;
11479  computed_factors = flags;
11480 
11481  const GridFunction *nodes = mesh->GetNodes();
11482  const FiniteElementSpace *fespace = nodes->FESpace();
11483  const int vdim = fespace->GetVDim();
11484  const int NF = fespace->GetNFbyType(type);
11485  const int NQ = ir.GetNPoints();
11486 
11487  const FaceRestriction *face_restr = fespace->GetFaceRestriction(
11489  type,
11491  Vector Fnodes(face_restr->Height());
11492  face_restr->Mult(*nodes, Fnodes);
11493 
11494  unsigned eval_flags = 0;
11496  {
11497  X.SetSize(vdim*NQ*NF);
11498  eval_flags |= FaceQuadratureInterpolator::VALUES;
11499  }
11500  if (flags & FaceGeometricFactors::JACOBIANS)
11501  {
11502  J.SetSize(vdim*vdim*NQ*NF);
11504  }
11506  {
11507  detJ.SetSize(NQ*NF);
11509  }
11510  if (flags & FaceGeometricFactors::NORMALS)
11511  {
11512  normal.SetSize(vdim*NQ*NF);
11514  }
11515 
11517  ir, type);
11518  qi->Mult(Fnodes, eval_flags, X, J, detJ, normal);
11519 }
11520 
11522  const double s_)
11523  : VectorCoefficient(dim), n(n_), s(s_), tip(p, dim-1)
11524 {
11525 }
11526 
11528  const IntegrationPoint &ip)
11529 {
11530  V.SetSize(vdim);
11531  T.Transform(ip, tip);
11532  V(0) = p[0];
11533  if (vdim == 2)
11534  {
11535  V(1) = s * ((ip.y + layer) / n);
11536  }
11537  else
11538  {
11539  V(1) = p[1];
11540  V(2) = s * ((ip.z + layer) / n);
11541  }
11542 }
11543 
11544 
11545 Mesh *Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
11546 {
11547  if (mesh->Dimension() != 1)
11548  {
11549  mfem::err << "Extrude1D : Not a 1D mesh!" << endl;
11550  mfem_error();
11551  }
11552 
11553  int nvy = (closed) ? (ny) : (ny + 1);
11554  int nvt = mesh->GetNV() * nvy;
11555 
11556  Mesh *mesh2d;
11557 
11558  if (closed)
11559  {
11560  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny, mesh->GetNBE()*ny);
11561  }
11562  else
11563  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny,
11564  mesh->GetNBE()*ny+2*mesh->GetNE());
11565 
11566  // vertices
11567  double vc[2];
11568  for (int i = 0; i < mesh->GetNV(); i++)
11569  {
11570  vc[0] = mesh->GetVertex(i)[0];
11571  for (int j = 0; j < nvy; j++)
11572  {
11573  vc[1] = sy * (double(j) / ny);
11574  mesh2d->AddVertex(vc);
11575  }
11576  }
11577  // elements
11578  Array<int> vert;
11579  for (int i = 0; i < mesh->GetNE(); i++)
11580  {
11581  const Element *elem = mesh->GetElement(i);
11582  elem->GetVertices(vert);
11583  const int attr = elem->GetAttribute();
11584  for (int j = 0; j < ny; j++)
11585  {
11586  int qv[4];
11587  qv[0] = vert[0] * nvy + j;
11588  qv[1] = vert[1] * nvy + j;
11589  qv[2] = vert[1] * nvy + (j + 1) % nvy;
11590  qv[3] = vert[0] * nvy + (j + 1) % nvy;
11591 
11592  mesh2d->AddQuad(qv, attr);
11593  }
11594  }
11595  // 2D boundary from the 1D boundary
11596  for (int i = 0; i < mesh->GetNBE(); i++)
11597  {
11598  const Element *elem = mesh->GetBdrElement(i);
11599  elem->GetVertices(vert);
11600  const int attr = elem->GetAttribute();
11601  for (int j = 0; j < ny; j++)
11602  {
11603  int sv[2];
11604  sv[0] = vert[0] * nvy + j;
11605  sv[1] = vert[0] * nvy + (j + 1) % nvy;
11606 
11607  if (attr%2)
11608  {
11609  Swap<int>(sv[0], sv[1]);
11610  }
11611 
11612  mesh2d->AddBdrSegment(sv, attr);
11613  }
11614  }
11615 
11616  if (!closed)
11617  {
11618  // 2D boundary from the 1D elements (bottom + top)
11619  int nba = (mesh->bdr_attributes.Size() > 0 ?
11620  mesh->bdr_attributes.Max() : 0);
11621  for (int i = 0; i < mesh->GetNE(); i++)
11622  {
11623  const Element *elem = mesh->GetElement(i);
11624  elem->GetVertices(vert);
11625  const int attr = nba + elem->GetAttribute();
11626  int sv[2];
11627  sv[0] = vert[0] * nvy;
11628  sv[1] = vert[1] * nvy;
11629 
11630  mesh2d->AddBdrSegment(sv, attr);
11631 
11632  sv[0] = vert[1] * nvy + ny;
11633  sv[1] = vert[0] * nvy + ny;
11634 
11635  mesh2d->AddBdrSegment(sv, attr);
11636  }
11637  }
11638 
11639  mesh2d->FinalizeQuadMesh(1, 0, false);
11640 
11641  GridFunction *nodes = mesh->GetNodes();
11642  if (nodes)
11643  {
11644  // duplicate the fec of the 1D mesh so that it can be deleted safely
11645  // along with its nodes, fes and fec
11646  FiniteElementCollection *fec2d = NULL;
11647  FiniteElementSpace *fes2d;
11648  const char *name = nodes->FESpace()->FEColl()->Name();
11649  string cname = name;
11650  if (cname == "Linear")
11651  {
11652  fec2d = new LinearFECollection;
11653  }
11654  else if (cname == "Quadratic")
11655  {
11656  fec2d = new QuadraticFECollection;
11657  }
11658  else if (cname == "Cubic")
11659  {
11660  fec2d = new CubicFECollection;
11661  }
11662  else if (!strncmp(name, "H1_", 3))
11663  {
11664  fec2d = new H1_FECollection(atoi(name + 7), 2);
11665  }
11666  else if (!strncmp(name, "L2_T", 4))
11667  {
11668  fec2d = new L2_FECollection(atoi(name + 10), 2, atoi(name + 4));
11669  }
11670  else if (!strncmp(name, "L2_", 3))
11671  {
11672  fec2d = new L2_FECollection(atoi(name + 7), 2);
11673  }
11674  else
11675  {
11676  delete mesh2d;
11677  mfem::err << "Extrude1D : The mesh uses unknown FE collection : "
11678  << cname << endl;
11679  mfem_error();
11680  }
11681  fes2d = new FiniteElementSpace(mesh2d, fec2d, 2);
11682  mesh2d->SetNodalFESpace(fes2d);
11683  GridFunction *nodes2d = mesh2d->GetNodes();
11684  nodes2d->MakeOwner(fec2d);
11685 
11686  NodeExtrudeCoefficient ecoeff(2, ny, sy);
11687  Vector lnodes;
11688  Array<int> vdofs2d;
11689  for (int i = 0; i < mesh->GetNE(); i++)
11690  {
11692  for (int j = ny-1; j >= 0; j--)
11693  {
11694  fes2d->GetElementVDofs(i*ny+j, vdofs2d);
11695  lnodes.SetSize(vdofs2d.Size());
11696  ecoeff.SetLayer(j);
11697  fes2d->GetFE(i*ny+j)->Project(ecoeff, T, lnodes);
11698  nodes2d->SetSubVector(vdofs2d, lnodes);
11699  }
11700  }
11701  }
11702  return mesh2d;
11703 }
11704 
11705 Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz)
11706 {
11707  if (mesh->Dimension() != 2)
11708  {
11709  mfem::err << "Extrude2D : Not a 2D mesh!" << endl;
11710  mfem_error();
11711  }
11712 
11713  int nvz = nz + 1;
11714  int nvt = mesh->GetNV() * nvz;
11715 
11716  Mesh *mesh3d = new Mesh(3, nvt, mesh->GetNE()*nz,
11717  mesh->GetNBE()*nz+2*mesh->GetNE());
11718 
11719  bool wdgMesh = false;
11720  bool hexMesh = false;
11721 
11722  // vertices
11723  double vc[3];
11724  for (int i = 0; i < mesh->GetNV(); i++)
11725  {
11726  vc[0] = mesh->GetVertex(i)[0];
11727  vc[1] = mesh->GetVertex(i)[1];
11728  for (int j = 0; j < nvz; j++)
11729  {
11730  vc[2] = sz * (double(j) / nz);
11731  mesh3d->AddVertex(vc);
11732  }
11733  }
11734  // elements
11735  Array<int> vert;
11736  for (int i = 0; i < mesh->GetNE(); i++)
11737  {
11738  const Element *elem = mesh->GetElement(i);
11739  elem->GetVertices(vert);
11740  const int attr = elem->GetAttribute();
11742  switch (geom)
11743  {
11744  case Geometry::TRIANGLE:
11745  wdgMesh = true;
11746  for (int j = 0; j < nz; j++)
11747  {
11748  int pv[6];
11749  pv[0] = vert[0] * nvz + j;
11750  pv[1] = vert[1] * nvz + j;
11751  pv[2] = vert[2] * nvz + j;
11752  pv[3] = vert[0] * nvz + (j + 1) % nvz;
11753  pv[4] = vert[1] * nvz + (j + 1) % nvz;
11754  pv[5] = vert[2] * nvz + (j + 1) % nvz;
11755 
11756  mesh3d->AddWedge(pv, attr);
11757  }
11758  break;
11759  case Geometry::SQUARE:
11760  hexMesh = true;
11761  for (int j = 0; j < nz; j++)
11762  {
11763  int hv[8];
11764  hv[0] = vert[0] * nvz + j;
11765  hv[1] = vert[1] * nvz + j;
11766  hv[2] = vert[2] * nvz + j;
11767  hv[3] = vert[3] * nvz + j;
11768  hv[4] = vert[0] * nvz + (j + 1) % nvz;
11769  hv[5] = vert[1] * nvz + (j + 1) % nvz;
11770  hv[6] = vert[2] * nvz + (j + 1) % nvz;
11771  hv[7] = vert[3] * nvz + (j + 1) % nvz;
11772 
11773  mesh3d->AddHex(hv, attr);
11774  }
11775  break;
11776  default:
11777  mfem::err << "Extrude2D : Invalid 2D element type \'"
11778  << geom << "\'" << endl;
11779  mfem_error();
11780  break;
11781  }
11782  }
11783  // 3D boundary from the 2D boundary
11784  for (int i = 0; i < mesh->GetNBE(); i++)
11785  {
11786  const Element *elem = mesh->GetBdrElement(i);
11787  elem->GetVertices(vert);
11788  const int attr = elem->GetAttribute();
11789  for (int j = 0; j < nz; j++)
11790  {
11791  int qv[4];
11792  qv[0] = vert[0] * nvz + j;
11793  qv[1] = vert[1] * nvz + j;
11794  qv[2] = vert[1] * nvz + (j + 1) % nvz;
11795  qv[3] = vert[0] * nvz + (j + 1) % nvz;
11796 
11797  mesh3d->AddBdrQuad(qv, attr);
11798  }
11799  }
11800 
11801  // 3D boundary from the 2D elements (bottom + top)
11802  int nba = (mesh->bdr_attributes.Size() > 0 ?
11803  mesh->bdr_attributes.Max() : 0);
11804  for (int i = 0; i < mesh->GetNE(); i++)
11805  {
11806  const Element *elem = mesh->GetElement(i);
11807  elem->GetVertices(vert);
11808  const int attr = nba + elem->GetAttribute();
11810  switch (geom)
11811  {
11812  case Geometry::TRIANGLE:
11813  {
11814  int tv[3];
11815  tv[0] = vert[0] * nvz;
11816  tv[1] = vert[2] * nvz;
11817  tv[2] = vert[1] * nvz;
11818 
11819  mesh3d->AddBdrTriangle(tv, attr);
11820 
11821  tv[0] = vert[0] * nvz + nz;
11822  tv[1] = vert[1] * nvz + nz;
11823  tv[2] = vert[2] * nvz + nz;
11824 
11825  mesh3d->AddBdrTriangle(tv, attr);
11826  }
11827  break;
11828  case Geometry::SQUARE:
11829  {
11830  int qv[4];
11831  qv[0] = vert[0] * nvz;
11832  qv[1] = vert[3] * nvz;
11833  qv[2] = vert[2] * nvz;
11834  qv[3] = vert[1] * nvz;
11835 
11836  mesh3d->AddBdrQuad(qv, attr);
11837 
11838  qv[0] = vert[0] * nvz + nz;
11839  qv[1] = vert[1] * nvz + nz;
11840  qv[2] = vert[2] * nvz + nz;
11841  qv[3] = vert[3] * nvz + nz;
11842 
11843  mesh3d->AddBdrQuad(qv, attr);
11844  }
11845  break;
11846  default:
11847  mfem::err << "Extrude2D : Invalid 2D element type \'"
11848  << geom << "\'" << endl;
11849  mfem_error();
11850  break;
11851  }
11852  }
11853 
11854  if ( hexMesh && wdgMesh )
11855  {
11856  mesh3d->FinalizeMesh(0, false);
11857  }
11858  else if ( hexMesh )
11859  {
11860  mesh3d->FinalizeHexMesh(1, 0, false);
11861  }
11862  else if ( wdgMesh )
11863  {
11864  mesh3d->FinalizeWedgeMesh(1, 0, false);
11865  }
11866 
11867  GridFunction *nodes = mesh->GetNodes();
11868  if (nodes)
11869  {
11870  // duplicate the fec of the 2D mesh so that it can be deleted safely
11871  // along with its nodes, fes and fec
11872  FiniteElementCollection *fec3d = NULL;
11873  FiniteElementSpace *fes3d;
11874  const char *name = nodes->FESpace()->FEColl()->Name();
11875  string cname = name;
11876  if (cname == "Linear")
11877  {
11878  fec3d = new LinearFECollection;
11879  }
11880  else if (cname == "Quadratic")
11881  {
11882  fec3d = new QuadraticFECollection;
11883  }
11884  else if (cname == "Cubic")
11885  {
11886  fec3d = new CubicFECollection;
11887  }
11888  else if (!strncmp(name, "H1_", 3))
11889  {
11890  fec3d = new H1_FECollection(atoi(name + 7), 3);
11891  }
11892  else if (!strncmp(name, "L2_T", 4))
11893  {
11894  fec3d = new L2_FECollection(atoi(name + 10), 3, atoi(name + 4));
11895  }
11896  else if (!strncmp(name, "L2_", 3))
11897  {
11898  fec3d = new L2_FECollection(atoi(name + 7), 3);
11899  }
11900  else
11901  {
11902  delete mesh3d;
11903  mfem::err << "Extrude3D : The mesh uses unknown FE collection : "
11904  << cname << endl;
11905  mfem_error();
11906  }
11907  fes3d = new FiniteElementSpace(mesh3d, fec3d, 3);
11908  mesh3d->SetNodalFESpace(fes3d);
11909  GridFunction *nodes3d = mesh3d->GetNodes();
11910  nodes3d->MakeOwner(fec3d);
11911 
11912  NodeExtrudeCoefficient ecoeff(3, nz, sz);
11913  Vector lnodes;
11914  Array<int> vdofs3d;
11915  for (int i = 0; i < mesh->GetNE(); i++)
11916  {
11918  for (int j = nz-1; j >= 0; j--)
11919  {
11920  fes3d->GetElementVDofs(i*nz+j, vdofs3d);
11921  lnodes.SetSize(vdofs3d.Size());
11922  ecoeff.SetLayer(j);
11923  fes3d->GetFE(i*nz+j)->Project(ecoeff, T, lnodes);
11924  nodes3d->SetSubVector(vdofs3d, lnodes);
11925  }
11926  }
11927  }
11928  return mesh3d;
11929 }
11930 
11931 #ifdef MFEM_DEBUG
11932 void Mesh::DebugDump(std::ostream &out) const
11933 {
11934  // dump vertices and edges (NCMesh "nodes")
11935  out << NumOfVertices + NumOfEdges << "\n";
11936  for (int i = 0; i < NumOfVertices; i++)
11937  {
11938  const double *v = GetVertex(i);
11939  out << i << " " << v[0] << " " << v[1] << " " << v[2]
11940  << " 0 0 " << i << " -1 0\n";
11941  }
11942 
11943  Array<int> ev;
11944  for (int i = 0; i < NumOfEdges; i++)
11945  {
11946  GetEdgeVertices(i, ev);
11947  double mid[3] = {0, 0, 0};
11948  for (int j = 0; j < 2; j++)
11949  {
11950  for (int k = 0; k < spaceDim; k++)
11951  {
11952  mid[k] += GetVertex(ev[j])[k];
11953  }
11954  }
11955  out << NumOfVertices+i << " "
11956  << mid[0]/2 << " " << mid[1]/2 << " " << mid[2]/2 << " "
11957  << ev[0] << " " << ev[1] << " -1 " << i << " 0\n";
11958  }
11959 
11960  // dump elements
11961  out << NumOfElements << "\n";
11962  for (int i = 0; i < NumOfElements; i++)
11963  {
11964  const Element* e = elements[i];
11965  out << e->GetNVertices() << " ";
11966  for (int j = 0; j < e->GetNVertices(); j++)
11967  {
11968  out << e->GetVertices()[j] << " ";
11969  }
11970  out << e->GetAttribute() << " 0 " << i << "\n";
11971  }
11972 
11973  // dump faces
11974  out << "0\n";
11975 }
11976 #endif
11977 
11978 }
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:4449
Abstract class for all finite elements.
Definition: fe.hpp:243
const IntegrationRule * IntRule
Definition: mesh.hpp:1613
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition: fespace.hpp:584
Geometry::Type GetGeometryType() const
Definition: element.hpp:52
void Loader(std::istream &input, int generate_edges=0, std::string parse_tag="")
Definition: mesh.cpp:3530
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:552
int Size() const
Return the logical size of the array.
Definition: array.hpp:134
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:551
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:10801
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:9615
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition: mesh.cpp:5758
static const int vtk_quadratic_hex[27]
Definition: mesh.hpp:181
virtual void Print(std::ostream &out=mfem::out) const
Definition: mesh.hpp:1387
int * CartesianPartitioning(int nxyz[])
Definition: mesh.cpp:6438
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.hpp:317
int Push(int i, int j)
Definition: table.cpp:220
int GetNDofs() const
Returns number of degrees of freedom.
Definition: fespace.hpp:537
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:678
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
int GetNV() const
Definition: nurbs.hpp:353
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition: mesh.hpp:1203
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:917
void NewDataAndSize(double *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition: vector.hpp:153
void ScaleElements(double sf)
Definition: mesh.cpp:10938
static const int HighOrderMap[Geometry::NUM_GEOMETRIES]
Definition: vtk.hpp:53
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:233
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T...
Definition: array.hpp:252
Table * GetEdgeVertexTable() const
Returns the edge-to-vertex Table (3D)
Definition: mesh.cpp:5573
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:5474
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition: array.hpp:288
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:804
void FreeElement(Element *E)
Definition: mesh.cpp:11252
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:2905
int AddQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1324
int CheckElementOrientation(bool fix_it=true)
Check (and optionally attempt to fix) the orientation of the elements.
Definition: mesh.cpp:4953
void SetVertices(const Vector &vert_coord)
Definition: mesh.cpp:7283
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:920
static const int vtk_quadratic_tet[10]
Definition: mesh.hpp:179
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:5536
void Make2D(int nx, int ny, Element::Type type, double sx, double sy, bool generate_edges, bool sfc_ordering)
Definition: mesh.cpp:2913
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition: eltrans.hpp:149
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:1643
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:78
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:1587
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:11527
static Mesh MakeSimplicial(const Mesh &orig_mesh)
Definition: mesh.cpp:4120
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:7588
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:85
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.cpp:126
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
static const int NumGeom
Definition: geom.hpp:41
Array< Slave > slaves
Definition: ncmesh.hpp:211
Array< Element * > boundary
Definition: mesh.hpp:91
void JacToPerfJac(int GeomType, const DenseMatrix &J, DenseMatrix &PJ) const
Definition: geom.cpp:734
int * GeneratePartitioning(int nparts, int part_method=1)
Definition: mesh.cpp:6477
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:5691
CoarseFineTransformations CoarseFineTr
Definition: mesh.hpp:171
int own_nodes
Definition: mesh.hpp:177
virtual void LimitNCLevel(int max_nc_level)
Definition: ncmesh.cpp:5279
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition: mesh.cpp:5428
bool Conforming() const
Definition: mesh.hpp:1366
void MoveVertices(const Vector &displacements)
Definition: mesh.cpp:7263
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:513
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:849
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:262
void PrintWithPartitioning(int *partitioning, std::ostream &out, 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:10310
const Geometry::Type geom
Definition: ex1.cpp:40
double Det() const
Definition: densemat.cpp:451
static FiniteElement * GetTransformationFEforElementType(Element::Type)
Definition: mesh.cpp:327
void SetElementOrder(int i, int p)
Sets the order of the i&#39;th finite element.
Definition: fespace.cpp:133
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:3297
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
Definition: mesh.cpp:7367
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:304
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:324
void UniformRefinement()
Definition: nurbs.cpp:3105
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:207
virtual void UniformRefinement2D()
Refine a mixed 2D mesh uniformly.
Definition: mesh.hpp:326
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Definition: mesh.cpp:7386
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:476
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:791
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition: mesh.cpp:5748
double Norml2() const
Returns the l2 norm of the vector.
Definition: vector.cpp:783
void ReadNetgen2DMesh(std::istream &input, int &curved)
void ShiftRight(int &a, int &b, int &c)
Definition: mesh.hpp:1684
void SetDims(int rows, int nnz)
Definition: table.cpp:144
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:205
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:5753
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:85
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:851
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:3307
A specialized ElementTransformation class representing a face and its two neighboring elements...
Definition: eltrans.hpp:467
unsigned matrix
index into NCList::point_matrices[geom]
Definition: ncmesh.hpp:197
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:525
T * GetData()
Returns the data.
Definition: array.hpp:108
unsigned int uint
Definition: gecko.hpp:204
void WriteBinaryOrASCII< float >(std::ostream &out, std::vector< char > &buf, const float &val, const char *suffix, VTKFormat format)
Definition: mesh.cpp:9867
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:1649
int GetNKV() const
Definition: nurbs.hpp:350
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:245
static const int Edges[NumEdges][2]
Definition: geom.hpp:241
void GetMeshComponents(Mesh &mesh) const
Fill Mesh::{vertices,elements,boundary} for the current finest level.
Definition: ncmesh.cpp:2269
int VectorDim() const
Definition: gridfunc.cpp:311
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:5439
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:224
Piecewise-(bi/tri)linear continuous finite elements.
Definition: fe_coll.hpp:523
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
GridFunction * Nodes
Definition: mesh.hpp:176
int Size() const
Returns the size of the vector.
Definition: vector.hpp:190
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:5476
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:191
Mesh * Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
Extrude a 1D mesh.
Definition: mesh.cpp:11545
int idxtype
Definition: mesh.cpp:44
int GetElementOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:160
void Transform(void(*f)(const Vector &, Vector &))
Definition: mesh.cpp:11008
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:511
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:5714
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:7396
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:846
static int GetQuadrature1D(int b_type)
Get the corresponding Quadrature1D constant, when that makes sense; otherwise return Quadrature1D::In...
Definition: fe.hpp:63
void FinalizeWedgeMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a wedge Mesh.
Definition: mesh.cpp:2435
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:1231
double kappa
Definition: ex24.cpp:54
void PrintVTU(std::ostream &out, int ref=1, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0, bool bdr_elements=false)
Definition: mesh.cpp:9884
Evaluate the derivatives at quadrature points.
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition: mesh.hpp:1555
NodeExtrudeCoefficient(const int dim, const int n_, const double s_)
Definition: mesh.cpp:11521
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec and fes.
Definition: gridfunc.hpp:118
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:3486
virtual void GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element &#39;elem&#39;.
Definition: fespace.cpp:2298
virtual void Transform(const IntegrationPoint &, Vector &)
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Definition: eltrans.cpp:479
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:5136
Data type quadrilateral element.
void GetVertices(Vector &vert_coord) const
Definition: mesh.cpp:7272
void ReadNetgen3DMesh(std::istream &input)
bool UsesTensorBasis(const FiniteElementSpace &fes)
Definition: fespace.hpp:957
The inverse transformation of a given ElementTransformation.
Definition: eltrans.hpp:172
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:70
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:199
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:361
virtual int OrderJ() const =0
Return the order of the elements of the Jacobian of the transformation.
void RemoveInternalBoundaries()
Definition: mesh.cpp:11164
void DebugDump(std::ostream &out) const
Output an NCMesh-compatible debug dump.
Definition: mesh.cpp:11932
Mesh * Extrude2D(Mesh *mesh, const int nz, const double sz)
Extrude a 2D mesh.
Definition: mesh.cpp:11705
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:971
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:1122
Array< Element * > faces
Definition: mesh.hpp:92
int spaceDim
dimensions of the elements and the vertex coordinates
Definition: ncmesh.hpp:398
virtual long ReduceInt(int value) const
Utility function: sum integers from all processors (Allreduce).
Definition: mesh.hpp:869
const IntegrationRule * GetVertices(int GeomType)
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType...
Definition: geom.cpp:225
void FinalizeHexMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a hexahedral Mesh.
Definition: mesh.cpp:2470
friend class NURBSExtension
Definition: mesh.hpp:59
Geometry::Type GetBdrElementGeometry(int i) const
Definition: mesh.hpp:962
void GetVertexToVertexTable(DSTable &) const
Definition: mesh.cpp:5829
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:288
Operation last_operation
Definition: mesh.hpp:218
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:979
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:291
void DeleteAll()
Delete the whole array.
Definition: array.hpp:841
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:108
int Dimension() const
Definition: nurbs.hpp:340
int master
master number (in Mesh numbering)
Definition: ncmesh.hpp:196
void InitRefinementTransforms()
Definition: mesh.cpp:9233
const NCList & GetFaceList()
Return the current list of conforming and nonconforming faces.
Definition: ncmesh.hpp:233
void UniformRefinement2D_base(bool update_nodes=true)
Definition: mesh.cpp:7429
Array< NCFaceInfo > nc_faces_info
Definition: mesh.hpp:154
Element * ReadElement(std::istream &)
Definition: mesh.cpp:3468
void KnotInsert(Array< KnotVector * > &kv)
Definition: mesh.cpp:4608
void OnMeshUpdated(Mesh *mesh)
Definition: ncmesh.cpp:2365
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:4483
Element * NewElement(int geom)
Definition: mesh.cpp:3415
Table * el_to_face
Definition: mesh.hpp:157
void SetTransformation(ElementTransformation &Trans)
Set a new forward ElementTransformation, Trans.
Definition: eltrans.hpp:279
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2662
void SetVerticesFromNodes(const GridFunction *nodes)
Helper to set vertex coordinates given a high-order curvature function.
Definition: mesh.cpp:4901
Structure for storing face geometric factors: coordinates, Jacobians, determinants of the Jacobians...
Definition: mesh.hpp:1609
ElementTransformation * GetBdrElementTransformation(int i)
Returns the transformation defining the i-th boundary element.
Definition: mesh.cpp:428
virtual void UpdateMeshPointer(Mesh *new_mesh)
Definition: fespace.cpp:3003
int AddBdrTriangle(int v1, int v2, int v3, int attr=1)
Definition: mesh.cpp:1454
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:9573
const Operator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition: fespace.cpp:1195
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:4915
void MakeRefined_(Mesh &orig_mesh, const Array< int > ref_factors, int ref_type)
Internal function used in Mesh::MakeRefined.
Definition: mesh.cpp:3897
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:3484
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe.hpp:320
friend class NCMesh
Definition: mesh.hpp:58
Piecewise-(bi)cubic continuous finite elements.
Definition: fe_coll.hpp:602
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:567
uint rank(Node::Index i) const
Definition: gecko.hpp:672
double Weight() const
Definition: densemat.cpp:508
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
void WriteBase64WithSizeAndClear(std::ostream &out, std::vector< char > &buf, int compression_level)
Definition: mesh.cpp:9876
static int GetTetOrientation(const int *base, const int *test)
Returns the orientation of &quot;test&quot; relative to &quot;base&quot;.
Definition: mesh.cpp:5184
Geometry Geometries
Definition: fe.cpp:13507
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:250
long GetSequence() const
Definition: mesh.hpp:1380
void GetVertexDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2619
int AddVertex(double x, double y=0.0, double z=0.0)
Definition: mesh.cpp:1263
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition: eltrans.hpp:388
bool Nonconforming() const
Definition: mesh.hpp:1367
const int * GetDofMap(Geometry::Type GeomType) const
Get the Cartesian to local H1 dof map.
Definition: fe_coll.cpp:1881
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:203
uint Index
Definition: gecko.hpp:595
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:1596
FaceType
Definition: mesh.hpp:45
static const int Edges[NumEdges][2]
Definition: geom.hpp:155
void MoveNodes(const Vector &displacements)
Definition: mesh.cpp:7331
The point is inside the element.
Definition: eltrans.hpp:211
double f(const Vector &xvec)
Definition: lor_mms.hpp:32
void UpdateNURBS()
Definition: mesh.cpp:4682
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:1778
DenseTensor point_matrices[Geometry::NumGeom]
Matrices for IsoparametricTransformation organized by Geometry::Type.
Definition: ncmesh.hpp:63
Native ordering as defined by the FiniteElement.
void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
Definition: mesh.cpp:6925
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:2675
void AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
Definition: mesh.cpp:5979
virtual void SetAttributes()
Definition: mesh.cpp:1209
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:746
void SetType(const int t)
Set the Quadrature1D type of points to use for subdivision.
Definition: geom.hpp:286
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition: mesh.cpp:8800
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: triangle.hpp:61
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:410
IntegrationPointTransformation Loc1
Definition: eltrans.hpp:511
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:1602
int FindCoarseElement(int i)
Definition: mesh.cpp:9245
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:153
virtual void Derefine(const Array< int > &derefs)
Definition: ncmesh.cpp:1822
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:3556
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:9143
static const int Map[Geometry::NUM_GEOMETRIES]
Definition: vtk.hpp:51
Float cost() const
Definition: gecko.cpp:856
void AddQuadFaceElement(int lf, int gf, int el, int v0, int v1, int v2, int v3)
Definition: mesh.cpp:6044
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:111
Type
Ordering methods:
Definition: fespace.hpp:32
static const int NumVerts[NumGeom]
Definition: geom.hpp:48
void CheckPartitioning(int *partitioning_)
Definition: mesh.cpp:6868
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:4747
void ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition: mesh.cpp:6263
void Reset()
Force the reevaluation of the Jacobian in the next call.
Definition: eltrans.hpp:81
A pair of objects.
Definition: sort_pairs.hpp:23
void WriteBinaryOrASCII< uint8_t >(std::ostream &out, std::vector< char > &buf, const uint8_t &val, const char *suffix, VTKFormat format)
Definition: mesh.cpp:9839
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Definition: mesh.cpp:4882
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:5776
void InitTables()
Definition: mesh.cpp:1116
void CheckDisplacements(const Vector &displacements, double &tmax)
Definition: mesh.cpp:7186
NURBSExtension * StealNURBSext()
Definition: fespace.cpp:1854
Array< DenseMatrix * > point_matrices[Geometry::NumGeom]
List of unique point matrices for each slave geometry.
Definition: ncmesh.hpp:214
VTKFormat
Definition: vtk.hpp:61
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition: fe.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:152
int AddBdrSegment(int v1, int v2, int attr=1)
Definition: mesh.cpp:1440
int AddElement(Element *elem)
The parameter elem should be allocated using the NewElement() method.
Definition: mesh.cpp:1426
int GetMaxElementOrder() const
Return the maximum polynomial order.
Definition: fespace.hpp:428
void ReadLineMesh(std::istream &input)
Array< Embedding > embeddings
Fine element positions in their parents.
Definition: ncmesh.hpp:65
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:820
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:1518
const CoarseFineTransformations & GetRefinementTransforms()
Definition: ncmesh.cpp:4315
void SetLayer(const int l)
Definition: mesh.hpp:1668
int GetAttribute() const
Return element&#39;s attribute.
Definition: element.hpp:55
int GetElementToEdgeTable(Table &, Array< int > &)
Definition: mesh.cpp:5854
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition: array.hpp:285
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:5726
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition: fespace.hpp:875
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:123
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:8824
Data type triangle element.
Definition: triangle.hpp:23
void MarkCoarseLevel()
Definition: ncmesh.cpp:4269
void WriteBinaryOrASCII(std::ostream &out, std::vector< char > &buf, const T &val, const char *suffix, VTKFormat format)
Definition: mesh.cpp:9830
const Element * GetElement(int i) const
Definition: mesh.hpp:942
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Definition: triangle.cpp:45
void ResetLazyData()
Definition: mesh.cpp:1199
void GetElementTopo(Array< Element * > &elements) const
Definition: nurbs.cpp:2445
IntegrationRule RefPts
Definition: geom.hpp:262
signed char local
local number within &#39;element&#39;
Definition: ncmesh.hpp:171
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
Definition: densemat.hpp:795
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:244
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
Definition: geom.cpp:942
int GetVDim()
Returns dimension of the vector.
void Init()
Definition: mesh.cpp:1098
virtual void GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element &#39;bel&#39;.
Definition: fespace.cpp:2418
void SetNodalFESpace(FiniteElementSpace *nfes)
Definition: mesh.cpp:4843
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:534
Vector normal
Normals at all quadrature points.
Definition: mesh.hpp:1656
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
Definition: ncmesh.hpp:109
static const int Edges[NumEdges][2]
Definition: geom.hpp:201
void SetData(double *d)
Definition: vector.hpp:140
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:629
int Dimension() const
Definition: mesh.hpp:911
virtual void ReorientTetMesh()
Definition: mesh.cpp:6376
prob_type prob
Definition: ex25.cpp:153
int NumOfBdrElements
Definition: mesh.hpp:69
Table * el_to_edge
Definition: mesh.hpp:156
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:1228
static const int QuadraticMap[Geometry::NUM_GEOMETRIES]
Definition: vtk.hpp:52
void GetColumn(int c, Vector &col) const
Definition: densemat.cpp:1285
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:430
double DistanceTo(const double *p) const
Compute the Euclidean distance to another vector.
Definition: vector.hpp:654
void ReadMFEMMesh(std::istream &input, int version, int &curved)
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: triangle.hpp:62
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:8180
class H1_WedgeElement WedgeFE
void FindPartitioningComponents(Table &elem_elem, const Array< int > &partitioning, Array< int > &component, Array< int > &num_comp)
Definition: mesh.cpp:6797
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
void MakeTopologyOnly()
Definition: ncmesh.hpp:393
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2629
List of mesh geometries stored as Array&lt;Geometry::Type&gt;.
Definition: mesh.hpp:994
A general vector function coefficient.
int CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition: mesh.cpp:5317
int SpaceDimension() const
Definition: mesh.hpp:912
GeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, MemoryType d_mt=MemoryType::DEFAULT)
Definition: mesh.cpp:11392
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:10429
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition: mesh.hpp:1165
static const int Edges[NumEdges][2]
Definition: geom.hpp:181
void AddPointFaceElement(int lf, int gf, int el)
Used in GenerateFaces()
Definition: mesh.cpp:5947
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
Definition: mesh.cpp:1055
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:3091
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:625
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:204
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
Definition: mesh.cpp:8422
void PrintVTK(std::ostream &out)
Definition: mesh.cpp:9629
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:2500
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:412
Table * el_to_el
Definition: mesh.hpp:158
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
Definition: mesh.cpp:1061
MPI_Comm GetComm() const
Definition: pmesh.hpp:276
int SpaceDimension() const
Definition: ncmesh.hpp:129
void Finalize()
Definition: table.cpp:243
Nonconforming edge/face within a bigger edge/face.
Definition: ncmesh.hpp:194
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:87
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe.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:3269
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition: mesh.cpp:11057
static void PrintElement(const Element *, std::ostream &)
Definition: mesh.cpp:3480
virtual void NURBSUniformRefinement()
Refine NURBS mesh.
Definition: mesh.cpp:4652
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:1373
const IntegrationRule * IntRule
Definition: mesh.hpp:1564
MemoryType
Memory types supported by MFEM.
Definition: mem_manager.hpp:31
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:1634
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition: mesh.cpp:2507
static void GetElementArrayEdgeTable(const Array< Element * > &elem_array, const DSTable &v_to_v, Table &el_to_edge)
Definition: mesh.cpp:5807
void AddAColumnInRow(int r)
Definition: table.hpp:77
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition: mesh.hpp:1258
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:674
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
Definition: mesh.cpp:2098
int AddBdrQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1468
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:414
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition: eltrans.cpp:533
int FindRoots(const Vector &z, Vector &x)
Definition: mesh.cpp:7005
bool IsSlaveFace(const FaceInfo &fi) const
Definition: mesh.cpp:976
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:135
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:3287
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Definition: mesh.cpp:1240
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
virtual void PrintXG(std::ostream &out=mfem::out) const
Print the mesh to the given stream using Netgen/Truegrid format.
Definition: mesh.cpp:9318
Geometry::Type GetElementGeometry(int i) const
Definition: mesh.hpp:957
void RefineAtVertex(const Vertex &vert, double eps=0.0, int nonconforming=-1)
Refine elements sharing the specified vertex. Uses GeneralRefinement.
Definition: mesh.cpp:8843
class Linear3DFiniteElement TetrahedronFE
Definition: fe.cpp:13494
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:3279
Array< Element * > elements
Definition: mesh.hpp:85
const Table & ElementToElementTable()
Definition: mesh.cpp:5893
double GetLength(int i, int j) const
Return the length of the segment from node i to node j.
Definition: mesh.cpp:5792
void SetRelaxedHpConformity(bool relaxed=true)
Definition: fespace.hpp:889
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition: gridfunc.cpp:164
void ShiftUpI()
Definition: table.cpp:119
Linear2DFiniteElement TriangleFE
Definition: fe.cpp:13490
int meshgen
Definition: mesh.hpp:77
static const int FaceVert[NumFaces][MaxFaceVert]
Definition: geom.hpp:227
const CoarseFineTransformations & GetRefinementTransforms()
Definition: mesh.cpp:9255
bool RefineByError(const Array< double > &elem_error, double threshold, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:8869
Table * bel_to_edge
Definition: mesh.hpp:160
Evaluate the values at quadrature points.
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition: mesh.hpp:1374
Table * GetFaceToElementTable() const
Definition: mesh.cpp:5634
int GetNE() const
Definition: nurbs.hpp:355
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:206
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:843
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:9821
void GetNode(int i, double *coord) const
Definition: mesh.cpp:7292
Array< int > be_to_edge
Definition: mesh.hpp:159
virtual const char * Name() const
Definition: fe_coll.hpp:61
const Table & ElementToFaceTable() const
Definition: mesh.cpp:5929
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:3438
void Swap(Mesh &other, bool non_geometry)
Definition: mesh.cpp:8612
FaceGeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, FaceType type)
Definition: mesh.cpp:11472
A standard isoparametric element transformation.
Definition: eltrans.hpp:348
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:5452
static const int vtk_quadratic_wedge[18]
Definition: mesh.hpp:180
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: mesh.cpp:347
static const int DimStart[MaxDim+2]
Definition: geom.hpp:47
void WriteBinaryOrASCII< double >(std::ostream &out, std::vector< char > &buf, const double &val, const char *suffix, VTKFormat format)
Definition: mesh.cpp:9848
const FiniteElementSpace * GetNodalFESpace() const
Definition: mesh.cpp:4877
Table * face_edge
Definition: mesh.hpp:162
void FinalizeQuadMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a quadrilateral Mesh.
Definition: mesh.cpp:1585
Array< int > leaf_elements
finest elements, in Mesh ordering (+ ghosts)
Definition: ncmesh.hpp:511
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
Definition: mesh.cpp:2600
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:192
bool DerefineByError(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
Definition: mesh.cpp:8539
Array< Master > masters
Definition: ncmesh.hpp:210
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
Definition: mesh.cpp:5506
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2650
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition: fespace.cpp:1256
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition: fespace.hpp:65
const char * VTKByteOrder()
Definition: vtk.cpp:590
void MakeJ()
Definition: table.cpp:95
void DegreeElevate(int rel_degree, int degree=16)
Definition: mesh.cpp:4665
int dim
Definition: ex24.cpp:53
Table * edge_vertex
Definition: mesh.hpp:163
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition: eltrans.hpp:368
long sequence
Definition: mesh.hpp:83
signed char geom
Geometry::Type (faces only) (char to save RAM)
Definition: ncmesh.hpp:172
void FindTMax(Vector &c, Vector &x, double &tmax, const double factor, const int Dim)
Definition: mesh.cpp:7152
IsoparametricTransformation Transf
Definition: eltrans.hpp:451
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:2388
int index(int i, int j, int nx, int ny)
Definition: life.cpp:237
ElementTransformation * Elem1
Definition: eltrans.hpp:509
static const int Edges[NumEdges][2]
Definition: geom.hpp:223
void WriteVTKEncodedCompressed(std::ostream &out, const void *bytes, uint32_t nbytes, int compression_level)
Definition: vtk.cpp:547
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
Definition: densemat.cpp:1222
const Mesh * mesh
Definition: mesh.hpp:1563
void MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
Definition: mesh.cpp:4127
Lexicographic ordering for tensor-product FiniteElements.
Array< FaceInfo > faces_info
Definition: mesh.hpp:153
double infinity()
Define a shortcut for std::numeric_limits&lt;double&gt;::infinity()
Definition: vector.hpp:46
virtual int GetNVertices() const =0
int parent
Element index in the coarse mesh.
Definition: ncmesh.hpp:49
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:2278
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:214
STable3D * GetFacesTable()
Definition: mesh.cpp:6214
Piecewise-(bi)quadratic continuous finite elements.
Definition: fe_coll.hpp:550
int Dimension() const
Definition: ncmesh.hpp:128
void AppendBytes(std::vector< char > &vec, const T &val)
Append the binary representation of val to the byte buffer vec.
Definition: binaryio.hpp:55
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
Definition: sparsemat.hpp:655
NCMesh * ncmesh
Optional non-conforming mesh extension.
Definition: mesh.hpp:207
Geometry::Type GetBdrElementBaseGeometry(int i) const
Definition: mesh.hpp:974
virtual void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level)
Definition: ncmesh.cpp:1793
virtual void UniformRefinement3D()
Refine a mixed 3D mesh uniformly.
Definition: mesh.hpp:336
int AddBdrElement(Element *elem)
Definition: mesh.cpp:1433
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:3456
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr=1)
Definition: mesh.cpp:1359
BlockArray< Element > elements
Definition: ncmesh.hpp:482
virtual bool NonconformingDerefinement(Array< double > &elem_error, double threshold, int nc_limit=0, int op=1)
NC version of GeneralDerefinement.
Definition: mesh.cpp:8491
int Dim
Definition: mesh.hpp:66
void Clear()
Clear the contents of the Mesh.
Definition: mesh.hpp:828
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:852
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:45
double AggregateError(const Array< double > &elem_error, const int *fine, int nfine, int op)
Derefinement helper.
Definition: mesh.cpp:8472
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:855
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:11277
Mesh & operator=(Mesh &&mesh)
Move assignment operstor.
Definition: mesh.cpp:3263
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:554
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:7343
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition: mesh.cpp:4941
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:5088
void SetNode(int i, const double *coord)
Definition: mesh.cpp:7311
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)
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:371
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:216
void XYZ_VectorFunction(const Vector &p, Vector &v)
Definition: mesh.cpp:4806
void GenerateFaces()
Definition: mesh.cpp:6071
void GetElementColoring(Array< int > &colors, int el0=0)
Definition: mesh.cpp:10235
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:3349
int spaceDim
Definition: mesh.hpp:67
Defines the coarse-fine transformations of all fine elements.
Definition: ncmesh.hpp:60
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:240
MemAlloc< Tetrahedron, 1024 > TetMemory
Definition: mesh.hpp:185
int GetNBE() const
Definition: nurbs.hpp:357
Table * GetFaceEdgeTable() const
Returns the face-to-edge Table (3D)
Definition: mesh.cpp:5545
bool IsGhost(const Element &el) const
Definition: ncmesh.hpp:541
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag)
Definition: tetrahedron.cpp:55
Node::Index insert_node(Float length=1)
Definition: gecko.cpp:656
TriLinear3DFiniteElement HexahedronFE
Definition: hexahedron.cpp:52
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
Definition: mesh.cpp:2164
void SetNodes(const Vector &node_coord)
Definition: mesh.cpp:7355
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:4871
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]
Definition: vtk.hpp:49
void ScaleSubdomains(double sf)
Definition: mesh.cpp:10868
Array< int > be_to_face
Definition: mesh.hpp:161
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:8568
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:8898
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:462
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition: eltrans.hpp:391
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:169
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition: mesh.cpp:8732
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:745
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:377
Abstract data type element.
Definition: element.hpp:28
int GetAttribute(int i) const
Return the attribute of element i.
Definition: mesh.hpp:1197
void AddTriangleFaceElement(int lf, int gf, int el, int v0, int v1, int v2)
Definition: mesh.cpp:6016
const Table & ElementToEdgeTable() const
Definition: mesh.cpp:5938
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:208
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition: fespace.hpp:561
void BdrBisection(int i, const HashTable< Hashed2 > &)
Bisect a boundary triangle: boundary element with index i is bisected.
Definition: mesh.cpp:9106
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:1015
int NumberOfElements()
Return the number of elements added to the table.
Definition: stable3d.hpp:70
void GenerateNCFaceInfo()
Definition: mesh.cpp:6156
Array< int > RefGeoms
Definition: geom.hpp:263
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition: mesh.hpp:1011
friend class Tetrahedron
Definition: mesh.hpp:184
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:202
Table * GetVertexToElementTable()
The returned Table must be destroyed by the caller.
Definition: mesh.cpp:5599
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:946
void EnsureNodes()
Definition: mesh.cpp:4849
void ConvertToPatches(const Vector &Nodes)
Definition: nurbs.cpp:2955
static const int Orient[NumOrient][NumVert]
Definition: geom.hpp:171
void GetElementData(const Array< Element * > &elem_array, int geom, Array< int > &elem_vtx, Array< int > &attr) const
Definition: mesh.cpp:8668
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:7417
Defines the position of a fine element within a coarse element.
Definition: ncmesh.hpp:46
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:1528
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:5668
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition: mesh.hpp:294
int matrix
Index into the DenseTensor corresponding to the parent Geometry::Type stored in CoarseFineTransformat...
Definition: ncmesh.hpp:52
Arbitrary order &quot;L2-conforming&quot; discontinuous finite elements.
Definition: fe_coll.hpp:285
Evaluate the values at quadrature points.
void Printer(std::ostream &out=mfem::out, std::string section_delimiter="") const
Definition: mesh.cpp:9482
Class used to extrude the nodes of a mesh.
Definition: mesh.hpp:1660
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:197
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:1285
int NumOfFaces
Definition: mesh.hpp:70