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" {
46    void METIS_PartGraphRecursive(int*, idxtype*, idxtype*, idxtype*, idxtype*,
47                                  int*, int*, int*, int*, int*, idxtype*);
48    void METIS_PartGraphKway(int*, idxtype*, idxtype*, idxtype*, idxtype*,
49                             int*, int*, int*, int*, int*, idxtype*);
50    void METIS_PartGraphVKway(int*, idxtype*, idxtype*, idxtype*, idxtype*,
51                              int*, int*, int*, int*, int*, idxtype*);
52 }
53 #endif
54 
55 using namespace std;
56 
57 namespace mfem
58 {
59 
GetElementJacobian(int i,DenseMatrix & J)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 
GetElementCenter(int i,Vector & center)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 
GetElementSize(ElementTransformation * T,int type)76 double Mesh::GetElementSize(ElementTransformation *T, int type)
77 {
78    DenseMatrix J(Dim);
79 
80    Geometry::Type geom = T->GetGeometryType();
81    T->SetIntPoint(&Geometries.GetCenter(geom));
82    Geometries.JacToPerfJac(geom, T->Jacobian(), J);
83 
84    if (type == 0)
85    {
86       return pow(fabs(J.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 
GetElementSize(int i,int type)98 double Mesh::GetElementSize(int i, int type)
99 {
100    return GetElementSize(GetElementTransformation(i), type);
101 }
102 
GetElementSize(int i,const Vector & dir)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 
GetElementVolume(int i)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
GetBoundingBox(Vector & min,Vector & max,int ref)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;
161       FaceElementTransformations *Tr;
162       ElementTransformation *T;
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 
GetCharacteristics(double & h_min,double & h_max,double & kappa_min,double & kappa_max,Vector * Vh,Vector * Vk)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
PrintElementsByGeometry(int dim,const Array<int> & num_elems_by_geom,std::ostream & out)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 
PrintCharacteristics(Vector * Vh,Vector * Vk,std::ostream & out)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 
GetTransformationFEforElementType(Element::Type ElemType)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 
GetElementTransformation(int i,IsoparametricTransformation * ElTr)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 
GetElementTransformation(int i,const Vector & nodes,IsoparametricTransformation * ElTr)378 void Mesh::GetElementTransformation(int i, const Vector &nodes,
379                                     IsoparametricTransformation *ElTr)
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 
GetElementTransformation(int i)421 ElementTransformation *Mesh::GetElementTransformation(int i)
422 {
423    GetElementTransformation(i, &Transformation);
424 
425    return &Transformation;
426 }
427 
GetBdrElementTransformation(int i)428 ElementTransformation *Mesh::GetBdrElementTransformation(int i)
429 {
430    GetBdrElementTransformation(i, &BdrTransformation);
431    return &BdrTransformation;
432 }
433 
GetBdrElementTransformation(int i,IsoparametricTransformation * ElTr)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 
GetFaceTransformation(int FaceNo,IsoparametricTransformation * FTr)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 
GetFaceTransformation(int FaceNo)561 ElementTransformation *Mesh::GetFaceTransformation(int FaceNo)
562 {
563    GetFaceTransformation(FaceNo, &FaceTransformation);
564    return &FaceTransformation;
565 }
566 
GetEdgeTransformation(int EdgeNo,IsoparametricTransformation * EdTr)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 
GetEdgeTransformation(int EdgeNo)626 ElementTransformation *Mesh::GetEdgeTransformation(int EdgeNo)
627 {
628    GetEdgeTransformation(EdgeNo, &EdgeTransformation);
629    return &EdgeTransformation;
630 }
631 
632 
GetLocalPtToSegTransformation(IsoparametricTransformation & Transf,int i)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 
GetLocalSegToTriTransformation(IsoparametricTransformation & Transf,int i)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 
GetLocalSegToQuadTransformation(IsoparametricTransformation & Transf,int i)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 
GetLocalTriToTetTransformation(IsoparametricTransformation & Transf,int i)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 
GetLocalTriToWdgTransformation(IsoparametricTransformation & Transf,int i)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 
GetLocalQuadToHexTransformation(IsoparametricTransformation & Transf,int i)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 
GetLocalQuadToWdgTransformation(IsoparametricTransformation & Transf,int i)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 
GetGeometricFactors(const IntegrationRule & ir,const int flags,MemoryType d_mt)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 
GetFaceGeometricFactors(const IntegrationRule & ir,const int flags,FaceType type)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 
DeleteGeometricFactors()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 
GetLocalFaceTransformation(int face_type,int elem_type,IsoparametricTransformation & Transf,int info)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 
GetFaceElementTransformations(int FaceNo,int mask)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 
IsSlaveFace(const FaceInfo & fi) const976 bool Mesh::IsSlaveFace(const FaceInfo &fi) const
977 {
978    return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
979 }
980 
ApplyLocalSlaveTransformation(FaceElementTransformations & FT,const FaceInfo & fi,bool is_ghost)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
994       IsoparametricTransformation &LT = FT.Loc2.Transf;
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
1009       IsoparametricTransformation &LT = FT.Loc1.Transf;
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 
GetBdrFaceTransformations(int BdrElemNo)1020 FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
1021 {
1022    FaceElementTransformations *tr;
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 
GetBdrFace(int BdrElemNo) const1037 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 
GetFaceElements(int Face,int * Elem1,int * Elem2) const1055 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 
GetFaceInfos(int Face,int * Inf1,int * Inf2) const1061 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 
GetFaceInfos(int Face,int * Inf1,int * Inf2,int * NCFace) const1067 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 
GetFaceGeometryType(int Face) const1074 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 
GetFaceElementType(int Face) const1093 Element::Type Mesh::GetFaceElementType(int Face) const
1094 {
1095    return (Dim == 1) ? Element::POINT : faces[Face]->GetType();
1096 }
1097 
Init()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 
InitTables()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 
SetEmpty()1122 void Mesh::SetEmpty()
1123 {
1124    Init();
1125    InitTables();
1126 }
1127 
DestroyTables()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 
DestroyPointers()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 
Destroy()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 
ResetLazyData()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 
SetAttributes()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 
InitMesh(int Dim_,int spaceDim_,int NVert,int NElem,int NBdrElem)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>
CheckEnlarge(Array<T> & array,int size)1258 static void CheckEnlarge(Array<T> &array, int size)
1259 {
1260    if (size >= array.Size()) { array.SetSize(size + 1); }
1261 }
1262 
AddVertex(double x,double y,double z)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 
AddVertex(const double * coords)1273 int Mesh::AddVertex(const double *coords)
1274 {
1275    CheckEnlarge(vertices, NumOfVertices);
1276    vertices[NumOfVertices].SetCoords(spaceDim, coords);
1277    return NumOfVertices++;
1278 }
1279 
AddVertexParents(int i,int p1,int p2)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 
AddSegment(int v1,int v2,int attr)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 
AddSegment(const int * vi,int attr)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 
AddTriangle(int v1,int v2,int v3,int attr)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 
AddTriangle(const int * vi,int attr)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 
AddQuad(int v1,int v2,int v3,int v4,int attr)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 
AddQuad(const int * vi,int attr)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 
AddTet(int v1,int v2,int v3,int v4,int attr)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 
AddTet(const int * vi,int attr)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 
AddWedge(int v1,int v2,int v3,int v4,int v5,int v6,int attr)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 
AddWedge(const int * vi,int attr)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 
AddHex(int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,int attr)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 
AddHex(const int * vi,int attr)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 
AddHexAsTets(const int * vi,int attr)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 
AddHexAsWedges(const int * vi,int attr)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 
AddElement(Element * elem)1426 int Mesh::AddElement(Element *elem)
1427 {
1428    CheckEnlarge(elements, NumOfElements);
1429    elements[NumOfElements] = elem;
1430    return NumOfElements++;
1431 }
1432 
AddBdrElement(Element * elem)1433 int Mesh::AddBdrElement(Element *elem)
1434 {
1435    CheckEnlarge(boundary, NumOfBdrElements);
1436    boundary[NumOfBdrElements] = elem;
1437    return NumOfBdrElements++;
1438 }
1439 
AddBdrSegment(int v1,int v2,int attr)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 
AddBdrSegment(const int * vi,int attr)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 
AddBdrTriangle(int v1,int v2,int v3,int attr)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 
AddBdrTriangle(const int * vi,int attr)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 
AddBdrQuad(int v1,int v2,int v3,int v4,int attr)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 
AddBdrQuad(const int * vi,int attr)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 
AddBdrQuadAsTriangles(const int * vi,int attr)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 
AddBdrPoint(int v,int attr)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 
GenerateBoundaryElements()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 
FinalizeCheck()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 
FinalizeTriMesh(int generate_edges,int refine,bool fix_orientation)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 
FinalizeQuadMesh(int generate_edges,int refine,bool fix_orientation)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:
GeckoProgress(double limit)1619    GeckoProgress(double limit) : limit(limit) { sw.Start(); }
quit() const1620    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:
GeckoVerboseProgress(double limit)1629    GeckoVerboseProgress(double limit) : GeckoProgress(limit) {}
1630 
beginorder(const Graph * graph,Float cost) const1631    virtual void beginorder(const Graph* graph, Float cost) const
1632    { mfem::out << "Begin Gecko ordering, cost = " << cost << std::endl; }
endorder(const Graph * graph,Float cost) const1633    virtual void endorder(const Graph* graph, Float cost) const
1634    { mfem::out << "End ordering, cost = " << cost << std::endl; }
1635 
beginiter(const Graph * graph,uint iter,uint maxiter,uint window) const1636    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    }
enditer(const Graph * graph,Float mincost,Float cost) const1642    virtual void enditer(const Graph* graph, Float mincost, Float cost) const
1643    { mfem::out << ", cost = " << cost << endl; }
1644 };
1645 
1646 
GetGeckoElementOrdering(Array<int> & ordering,int iterations,int window,int period,int seed,bool verbose,double time_limit)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 
HilbertCmpmfem::HilbertCmp1698    HilbertCmp(int coord, bool dir, const Array<double> &points, double mid)
1699       : coord(coord), dir(dir), points(points), mid(mid) {}
1700 
operator ()mfem::HilbertCmp1701    bool operator()(int i) const
1702    {
1703       return (points[3*i + coord] < mid) != dir;
1704    }
1705 };
1706 
HilbertSort2D(int coord1,bool dir1,bool dir2,const Array<double> & points,int * beg,int * end,double xmin,double ymin,double xmax,double ymax)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 
HilbertSort3D(int coord1,bool dir1,bool dir2,bool dir3,const Array<double> & points,int * beg,int * end,double xmin,double ymin,double zmin,double xmax,double ymax,double zmax)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 
GetHilbertElementOrdering(Array<int> & ordering)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 
ReorderElements(const Array<int> & ordering,bool reorder_vertices)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 
MarkForRefinement()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 
MarkTriMeshForRefinement()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 
GetEdgeOrdering(DSTable & v_to_v,Array<int> & order)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 
MarkTetMeshForRefinement(DSTable & v_to_v)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 
PrepareNodeReorder(DSTable ** old_v_to_v,Table ** old_elem_vert)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 
DoNodeReorder(DSTable * old_v_to_v,Table * old_elem_vert)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 
FinalizeTetMesh(int generate_edges,int refine,bool fix_orientation)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 
FinalizeWedgeMesh(int generate_edges,int refine,bool fix_orientation)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 
FinalizeHexMesh(int generate_edges,int refine,bool fix_orientation)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 
FinalizeMesh(int refine,bool fix_orientation)2500 void Mesh::FinalizeMesh(int refine, bool fix_orientation)
2501 {
2502    FinalizeTopology();
2503 
2504    Finalize(refine, fix_orientation);
2505 }
2506 
FinalizeTopology(bool generate_bdr)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 
Finalize(bool refine,bool fix_orientation)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 
Make3D(int nx,int ny,int nz,Element::Type type,double sx,double sy,double sz,bool sfc_ordering)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 
Make2D(int nx,int ny,Element::Type type,double sx,double sy,bool generate_edges,bool sfc_ordering)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 
Make1D(int n,double sx)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 
Mesh(const Mesh & mesh,bool copy_nodes)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 
Mesh(Mesh && mesh)3258 Mesh::Mesh(Mesh &&mesh) : Mesh()
3259 {
3260    Swap(mesh, true);
3261 }
3262 
operator =(Mesh && mesh)3263 Mesh& Mesh::operator=(Mesh &&mesh)
3264 {
3265    Swap(mesh, true);
3266    return *this;
3267 }
3268 
LoadFromFile(const char * filename,int generate_edges,int refine,bool fix_orientation)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 
MakeCartesian1D(int n,double sx)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 
MakeCartesian2D(int nx,int ny,Element::Type type,bool generate_edges,double sx,double sy,bool sfc_ordering)3287 Mesh Mesh::MakeCartesian2D(
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 
MakeCartesian3D(int nx,int ny,int nz,Element::Type type,double sx,double sy,double sz,bool sfc_ordering)3297 Mesh Mesh::MakeCartesian3D(
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 
MakeRefined(Mesh & orig_mesh,int ref_factor,int ref_type)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 
MakeRefined(Mesh & orig_mesh,const Array<int> & ref_factors,int ref_type)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 
Mesh(const char * filename,int generate_edges,int refine,bool fix_orientation)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 
Mesh(std::istream & input,int generate_edges,int refine,bool fix_orientation)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 
ChangeVertexDataOwnership(double * vertex_data,int len_vertex_data,bool zerocopy)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 
Mesh(double * vertices_,int num_vertices,int * element_indices,Geometry::Type element_type,int * element_attributes,int num_elements,int * boundary_indices,Geometry::Type boundary_type,int * boundary_attributes,int num_boundary_elements,int dimension,int space_dimension)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 
NewElement(int geom)3415 Element *Mesh::NewElement(int geom)
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 
ReadElementWithoutAttr(std::istream & input)3438 Element *Mesh::ReadElementWithoutAttr(std::istream &input)
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 
PrintElementWithoutAttr(const Element * el,std::ostream & out)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 
ReadElement(std::istream & input)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 
PrintElement(const Element * el,std::ostream & out)3480 void Mesh::PrintElement(const Element *el, std::ostream &out)
3481 {
3482    out << el->GetAttribute() << ' ';
3483    PrintElementWithoutAttr(el, out);
3484 }
3485 
SetMeshGen()3486 void Mesh::SetMeshGen()
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:
3495             mesh_geoms |= (1 << Geometry::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);
3507          case Element::QUADRILATERAL:
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 
Loader(std::istream & input,int generate_edges,std::string parse_tag)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       }
3592       InitFromNCMesh(*ncmesh);
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'
3714       SetVerticesFromNodes(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 
Mesh(Mesh * mesh_array[],int num_pieces)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 
3764       NumOfVertices = NURBSext->GetNV();
3765       NumOfElements = NURBSext->GetNE();
3766 
3767       NURBSext->GetElementTopo(elements);
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);
3886    CheckBdrElementOrientation(false);
3887 #endif
3888 }
3889 
Mesh(Mesh * orig_mesh,int ref_factor,int ref_type)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 
MakeRefined_(Mesh & orig_mesh,const Array<int> ref_factors,int ref_type)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);
3982       Geometry::Type geom = orig_mesh.GetBdrElementBaseGeometry(el);
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;
4005    last_operation = Mesh::REFINE;
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 
MakeSimplicial(const Mesh & orig_mesh)4120 Mesh Mesh::MakeSimplicial(const Mesh &orig_mesh)
4121 {
4122    Mesh mesh;
4123    mesh.MakeSimplicial_(orig_mesh, NULL);
4124    return mesh;
4125 }
4126 
MakeSimplicial_(const Mesh & orig_mesh,int * vglobal)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          {
4298             Element *e = NewElement(Geometry::TRIANGLE);
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          {
4327             Element *e = NewElement(Geometry::TETRAHEDRON);
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          {
4390             Element *e = NewElement(Geometry::TETRAHEDRON);
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          {
4425             Element *be = NewElement(Geometry::TRIANGLE);
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 
MakePeriodic(const Mesh & orig_mesh,const std::vector<int> & v2v)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 
CreatePeriodicVertexMapping(const std::vector<Vector> & translations,double tol) const4483 std::vector<int> Mesh::CreatePeriodicVertexMapping(
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 
KnotInsert(Array<KnotVector * > & kv)4608 void Mesh::KnotInsert(Array<KnotVector *> &kv)
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 
4620    NURBSext->ConvertToPatches(*Nodes);
4621 
4622    NURBSext->KnotInsert(kv);
4623 
4624    last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
4625    sequence++;
4626 
4627    UpdateNURBS();
4628 }
4629 
KnotInsert(Array<Vector * > & kv)4630 void Mesh::KnotInsert(Array<Vector *> &kv)
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 
4642    NURBSext->ConvertToPatches(*Nodes);
4643 
4644    NURBSext->KnotInsert(kv);
4645 
4646    last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
4647    sequence++;
4648 
4649    UpdateNURBS();
4650 }
4651 
NURBSUniformRefinement()4652 void Mesh::NURBSUniformRefinement()
4653 {
4654    // do not check for NURBSext since this method is protected
4655    NURBSext->ConvertToPatches(*Nodes);
4656 
4657    NURBSext->UniformRefinement();
4658 
4659    last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
4660    sequence++;
4661 
4662    UpdateNURBS();
4663 }
4664 
DegreeElevate(int rel_degree,int degree)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 
4672    NURBSext->ConvertToPatches(*Nodes);
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 
UpdateNURBS()4682 void Mesh::UpdateNURBS()
4683 {
4684    ResetLazyData();
4685 
4686    NURBSext->SetKnotsFromPatches();
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       }
4697       NumOfElements = NURBSext->GetNE();
4698       NURBSext->GetElementTopo(elements);
4699    }
4700 
4701    if (NumOfBdrElements != NURBSext->GetNBE())
4702    {
4703       for (int i = 0; i < boundary.Size(); i++)
4704       {
4705          FreeElement(boundary[i]);
4706       }
4707       NumOfBdrElements = NURBSext->GetNBE();
4708       NURBSext->GetBdrElementTopo(boundary);
4709    }
4710 
4711    Nodes->FESpace()->Update();
4712    Nodes->Update();
4713    NURBSext->SetCoordsFromPatches(*Nodes);
4714 
4715    if (NumOfVertices != NURBSext->GetNV())
4716    {
4717       NumOfVertices = NURBSext->GetNV();
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    {
4733       NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
4734       if (Dim == 2)
4735       {
4736          GenerateFaces();
4737       }
4738    }
4739 
4740    if (el_to_face)
4741    {
4742       GetElementToFaceTable();
4743       GenerateFaces();
4744    }
4745 }
4746 
LoadPatchTopo(std::istream & input,Array<int> & edge_to_knot)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 
XYZ_VectorFunction(const Vector & p,Vector & v)4806 void XYZ_VectorFunction(const Vector &p, Vector &v)
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 
GetNodes(GridFunction & nodes) const4829 void Mesh::GetNodes(GridFunction &nodes) const
4830 {
4831    if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
4832    {
4833       const int newSpaceDim = nodes.FESpace()->GetVDim();
4834       VectorFunctionCoefficient xyz(newSpaceDim, XYZ_VectorFunction);
4835       nodes.ProjectCoefficient(xyz);
4836    }
4837    else
4838    {
4839       nodes = *Nodes;
4840    }
4841 }
4842 
SetNodalFESpace(FiniteElementSpace * nfes)4843 void Mesh::SetNodalFESpace(FiniteElementSpace *nfes)
4844 {
4845    GridFunction *nodes = new GridFunction(nfes);
4846    SetNodalGridFunction(nodes, true);
4847 }
4848 
EnsureNodes()4849 void Mesh::EnsureNodes()
4850 {
4851    if (Nodes)
4852    {
4853       const FiniteElementCollection *fec = GetNodalFESpace()->FEColl();
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 
SetNodalGridFunction(GridFunction * nodes,bool make_owner)4871 void Mesh::SetNodalGridFunction(GridFunction *nodes, bool make_owner)
4872 {
4873    GetNodes(*nodes);
4874    NewNodes(*nodes, make_owner);
4875 }
4876 
GetNodalFESpace() const4877 const FiniteElementSpace *Mesh::GetNodalFESpace() const
4878 {
4879    return ((Nodes) ? Nodes->FESpace() : NULL);
4880 }
4881 
SetCurvature(int order,bool discont,int space_dim,int ordering)4882 void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
4883 {
4884    space_dim = (space_dim == -1) ? spaceDim : space_dim;
4885    FiniteElementCollection* nfec;
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 
SetVerticesFromNodes(const GridFunction * nodes)4901 void Mesh::SetVerticesFromNodes(const GridFunction *nodes)
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 
GetNumFaces() const4915 int Mesh::GetNumFaces() const
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 
CountFacesByType(const Mesh & mesh,const FaceType type)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 
GetNFbyType(FaceType type) const4941 int Mesh::GetNFbyType(FaceType type) const
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 
CheckElementOrientation(bool fix_it)4953 int Mesh::CheckElementOrientation(bool fix_it)
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;
4991                   case Element::QUADRILATERAL:
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 
GetTriOrientation(const int * base,const int * test)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 
GetQuadOrientation(const int * base,const int * test)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 
GetTetOrientation(const int * base,const int * test)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 
CheckBdrElementOrientation(bool fix_it)5317 int Mesh::CheckBdrElementOrientation(bool fix_it)
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;
5326          NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
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             }
5370             case Element::QUADRILATERAL:
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             }
5400             case Element::QUADRILATERAL:
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 
GetNumGeometries(int dim) const5428 int Mesh::GetNumGeometries(int dim) const
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 
GetGeometries(int dim,Array<Geometry::Type> & el_geoms) const5439 void Mesh::GetGeometries(int dim, Array<Geometry::Type> &el_geoms) const
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 
GetElementEdges(int i,Array<int> & edges,Array<int> & cor) const5452 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 
GetBdrElementEdges(int i,Array<int> & edges,Array<int> & cor) const5474 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 
GetFaceEdges(int i,Array<int> & edges,Array<int> & o) const5506 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 
GetEdgeVertices(int i,Array<int> & vert) const5536 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 
GetFaceEdgeTable() const5545 Table *Mesh::GetFaceEdgeTable() const
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;
5568    GetElementArrayEdgeTable(faces, v_to_v, *face_edge);
5569 
5570    return (face_edge);
5571 }
5572 
GetEdgeVertexTable() const5573 Table *Mesh::GetEdgeVertexTable() const
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 
GetVertexToElementTable()5599 Table *Mesh::GetVertexToElementTable()
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 
GetFaceToElementTable() const5634 Table *Mesh::GetFaceToElementTable() const
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 
GetElementFaces(int i,Array<int> & faces,Array<int> & ori) const5668 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 
GetBdrElementFace(int i,int * f,int * o) const5691 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;
5706       case Element::QUADRILATERAL:
5707          *o = GetQuadOrientation(fv, bv);
5708          break;
5709       default:
5710          MFEM_ABORT("invalid geometry");
5711    }
5712 }
5713 
GetBdrElementEdgeIndex(int i) const5714 int Mesh::GetBdrElementEdgeIndex(int i) const
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 
GetBdrElementAdjacentElement(int bdr_el,int & el,int & info) const5726 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 
GetElementType(int i) const5748 Element::Type Mesh::GetElementType(int i) const
5749 {
5750    return elements[i]->GetType();
5751 }
5752 
GetBdrElementType(int i) const5753 Element::Type Mesh::GetBdrElementType(int i) const
5754 {
5755    return boundary[i]->GetType();
5756 }
5757 
GetPointMatrix(int i,DenseMatrix & pointmat) const5758 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 
GetBdrPointMatrix(int i,DenseMatrix & pointmat) const5776 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 
GetLength(int i,int j) const5792 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
GetElementArrayEdgeTable(const Array<Element * > & elem_array,const DSTable & v_to_v,Table & el_to_edge)5807 void Mesh::GetElementArrayEdgeTable(const Array<Element*> &elem_array,
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 
GetVertexToVertexTable(DSTable & v_to_v) const5829 void Mesh::GetVertexToVertexTable(DSTable &v_to_v) const
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 
GetElementToEdgeTable(Table & e_to_f,Array<int> & be_to_f)5854 int Mesh::GetElementToEdgeTable(Table & e_to_f, Array<int> &be_to_f)
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       }
5882       GetElementArrayEdgeTable(boundary, v_to_v, *bel_to_edge);
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 
ElementToElementTable()5893 const Table & Mesh::ElementToElementTable()
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 
ElementToFaceTable() const5929 const Table & Mesh::ElementToFaceTable() const
5930 {
5931    if (el_to_face == NULL)
5932    {
5933       mfem_error("Mesh::ElementToFaceTable()");
5934    }
5935    return *el_to_face;
5936 }
5937 
ElementToEdgeTable() const5938 const Table & Mesh::ElementToEdgeTable() const
5939 {
5940    if (el_to_edge == NULL)
5941    {
5942       mfem_error("Mesh::ElementToEdgeTable()");
5943    }
5944    return *el_to_edge;
5945 }
5946 
AddPointFaceElement(int lf,int gf,int el)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 
AddSegmentFaceElement(int lf,int gf,int el,int v0,int v1)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 
AddTriangleFaceElement(int lf,int gf,int el,int v0,int v1,int v2)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 
AddQuadFaceElement(int lf,int gf,int el,int v0,int v1,int v2,int v3)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 
GenerateFaces()6071 void Mesh::GenerateFaces()
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 
GenerateNCFaceInfo()6156 void Mesh::GenerateNCFaceInfo()
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 
GetFacesTable()6214 STable3D *Mesh::GetFacesTable()
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 
GetElementToFaceTable(int ret_ftbl)6263 STable3D *Mesh::GetElementToFaceTable(int ret_ftbl)
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();
6323    be_to_face.SetSize(NumOfBdrElements);
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          }
6334          case Element::QUADRILATERAL:
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
Rotate3(int & a,int & b,int & c)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 
ReorientTetMesh()6376 void Mesh::ReorientTetMesh()
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    {
6395       if (GetElementType(i) == Element::TETRAHEDRON)
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    {
6413       if (GetBdrElementType(i) == Element::TRIANGLE)
6414       {
6415          int *v = boundary[i]->GetVertices();
6416 
6417          Rotate3(v[0], v[1], v[2]);
6418       }
6419    }
6420 
6421    if (!Nodes)
6422    {
6423       GetElementToFaceTable();
6424       GenerateFaces();
6425       if (el_to_edge)
6426       {
6427          NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
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 
CartesianPartitioning(int nxyz[])6438 int *Mesh::CartesianPartitioning(int nxyz[])
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(
6462          Geometries.GetCenter(GetElementBaseGeometry(el)), pt);
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 
GeneratePartitioning(int nparts,int part_method)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 
6497    ElementToElementTable();
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
6578          METIS_PartGraphRecursive(&n,
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
6616          METIS_PartGraphKway(&n,
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
6654          METIS_PartGraphVKway(&n,
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 */
FindPartitioningComponents(Table & elem_elem,const Array<int> & partitioning,Array<int> & component,Array<int> & num_comp)6797 void FindPartitioningComponents(Table &elem_elem,
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 
CheckPartitioning(int * partitioning_)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 
6874    ElementToElementTable();
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
DetOfLinComb(const DenseMatrix & A,const DenseMatrix & B,Vector & c)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.
FindRoots(const Vector & z,Vector & x)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 
FindTMax(Vector & c,Vector & x,double & tmax,const double factor,const int Dim)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 
CheckDisplacements(const Vector & displacements,double & tmax)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 =
7213          GetTransformationFEforElementType(el->GetType());
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 
7236          case Element::QUADRILATERAL:
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 
MoveVertices(const Vector & displacements)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 
GetVertices(Vector & vert_coord) const7272 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 
SetVertices(const Vector & vert_coord)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 
GetNode(int i,double * coord) const7292 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 
SetNode(int i,const double * coord)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 
MoveNodes(const Vector & displacements)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 
GetNodes(Vector & node_coord) const7343 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 
SetNodes(const Vector & node_coord)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 
NewNodes(GridFunction & nodes,bool make_owner)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    {
7382       ncmesh->MakeTopologyOnly();
7383    }
7384 }
7385 
SwapNodes(GridFunction * & nodes,int & own_nodes_)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 
AverageVertices(const int * indexes,int n,int result)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 
UpdateNodes()7417 void Mesh::UpdateNodes()
7418 {
7419    if (Nodes)
7420    {
7421       Nodes->FESpace()->Update();
7422       Nodes->Update();
7423 
7424       // update vertex coordinates for compatibility (e.g., GetVertex())
7425       SetVerticesFromNodes(Nodes);
7426    }
7427 }
7428 
UniformRefinement2D_base(bool update_nodes)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;
7436       NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
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 
7548    CoarseFineTr.point_matrices[Geometry::TRIANGLE]
7549    .UseExternalData(tri_children, 2, 3, 4);
7550    CoarseFineTr.point_matrices[Geometry::SQUARE]
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 
7566    NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
7567    GenerateFaces();
7568 
7569    last_operation = Mesh::REFINE;
7570    sequence++;
7571 
7572    if (update_nodes) { UpdateNodes(); }
7573 
7574 #ifdef MFEM_DEBUG
7575    if (!Nodes || update_nodes)
7576    {
7577       CheckElementOrientation(false);
7578    }
7579    CheckBdrElementOrientation(false);
7580 #endif
7581 }
7582 
sqr(const double & x)7583 static inline double sqr(const double &x)
7584 {
7585    return x*x;
7586 }
7587 
UniformRefinement3D_base(Array<int> * f2qf_ptr,DSTable * v_to_v_p,bool update_nodes)7588 void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
7589                                     bool update_nodes)
7590 {
7591    ResetLazyData();
7592 
7593    if (el_to_edge == NULL)
7594    {
7595       el_to_edge = new Table;
7596       NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
7597    }
7598 
7599    if (el_to_face == NULL)
7600    {
7601       GetElementToFaceTable();
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;
7609    if (HasGeometry(Geometry::SQUARE))
7610    {
7611       if (HasGeometry(Geometry::TRIANGLE))
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;
7630    if (HasGeometry(Geometry::CUBE))
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;
7644    if (HasGeometry(Geometry::TETRAHEDRON))
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;
7738             ElementTransformation *T = GetElementTransformation(i);
7739             T->SetIntPoint(&Geometries.GetCenter(Geometry::TETRAHEDRON));
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                }
7790                Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
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                }
7798                Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
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                }
7810                Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
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                }
7818                Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
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                }
7830                Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
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                }
7838                Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
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 
8144    CoarseFineTr.point_matrices[Geometry::TETRAHEDRON]
8145    .UseExternalData(tet_children, 3, 4, 16);
8146    CoarseFineTr.point_matrices[Geometry::PRISM]
8147    .UseExternalData(pri_children, 3, 6, 8);
8148    CoarseFineTr.point_matrices[Geometry::CUBE]
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 
8165    GetElementToFaceTable();
8166    GenerateFaces();
8167 
8168 #ifdef MFEM_DEBUG
8169    CheckBdrElementOrientation(false);
8170 #endif
8171 
8172    NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
8173 
8174    last_operation = Mesh::REFINE;
8175    sequence++;
8176 
8177    if (update_nodes) { UpdateNodes(); }
8178 }
8179 
LocalRefinement(const Array<int> & marked_el,int type)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 
8192    InitRefinementTransforms();
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);
8201       CoarseFineTr.embeddings.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 };
8218       CoarseFineTr.point_matrices[Geometry::SEGMENT].
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       {
8306          NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
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       {
8402          NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
8403       }
8404       if (el_to_face != NULL)
8405       {
8406          GetElementToFaceTable();
8407          GenerateFaces();
8408       }
8409 
8410    } //  end 'if (Dim == 3)'
8411 
8412    last_operation = Mesh::REFINE;
8413    sequence++;
8414 
8415    UpdateNodes();
8416 
8417 #ifdef MFEM_DEBUG
8418    CheckElementOrientation(false);
8419 #endif
8420 }
8421 
NonconformingRefinement(const Array<Refinement> & refinements,int nc_limit)8422 void Mesh::NonconformingRefinement(const Array<Refinement> &refinements,
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    {
8438       last_operation = Mesh::NONE;
8439       return;
8440    }
8441 
8442    // do the refinements
8443    ncmesh->MarkCoarseLevel();
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 
8460    GenerateNCFaceInfo();
8461 
8462    last_operation = Mesh::REFINE;
8463    sequence++;
8464 
8465    if (Nodes) // update/interpolate curved mesh
8466    {
8467       Nodes->FESpace()->Update();
8468       Nodes->Update();
8469    }
8470 }
8471 
AggregateError(const Array<double> & elem_error,const int * fine,int nfine,int op)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 
NonconformingDerefinement(Array<double> & elem_error,double threshold,int nc_limit,int op)8491 bool Mesh::NonconformingDerefinement(Array<double> &elem_error,
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 
8529    GenerateNCFaceInfo();
8530 
8531    last_operation = Mesh::DEREFINE;
8532    sequence++;
8533 
8534    UpdateNodes();
8535 
8536    return true;
8537 }
8538 
DerefineByError(Array<double> & elem_error,double threshold,int nc_limit,int op)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 
DerefineByError(const Vector & elem_error,double threshold,int nc_limit,int op)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 
InitFromNCMesh(const NCMesh & ncmesh)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;
8584    nbInteriorFaces = nbBoundaryFaces = -1;
8585 
8586    if (Dim > 1)
8587    {
8588       el_to_edge = new Table;
8589       NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
8590    }
8591    if (Dim > 2)
8592    {
8593       GetElementToFaceTable();
8594    }
8595    GenerateFaces();
8596 #ifdef MFEM_DEBUG
8597    CheckBdrElementOrientation(false);
8598 #endif
8599 
8600    // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
8601    // outside after this method.
8602 }
8603 
Mesh(const NCMesh & ncmesh)8604 Mesh::Mesh(const NCMesh &ncmesh)
8605 {
8606    Init();
8607    InitTables();
8608    InitFromNCMesh(ncmesh);
8609    SetAttributes();
8610 }
8611 
Swap(Mesh & other,bool non_geometry)8612 void Mesh::Swap(Mesh& other, bool non_geometry)
8613 {
8614    mfem::Swap(Dim, other.Dim);
8615    mfem::Swap(spaceDim, other.spaceDim);
8616 
8617    mfem::Swap(NumOfVertices, other.NumOfVertices);
8618    mfem::Swap(NumOfElements, other.NumOfElements);
8619    mfem::Swap(NumOfBdrElements, other.NumOfBdrElements);
8620    mfem::Swap(NumOfEdges, other.NumOfEdges);
8621    mfem::Swap(NumOfFaces, other.NumOfFaces);
8622 
8623    mfem::Swap(meshgen, other.meshgen);
8624    mfem::Swap(mesh_geoms, other.mesh_geoms);
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);
8630    mfem::Swap(faces_info, other.faces_info);
8631    mfem::Swap(nc_faces_info, other.nc_faces_info);
8632 
8633    mfem::Swap(el_to_edge, other.el_to_edge);
8634    mfem::Swap(el_to_face, other.el_to_face);
8635    mfem::Swap(el_to_el, other.el_to_el);
8636    mfem::Swap(be_to_edge, other.be_to_edge);
8637    mfem::Swap(bel_to_edge, other.bel_to_edge);
8638    mfem::Swap(be_to_face, other.be_to_face);
8639    mfem::Swap(face_edge, other.face_edge);
8640    mfem::Swap(edge_vertex, other.edge_vertex);
8641 
8642    mfem::Swap(attributes, other.attributes);
8643    mfem::Swap(bdr_attributes, other.bdr_attributes);
8644 
8645    mfem::Swap(geom_factors, other.geom_factors);
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 
8661       mfem::Swap(CoarseFineTr, other.CoarseFineTr);
8662 
8663       mfem::Swap(sequence, other.sequence);
8664       mfem::Swap(last_operation, other.last_operation);
8665    }
8666 }
8667 
GetElementData(const Array<Element * > & elem_array,int geom,Array<int> & elem_vtx,Array<int> & attr) const8668 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 
AllElements(Array<int> & list,int nelem)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 
UniformRefinement(int ref_algo)8703 void Mesh::UniformRefinement(int ref_algo)
8704 {
8705    Array<int> list;
8706 
8707    if (NURBSext)
8708    {
8709       NURBSUniformRefinement();
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 
GeneralRefinement(const Array<Refinement> & refinements,int nonconforming,int nc_limit)8732 void Mesh::GeneralRefinement(const Array<Refinement> &refinements,
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 
GeneralRefinement(const Array<int> & el_to_refine,int nonconforming,int nc_limit)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 
EnsureNCMesh(bool simplices_nonconforming)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);
8819          GenerateNCFaceInfo();
8820       }
8821    }
8822 }
8823 
RandomRefinement(double prob,bool aniso,int nonconforming,int nc_limit)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 
RefineAtVertex(const Vertex & vert,double eps,int nonconforming)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 
RefineByError(const Array<double> & elem_error,double threshold,int nonconforming,int nc_limit)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 
RefineByError(const Vector & elem_error,double threshold,int nonconforming,int nc_limit)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 
Bisection(int i,const DSTable & v_to_v,int * edge1,int * edge2,int * middle)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 
Bisection(int i,HashTable<Hashed2> & v_to_v)8987 void Mesh::Bisection(int i, HashTable<Hashed2> &v_to_v)
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 
BdrBisection(int i,const HashTable<Hashed2> & v_to_v)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 
UniformRefinement(int i,const DSTable & v_to_v,int * edge1,int * edge2,int * middle)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 
InitRefinementTransforms()9233 void Mesh::InitRefinementTransforms()
9234 {
9235    // initialize CoarseFineTr
9236    CoarseFineTr.Clear();
9237    CoarseFineTr.embeddings.SetSize(NumOfElements);
9238    for (int i = 0; i < NumOfElements; i++)
9239    {
9240       elements[i]->ResetTransform(0);
9241       CoarseFineTr.embeddings[i] = Embedding(i);
9242    }
9243 }
9244 
FindCoarseElement(int i)9245 int Mesh::FindCoarseElement(int i)
9246 {
9247    int coarse;
9248    while ((coarse = CoarseFineTr.embeddings[i].parent) != i)
9249    {
9250       i = coarse;
9251    }
9252    return coarse;
9253 }
9254 
GetRefinementTransforms()9255 const CoarseFineTransformations& Mesh::GetRefinementTransforms()
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 
9290          DenseTensor &pmats = CoarseFineTr.point_matrices[geom];
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 
PrintXG(std::ostream & out) const9318 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 
Printer(std::ostream & out,std::string section_delimiter) const9482 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 
PrintTopo(std::ostream & out,const Array<int> & e_to_k) const9573 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 
Save(const char * fname,int precision) const9615 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
Print(adios2stream & out) const9623 void Mesh::Print(adios2stream &out) const
9624 {
9625    out.Print(*this);
9626 }
9627 #endif
9628 
PrintVTK(std::ostream & out)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;
9778       Geometry::Type geom = GetElement(i)->GetGeometryType();
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 
PrintVTU(std::string fname,VTKFormat format,bool high_order_output,int compression_level,bool bdr)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 
PrintBdrVTU(std::string fname,VTKFormat format,bool high_order_output,int compression_level)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>
WriteBinaryOrASCII(std::ostream & out,std::vector<char> & buf,const T & val,const char * suffix,VTKFormat format)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 <>
WriteBinaryOrASCII(std::ostream & out,std::vector<char> & buf,const uint8_t & val,const char * suffix,VTKFormat format)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 <>
WriteBinaryOrASCII(std::ostream & out,std::vector<char> & buf,const double & val,const char * suffix,VTKFormat format)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 <>
WriteBinaryOrASCII(std::ostream & out,std::vector<char> & buf,const float & val,const char * suffix,VTKFormat format)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 
WriteBase64WithSizeAndClear(std::ostream & out,std::vector<char> & buf,int compression_level)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 
PrintVTU(std::ostream & out,int ref,VTKFormat format,bool high_order_output,int compression_level,bool bdr_elements)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 
PrintVTK(std::ostream & out,int ref,int field_data)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    {
10120       Geometry::Type geom = GetElementBaseGeometry(i);
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    {
10164       Geometry::Type geom = GetElementBaseGeometry(i);
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    {
10183       Geometry::Type geom = GetElementBaseGeometry(i);
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    {
10200       Geometry::Type geom = GetElementBaseGeometry(i);
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       {
10221          Geometry::Type geom = GetElementBaseGeometry(i);
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 
GetElementColoring(Array<int> & colors,int el0)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 
PrintWithPartitioning(int * partitioning,std::ostream & out,int elem_attr) const10310 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 
PrintElementsWithPartitioning(int * partitioning,std::ostream & out,int interior_faces)10429 void Mesh::PrintElementsWithPartitioning(int *partitioning,
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 
PrintSurfaces(const Table & Aface_face,std::ostream & out) const10801 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 
ScaleSubdomains(double sf)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 
ScaleElements(double sf)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 
Transform(void (* f)(const Vector &,Vector &))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());
11027       VectorFunctionCoefficient f_pert(spaceDim, f);
11028       xnew.ProjectCoefficient(f_pert);
11029       *Nodes = xnew;
11030    }
11031 }
11032 
Transform(VectorCoefficient & deformation)11033 void Mesh::Transform(VectorCoefficient &deformation)
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 
RemoveUnusedVertices()11057 void Mesh::RemoveUnusedVertices()
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;
11141       NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
11142    }
11143    if (Dim > 2)
11144    {
11145       // generate el_to_face, be_to_face
11146       GetElementToFaceTable();
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 
RemoveInternalBoundaries()11164 void Mesh::RemoveInternalBoundaries()
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    {
11172       if (FaceIsInterior(GetBdrElementEdgeIndex(i)))
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    {
11204       if (!FaceIsInterior(GetBdrElementEdgeIndex(i)))
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();
11248    bdr_attributes.DeleteAll();
11249    attribs.Copy(bdr_attributes);
11250 }
11251 
FreeElement(Element * E)11252 void Mesh::FreeElement(Element *E)
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 
operator <<(std::ostream & out,const Mesh & mesh)11271 std::ostream &operator<<(std::ostream &out, const Mesh &mesh)
11272 {
11273    mesh.Print(out);
11274    return out;
11275 }
11276 
FindPoints(DenseMatrix & point_mat,Array<int> & elem_ids,Array<IntegrationPoint> & ips,bool warn,InverseElementTransformation * inv_trans)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(
11303          Geometries.GetCenter(GetElementBaseGeometry(i)), pt);
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]);
11323       if (res == InverseElementTransformation::Inside)
11324       {
11325          elem_ids[k] = e_idx[k];
11326          pts_found++;
11327       }
11328    }
11329    if (pts_found != npts)
11330    {
11331       Array<int> vertices;
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]);
11349                if (res == InverseElementTransformation::Inside)
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;
11368                inv_tr->SetTransformation(*GetElementTransformation(el));
11369                int res = inv_tr->Transform(pt, ips[k]);
11370                if (res == InverseElementTransformation::Inside)
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 
GeometricFactors(const Mesh * mesh,const IntegrationRule & ir,int flags,MemoryType d_mt)11392 GeometricFactors::GeometricFactors(const Mesh *mesh, const IntegrationRule &ir,
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 
GeometricFactors(const GridFunction & nodes,const IntegrationRule & ir,int flags,MemoryType d_mt)11406 GeometricFactors::GeometricFactors(const GridFunction &nodes,
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 
Compute(const GridFunction & nodes,MemoryType d_mt)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 :
11431                         Device::GetDeviceMemoryType();
11432    if (computed_factors & GeometricFactors::COORDINATES)
11433    {
11434       X.SetSize(vdim*NQ*NE, my_d_mt); // NQ x SDIM x NE
11435       eval_flags |= QuadratureInterpolator::VALUES;
11436    }
11437    if (computed_factors & GeometricFactors::JACOBIANS)
11438    {
11439       J.SetSize(dim*vdim*NQ*NE, my_d_mt); // NQ x SDIM x DIM x NE
11440       eval_flags |= QuadratureInterpolator::DERIVATIVES;
11441    }
11442    if (computed_factors & GeometricFactors::DETERMINANTS)
11443    {
11444       detJ.SetSize(NQ*NE, my_d_mt); // NQ x NE
11445       eval_flags |= QuadratureInterpolator::DETERMINANTS;
11446    }
11447 
11448    const QuadratureInterpolator *qi = fespace->GetQuadratureInterpolator(*IntRule);
11449    // All X, J, and detJ use this layout:
11450    qi->SetOutputLayout(QVectorLayout::byNODES);
11451 
11452    const bool use_tensor_products = UsesTensorBasis(*fespace);
11453 
11454    qi->DisableTensorProducts(!use_tensor_products);
11455    const ElementDofOrdering e_ordering = use_tensor_products ?
11456                                          ElementDofOrdering::LEXICOGRAPHIC :
11457                                          ElementDofOrdering::NATIVE;
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 
FaceGeometricFactors(const Mesh * mesh,const IntegrationRule & ir,int flags,FaceType type)11472 FaceGeometricFactors::FaceGeometricFactors(const Mesh *mesh,
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(
11488                                           ElementDofOrdering::LEXICOGRAPHIC,
11489                                           type,
11490                                           L2FaceValues::SingleValued );
11491    Vector Fnodes(face_restr->Height());
11492    face_restr->Mult(*nodes, Fnodes);
11493 
11494    unsigned eval_flags = 0;
11495    if (flags & FaceGeometricFactors::COORDINATES)
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);
11503       eval_flags |= FaceQuadratureInterpolator::DERIVATIVES;
11504    }
11505    if (flags & FaceGeometricFactors::DETERMINANTS)
11506    {
11507       detJ.SetSize(NQ*NF);
11508       eval_flags |= FaceQuadratureInterpolator::DETERMINANTS;
11509    }
11510    if (flags & FaceGeometricFactors::NORMALS)
11511    {
11512       normal.SetSize(vdim*NQ*NF);
11513       eval_flags |= FaceQuadratureInterpolator::NORMALS;
11514    }
11515 
11516    const FaceQuadratureInterpolator *qi = fespace->GetFaceQuadratureInterpolator(
11517                                              ir, type);
11518    qi->Mult(Fnodes, eval_flags, X, J, detJ, normal);
11519 }
11520 
NodeExtrudeCoefficient(const int dim,const int n_,const double s_)11521 NodeExtrudeCoefficient::NodeExtrudeCoefficient(const int dim, const int n_,
11522                                                const double s_)
11523    : VectorCoefficient(dim), n(n_), s(s_), tip(p, dim-1)
11524 {
11525 }
11526 
Eval(Vector & V,ElementTransformation & T,const IntegrationPoint & ip)11527 void NodeExtrudeCoefficient::Eval(Vector &V, ElementTransformation &T,
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 
Extrude1D(Mesh * mesh,const int ny,const double sy,const bool closed)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       {
11691          ElementTransformation &T = *mesh->GetElementTransformation(i);
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 
Extrude2D(Mesh * mesh,const int nz,const double sz)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();
11741       Geometry::Type geom = elem->GetGeometryType();
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();
11809       Geometry::Type geom = elem->GetGeometryType();
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       {
11917          ElementTransformation &T = *mesh->GetElementTransformation(i);
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
DebugDump(std::ostream & out) const11932 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 }
11979