MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
mesh.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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"
18#include "../general/text.hpp"
19#include "../general/device.hpp"
21#include "../general/gecko.hpp"
22#include "../general/kdtree.hpp"
23#include "../general/sets.hpp"
25
26// headers already included by mesh.hpp: <iostream>, <array>, <map>, <memory>
27#include <sstream>
28#include <fstream>
29#include <limits>
30#include <cmath>
31#include <cstring>
32#include <ctime>
33#include <functional>
34#include <unordered_map>
35#include <unordered_set>
36
37// Include the METIS header, if using version 5. If using METIS 4, the needed
38// declarations are inlined below, i.e. no header is needed.
39#if defined(MFEM_USE_METIS) && defined(MFEM_USE_METIS_5)
40#include "metis.h"
41#endif
42
43// METIS 4 prototypes
44#if defined(MFEM_USE_METIS) && !defined(MFEM_USE_METIS_5)
45typedef int idx_t;
46typedef int idxtype;
47extern "C" {
49 int*, int*, int*, int*, int*, idxtype*);
51 int*, int*, int*, int*, int*, idxtype*);
53 int*, int*, int*, int*, int*, idxtype*);
54}
55#endif
56
57using namespace std;
58
59namespace mfem
60{
61
63{
66 if (ip == NULL)
67 {
68 eltransf->SetIntPoint(&Geometries.GetCenter(geom));
69 }
70 else
71 {
72 eltransf->SetIntPoint(ip);
73 }
74 Geometries.JacToPerfJac(geom, eltransf->Jacobian(), J);
75}
76
77void Mesh::GetElementCenter(int i, Vector &center)
78{
79 center.SetSize(spaceDim);
80 int geom = GetElementBaseGeometry(i);
82 eltransf->Transform(Geometries.GetCenter(geom), center);
83}
84
86{
88
91 Geometries.JacToPerfJac(geom, T->Jacobian(), J);
92
93 if (type == 0)
94 {
95 return pow(fabs(J.Weight()), 1./Dim);
96 }
97 else if (type == 1)
98 {
99 return J.CalcSingularvalue(Dim-1); // h_min
100 }
101 else
102 {
103 return J.CalcSingularvalue(0); // h_max
104 }
105}
106
108{
110}
111
113{
115 Vector d_hat(Dim);
116 GetElementJacobian(i, J);
117 J.MultTranspose(dir, d_hat);
118 return sqrt((d_hat * d_hat) / (dir * dir));
119}
120
122{
125 et->OrderJ());
126 real_t volume = 0.0;
127 for (int j = 0; j < ir.GetNPoints(); j++)
128 {
129 const IntegrationPoint &ip = ir.IntPoint(j);
130 et->SetIntPoint(&ip);
131 volume += ip.weight * et->Weight();
132 }
133
134 return volume;
135}
136
137// Similar to VisualizationSceneSolution3d::FindNewBox in GLVis
138void Mesh::GetBoundingBox(Vector &min, Vector &max, int ref)
139{
140 min.SetSize(spaceDim);
141 max.SetSize(spaceDim);
142
143 for (int d = 0; d < spaceDim; d++)
144 {
145 min(d) = infinity();
146 max(d) = -infinity();
147 }
148
149 if (Nodes == NULL)
150 {
151 real_t *coord;
152 for (int i = 0; i < NumOfVertices; i++)
153 {
154 coord = GetVertex(i);
155 for (int d = 0; d < spaceDim; d++)
156 {
157 if (coord[d] < min(d)) { min(d) = coord[d]; }
158 if (coord[d] > max(d)) { max(d) = coord[d]; }
159 }
160 }
161 }
162 else
163 {
164 const bool use_boundary = false; // make this a parameter?
165 int ne = use_boundary ? GetNBE() : GetNE();
166 int fn, fo;
167 DenseMatrix pointmat;
168 RefinedGeometry *RefG;
169 IntegrationRule eir;
172
173 for (int i = 0; i < ne; i++)
174 {
175 if (use_boundary)
176 {
177 GetBdrElementFace(i, &fn, &fo);
180 eir.SetSize(RefG->RefPts.GetNPoints());
181 Tr->Loc1.Transform(RefG->RefPts, eir);
182 Tr->Elem1->Transform(eir, pointmat);
183 }
184 else
185 {
188 T->Transform(RefG->RefPts, pointmat);
189 }
190 for (int j = 0; j < pointmat.Width(); j++)
191 {
192 for (int d = 0; d < pointmat.Height(); d++)
193 {
194 if (pointmat(d,j) < min(d)) { min(d) = pointmat(d,j); }
195 if (pointmat(d,j) > max(d)) { max(d) = pointmat(d,j); }
196 }
197 }
198 }
199 }
200}
201
203 real_t &kappa_min, real_t &kappa_max,
204 Vector *Vh, Vector *Vk)
205{
206 int i, dim, sdim;
207 DenseMatrix J;
208 real_t h, kappa;
209
210 dim = Dimension();
211 sdim = SpaceDimension();
212
213 if (Vh) { Vh->SetSize(NumOfElements); }
214 if (Vk) { Vk->SetSize(NumOfElements); }
215
216 h_min = kappa_min = infinity();
217 h_max = kappa_max = -h_min;
218 if (dim == 0) { if (Vh) { *Vh = 1.0; } if (Vk) {*Vk = 1.0; } return; }
219 J.SetSize(sdim, dim);
220 for (i = 0; i < NumOfElements; i++)
221 {
222 GetElementJacobian(i, J);
223 h = pow(fabs(J.Weight()), 1.0/real_t(dim));
224 kappa = (dim == sdim) ?
225 J.CalcSingularvalue(0) / J.CalcSingularvalue(dim-1) : -1.0;
226 if (Vh) { (*Vh)(i) = h; }
227 if (Vk) { (*Vk)(i) = kappa; }
228
229 if (h < h_min) { h_min = h; }
230 if (h > h_max) { h_max = h; }
231 if (kappa < kappa_min) { kappa_min = kappa; }
232 if (kappa > kappa_max) { kappa_max = kappa; }
233 }
234}
235
236// static method
238 const Array<int> &num_elems_by_geom,
239 std::ostream &os)
240{
241 for (int g = Geometry::DimStart[dim], first = 1;
242 g < Geometry::DimStart[dim+1]; g++)
243 {
244 if (!num_elems_by_geom[g]) { continue; }
245 if (!first) { os << " + "; }
246 else { first = 0; }
247 os << num_elems_by_geom[g] << ' ' << Geometry::Name[g] << "(s)";
248 }
249}
250
251void Mesh::PrintCharacteristics(Vector *Vh, Vector *Vk, std::ostream &os)
252{
253 real_t h_min, h_max, kappa_min, kappa_max;
254
255 os << "Mesh Characteristics:";
256
257 this->GetCharacteristics(h_min, h_max, kappa_min, kappa_max, Vh, Vk);
258
259 Array<int> num_elems_by_geom(Geometry::NumGeom);
260 num_elems_by_geom = 0;
261 for (int i = 0; i < GetNE(); i++)
262 {
263 num_elems_by_geom[GetElementBaseGeometry(i)]++;
264 }
265
266 os << '\n'
267 << "Dimension : " << Dimension() << '\n'
268 << "Space dimension : " << SpaceDimension();
269 if (Dim == 0)
270 {
271 os << '\n'
272 << "Number of vertices : " << GetNV() << '\n'
273 << "Number of elements : " << GetNE() << '\n'
274 << "Number of bdr elem : " << GetNBE() << '\n';
275 }
276 else if (Dim == 1)
277 {
278 os << '\n'
279 << "Number of vertices : " << GetNV() << '\n'
280 << "Number of elements : " << GetNE() << '\n'
281 << "Number of bdr elem : " << GetNBE() << '\n'
282 << "h_min : " << h_min << '\n'
283 << "h_max : " << h_max << '\n';
284 }
285 else if (Dim == 2)
286 {
287 os << '\n'
288 << "Number of vertices : " << GetNV() << '\n'
289 << "Number of edges : " << GetNEdges() << '\n'
290 << "Number of elements : " << GetNE() << " -- ";
291 PrintElementsByGeometry(2, num_elems_by_geom, os);
292 os << '\n'
293 << "Number of bdr elem : " << GetNBE() << '\n'
294 << "Euler Number : " << EulerNumber2D() << '\n'
295 << "h_min : " << h_min << '\n'
296 << "h_max : " << h_max << '\n'
297 << "kappa_min : " << kappa_min << '\n'
298 << "kappa_max : " << kappa_max << '\n';
299 }
300 else
301 {
302 Array<int> num_bdr_elems_by_geom(Geometry::NumGeom);
303 num_bdr_elems_by_geom = 0;
304 for (int i = 0; i < GetNBE(); i++)
305 {
306 num_bdr_elems_by_geom[GetBdrElementGeometry(i)]++;
307 }
308 Array<int> num_faces_by_geom(Geometry::NumGeom);
309 num_faces_by_geom = 0;
310 for (int i = 0; i < GetNFaces(); i++)
311 {
312 num_faces_by_geom[GetFaceGeometry(i)]++;
313 }
314
315 os << '\n'
316 << "Number of vertices : " << GetNV() << '\n'
317 << "Number of edges : " << GetNEdges() << '\n'
318 << "Number of faces : " << GetNFaces() << " -- ";
319 PrintElementsByGeometry(Dim-1, num_faces_by_geom, os);
320 os << '\n'
321 << "Number of elements : " << GetNE() << " -- ";
322 PrintElementsByGeometry(Dim, num_elems_by_geom, os);
323 os << '\n'
324 << "Number of bdr elem : " << GetNBE() << " -- ";
325 PrintElementsByGeometry(Dim-1, num_bdr_elems_by_geom, os);
326 os << '\n'
327 << "Euler Number : " << EulerNumber() << '\n'
328 << "h_min : " << h_min << '\n'
329 << "h_max : " << h_max << '\n'
330 << "kappa_min : " << kappa_min << '\n'
331 << "kappa_max : " << kappa_max << '\n';
332 }
333 os << '\n' << std::flush;
334}
335
337{
338 switch (ElemType)
339 {
340 case Element::POINT : return &PointFE;
341 case Element::SEGMENT : return &SegmentFE;
342 case Element::TRIANGLE : return &TriangleFE;
344 case Element::TETRAHEDRON : return &TetrahedronFE;
345 case Element::HEXAHEDRON : return &HexahedronFE;
346 case Element::WEDGE : return &WedgeFE;
347 case Element::PYRAMID : return &PyramidFE;
348 default:
349 MFEM_ABORT("Unknown element type \"" << ElemType << "\"");
350 break;
351 }
352 MFEM_ABORT("Unknown element type");
353 return NULL;
354}
355
356
358 IsoparametricTransformation *ElTr) const
359{
360 ElTr->Attribute = GetAttribute(i);
361 ElTr->ElementNo = i;
363 ElTr->mesh = this;
364 ElTr->Reset();
365 if (Nodes == NULL)
366 {
367 GetPointMatrix(i, ElTr->GetPointMat());
369 }
370 else
371 {
372 DenseMatrix &pm = ElTr->GetPointMat();
373 Array<int> vdofs;
374 Nodes->FESpace()->GetElementVDofs(i, vdofs);
375 Nodes->HostRead();
376 const GridFunction &nodes = *Nodes;
377 int n = vdofs.Size()/spaceDim;
378 pm.SetSize(spaceDim, n);
379 for (int k = 0; k < spaceDim; k++)
380 {
381 for (int j = 0; j < n; j++)
382 {
383 pm(k,j) = nodes(vdofs[n*k+j]);
384 }
385 }
386 ElTr->SetFE(Nodes->FESpace()->GetFE(i));
387 }
388}
389
412
418
420 IsoparametricTransformation *ElTr) const
421{
422 ElTr->Attribute = GetAttribute(i);
423 ElTr->ElementNo = i;
425 ElTr->mesh = this;
426 DenseMatrix &pm = ElTr->GetPointMat();
427 ElTr->Reset();
428 nodes.HostRead();
429 if (Nodes == NULL)
430 {
431 MFEM_ASSERT(nodes.Size() == spaceDim*GetNV(), "");
432 int nv = elements[i]->GetNVertices();
433 const int *v = elements[i]->GetVertices();
434 int n = vertices.Size();
435 pm.SetSize(spaceDim, nv);
436 for (int k = 0; k < spaceDim; k++)
437 {
438 for (int j = 0; j < nv; j++)
439 {
440 pm(k, j) = nodes(k*n+v[j]);
441 }
442 }
444 }
445 else
446 {
447 MFEM_ASSERT(nodes.Size() == Nodes->Size(), "");
448 Array<int> vdofs;
449 Nodes->FESpace()->GetElementVDofs(i, vdofs);
450 int n = vdofs.Size()/spaceDim;
451 pm.SetSize(spaceDim, n);
452 for (int k = 0; k < spaceDim; k++)
453 {
454 for (int j = 0; j < n; j++)
455 {
456 pm(k,j) = nodes(vdofs[n*k+j]);
457 }
458 }
459 ElTr->SetFE(Nodes->FESpace()->GetFE(i));
460 }
461}
462
464 IsoparametricTransformation* ElTr) const
465{
466 ElTr->Attribute = GetBdrAttribute(i);
467 ElTr->ElementNo = i; // boundary element number
469 ElTr->mesh = this;
470 DenseMatrix &pm = ElTr->GetPointMat();
471 ElTr->Reset();
472 if (Nodes == NULL)
473 {
474 GetBdrPointMatrix(i, pm);
476 }
477 else
478 {
479 const FiniteElement *bdr_el = Nodes->FESpace()->GetBE(i);
480 Nodes->HostRead();
481 const GridFunction &nodes = *Nodes;
482 if (bdr_el)
483 {
484 Array<int> vdofs;
485 Nodes->FESpace()->GetBdrElementVDofs(i, vdofs);
486 int n = vdofs.Size()/spaceDim;
487 pm.SetSize(spaceDim, n);
488 for (int k = 0; k < spaceDim; k++)
489 {
490 for (int j = 0; j < n; j++)
491 {
492 int idx = vdofs[n*k+j];
493 pm(k,j) = nodes((idx<0)? -1-idx:idx);
494 }
495 }
496 ElTr->SetFE(bdr_el);
497 }
498 else // L2 Nodes (e.g., periodic mesh)
499 {
500 int elem_id, face_info;
501 GetBdrElementAdjacentElement(i, elem_id, face_info);
503 face_info = EncodeFaceInfo(
504 DecodeFaceInfoLocalIndex(face_info),
506 face_geom, DecodeFaceInfoOrientation(face_info))
507 );
508
511 GetElementType(elem_id),
512 Loc1.Transf, face_info);
513 const FiniteElement *face_el =
514 Nodes->FESpace()->GetTraceElement(elem_id, face_geom);
515 MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
516 "Mesh requires nodal Finite Element.");
517
518 IntegrationRule eir(face_el->GetDof());
519 Loc1.Transf.ElementNo = elem_id;
520 Loc1.Transf.mesh = this;
522 Loc1.Transform(face_el->GetNodes(), eir);
523 Nodes->GetVectorValues(Loc1.Transf, eir, pm);
524
525 ElTr->SetFE(face_el);
526 }
527 }
528}
529
535
538{
539 FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute();
540 FTr->ElementNo = FaceNo;
542 FTr->mesh = this;
543 DenseMatrix &pm = FTr->GetPointMat();
544 FTr->Reset();
545 if (Nodes == NULL)
546 {
547 const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
548 const int nv = (Dim == 1) ? 1 : faces[FaceNo]->GetNVertices();
549 pm.SetSize(spaceDim, nv);
550 for (int i = 0; i < spaceDim; i++)
551 {
552 for (int j = 0; j < nv; j++)
553 {
554 pm(i, j) = vertices[v[j]](i);
555 }
556 }
558 }
559 else // curved mesh
560 {
561 const FiniteElement *face_el = Nodes->FESpace()->GetFaceElement(FaceNo);
562 Nodes->HostRead();
563 const GridFunction &nodes = *Nodes;
564 if (face_el)
565 {
566 Array<int> vdofs;
567 Nodes->FESpace()->GetFaceVDofs(FaceNo, vdofs);
568 int n = vdofs.Size()/spaceDim;
569 pm.SetSize(spaceDim, n);
570 for (int i = 0; i < spaceDim; i++)
571 {
572 for (int j = 0; j < n; j++)
573 {
574 pm(i, j) = nodes(vdofs[n*i+j]);
575 }
576 }
577 FTr->SetFE(face_el);
578 }
579 else // L2 Nodes (e.g., periodic mesh), go through the volume of Elem1
580 {
581 const FaceInfo &face_info = faces_info[FaceNo];
582 Geometry::Type face_geom = GetFaceGeometry(FaceNo);
583 Element::Type face_type = GetFaceElementType(FaceNo);
584
587 GetElementType(face_info.Elem1No),
588 Loc1.Transf, face_info.Elem1Inf);
589
590 face_el = Nodes->FESpace()->GetTraceElement(face_info.Elem1No,
591 face_geom);
592 MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
593 "Mesh requires nodal Finite Element.");
594
595 IntegrationRule eir(face_el->GetDof());
596 Loc1.Transf.ElementNo = face_info.Elem1No;
598 Loc1.Transf.mesh = this;
599 Loc1.Transform(face_el->GetNodes(), eir);
600 Nodes->GetVectorValues(Loc1.Transf, eir, pm);
601
602 FTr->SetFE(face_el);
603 }
604 }
605}
606
612
614 IsoparametricTransformation *EdTr) const
615{
616 if (Dim == 2)
617 {
618 GetFaceTransformation(EdgeNo, EdTr);
619 return;
620 }
621 if (Dim == 1)
622 {
623 mfem_error("Mesh::GetEdgeTransformation not defined in 1D \n");
624 }
625
626 EdTr->Attribute = 1;
627 EdTr->ElementNo = EdgeNo;
629 EdTr->mesh = this;
630 DenseMatrix &pm = EdTr->GetPointMat();
631 EdTr->Reset();
632 if (Nodes == NULL)
633 {
634 Array<int> v;
635 GetEdgeVertices(EdgeNo, v);
636 const int nv = 2;
637 pm.SetSize(spaceDim, nv);
638 for (int i = 0; i < spaceDim; i++)
639 {
640 for (int j = 0; j < nv; j++)
641 {
642 pm(i, j) = vertices[v[j]](i);
643 }
644 }
646 }
647 else
648 {
649 const FiniteElement *edge_el = Nodes->FESpace()->GetEdgeElement(EdgeNo);
650 Nodes->HostRead();
651 const GridFunction &nodes = *Nodes;
652 if (edge_el)
653 {
654 Array<int> vdofs;
655 Nodes->FESpace()->GetEdgeVDofs(EdgeNo, vdofs);
656 int n = vdofs.Size()/spaceDim;
657 pm.SetSize(spaceDim, n);
658 for (int i = 0; i < spaceDim; i++)
659 {
660 for (int j = 0; j < n; j++)
661 {
662 pm(i, j) = nodes(vdofs[n*i+j]);
663 }
664 }
665 EdTr->SetFE(edge_el);
666 }
667 else
668 {
669 MFEM_ABORT("Not implemented.");
670 }
671 }
672}
673
679
680
682 IsoparametricTransformation &Transf, int i) const
683{
684 const IntegrationRule *SegVert;
685 DenseMatrix &locpm = Transf.GetPointMat();
686 Transf.Reset();
687
688 Transf.SetFE(&PointFE);
690 locpm.SetSize(1, 1);
691 locpm(0, 0) = SegVert->IntPoint(i/64).x;
692 // (i/64) is the local face no. in the segment
693 // (i%64) is the orientation of the point (not used)
694}
695
697 IsoparametricTransformation &Transf, int i) const
698{
699 const int *tv, *so;
700 const IntegrationRule *TriVert;
701 DenseMatrix &locpm = Transf.GetPointMat();
702 Transf.Reset();
703
704 Transf.SetFE(&SegmentFE);
705 tv = tri_t::Edges[i/64]; // (i/64) is the local face no. in the triangle
706 so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
708 locpm.SetSize(2, 2);
709 for (int j = 0; j < 2; j++)
710 {
711 locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x;
712 locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y;
713 }
714}
715
717 IsoparametricTransformation &Transf, int i) const
718{
719 const int *qv, *so;
720 const IntegrationRule *QuadVert;
721 DenseMatrix &locpm = Transf.GetPointMat();
722 Transf.Reset();
723
724 Transf.SetFE(&SegmentFE);
725 qv = quad_t::Edges[i/64]; // (i/64) is the local face no. in the quad
726 so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
728 locpm.SetSize(2, 2);
729 for (int j = 0; j < 2; j++)
730 {
731 locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x;
732 locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y;
733 }
734}
735
737 IsoparametricTransformation &Transf, int i) const
738{
739 DenseMatrix &locpm = Transf.GetPointMat();
740 Transf.Reset();
741
742 Transf.SetFE(&TriangleFE);
743 // (i/64) is the local face no. in the tet
744 const int *tv = tet_t::FaceVert[i/64];
745 // (i%64) is the orientation of the tetrahedron face
746 // w.r.t. the face element
747 const int *to = tri_t::Orient[i%64];
748 const IntegrationRule *TetVert =
750 locpm.SetSize(3, 3);
751 for (int j = 0; j < 3; j++)
752 {
753 const IntegrationPoint &vert = TetVert->IntPoint(tv[to[j]]);
754 locpm(0, j) = vert.x;
755 locpm(1, j) = vert.y;
756 locpm(2, j) = vert.z;
757 }
759
761 IsoparametricTransformation &Transf, int i) const
762{
763 DenseMatrix &locpm = Transf.GetPointMat();
764 Transf.Reset();
765
766 Transf.SetFE(&TriangleFE);
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 triangular face of a wedge.");
770 const int *pv = pri_t::FaceVert[i/64];
771 // (i%64) is the orientation of the wedge face
772 // w.r.t. the face element
773 const int *to = tri_t::Orient[i%64];
774 const IntegrationRule *PriVert =
776 locpm.SetSize(3, 3);
777 for (int j = 0; j < 3; j++)
778 {
779 const IntegrationPoint &vert = PriVert->IntPoint(pv[to[j]]);
780 locpm(0, j) = vert.x;
781 locpm(1, j) = vert.y;
782 locpm(2, j) = vert.z;
783 }
784}
785
787 IsoparametricTransformation &Transf, int i) const
788{
789 DenseMatrix &locpm = Transf.GetPointMat();
790
791 Transf.SetFE(&TriangleFE);
792 // (i/64) is the local face no. in the pyr
793 MFEM_VERIFY(i >= 64, "Local face index " << i/64
794 << " is not a triangular face of a pyramid.");
795 const int *pv = pyr_t::FaceVert[i/64];
796 // (i%64) is the orientation of the pyramid face
797 // w.r.t. the face element
798 const int *to = tri_t::Orient[i%64];
799 const IntegrationRule *PyrVert =
801 locpm.SetSize(3, 3);
802 for (int j = 0; j < 3; j++)
803 {
804 const IntegrationPoint &vert = PyrVert->IntPoint(pv[to[j]]);
805 locpm(0, j) = vert.x;
806 locpm(1, j) = vert.y;
807 locpm(2, j) = vert.z;
808 }
809}
810
812 IsoparametricTransformation &Transf, int i) const
813{
814 DenseMatrix &locpm = Transf.GetPointMat();
815 Transf.Reset();
816
817 Transf.SetFE(&QuadrilateralFE);
818 // (i/64) is the local face no. in the hex
819 const int *hv = hex_t::FaceVert[i/64];
820 // (i%64) is the orientation of the quad
821 const int *qo = quad_t::Orient[i%64];
823 locpm.SetSize(3, 4);
824 for (int j = 0; j < 4; j++)
825 {
826 const IntegrationPoint &vert = HexVert->IntPoint(hv[qo[j]]);
827 locpm(0, j) = vert.x;
828 locpm(1, j) = vert.y;
829 locpm(2, j) = vert.z;
830 }
831}
832
834 IsoparametricTransformation &Transf, int i) const
835{
836 DenseMatrix &locpm = Transf.GetPointMat();
837 Transf.Reset();
838
839 Transf.SetFE(&QuadrilateralFE);
840 // (i/64) is the local face no. in the pri
841 MFEM_VERIFY(i >= 128, "Local face index " << i/64
842 << " is not a quadrilateral face of a wedge.");
843 const int *pv = pri_t::FaceVert[i/64];
844 // (i%64) is the orientation of the quad
845 const int *qo = quad_t::Orient[i%64];
847 locpm.SetSize(3, 4);
848 for (int j = 0; j < 4; j++)
849 {
850 const IntegrationPoint &vert = PriVert->IntPoint(pv[qo[j]]);
851 locpm(0, j) = vert.x;
852 locpm(1, j) = vert.y;
853 locpm(2, j) = vert.z;
854 }
855}
856
858 IsoparametricTransformation &Transf, int i) const
859{
860 DenseMatrix &locpm = Transf.GetPointMat();
861
862 Transf.SetFE(&QuadrilateralFE);
863 // (i/64) is the local face no. in the pyr
864 MFEM_VERIFY(i < 64, "Local face index " << i/64
865 << " is not a quadrilateral face of a pyramid.");
866 const int *pv = pyr_t::FaceVert[i/64];
867 // (i%64) is the orientation of the quad
868 const int *qo = quad_t::Orient[i%64];
870 locpm.SetSize(3, 4);
871 for (int j = 0; j < 4; j++)
872 {
873 const IntegrationPoint &vert = PyrVert->IntPoint(pv[qo[j]]);
874 locpm(0, j) = vert.x;
875 locpm(1, j) = vert.y;
876 locpm(2, j) = vert.z;
877 }
878}
879
881 const int flags,
882 MemoryType d_mt)
883{
884 for (int i = 0; i < geom_factors.Size(); i++)
885 {
887 if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags)
888 {
889 return gf;
890 }
891 }
892
893 this->EnsureNodes();
894
895 GeometricFactors *gf = new GeometricFactors(this, ir, flags, d_mt);
896 geom_factors.Append(gf);
897 return gf;
898}
899
901 const IntegrationRule& ir,
902 const int flags, FaceType type, MemoryType d_mt)
903{
904 for (int i = 0; i < face_geom_factors.Size(); i++)
905 {
907 if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags &&
908 gf->type==type)
909 {
910 return gf;
911 }
912 }
913
914 this->EnsureNodes();
915
916 FaceGeometricFactors *gf = new FaceGeometricFactors(this, ir, flags, type,
917 d_mt);
918 face_geom_factors.Append(gf);
919 return gf;
920}
921
923{
924 for (int i = 0; i < geom_factors.Size(); i++)
925 {
926 delete geom_factors[i];
927 }
928 geom_factors.SetSize(0);
929 for (int i = 0; i < face_geom_factors.Size(); i++)
930 {
931 delete face_geom_factors[i];
932 }
933 face_geom_factors.SetSize(0);
934
936}
937
938void Mesh::GetLocalFaceTransformation(int face_type, int elem_type,
940 int info) const
941{
942 switch (face_type)
943 {
944 case Element::POINT:
945 GetLocalPtToSegTransformation(Transf, info);
946 break;
947
948 case Element::SEGMENT:
949 if (elem_type == Element::TRIANGLE)
950 {
951 GetLocalSegToTriTransformation(Transf, info);
952 }
953 else
954 {
955 MFEM_ASSERT(elem_type == Element::QUADRILATERAL, "");
957 }
958 break;
959
961 if (elem_type == Element::TETRAHEDRON)
962 {
963 GetLocalTriToTetTransformation(Transf, info);
964 }
965 else if (elem_type == Element::WEDGE)
966 {
967 GetLocalTriToWdgTransformation(Transf, info);
968 }
969 else if (elem_type == Element::PYRAMID)
970 {
971 GetLocalTriToPyrTransformation(Transf, info);
972 }
973 else
974 {
975 MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
976 "face type " << face_type
977 << " and element type " << elem_type << "\n");
978 }
979 break;
980
982 if (elem_type == Element::HEXAHEDRON)
983 {
985 }
986 else if (elem_type == Element::WEDGE)
987 {
989 }
990 else if (elem_type == Element::PYRAMID)
991 {
993 }
994 else
995 {
996 MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
997 "face type " << face_type
998 << " and element type " << elem_type << "\n");
999 }
1000 break;
1001 }
1002}
1003
1011
1016 int mask) const
1017{
1018 const FaceInfo &face_info = faces_info[FaceNo];
1019
1020 int cmask = 0;
1021 FElTr.SetConfigurationMask(cmask);
1022 FElTr.Elem1 = NULL;
1023 FElTr.Elem2 = NULL;
1024
1025 // setup the transformation for the first element
1026 FElTr.Elem1No = face_info.Elem1No;
1028 {
1029 GetElementTransformation(FElTr.Elem1No, &ElTr1);
1030 FElTr.Elem1 = &ElTr1;
1031 cmask |= 1;
1032 }
1033
1034 // setup the transformation for the second element
1035 // return NULL in the Elem2 field if there's no second element, i.e.
1036 // the face is on the "boundary"
1037 FElTr.Elem2No = face_info.Elem2No;
1039 FElTr.Elem2No >= 0)
1040 {
1041#ifdef MFEM_DEBUG
1043 { MFEM_ABORT("NURBS mesh not supported!"); }
1044#endif
1045 GetElementTransformation(FElTr.Elem2No, &ElTr2);
1046 FElTr.Elem2 = &ElTr2;
1047 cmask |= 2;
1048 }
1049
1050 // setup the face transformation
1052 {
1053 GetFaceTransformation(FaceNo, &FElTr);
1054 cmask |= 16;
1055 }
1056 else
1057 {
1058 FElTr.SetGeometryType(GetFaceGeometry(FaceNo));
1059 }
1060
1061 // setup Loc1 & Loc2
1062 int face_type = GetFaceElementType(FaceNo);
1064 {
1065 int elem_type = GetElementType(face_info.Elem1No);
1066 GetLocalFaceTransformation(face_type, elem_type,
1067 FElTr.Loc1.Transf, face_info.Elem1Inf);
1068 cmask |= 4;
1069 }
1071 FElTr.Elem2No >= 0)
1072 {
1073 int elem_type = GetElementType(face_info.Elem2No);
1074 GetLocalFaceTransformation(face_type, elem_type,
1075 FElTr.Loc2.Transf, face_info.Elem2Inf);
1076
1077 // NC meshes: prepend slave edge/face transformation to Loc2
1078 if (Nonconforming() && IsSlaveFace(face_info))
1079 {
1080 ApplyLocalSlaveTransformation(FElTr, face_info, false);
1081 }
1082 cmask |= 8;
1083 }
1084
1085 FElTr.SetConfigurationMask(cmask);
1086
1087 // This check can be useful for internal debugging, however it will fail on
1088 // periodic boundary faces, so we keep it disabled in general.
1089#if 0
1090#ifdef MFEM_DEBUG
1091 real_t dist = FElTr.CheckConsistency();
1092 if (dist >= 1e-12)
1093 {
1094 mfem::out << "\nInternal error: face id = " << FaceNo
1095 << ", dist = " << dist << '\n';
1096 FElTr.CheckConsistency(1); // print coordinates
1097 MFEM_ABORT("internal error");
1098 }
1099#endif
1100#endif
1101}
1102
1109
1113 IsoparametricTransformation &ElTr2) const
1114{
1115 if (faces_info[FaceNo].Elem2No < 0)
1116 {
1118 return;
1119 }
1120 GetFaceElementTransformations(FaceNo, FElTr, ElTr1, ElTr2);
1121}
1122
1129
1133 IsoparametricTransformation &ElTr2) const
1134{
1135 // Check if the face is interior, shared, or nonconforming.
1136 int fn = GetBdrElementFaceIndex(BdrElemNo);
1137 if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
1138 {
1140 return;
1141 }
1142 GetFaceElementTransformations(fn, FElTr, ElTr1, ElTr2, 21);
1143 FElTr.Attribute = boundary[BdrElemNo]->GetAttribute();
1144 FElTr.ElementNo = BdrElemNo;
1146 FElTr.mesh = this;
1147}
1148
1149bool Mesh::IsSlaveFace(const FaceInfo &fi) const
1150{
1151 return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
1152}
1153
1155 const FaceInfo &fi, bool is_ghost) const
1156{
1157#ifdef MFEM_THREAD_SAFE
1158 DenseMatrix composition;
1159#else
1160 static DenseMatrix composition;
1161#endif
1162 MFEM_ASSERT(fi.NCFace >= 0, "");
1163 MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error");
1164 if (!is_ghost)
1165 {
1166 // side 1 -> child side, side 2 -> parent side
1168 LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1169 // In 2D, we need to flip the point matrix since it is aligned with the
1170 // parent side.
1171 if (Dim == 2)
1172 {
1173 // swap points (columns) 0 and 1
1174 std::swap(composition(0,0), composition(0,1));
1175 std::swap(composition(1,0), composition(1,1));
1176 }
1177 LT.SetPointMat(composition);
1178 }
1179 else // is_ghost == true
1180 {
1181 // side 1 -> parent side, side 2 -> child side
1183 LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1184 // In 2D, there is no need to flip the point matrix since it is already
1185 // aligned with the parent side, see also ParNCMesh::GetFaceNeighbors.
1186 // In 3D the point matrix was flipped during construction in
1187 // ParNCMesh::GetFaceNeighbors and due to that it is already aligned with
1188 // the parent side.
1189 LT.SetPointMat(composition);
1190 }
1191}
1192
1194{
1195 FaceInformation face;
1196 int e1, e2;
1197 int inf1, inf2;
1198 int ncface;
1199 GetFaceElements(f, &e1, &e2);
1200 GetFaceInfos(f, &inf1, &inf2, &ncface);
1201 face.element[0].index = e1;
1203 face.element[0].orientation = inf1%64;
1204 face.element[0].local_face_id = inf1/64;
1205 face.element[1].local_face_id = inf2/64;
1206 face.ncface = ncface;
1207 face.point_matrix = nullptr;
1208 // The following figures out face.location, face.conformity,
1209 // face.element[1].index, and face.element[1].orientation.
1210 if (f < GetNumFaces()) // Non-ghost face
1211 {
1212 if (e2>=0)
1213 {
1214 if (ncface==-1)
1215 {
1221 face.element[1].index = e2;
1222 face.element[1].orientation = inf2%64;
1223 }
1224 else // ncface >= 0
1225 {
1231 face.element[1].index = e2;
1232 MFEM_ASSERT(inf2%64==0, "unexpected slave face orientation.");
1233 face.element[1].orientation = inf2%64;
1234 face.point_matrix = nc_faces_info[ncface].PointMatrix;
1235 }
1236 }
1237 else // e2<0
1238 {
1239 if (ncface==-1)
1240 {
1241 if (inf2<0)
1242 {
1248 face.element[1].index = -1;
1249 face.element[1].orientation = -1;
1250 }
1251 else // inf2 >= 0
1252 {
1258 face.element[1].index = -1 - e2;
1259 face.element[1].orientation = inf2%64;
1260 }
1261 }
1262 else // ncface >= 0
1263 {
1264 if (inf2 < 0)
1265 {
1271 face.element[1].index = -1;
1272 face.element[1].orientation = -1;
1273 }
1274 else
1275 {
1281 face.element[1].index = -1 - e2;
1282 face.element[1].orientation = inf2%64;
1283 }
1284 face.point_matrix = nc_faces_info[ncface].PointMatrix;
1285 }
1286 }
1287 }
1288 else // Ghost face
1289 {
1290 if (e1==-1)
1291 {
1297 face.element[1].index = -1;
1298 face.element[1].orientation = -1;
1299 }
1300 else
1301 {
1307 face.element[1].index = -1 - e2;
1308 face.element[1].orientation = inf2%64;
1309 face.point_matrix = nc_faces_info[ncface].PointMatrix;
1310 }
1311 }
1312 return face;
1313}
1314
1315Mesh::FaceInformation::operator Mesh::FaceInfo() const
1316{
1317 FaceInfo res {-1, -1, -1, -1, -1};
1318 switch (tag)
1319 {
1321 res.Elem1No = element[0].index;
1322 res.Elem2No = element[1].index;
1323 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1324 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1325 res.NCFace = ncface;
1326 break;
1328 res.Elem1No = element[0].index;
1329 res.Elem2No = element[1].index;
1330 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1331 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1332 res.NCFace = ncface;
1333 break;
1335 res.Elem1No = element[0].index;
1336 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1337 break;
1339 res.Elem1No = element[0].index;
1340 res.Elem2No = -1 - element[1].index;
1341 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1342 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1343 break;
1345 res.Elem1No = element[0].index;
1346 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1347 break;
1349 res.Elem1No = element[0].index;
1350 res.Elem2No = -1 - element[1].index;
1351 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1352 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1353 break;
1355 break;
1357 res.Elem1No = element[0].index;
1358 res.Elem2No = -1 - element[1].index;
1359 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1360 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1361 break;
1362 }
1363 return res;
1364}
1365
1366std::ostream &operator<<(std::ostream &os, const Mesh::FaceInformation& info)
1367{
1368 os << "face topology=";
1369 switch (info.topology)
1370 {
1372 os << "Boundary";
1373 break;
1375 os << "Conforming";
1376 break;
1378 os << "Non-conforming";
1379 break;
1381 os << "NA";
1382 break;
1383 }
1384 os << '\n';
1385 os << "element[0].location=";
1386 switch (info.element[0].location)
1387 {
1389 os << "Local";
1390 break;
1392 os << "FaceNbr";
1393 break;
1395 os << "NA";
1396 break;
1397 }
1398 os << '\n';
1399 os << "element[1].location=";
1400 switch (info.element[1].location)
1401 {
1403 os << "Local";
1404 break;
1406 os << "FaceNbr";
1407 break;
1409 os << "NA";
1410 break;
1411 }
1412 os << '\n';
1413 os << "element[0].conformity=";
1414 switch (info.element[0].conformity)
1415 {
1417 os << "Coincident";
1418 break;
1420 os << "Superset";
1421 break;
1423 os << "Subset";
1424 break;
1426 os << "NA";
1427 break;
1428 }
1429 os << '\n';
1430 os << "element[1].conformity=";
1431 switch (info.element[1].conformity)
1432 {
1434 os << "Coincident";
1435 break;
1437 os << "Superset";
1438 break;
1440 os << "Subset";
1441 break;
1443 os << "NA";
1444 break;
1445 }
1446 os << '\n';
1447 os << "element[0].index=" << info.element[0].index << '\n'
1448 << "element[1].index=" << info.element[1].index << '\n'
1449 << "element[0].local_face_id=" << info.element[0].local_face_id << '\n'
1450 << "element[1].local_face_id=" << info.element[1].local_face_id << '\n'
1451 << "element[0].orientation=" << info.element[0].orientation << '\n'
1452 << "element[1].orientation=" << info.element[1].orientation << '\n'
1453 << "ncface=" << info.ncface << std::endl;
1454 return os;
1455}
1456
1457void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2) const
1458{
1459 *Elem1 = faces_info[Face].Elem1No;
1460 *Elem2 = faces_info[Face].Elem2No;
1461}
1462
1463void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const
1464{
1465 *Inf1 = faces_info[Face].Elem1Inf;
1466 *Inf2 = faces_info[Face].Elem2Inf;
1467}
1468
1469void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2, int *NCFace) const
1470{
1471 *Inf1 = faces_info[Face].Elem1Inf;
1472 *Inf2 = faces_info[Face].Elem2Inf;
1473 *NCFace = faces_info[Face].NCFace;
1474}
1475
1477{
1478 switch (Dim)
1479 {
1480 case 1: return Geometry::POINT;
1481 case 2: return Geometry::SEGMENT;
1482 case 3:
1483 if (Face < NumOfFaces) // local (non-ghost) face
1484 {
1485 return faces[Face]->GetGeometryType();
1486 }
1487 // ghost face
1488 const int nc_face_id = faces_info[Face].NCFace;
1489
1490 MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported");
1491 return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType();
1492 }
1493 return Geometry::INVALID;
1494}
1495
1497{
1499 switch (elem_geom)
1500 {
1505 case Geometry::CUBE: return Geometry::SQUARE;
1508 default: return Geometry::INVALID;
1509 }
1510}
1511
1513{
1514 return (Dim == 1) ? Element::POINT : faces[Face]->GetType();
1515}
1516
1518{
1519 Array<int> face_to_be(Dim == 2 ? NumOfEdges : NumOfFaces);
1520 face_to_be = -1;
1521 for (int i = 0; i < NumOfBdrElements; i++)
1522 {
1523 face_to_be[GetBdrElementFaceIndex(i)] = i;
1524 }
1525 return face_to_be;
1526}
1527
1529{
1530 if (GetNE() > 0) { return GetElementGeometry(0); }
1531
1532 const int dim = Dimension();
1533 if (dim == 1)
1534 {
1535 return Geometry::SEGMENT;
1536 }
1538 if (dim == 2)
1539 {
1540 geom = ((meshgen & 1) ? Geometry::TRIANGLE :
1542 }
1543 else if (dim == 3)
1544 {
1545 geom = ((meshgen & 1) ? Geometry::TETRAHEDRON :
1546 ((meshgen & 2) ? Geometry::CUBE :
1547 ((meshgen & 4) ? Geometry::PRISM :
1549 }
1550 MFEM_VERIFY(geom != Geometry::INVALID,
1551 "Could not determine a typical element Geometry!");
1552 return geom;
1553}
1554
1556{
1557 const int num_faces = GetNumFaces();
1558
1559 face_marker.SetSize(num_faces);
1560
1561 for (int f = 0; f < num_faces; f++)
1562 {
1563 if (FaceIsTrueInterior(f))
1564 {
1565 face_marker[f] = 0;
1566 }
1567 else
1568 {
1569 face_marker[f] = 1;
1570 }
1571 }
1572}
1573
1574void Mesh::UnmarkInternalBoundaries(Array<int> &bdr_marker, bool excl) const
1575{
1576 const int max_bdr_attr = bdr_attributes.Max();
1577
1578 MFEM_VERIFY(bdr_marker.Size() >= max_bdr_attr,
1579 "bdr_marker must be at least bdr_attriburtes.Max() in length");
1580
1581 Array<bool> interior_bdr(max_bdr_attr); interior_bdr = false;
1582 Array<bool> exterior_bdr(max_bdr_attr); exterior_bdr = false;
1583
1584 // Identify attributes which contain interior faces and those which
1585 // contain exterior faces.
1586 for (int be = 0; be < boundary.Size(); be++)
1587 {
1588 const int bea = boundary[be]->GetAttribute();
1589
1590 if (bdr_marker[bea-1] != 0)
1591 {
1592 const int f = be_to_face[be];
1593
1594 if (FaceIsTrueInterior(f))
1595 {
1596 interior_bdr[bea-1] = true;
1597 }
1598 else
1599 {
1600 exterior_bdr[bea-1] = true;
1601 }
1602 }
1603 }
1604
1605 // Unmark attributes which are currently marked, contain interior faces,
1606 // and satisfy the appropriate exclusivity requirement.
1607 for (int b = 0; b < max_bdr_attr; b++)
1608 {
1609 if (bdr_marker[b] != 0 && interior_bdr[b])
1610 {
1611 if (!excl || !exterior_bdr[b])
1612 {
1613 bdr_marker[b] = 0;
1614 }
1615 }
1616 }
1617}
1618
1619void Mesh::UnmarkNamedBoundaries(const std::string &set_name,
1620 Array<int> &bdr_marker) const
1621{
1622 const int max_bdr_attr = bdr_attributes.Max();
1623
1624 MFEM_VERIFY(bdr_attribute_sets.AttributeSetExists(set_name),
1625 "Named set is not defined in this mesh!");
1626 MFEM_VERIFY(bdr_marker.Size() >= bdr_attributes.Max(),
1627 "bdr_marker must be at least bdr_attriburtes.Max() in length");
1628
1630
1631 for (int b = 0; b < max_bdr_attr; b++)
1632 {
1633 if (set_marker[b])
1634 {
1635 bdr_marker[b] = 0;
1636 }
1637 }
1638}
1639
1640void Mesh::MarkExternalBoundaries(Array<int> &bdr_marker, bool excl) const
1641{
1642 const int max_bdr_attr = bdr_attributes.Max();
1643
1644 MFEM_VERIFY(bdr_marker.Size() >= max_bdr_attr,
1645 "bdr_marker must be at least bdr_attriburtes.Max() in length");
1646
1647 Array<bool> interior_bdr(max_bdr_attr); interior_bdr = false;
1648 Array<bool> exterior_bdr(max_bdr_attr); exterior_bdr = false;
1649
1650 // Mark boundary attributes containing exterior faces while keeping track of
1651 // those which also contain interior faces.
1652 for (int be = 0; be < boundary.Size(); be++)
1653 {
1654 const int bea = boundary[be]->GetAttribute();
1655
1656 const int f = be_to_face[be];
1657
1658 if (FaceIsTrueInterior(f))
1659 {
1660 interior_bdr[bea-1] = true;
1661 }
1662 else
1663 {
1664 exterior_bdr[bea-1] = true;
1665 }
1666 }
1667
1668 // Mark attributes which were found to contain exterior faces and satisfy
1669 // the appropriate exclusivity requirement.
1670 for (int b = 0; b < max_bdr_attr; b++)
1671 {
1672 if (bdr_marker[b] == 0 && exterior_bdr[b])
1673 {
1674 if (!excl || !interior_bdr[b])
1675 {
1676 bdr_marker[b] = 1;
1677 }
1678 }
1679 }
1680}
1681
1682void Mesh::MarkNamedBoundaries(const std::string &set_name,
1683 Array<int> &bdr_marker) const
1684{
1685 const int max_bdr_attr = bdr_attributes.Max();
1686
1687 MFEM_VERIFY(bdr_attribute_sets.AttributeSetExists(set_name),
1688 "Named set is not defined in this mesh!");
1689 MFEM_VERIFY(bdr_marker.Size() >= max_bdr_attr,
1690 "bdr_marker must be at least bdr_attriburtes.Max() in length");
1691
1693
1694 for (int b = 0; b < max_bdr_attr; b++)
1695 {
1696 if (set_marker[b])
1697 {
1698 bdr_marker[b] = 1;
1699 }
1700 }
1701}
1702
1704{
1705 // in order of declaration:
1706 Dim = spaceDim = 0;
1707 NumOfVertices = -1;
1709 NumOfEdges = NumOfFaces = 0;
1710 nbInteriorFaces = -1;
1711 nbBoundaryFaces = -1;
1712 meshgen = mesh_geoms = 0;
1713 sequence = 0;
1714 nodes_sequence = 0;
1715 Nodes = NULL;
1716 own_nodes = 1;
1717 NURBSext = NULL;
1718 ncmesh = NULL;
1720}
1721
1723{
1724 el_to_edge =
1726 face_to_elem = NULL;
1727}
1728
1730{
1731 Init();
1732 InitTables();
1733}
1734
1736{
1737 delete el_to_edge;
1738 delete el_to_face;
1739 delete el_to_el;
1741
1742 if (Dim == 3)
1743 {
1744 delete bel_to_edge;
1745 }
1746
1747 delete face_edge;
1748 delete edge_vertex;
1749
1750 delete face_to_elem;
1751 face_to_elem = NULL;
1752}
1753
1755{
1756 if (own_nodes) { delete Nodes; }
1757
1758 delete ncmesh;
1759
1760 delete NURBSext;
1761
1762 for (int i = 0; i < NumOfElements; i++)
1763 {
1765 }
1766
1767 for (int i = 0; i < NumOfBdrElements; i++)
1768 {
1770 }
1771
1772 for (int i = 0; i < faces.Size(); i++)
1773 {
1774 FreeElement(faces[i]);
1775 }
1776
1777 DestroyTables();
1778}
1779
1781{
1783
1784 elements.DeleteAll();
1785 vertices.DeleteAll();
1786 boundary.DeleteAll();
1787 faces.DeleteAll();
1788 faces_info.DeleteAll();
1789 nc_faces_info.DeleteAll();
1791
1792 // TODO:
1793 // IsoparametricTransformations
1794 // Transformation, Transformation2, BdrTransformation, FaceTransformation,
1795 // EdgeTransformation;
1796 // FaceElementTransformations FaceElemTr;
1797
1799
1800#ifdef MFEM_USE_MEMALLOC
1801 TetMemory.Clear();
1802#endif
1803
1806}
1807
1809{
1810 delete el_to_el; el_to_el = NULL;
1811 delete face_edge; face_edge = NULL;
1812 delete face_to_elem; face_to_elem = NULL;
1813 delete edge_vertex; edge_vertex = NULL;
1815 nbInteriorFaces = -1;
1816 nbBoundaryFaces = -1;
1817}
1818
1820{
1821 Array<int> attribs;
1822
1823 attribs.SetSize(GetNBE());
1824 for (int i = 0; i < attribs.Size(); i++)
1825 {
1826 attribs[i] = GetBdrAttribute(i);
1827 }
1828 attribs.Sort();
1829 attribs.Unique();
1830 attribs.Copy(bdr_attributes);
1831 if (bdr_attributes.Size() > 0 && bdr_attributes[0] <= 0)
1832 {
1833 MFEM_WARNING("Non-positive attributes on the boundary!");
1834 }
1835
1836 attribs.SetSize(GetNE());
1837 for (int i = 0; i < attribs.Size(); i++)
1838 {
1839 attribs[i] = GetAttribute(i);
1840 }
1841 attribs.Sort();
1842 attribs.Unique();
1843 attribs.Copy(attributes);
1844 if (attributes.Size() > 0 && attributes[0] <= 0)
1845 {
1846 MFEM_WARNING("Non-positive attributes in the domain!");
1847 }
1848}
1849
1850void Mesh::InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
1851{
1852 SetEmpty();
1853
1854 Dim = Dim_;
1855 spaceDim = spaceDim_;
1856
1857 NumOfVertices = 0;
1858 vertices.SetSize(NVert); // just allocate space for vertices
1859
1860 NumOfElements = 0;
1861 elements.SetSize(NElem); // just allocate space for Element *
1862
1863 NumOfBdrElements = 0;
1864 boundary.SetSize(NBdrElem); // just allocate space for Element *
1865}
1866
1867template<typename T>
1868static void CheckEnlarge(Array<T> &array, int size)
1869{
1870 if (size >= array.Size()) { array.SetSize(size + 1); }
1871}
1872
1874{
1875 CheckEnlarge(vertices, NumOfVertices);
1877 v[0] = x;
1878 v[1] = y;
1879 v[2] = z;
1880 return NumOfVertices++;
1881}
1882
1883int Mesh::AddVertex(const real_t *coords)
1884{
1885 CheckEnlarge(vertices, NumOfVertices);
1886 vertices[NumOfVertices].SetCoords(spaceDim, coords);
1887 return NumOfVertices++;
1888}
1889
1890int Mesh::AddVertex(const Vector &coords)
1891{
1892 MFEM_ASSERT(coords.Size() >= spaceDim,
1893 "invalid 'coords' size: " << coords.Size());
1894 return AddVertex(coords.GetData());
1895}
1896
1897void Mesh::AddVertexParents(int i, int p1, int p2)
1898{
1899 tmp_vertex_parents.Append(Triple<int, int, int>(i, p1, p2));
1900
1901 // if vertex coordinates are defined, make sure the hanging vertex has the
1902 // correct position
1903 if (i < vertices.Size())
1904 {
1905 real_t *vi = vertices[i](), *vp1 = vertices[p1](), *vp2 = vertices[p2]();
1906 for (int j = 0; j < 3; j++)
1907 {
1908 vi[j] = (vp1[j] + vp2[j]) * 0.5;
1909 }
1910 }
1911}
1912
1913int Mesh::AddVertexAtMeanCenter(const int *vi, int nverts, int dim)
1914{
1915 Vector vii(dim);
1916 vii = 0.0;
1917 for (int i = 0; i < nverts; i++)
1918 {
1919 real_t *vp = vertices[vi[i]]();
1920 for (int j = 0; j < dim; j++)
1921 {
1922 vii(j) += vp[j];
1923 }
1924 }
1925 vii /= nverts;
1926 AddVertex(vii);
1927 return NumOfVertices;
1928}
1929
1930int Mesh::AddSegment(int v1, int v2, int attr)
1931{
1932 CheckEnlarge(elements, NumOfElements);
1933 elements[NumOfElements] = new Segment(v1, v2, attr);
1934 return NumOfElements++;
1935}
1936
1937int Mesh::AddSegment(const int *vi, int attr)
1938{
1939 CheckEnlarge(elements, NumOfElements);
1940 elements[NumOfElements] = new Segment(vi, attr);
1941 return NumOfElements++;
1942}
1943
1944int Mesh::AddTriangle(int v1, int v2, int v3, int attr)
1945{
1946 CheckEnlarge(elements, NumOfElements);
1947 elements[NumOfElements] = new Triangle(v1, v2, v3, attr);
1948 return NumOfElements++;
1949}
1950
1951int Mesh::AddTriangle(const int *vi, int attr)
1952{
1953 CheckEnlarge(elements, NumOfElements);
1954 elements[NumOfElements] = new Triangle(vi, attr);
1955 return NumOfElements++;
1956}
1957
1958int Mesh::AddQuad(int v1, int v2, int v3, int v4, int attr)
1959{
1960 CheckEnlarge(elements, NumOfElements);
1961 elements[NumOfElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1962 return NumOfElements++;
1963}
1964
1965int Mesh::AddQuad(const int *vi, int attr)
1966{
1967 CheckEnlarge(elements, NumOfElements);
1968 elements[NumOfElements] = new Quadrilateral(vi, attr);
1969 return NumOfElements++;
1970}
1971
1972int Mesh::AddTet(int v1, int v2, int v3, int v4, int attr)
1973{
1974 int vi[4] = {v1, v2, v3, v4};
1975 return AddTet(vi, attr);
1976}
1977
1978int Mesh::AddTet(const int *vi, int attr)
1979{
1980 CheckEnlarge(elements, NumOfElements);
1981#ifdef MFEM_USE_MEMALLOC
1982 Tetrahedron *tet;
1983 tet = TetMemory.Alloc();
1984 tet->SetVertices(vi);
1985 tet->SetAttribute(attr);
1986 elements[NumOfElements] = tet;
1987#else
1988 elements[NumOfElements] = new Tetrahedron(vi, attr);
1989#endif
1990 return NumOfElements++;
1991}
1992
1993int Mesh::AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr)
1994{
1995 CheckEnlarge(elements, NumOfElements);
1996 elements[NumOfElements] = new Wedge(v1, v2, v3, v4, v5, v6, attr);
1997 return NumOfElements++;
1998}
1999
2000int Mesh::AddWedge(const int *vi, int attr)
2001{
2002 CheckEnlarge(elements, NumOfElements);
2003 elements[NumOfElements] = new Wedge(vi, attr);
2004 return NumOfElements++;
2005}
2006
2007int Mesh::AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr)
2008{
2009 CheckEnlarge(elements, NumOfElements);
2010 elements[NumOfElements] = new Pyramid(v1, v2, v3, v4, v5, attr);
2011 return NumOfElements++;
2012}
2013
2014int Mesh::AddPyramid(const int *vi, int attr)
2015{
2016 CheckEnlarge(elements, NumOfElements);
2017 elements[NumOfElements] = new Pyramid(vi, attr);
2018 return NumOfElements++;
2019}
2020
2021int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
2022 int attr)
2023{
2024 CheckEnlarge(elements, NumOfElements);
2026 new Hexahedron(v1, v2, v3, v4, v5, v6, v7, v8, attr);
2027 return NumOfElements++;
2028}
2029
2030int Mesh::AddHex(const int *vi, int attr)
2031{
2032 CheckEnlarge(elements, NumOfElements);
2033 elements[NumOfElements] = new Hexahedron(vi, attr);
2034 return NumOfElements++;
2035}
2036
2037void Mesh::AddHexAsTets(const int *vi, int attr)
2038{
2039 static const int hex_to_tet[6][4] =
2040 {
2041 { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
2042 { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
2043 };
2044 int ti[4];
2045
2046 for (int i = 0; i < 6; i++)
2047 {
2048 for (int j = 0; j < 4; j++)
2049 {
2050 ti[j] = vi[hex_to_tet[i][j]];
2051 }
2052 AddTet(ti, attr);
2053 }
2054}
2055
2056void Mesh::AddHexAsWedges(const int *vi, int attr)
2057{
2058 static const int hex_to_wdg[2][6] =
2059 {
2060 { 0, 1, 2, 4, 5, 6 }, { 0, 2, 3, 4, 6, 7 }
2061 };
2062 int ti[6];
2063
2064 for (int i = 0; i < 2; i++)
2065 {
2066 for (int j = 0; j < 6; j++)
2067 {
2068 ti[j] = vi[hex_to_wdg[i][j]];
2069 }
2070 AddWedge(ti, attr);
2071 }
2072}
2073
2074void Mesh::AddHexAsPyramids(const int *vi, int attr)
2075{
2076 static const int hex_to_pyr[6][5] =
2077 {
2078 { 0, 1, 2, 3, 8 }, { 0, 4, 5, 1, 8 }, { 1, 5, 6, 2, 8 },
2079 { 2, 6, 7, 3, 8 }, { 3, 7, 4, 0, 8 }, { 7, 6, 5, 4, 8 }
2080 };
2081 int ti[5];
2082
2083 for (int i = 0; i < 6; i++)
2084 {
2085 for (int j = 0; j < 5; j++)
2086 {
2087 ti[j] = vi[hex_to_pyr[i][j]];
2088 }
2089 AddPyramid(ti, attr);
2090 }
2091}
2092
2093void Mesh::AddQuadAs4TrisWithPoints(int *vi, int attr)
2094{
2095 int num_faces = 4;
2096 static const int quad_to_tri[4][2] =
2097 {
2098 {0, 1}, {1, 2}, {2, 3}, {3, 0}
2099 };
2100
2101 int elem_center_index = AddVertexAtMeanCenter(vi, 4, 2) - 1;
2102
2103 int ti[3];
2104 ti[2] = elem_center_index;
2105 for (int i = 0; i < num_faces; i++)
2106 {
2107 for (int j = 0; j < 2; j++)
2108 {
2109 ti[j] = vi[quad_to_tri[i][j]];
2110 }
2111 AddTri(ti, attr);
2112 }
2113}
2114
2115void Mesh::AddQuadAs5QuadsWithPoints(int *vi, int attr)
2116{
2117 int num_faces = 4;
2118 static const int quad_faces[4][2] =
2119 {
2120 {0, 1}, {1, 2}, {2, 3}, {3, 0}
2121 };
2122
2123 Vector px(4), py(4);
2124 for (int i = 0; i < 4; i++)
2125 {
2126 real_t *vp = vertices[vi[i]]();
2127 px(i) = vp[0];
2128 py(i) = vp[1];
2129 }
2130
2131 int vnew_index[4];
2132 real_t vnew[2];
2133 real_t r = 0.25, s = 0.25;
2134 vnew[0] = px(0)*(1-r)*(1-s) + px(1)*(r)*(1-s) + px(2)*r*s + px(3)*(1-r)*s;
2135 vnew[1] = py(0)*(1-r)*(1-s) + py(1)*(r)*(1-s) + py(2)*r*s + py(3)*(1-r)*s;
2136 AddVertex(vnew);
2137 vnew_index[0] = NumOfVertices-1;
2138
2139 r = 0.75, s = 0.25;
2140 vnew[0] = px(0)*(1-r)*(1-s) + px(1)*(r)*(1-s) + px(2)*r*s + px(3)*(1-r)*s;
2141 vnew[1] = py(0)*(1-r)*(1-s) + py(1)*(r)*(1-s) + py(2)*r*s + py(3)*(1-r)*s;
2142 AddVertex(vnew);
2143 vnew_index[1] = NumOfVertices-1;
2144
2145 r = 0.75, s = 0.75;
2146 vnew[0] = px(0)*(1-r)*(1-s) + px(1)*(r)*(1-s) + px(2)*r*s + px(3)*(1-r)*s;
2147 vnew[1] = py(0)*(1-r)*(1-s) + py(1)*(r)*(1-s) + py(2)*r*s + py(3)*(1-r)*s;
2148 AddVertex(vnew);
2149 vnew_index[2] = NumOfVertices-1;
2150
2151 r = 0.25, s = 0.75;
2152 vnew[0] = px(0)*(1-r)*(1-s) + px(1)*(r)*(1-s) + px(2)*r*s + px(3)*(1-r)*s;
2153 vnew[1] = py(0)*(1-r)*(1-s) + py(1)*(r)*(1-s) + py(2)*r*s + py(3)*(1-r)*s;
2154 AddVertex(vnew);
2155 vnew_index[3] = NumOfVertices-1;
2156
2157 static const int quad_faces_new[4][2] =
2158 {
2159 { 1, 0}, { 2, 1}, { 3, 2}, { 0, 3}
2160 };
2161
2162 int ti[4];
2163 for (int i = 0; i < num_faces; i++)
2164 {
2165 for (int j = 0; j < 2; j++)
2166 {
2167 ti[j] = vi[quad_faces[i][j]];
2168 ti[j+2] = vnew_index[quad_faces_new[i][j]];
2169 }
2170 AddQuad(ti, attr);
2171 }
2172 AddQuad(vnew_index, attr);
2173}
2174
2176 std::map<std::array<int, 4>, int> &hex_face_verts,
2177 int attr)
2178{
2179 auto get4arraysorted = [](Array<int> v)
2180 {
2181 v.Sort();
2182 return std::array<int, 4> {v[0], v[1], v[2], v[3]};
2183 };
2184
2185 int num_faces = 6;
2186 static const int hex_to_tet[6][4] =
2187 {
2188 { 0, 1, 2, 3 }, { 1, 2, 6, 5 }, { 5, 4, 7, 6},
2189 { 0, 1, 5, 4 }, { 2, 3, 7, 6 }, { 0,3, 7, 4}
2190 };
2191
2192 int elem_center_index = AddVertexAtMeanCenter(vi, 8, 3) - 1;
2193
2194 Array<int> flist(4);
2195
2196 // local vertex indices for each of the 4 edges of the face
2197 static const int tet_face[4][2] =
2198 {
2199 {0, 1}, {1, 2}, {3, 2}, {3, 0}
2200 };
2201
2202 for (int i = 0; i < num_faces; i++)
2203 {
2204 for (int j = 0; j < 4; j++)
2205 {
2206 flist[j] = vi[hex_to_tet[i][j]];
2207 }
2208 int face_center_index;
2209
2210 auto t = get4arraysorted(flist);
2211 auto it = hex_face_verts.find(t);
2212 if (it == hex_face_verts.end())
2213 {
2214 face_center_index = AddVertexAtMeanCenter(flist.GetData(),
2215 flist.Size(), 3) - 1;
2216 hex_face_verts.insert({t, face_center_index});
2217 }
2218 else
2219 {
2220 face_center_index = it->second;
2221 }
2222 int fti[4];
2223 fti[2] = face_center_index;
2224 fti[3] = elem_center_index;
2225 for (int j = 0; j < 4; j++)
2226 {
2227 for (int k = 0; k < 2; k++)
2228 {
2229 fti[k] = flist[tet_face[j][k]];
2230 }
2231 AddTet(fti, attr);
2232 }
2233 }
2234}
2235
2237{
2238 CheckEnlarge(elements, NumOfElements);
2239 elements[NumOfElements] = elem;
2240 return NumOfElements++;
2241}
2242
2244{
2245 CheckEnlarge(boundary, NumOfBdrElements);
2246 boundary[NumOfBdrElements] = elem;
2247 return NumOfBdrElements++;
2248}
2249
2251 const Array<int> &new_be_to_face)
2252{
2253 boundary.Reserve(boundary.Size() + bdr_elems.Size());
2254 MFEM_ASSERT(bdr_elems.Size() == new_be_to_face.Size(), "wrong size");
2255 for (int i = 0; i < bdr_elems.Size(); i++)
2256 {
2257 AddBdrElement(bdr_elems[i]);
2258 }
2259 be_to_face.Append(new_be_to_face);
2260}
2261
2262int Mesh::AddBdrSegment(int v1, int v2, int attr)
2263{
2264 CheckEnlarge(boundary, NumOfBdrElements);
2265 boundary[NumOfBdrElements] = new Segment(v1, v2, attr);
2266 return NumOfBdrElements++;
2267}
2268
2269int Mesh::AddBdrSegment(const int *vi, int attr)
2270{
2271 CheckEnlarge(boundary, NumOfBdrElements);
2272 boundary[NumOfBdrElements] = new Segment(vi, attr);
2273 return NumOfBdrElements++;
2274}
2275
2276int Mesh::AddBdrTriangle(int v1, int v2, int v3, int attr)
2277{
2278 CheckEnlarge(boundary, NumOfBdrElements);
2279 boundary[NumOfBdrElements] = new Triangle(v1, v2, v3, attr);
2280 return NumOfBdrElements++;
2281}
2282
2283int Mesh::AddBdrTriangle(const int *vi, int attr)
2284{
2285 CheckEnlarge(boundary, NumOfBdrElements);
2286 boundary[NumOfBdrElements] = new Triangle(vi, attr);
2287 return NumOfBdrElements++;
2288}
2289
2290int Mesh::AddBdrQuad(int v1, int v2, int v3, int v4, int attr)
2291{
2292 CheckEnlarge(boundary, NumOfBdrElements);
2293 boundary[NumOfBdrElements] = new Quadrilateral(v1, v2, v3, v4, attr);
2294 return NumOfBdrElements++;
2295}
2296
2297int Mesh::AddBdrQuad(const int *vi, int attr)
2298{
2299 CheckEnlarge(boundary, NumOfBdrElements);
2300 boundary[NumOfBdrElements] = new Quadrilateral(vi, attr);
2301 return NumOfBdrElements++;
2302}
2303
2304void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
2305{
2306 static const int quad_to_tri[2][3] = { { 0, 1, 2 }, { 0, 2, 3 } };
2307 int ti[3];
2308
2309 for (int i = 0; i < 2; i++)
2310 {
2311 for (int j = 0; j < 3; j++)
2312 {
2313 ti[j] = vi[quad_to_tri[i][j]];
2314 }
2315 AddBdrTriangle(ti, attr);
2316 }
2317}
2318
2319int Mesh::AddBdrPoint(int v, int attr)
2320{
2321 CheckEnlarge(boundary, NumOfBdrElements);
2322 boundary[NumOfBdrElements] = new Point(&v, attr);
2323 return NumOfBdrElements++;
2324}
2325
2327{
2328 for (auto &b : boundary)
2329 {
2330 FreeElement(b);
2331 }
2332
2333 if (Dim == 3)
2334 {
2335 delete bel_to_edge;
2336 bel_to_edge = NULL;
2337 }
2338
2339 // count the 'NumOfBdrElements'
2340 NumOfBdrElements = 0;
2341 for (const auto &fi : faces_info)
2342 {
2343 if (fi.Elem2No < 0) { ++NumOfBdrElements; }
2344 }
2345
2346 // Add the boundary elements
2349 for (int i = 0, j = 0; i < faces_info.Size(); i++)
2350 {
2351 if (faces_info[i].Elem2No < 0)
2352 {
2353 boundary[j] = faces[i]->Duplicate(this);
2354 be_to_face[j++] = i;
2355 }
2356 }
2357
2358 // Note: in 3D, 'bel_to_edge' is destroyed but it's not updated.
2359}
2360
2362{
2363 MFEM_VERIFY(vertices.Size() == NumOfVertices ||
2364 vertices.Size() == 0,
2365 "incorrect number of vertices: preallocated: " << vertices.Size()
2366 << ", actually added: " << NumOfVertices);
2367 MFEM_VERIFY(elements.Size() == NumOfElements,
2368 "incorrect number of elements: preallocated: " << elements.Size()
2369 << ", actually added: " << NumOfElements);
2370 MFEM_VERIFY(boundary.Size() == NumOfBdrElements,
2371 "incorrect number of boundary elements: preallocated: "
2372 << boundary.Size() << ", actually added: " << NumOfBdrElements);
2373}
2374
2375void Mesh::FinalizeTriMesh(int generate_edges, int refine, bool fix_orientation)
2376{
2377 FinalizeCheck();
2378 CheckElementOrientation(fix_orientation);
2379
2380 if (refine)
2381 {
2383 }
2384
2385 if (generate_edges)
2386 {
2387 el_to_edge = new Table;
2389 GenerateFaces();
2391 }
2392 else
2393 {
2394 NumOfEdges = 0;
2395 }
2396
2397 NumOfFaces = 0;
2398
2399 SetAttributes();
2400
2401 SetMeshGen();
2402}
2403
2404void Mesh::FinalizeQuadMesh(int generate_edges, int refine,
2405 bool fix_orientation)
2406{
2407 FinalizeCheck();
2408 if (fix_orientation)
2409 {
2410 CheckElementOrientation(fix_orientation);
2411 }
2412
2413 if (generate_edges)
2414 {
2415 el_to_edge = new Table;
2417 GenerateFaces();
2419 }
2420 else
2421 {
2422 NumOfEdges = 0;
2423 }
2424
2425 NumOfFaces = 0;
2426
2427 SetAttributes();
2428
2429 SetMeshGen();
2430}
2431
2432
2433class GeckoProgress : public Gecko::Progress
2434{
2435 real_t limit;
2436 mutable StopWatch sw;
2437public:
2438 GeckoProgress(real_t limit) : limit(limit) { sw.Start(); }
2439 bool quit() const override { return limit > 0 && sw.UserTime() > limit; }
2440};
2441
2442class GeckoVerboseProgress : public GeckoProgress
2443{
2444 using Float = Gecko::Float;
2445 using Graph = Gecko::Graph;
2446 using uint = Gecko::uint;
2447public:
2448 GeckoVerboseProgress(real_t limit) : GeckoProgress(limit) {}
2449
2450 void beginorder(const Graph* graph, Float cost) const override
2451 { mfem::out << "Begin Gecko ordering, cost = " << cost << std::endl; }
2452 void endorder(const Graph* graph, Float cost) const override
2453 { mfem::out << "End ordering, cost = " << cost << std::endl; }
2454
2455 void beginiter(const Graph* graph,
2456 uint iter, uint maxiter, uint window) const override
2457 {
2458 mfem::out << "Iteration " << iter << "/" << maxiter << ", window "
2459 << window << std::flush;
2460 }
2461 void enditer(const Graph* graph, Float mincost, Float cost) const override
2462 { mfem::out << ", cost = " << cost << endl; }
2463};
2464
2465
2467 int iterations, int window,
2468 int period, int seed, bool verbose,
2469 real_t time_limit)
2470{
2471 Gecko::Graph graph;
2472 Gecko::FunctionalGeometric functional; // edge product cost
2473
2474 GeckoProgress progress(time_limit);
2475 GeckoVerboseProgress vprogress(time_limit);
2476
2477 // insert elements as nodes in the graph
2478 for (int elemid = 0; elemid < GetNE(); ++elemid)
2479 {
2480 graph.insert_node();
2481 }
2482
2483 // insert graph edges for element neighbors
2484 // NOTE: indices in Gecko are 1 based hence the +1 on insertion
2485 const Table &my_el_to_el = ElementToElementTable();
2486 for (int elemid = 0; elemid < GetNE(); ++elemid)
2487 {
2488 const int *neighid = my_el_to_el.GetRow(elemid);
2489 for (int i = 0; i < my_el_to_el.RowSize(elemid); ++i)
2490 {
2491 graph.insert_arc(elemid + 1, neighid[i] + 1);
2492 }
2493 }
2494
2495 // get the ordering from Gecko and copy it into the Array<int>
2496 graph.order(&functional, iterations, window, period, seed,
2497 verbose ? &vprogress : &progress);
2498
2499 ordering.SetSize(GetNE());
2501 for (Gecko::Node::Index gnodeid = 1; gnodeid <= NE; ++gnodeid)
2502 {
2503 ordering[gnodeid - 1] = graph.rank(gnodeid);
2504 }
2505
2506 return graph.cost();
2507}
2508
2509
2510struct HilbertCmp
2511{
2512 int coord;
2513 bool dir;
2514 const Array<real_t> &points;
2515 real_t mid;
2516
2517 HilbertCmp(int coord, bool dir, const Array<real_t> &points, real_t mid)
2518 : coord(coord), dir(dir), points(points), mid(mid) {}
2519
2520 bool operator()(int i) const
2521 {
2522 return (points[3*i + coord] < mid) != dir;
2523 }
2524};
2525
2526static void HilbertSort2D(int coord1, // major coordinate to sort points by
2527 bool dir1, // sort coord1 ascending/descending?
2528 bool dir2, // sort coord2 ascending/descending?
2529 const Array<real_t> &points, int *beg, int *end,
2530 real_t xmin, real_t ymin, real_t xmax, real_t ymax)
2531{
2532 if (end - beg <= 1) { return; }
2533
2534 real_t xmid = (xmin + xmax)*0.5;
2535 real_t ymid = (ymin + ymax)*0.5;
2536
2537 int coord2 = (coord1 + 1) % 2; // the 'other' coordinate
2538
2539 // sort (partition) points into four quadrants
2540 int *p0 = beg, *p4 = end;
2541 int *p2 = std::partition(p0, p4, HilbertCmp(coord1, dir1, points, xmid));
2542 int *p1 = std::partition(p0, p2, HilbertCmp(coord2, dir2, points, ymid));
2543 int *p3 = std::partition(p2, p4, HilbertCmp(coord2, !dir2, points, ymid));
2544
2545 if (p1 != p4)
2546 {
2547 HilbertSort2D(coord2, dir2, dir1, points, p0, p1,
2548 ymin, xmin, ymid, xmid);
2549 }
2550 if (p1 != p0 || p2 != p4)
2551 {
2552 HilbertSort2D(coord1, dir1, dir2, points, p1, p2,
2553 xmin, ymid, xmid, ymax);
2554 }
2555 if (p2 != p0 || p3 != p4)
2556 {
2557 HilbertSort2D(coord1, dir1, dir2, points, p2, p3,
2558 xmid, ymid, xmax, ymax);
2559 }
2560 if (p3 != p0)
2561 {
2562 HilbertSort2D(coord2, !dir2, !dir1, points, p3, p4,
2563 ymid, xmax, ymin, xmid);
2564 }
2565}
2566
2567static void HilbertSort3D(int coord1, bool dir1, bool dir2, bool dir3,
2568 const Array<real_t> &points, int *beg, int *end,
2569 real_t xmin, real_t ymin, real_t zmin,
2570 real_t xmax, real_t ymax, real_t zmax)
2571{
2572 if (end - beg <= 1) { return; }
2573
2574 real_t xmid = (xmin + xmax)*0.5;
2575 real_t ymid = (ymin + ymax)*0.5;
2576 real_t zmid = (zmin + zmax)*0.5;
2577
2578 int coord2 = (coord1 + 1) % 3;
2579 int coord3 = (coord1 + 2) % 3;
2580
2581 // sort (partition) points into eight octants
2582 int *p0 = beg, *p8 = end;
2583 int *p4 = std::partition(p0, p8, HilbertCmp(coord1, dir1, points, xmid));
2584 int *p2 = std::partition(p0, p4, HilbertCmp(coord2, dir2, points, ymid));
2585 int *p6 = std::partition(p4, p8, HilbertCmp(coord2, !dir2, points, ymid));
2586 int *p1 = std::partition(p0, p2, HilbertCmp(coord3, dir3, points, zmid));
2587 int *p3 = std::partition(p2, p4, HilbertCmp(coord3, !dir3, points, zmid));
2588 int *p5 = std::partition(p4, p6, HilbertCmp(coord3, dir3, points, zmid));
2589 int *p7 = std::partition(p6, p8, HilbertCmp(coord3, !dir3, points, zmid));
2590
2591 if (p1 != p8)
2592 {
2593 HilbertSort3D(coord3, dir3, dir1, dir2, points, p0, p1,
2594 zmin, xmin, ymin, zmid, xmid, ymid);
2595 }
2596 if (p1 != p0 || p2 != p8)
2597 {
2598 HilbertSort3D(coord2, dir2, dir3, dir1, points, p1, p2,
2599 ymin, zmid, xmin, ymid, zmax, xmid);
2600 }
2601 if (p2 != p0 || p3 != p8)
2602 {
2603 HilbertSort3D(coord2, dir2, dir3, dir1, points, p2, p3,
2604 ymid, zmid, xmin, ymax, zmax, xmid);
2605 }
2606 if (p3 != p0 || p4 != p8)
2607 {
2608 HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p3, p4,
2609 xmin, ymax, zmid, xmid, ymid, zmin);
2610 }
2611 if (p4 != p0 || p5 != p8)
2612 {
2613 HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p4, p5,
2614 xmid, ymax, zmid, xmax, ymid, zmin);
2615 }
2616 if (p5 != p0 || p6 != p8)
2617 {
2618 HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p5, p6,
2619 ymax, zmid, xmax, ymid, zmax, xmid);
2620 }
2621 if (p6 != p0 || p7 != p8)
2622 {
2623 HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p6, p7,
2624 ymid, zmid, xmax, ymin, zmax, xmid);
2625 }
2626 if (p7 != p0)
2627 {
2628 HilbertSort3D(coord3, !dir3, !dir1, dir2, points, p7, p8,
2629 zmid, xmax, ymin, zmin, xmid, ymid);
2630 }
2631}
2632
2634{
2635 MFEM_VERIFY(spaceDim <= 3, "");
2636
2637 Vector min, max, center;
2638 GetBoundingBox(min, max);
2639
2640 Array<int> indices(GetNE());
2641 Array<real_t> points(3*GetNE());
2642
2643 if (spaceDim < 3) { points = 0.0; }
2644
2645 // calculate element centers
2646 for (int i = 0; i < GetNE(); i++)
2647 {
2648 GetElementCenter(i, center);
2649 for (int j = 0; j < spaceDim; j++)
2650 {
2651 points[3*i + j] = center(j);
2652 }
2653 indices[i] = i;
2654 }
2655
2656 if (spaceDim == 1)
2657 {
2658 indices.Sort([&](int a, int b)
2659 { return points[3*a] < points[3*b]; });
2660 }
2661 else if (spaceDim == 2)
2662 {
2663 // recursively partition the points in 2D
2664 HilbertSort2D(0, false, false,
2665 points, indices.begin(), indices.end(),
2666 min(0), min(1), max(0), max(1));
2667 }
2668 else
2669 {
2670 // recursively partition the points in 3D
2671 HilbertSort3D(0, false, false, false,
2672 points, indices.begin(), indices.end(),
2673 min(0), min(1), min(2), max(0), max(1), max(2));
2674 }
2675
2676 // return ordering in the format required by ReorderElements
2677 ordering.SetSize(GetNE());
2678 for (int i = 0; i < GetNE(); i++)
2679 {
2680 ordering[indices[i]] = i;
2681 }
2682}
2683
2684
2685void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
2686{
2687 if (NURBSext)
2688 {
2689 MFEM_WARNING("element reordering of NURBS meshes is not supported.");
2690 return;
2691 }
2692 if (ncmesh)
2693 {
2694 MFEM_WARNING("element reordering of non-conforming meshes is not"
2695 " supported.");
2696 return;
2697 }
2698 MFEM_VERIFY(ordering.Size() == GetNE(), "invalid reordering array.")
2699
2700 // Data members that need to be updated:
2701
2702 // - elements - reorder of the pointers and the vertex ids if reordering
2703 // the vertices
2704 // - vertices - if reordering the vertices
2705 // - boundary - update the vertex ids, if reordering the vertices
2706 // - faces - regenerate
2707 // - faces_info - regenerate
2708
2709 // Deleted by DeleteTables():
2710 // - el_to_edge - rebuild in 2D and 3D only
2711 // - el_to_face - rebuild in 3D only
2712 // - bel_to_edge - rebuild in 3D only
2713 // - el_to_el - no need to rebuild
2714 // - face_edge - no need to rebuild
2715 // - edge_vertex - no need to rebuild
2716 // - geom_factors - no need to rebuild
2717
2718 // - be_to_face
2719
2720 // - Nodes
2721
2722 // Save the locations of the Nodes so we can rebuild them later
2723 Array<Vector*> old_elem_node_vals;
2724 FiniteElementSpace *nodes_fes = NULL;
2725 if (Nodes)
2726 {
2727 old_elem_node_vals.SetSize(GetNE());
2728 nodes_fes = Nodes->FESpace();
2729 Array<int> old_dofs;
2730 Vector vals;
2731 for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2732 {
2733 nodes_fes->GetElementVDofs(old_elid, old_dofs);
2734 Nodes->GetSubVector(old_dofs, vals);
2735 old_elem_node_vals[old_elid] = new Vector(vals);
2736 }
2737 }
2738
2739 // Get the newly ordered elements
2740 Array<Element *> new_elements(GetNE());
2741 for (int old_elid = 0; old_elid < ordering.Size(); ++old_elid)
2742 {
2743 int new_elid = ordering[old_elid];
2744 new_elements[new_elid] = elements[old_elid];
2745 }
2746 mfem::Swap(elements, new_elements);
2747 new_elements.DeleteAll();
2748
2749 if (reorder_vertices)
2750 {
2751 // Get the new vertex ordering permutation vectors and fill the new
2752 // vertices
2753 Array<int> vertex_ordering(GetNV());
2754 vertex_ordering = -1;
2755 Array<Vertex> new_vertices(GetNV());
2756 int new_vertex_ind = 0;
2757 for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2758 {
2759 int *elem_vert = elements[new_elid]->GetVertices();
2760 int nv = elements[new_elid]->GetNVertices();
2761 for (int vi = 0; vi < nv; ++vi)
2762 {
2763 int old_vertex_ind = elem_vert[vi];
2764 if (vertex_ordering[old_vertex_ind] == -1)
2765 {
2766 vertex_ordering[old_vertex_ind] = new_vertex_ind;
2767 new_vertices[new_vertex_ind] = vertices[old_vertex_ind];
2768 new_vertex_ind++;
2769 }
2770 }
2771 }
2772 mfem::Swap(vertices, new_vertices);
2773 new_vertices.DeleteAll();
2774
2775 // Replace the vertex ids in the elements with the reordered vertex
2776 // numbers
2777 for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2778 {
2779 int *elem_vert = elements[new_elid]->GetVertices();
2780 int nv = elements[new_elid]->GetNVertices();
2781 for (int vi = 0; vi < nv; ++vi)
2782 {
2783 elem_vert[vi] = vertex_ordering[elem_vert[vi]];
2784 }
2785 }
2786
2787 // Replace the vertex ids in the boundary with reordered vertex numbers
2788 for (int belid = 0; belid < GetNBE(); ++belid)
2789 {
2790 int *be_vert = boundary[belid]->GetVertices();
2791 int nv = boundary[belid]->GetNVertices();
2792 for (int vi = 0; vi < nv; ++vi)
2793 {
2794 be_vert[vi] = vertex_ordering[be_vert[vi]];
2795 }
2796 }
2797 }
2798
2799 // Destroy tables that need to be rebuild
2800 DeleteTables();
2801
2802 if (Dim > 1)
2803 {
2804 // generate el_to_edge, be_to_face (2D), bel_to_edge (3D)
2805 el_to_edge = new Table;
2807 }
2808 if (Dim > 2)
2809 {
2810 // generate el_to_face, be_to_face
2812 }
2813 // Update faces and faces_info
2814 GenerateFaces();
2815
2816 // Build the nodes from the saved locations if they were around before
2817 if (Nodes)
2818 {
2819 // To force FE space update, we need to increase 'sequence':
2820 sequence++;
2823 nodes_fes->Update(false); // want_transform = false
2824 Nodes->Update(); // just needed to update Nodes->sequence
2825 Array<int> new_dofs;
2826 for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2827 {
2828 int new_elid = ordering[old_elid];
2829 nodes_fes->GetElementVDofs(new_elid, new_dofs);
2830 Nodes->SetSubVector(new_dofs, *(old_elem_node_vals[old_elid]));
2831 delete old_elem_node_vals[old_elid];
2832 }
2833 }
2834}
2835
2836
2838{
2839 if (meshgen & 1)
2840 {
2841 if (Dim == 2)
2842 {
2844 }
2845 else if (Dim == 3)
2846 {
2847 DSTable v_to_v(NumOfVertices);
2848 GetVertexToVertexTable(v_to_v);
2850 }
2851 }
2852}
2853
2855{
2856 // Mark the longest triangle edge by rotating the indices so that
2857 // vertex 0 - vertex 1 is the longest edge in the triangle.
2858 DenseMatrix pmat;
2859 for (int i = 0; i < NumOfElements; i++)
2860 {
2861 if (elements[i]->GetType() == Element::TRIANGLE)
2862 {
2863 GetPointMatrix(i, pmat);
2864 static_cast<Triangle*>(elements[i])->MarkEdge(pmat);
2865 }
2866 }
2867}
2868
2869void Mesh::GetEdgeOrdering(const DSTable &v_to_v, Array<int> &order)
2870{
2871 NumOfEdges = v_to_v.NumberOfEntries();
2872 order.SetSize(NumOfEdges);
2873 Array<Pair<real_t, int> > length_idx(NumOfEdges);
2874
2875 for (int i = 0; i < NumOfVertices; i++)
2876 {
2877 for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
2878 {
2879 int j = it.Index();
2880 length_idx[j].one = GetLength(i, it.Column());
2881 length_idx[j].two = j;
2882 }
2883 }
2884
2885 // Sort by increasing edge-length.
2886 length_idx.Sort();
2887
2888 for (int i = 0; i < NumOfEdges; i++)
2889 {
2890 order[length_idx[i].two] = i;
2891 }
2892}
2893
2895{
2896 // Mark the longest tetrahedral edge by rotating the indices so that
2897 // vertex 0 - vertex 1 is the longest edge in the element.
2898 Array<int> order;
2899 GetEdgeOrdering(v_to_v, order);
2900
2901 for (int i = 0; i < NumOfElements; i++)
2902 {
2903 if (elements[i]->GetType() == Element::TETRAHEDRON)
2904 {
2905 elements[i]->MarkEdge(v_to_v, order);
2906 }
2907 }
2908 for (int i = 0; i < NumOfBdrElements; i++)
2909 {
2910 if (boundary[i]->GetType() == Element::TRIANGLE)
2911 {
2912 boundary[i]->MarkEdge(v_to_v, order);
2913 }
2914 }
2915}
2916
2917void Mesh::PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
2918{
2919 if (*old_v_to_v && *old_elem_vert)
2920 {
2921 return;
2922 }
2923
2925
2926 if (*old_v_to_v == NULL)
2927 {
2928 bool need_v_to_v = false;
2929 Array<int> dofs;
2930 for (int i = 0; i < GetNEdges(); i++)
2931 {
2932 // Since edge indices may change, we need to permute edge interior dofs
2933 // any time an edge index changes and there is at least one dof on that
2934 // edge.
2935 fes->GetEdgeInteriorDofs(i, dofs);
2936 if (dofs.Size() > 0)
2937 {
2938 need_v_to_v = true;
2939 break;
2940 }
2941 }
2942 if (need_v_to_v)
2943 {
2944 *old_v_to_v = new DSTable(NumOfVertices);
2945 GetVertexToVertexTable(*(*old_v_to_v));
2946 }
2947 }
2948 if (*old_elem_vert == NULL)
2949 {
2950 bool need_elem_vert = false;
2951 Array<int> dofs;
2952 for (int i = 0; i < GetNE(); i++)
2953 {
2954 // Since element indices do not change, we need to permute element
2955 // interior dofs only when there are at least 2 interior dofs in an
2956 // element (assuming the nodal dofs are non-directional).
2957 fes->GetElementInteriorDofs(i, dofs);
2958 if (dofs.Size() > 1)
2959 {
2960 need_elem_vert = true;
2961 break;
2962 }
2963 }
2964 if (need_elem_vert)
2965 {
2966 *old_elem_vert = new Table;
2967 (*old_elem_vert)->MakeI(GetNE());
2968 for (int i = 0; i < GetNE(); i++)
2969 {
2970 (*old_elem_vert)->AddColumnsInRow(i, elements[i]->GetNVertices());
2971 }
2972 (*old_elem_vert)->MakeJ();
2973 for (int i = 0; i < GetNE(); i++)
2974 {
2975 (*old_elem_vert)->AddConnections(i, elements[i]->GetVertices(),
2976 elements[i]->GetNVertices());
2977 }
2978 (*old_elem_vert)->ShiftUpI();
2979 }
2980 }
2981}
2982
2983void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
2984{
2986 const FiniteElementCollection *fec = fes->FEColl();
2987 Array<int> old_dofs, new_dofs;
2988
2989 // assuming that all edges have the same number of dofs
2990 if (NumOfEdges) { fes->GetEdgeInteriorDofs(0, old_dofs); }
2991 const int num_edge_dofs = old_dofs.Size();
2992
2993 // Save the original nodes
2994 const Vector onodes = *Nodes;
2995
2996 // vertex dofs do not need to be moved
2997 fes->GetVertexDofs(0, old_dofs);
2998 int offset = NumOfVertices * old_dofs.Size();
2999
3000 // edge dofs:
3001 // edge enumeration may be different but edge orientation is the same
3002 if (num_edge_dofs > 0)
3003 {
3004 DSTable new_v_to_v(NumOfVertices);
3005 GetVertexToVertexTable(new_v_to_v);
3006
3007 for (int i = 0; i < NumOfVertices; i++)
3008 {
3009 for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it)
3010 {
3011 const int old_i = (*old_v_to_v)(i, it.Column());
3012 const int new_i = it.Index();
3013 if (new_i == old_i) { continue; }
3014
3015 old_dofs.SetSize(num_edge_dofs);
3016 new_dofs.SetSize(num_edge_dofs);
3017 for (int j = 0; j < num_edge_dofs; j++)
3018 {
3019 old_dofs[j] = offset + old_i * num_edge_dofs + j;
3020 new_dofs[j] = offset + new_i * num_edge_dofs + j;
3021 }
3022 fes->DofsToVDofs(old_dofs);
3023 fes->DofsToVDofs(new_dofs);
3024 for (int j = 0; j < old_dofs.Size(); j++)
3025 {
3026 (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
3027 }
3028 }
3029 }
3030 offset += NumOfEdges * num_edge_dofs;
3031 }
3032
3033 // face dofs:
3034 // both enumeration and orientation of the faces may be different
3035 if (fes->GetNFDofs() > 0)
3036 {
3037 // generate the old face-vertex table using the unmodified 'faces'
3038 Table old_face_vertex;
3039 old_face_vertex.MakeI(NumOfFaces);
3040 for (int i = 0; i < NumOfFaces; i++)
3041 {
3042 old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices());
3043 }
3044 old_face_vertex.MakeJ();
3045 for (int i = 0; i < NumOfFaces; i++)
3046 old_face_vertex.AddConnections(i, faces[i]->GetVertices(),
3047 faces[i]->GetNVertices());
3048 old_face_vertex.ShiftUpI();
3049
3050 // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info'
3051 STable3D *faces_tbl = GetElementToFaceTable(1);
3052 GenerateFaces();
3053
3054 // compute the new face dof offsets
3055 Array<int> new_fdofs(NumOfFaces+1);
3056 new_fdofs[0] = 0;
3057 for (int i = 0; i < NumOfFaces; i++) // i = old face index
3058 {
3059 const int *old_v = old_face_vertex.GetRow(i);
3060 int new_i; // new face index
3061 switch (old_face_vertex.RowSize(i))
3062 {
3063 case 3:
3064 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
3065 break;
3066 case 4:
3067 default:
3068 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
3069 break;
3070 }
3071 fes->GetFaceInteriorDofs(i, old_dofs);
3072 new_fdofs[new_i+1] = old_dofs.Size();
3073 }
3074 new_fdofs.PartialSum();
3075
3076 // loop over the old face numbers
3077 for (int i = 0; i < NumOfFaces; i++)
3078 {
3079 const int *old_v = old_face_vertex.GetRow(i), *new_v;
3080 const int *dof_ord;
3081 int new_i, new_or;
3082 switch (old_face_vertex.RowSize(i))
3083 {
3084 case 3:
3085 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
3086 new_v = faces[new_i]->GetVertices();
3087 new_or = GetTriOrientation(old_v, new_v);
3088 dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, new_or);
3089 break;
3090 case 4:
3091 default:
3092 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
3093 new_v = faces[new_i]->GetVertices();
3094 new_or = GetQuadOrientation(old_v, new_v);
3095 dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, new_or);
3096 break;
3097 }
3098
3099 fes->GetFaceInteriorDofs(i, old_dofs);
3100 new_dofs.SetSize(old_dofs.Size());
3101 for (int j = 0; j < old_dofs.Size(); j++)
3102 {
3103 // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
3104 const int old_j = dof_ord[j];
3105 new_dofs[old_j] = offset + new_fdofs[new_i] + j;
3106 }
3107 fes->DofsToVDofs(old_dofs);
3108 fes->DofsToVDofs(new_dofs);
3109 for (int j = 0; j < old_dofs.Size(); j++)
3110 {
3111 (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
3112 }
3113 }
3114
3115 offset += fes->GetNFDofs();
3116 delete faces_tbl;
3117 }
3118
3119 // element dofs:
3120 // element orientation may be different
3121 if (old_elem_vert) // have elements with 2 or more dofs
3122 {
3123 // matters when the 'fec' is
3124 // (this code is executed only for triangles/tets)
3125 // - Pk on triangles, k >= 4
3126 // - Qk on quads, k >= 3
3127 // - Pk on tets, k >= 5
3128 // - Qk on hexes, k >= 3
3129 // - DG spaces
3130 // - ...
3131
3132 // loop over all elements
3133 for (int i = 0; i < GetNE(); i++)
3134 {
3135 const int *old_v = old_elem_vert->GetRow(i);
3136 const int *new_v = elements[i]->GetVertices();
3137 const int *dof_ord;
3138 int new_or;
3139 const Geometry::Type geom = elements[i]->GetGeometryType();
3140 switch (geom)
3141 {
3142 case Geometry::SEGMENT:
3143 new_or = (old_v[0] == new_v[0]) ? +1 : -1;
3144 break;
3145 case Geometry::TRIANGLE:
3146 new_or = GetTriOrientation(old_v, new_v);
3147 break;
3148 case Geometry::SQUARE:
3149 new_or = GetQuadOrientation(old_v, new_v);
3150 break;
3152 new_or = GetTetOrientation(old_v, new_v);
3153 break;
3154 default:
3155 new_or = 0;
3156 MFEM_ABORT(Geometry::Name[geom] << " elements (" << fec->Name()
3157 << " FE collection) are not supported yet!");
3158 break;
3159 }
3160 dof_ord = fec->DofOrderForOrientation(geom, new_or);
3161 MFEM_VERIFY(dof_ord != NULL,
3162 "FE collection '" << fec->Name()
3163 << "' does not define reordering for "
3164 << Geometry::Name[geom] << " elements!");
3165 fes->GetElementInteriorDofs(i, old_dofs);
3166 new_dofs.SetSize(old_dofs.Size());
3167 for (int j = 0; j < new_dofs.Size(); j++)
3168 {
3169 // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
3170 const int old_j = dof_ord[j];
3171 new_dofs[old_j] = offset + j;
3172 }
3173 offset += new_dofs.Size();
3174 fes->DofsToVDofs(old_dofs);
3175 fes->DofsToVDofs(new_dofs);
3176 for (int j = 0; j < old_dofs.Size(); j++)
3177 {
3178 (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
3179 }
3180 }
3181 }
3182
3183 // Update Tables, faces, etc
3184 if (Dim > 2)
3185 {
3186 if (fes->GetNFDofs() == 0)
3187 {
3188 // needed for FE spaces that have face dofs, even if
3189 // the 'Nodes' do not have face dofs.
3191 GenerateFaces();
3192 }
3194 }
3195 if (el_to_edge)
3196 {
3197 // update 'el_to_edge', 'be_to_face' (2D), 'bel_to_edge' (3D)
3199 if (Dim == 2)
3200 {
3201 // update 'faces' and 'faces_info'
3202 GenerateFaces();
3204 }
3205 }
3206 // To force FE space update, we need to increase 'sequence':
3207 sequence++;
3210 fes->Update(false); // want_transform = false
3211 Nodes->Update(); // just needed to update Nodes->sequence
3212}
3213
3214void Mesh::SetPatchAttribute(int i, int attr)
3215{
3216 MFEM_ASSERT(NURBSext, "SetPatchAttribute is only for NURBS meshes");
3217 NURBSext->SetPatchAttribute(i, attr);
3218 const Array<int>& elems = NURBSext->GetPatchElements(i);
3219 for (auto e : elems)
3220 {
3221 SetAttribute(e, attr);
3222 }
3223}
3224
3226{
3227 MFEM_ASSERT(NURBSext, "GetPatchAttribute is only for NURBS meshes");
3228 return NURBSext->GetPatchAttribute(i);
3229}
3230
3231void Mesh::SetPatchBdrAttribute(int i, int attr)
3232{
3233 MFEM_ASSERT(NURBSext, "SetPatchBdrAttribute is only for NURBS meshes");
3235
3236 const Array<int>& bdryelems = NURBSext->GetPatchBdrElements(i);
3237 for (auto be : bdryelems)
3238 {
3239 SetBdrAttribute(be, attr);
3240 }
3241}
3242
3244{
3245 MFEM_ASSERT(NURBSext, "GetBdrPatchBdrAttribute is only for NURBS meshes");
3246 return NURBSext->GetPatchBdrAttribute(i);
3247}
3248
3249void Mesh::FinalizeTetMesh(int generate_edges, int refine, bool fix_orientation)
3250{
3251 FinalizeCheck();
3252 CheckElementOrientation(fix_orientation);
3253
3254 if (!HasBoundaryElements())
3255 {
3257 GenerateFaces();
3259 }
3260
3261 if (refine)
3262 {
3263 DSTable v_to_v(NumOfVertices);
3264 GetVertexToVertexTable(v_to_v);
3266 }
3267
3269 GenerateFaces();
3270
3272
3273 if (generate_edges == 1)
3274 {
3275 el_to_edge = new Table;
3277 }
3278 else
3279 {
3280 el_to_edge = NULL; // Not really necessary -- InitTables was called
3281 bel_to_edge = NULL;
3282 NumOfEdges = 0;
3283 }
3284
3285 SetAttributes();
3286
3287 SetMeshGen();
3288}
3289
3290void Mesh::FinalizeWedgeMesh(int generate_edges, int refine,
3291 bool fix_orientation)
3292{
3293 FinalizeCheck();
3294 CheckElementOrientation(fix_orientation);
3295
3296 if (!HasBoundaryElements())
3297 {
3299 GenerateFaces();
3301 }
3302
3304 GenerateFaces();
3305
3307
3308 if (generate_edges == 1)
3309 {
3310 el_to_edge = new Table;
3312 }
3313 else
3314 {
3315 el_to_edge = NULL; // Not really necessary -- InitTables was called
3316 bel_to_edge = NULL;
3317 NumOfEdges = 0;
3318 }
3319
3320 SetAttributes();
3321
3322 SetMeshGen();
3323}
3324
3325void Mesh::FinalizeHexMesh(int generate_edges, int refine, bool fix_orientation)
3326{
3327 FinalizeCheck();
3328 CheckElementOrientation(fix_orientation);
3329
3331 GenerateFaces();
3332
3333 if (!HasBoundaryElements())
3334 {
3336 }
3337
3339
3340 if (generate_edges)
3341 {
3342 el_to_edge = new Table;
3344 }
3345 else
3346 {
3347 NumOfEdges = 0;
3348 }
3349
3350 SetAttributes();
3351
3352 SetMeshGen();
3353}
3354
3355void Mesh::FinalizeMesh(int refine, bool fix_orientation)
3356{
3358
3359 Finalize(refine, fix_orientation);
3360}
3361
3362void Mesh::FinalizeTopology(bool generate_bdr)
3363{
3364 // Requirements: the following should be defined:
3365 // 1) Dim
3366 // 2) NumOfElements, elements
3367 // 3) NumOfBdrElements, boundary
3368 // 4) NumOfVertices
3369 // Optional:
3370 // 2) ncmesh may be defined
3371 // 3) el_to_edge may be allocated (it will be re-computed)
3372
3373 FinalizeCheck();
3374 bool generate_edges = true;
3375
3376 if (spaceDim == 0) { spaceDim = Dim; }
3377 if (ncmesh) { ncmesh->spaceDim = spaceDim; }
3378
3379 // if the user defined any hanging nodes (see AddVertexParent),
3380 // we're initializing a non-conforming mesh
3381 if (tmp_vertex_parents.Size())
3382 {
3383 MFEM_VERIFY(ncmesh == NULL, "");
3384 ncmesh = new NCMesh(this);
3385
3386 // we need to recreate the Mesh because NCMesh reorders the vertices
3387 // (see NCMesh::UpdateVertices())
3389 ncmesh->OnMeshUpdated(this);
3391
3392 SetAttributes();
3393
3394 tmp_vertex_parents.DeleteAll();
3395 return;
3396 }
3397
3398 // set the mesh type: 'meshgen', ...
3399 SetMeshGen();
3400
3401 // generate the faces
3402 if (Dim > 2)
3403 {
3405 GenerateFaces();
3406 if (!HasBoundaryElements() && generate_bdr)
3407 {
3409 GetElementToFaceTable(); // update be_to_face
3410 }
3411 }
3412 else
3413 {
3414 NumOfFaces = 0;
3415 }
3416
3417 // generate edges if requested
3418 if (Dim > 1 && generate_edges)
3419 {
3420 // el_to_edge may already be allocated (P2 VTK meshes)
3421 if (!el_to_edge) { el_to_edge = new Table; }
3423 if (Dim == 2)
3424 {
3425 GenerateFaces(); // 'Faces' in 2D refers to the edges
3426 if (!HasBoundaryElements() && generate_bdr)
3427 {
3429 }
3430 }
3431 }
3432 else
3433 {
3434 NumOfEdges = 0;
3435 }
3436
3437 if (Dim == 1)
3438 {
3439 GenerateFaces();
3440 if (!HasBoundaryElements() && generate_bdr)
3441 {
3442 // be_to_face will be set inside GenerateBoundaryElements
3444 }
3445 else
3446 {
3448 for (int i = 0; i < NumOfBdrElements; ++i)
3449 {
3450 be_to_face[i] = boundary[i]->GetVertices()[0];
3451 }
3452 }
3453 }
3454
3455 if (ncmesh)
3456 {
3457 // tell NCMesh the numbering of edges/faces
3458 ncmesh->OnMeshUpdated(this);
3459
3460 // update faces_info with NC relations
3462 }
3463
3464 // generate the arrays 'attributes' and 'bdr_attributes'
3465 SetAttributes();
3466}
3467
3468void Mesh::Finalize(bool refine, bool fix_orientation)
3469{
3470 if (NURBSext || ncmesh)
3471 {
3472 MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
3473 MFEM_ASSERT(CheckBdrElementOrientation() == 0, "");
3474 return;
3475 }
3476
3477 // Requirements:
3478 // 1) FinalizeTopology() or equivalent was called
3479 // 2) if (Nodes == NULL), vertices must be defined
3480 // 3) if (Nodes != NULL), Nodes must be defined
3481
3482 const bool check_orientation = true; // for regular elements, not boundary
3483 const bool curved = (Nodes != NULL);
3484 const bool may_change_topology =
3485 ( refine && (Dim > 1 && (meshgen & 1)) ) ||
3486 ( check_orientation && fix_orientation &&
3487 (Dim == 2 || (Dim == 3 && (meshgen & 1))) );
3488
3489 DSTable *old_v_to_v = NULL;
3490 Table *old_elem_vert = NULL;
3491
3492 if (curved && may_change_topology)
3493 {
3494 PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
3495 }
3496
3497 if (check_orientation)
3498 {
3499 // check and optionally fix element orientation
3500 CheckElementOrientation(fix_orientation);
3501 }
3502 if (refine)
3503 {
3504 MarkForRefinement(); // may change topology!
3505 }
3506
3507 if (may_change_topology)
3508 {
3509 if (curved)
3510 {
3511 DoNodeReorder(old_v_to_v, old_elem_vert); // updates the mesh topology
3512 delete old_elem_vert;
3513 delete old_v_to_v;
3514 }
3515 else
3516 {
3517 FinalizeTopology(); // Re-computes some data unnecessarily.
3518 }
3519
3520 // TODO: maybe introduce Mesh::NODE_REORDER operation and FESpace::
3521 // NodeReorderMatrix and do Nodes->Update() instead of DoNodeReorder?
3522 }
3523
3524 // check and fix boundary element orientation
3526
3527#ifdef MFEM_DEBUG
3528 // For non-orientable surfaces/manifolds, the check below will fail, so we
3529 // only perform it when Dim == spaceDim.
3530 if (Dim >= 2 && Dim == spaceDim)
3531 {
3532 const int num_faces = GetNumFaces();
3533 for (int i = 0; i < num_faces; i++)
3534 {
3535 MFEM_VERIFY(faces_info[i].Elem2No < 0 ||
3536 faces_info[i].Elem2Inf%2 != 0, "Invalid mesh topology."
3537 " Interior face with incompatible orientations.");
3538 }
3539 }
3540#endif
3541}
3542
3543void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
3544 real_t sx, real_t sy, real_t sz, bool sfc_ordering)
3545{
3546 int x, y, z;
3547
3548 int NVert, NElem, NBdrElem;
3549
3550 NVert = (nx+1) * (ny+1) * (nz+1);
3551 NElem = nx * ny * nz;
3552 NBdrElem = 2*(nx*ny+nx*nz+ny*nz);
3553 if (type == Element::TETRAHEDRON)
3554 {
3555 NElem *= 6;
3556 NBdrElem *= 2;
3557 }
3558 else if (type == Element::WEDGE)
3559 {
3560 NElem *= 2;
3561 NBdrElem += 2*nx*ny;
3562 }
3563 else if (type == Element::PYRAMID)
3564 {
3565 NElem *= 6;
3566 NVert += nx * ny * nz;
3567 }
3568
3569 InitMesh(3, 3, NVert, NElem, NBdrElem);
3570
3571 real_t coord[3];
3572 int ind[9];
3573
3574 // Sets vertices and the corresponding coordinates
3575 for (z = 0; z <= nz; z++)
3576 {
3577 coord[2] = ((real_t) z / nz) * sz;
3578 for (y = 0; y <= ny; y++)
3579 {
3580 coord[1] = ((real_t) y / ny) * sy;
3581 for (x = 0; x <= nx; x++)
3582 {
3583 coord[0] = ((real_t) x / nx) * sx;
3584 AddVertex(coord);
3585 }
3586 }
3587 }
3588 if (type == Element::PYRAMID)
3589 {
3590 for (z = 0; z < nz; z++)
3591 {
3592 coord[2] = (((real_t) z + 0.5) / nz) * sz;
3593 for (y = 0; y < ny; y++)
3594 {
3595 coord[1] = (((real_t) y + 0.5) / ny) * sy;
3596 for (x = 0; x < nx; x++)
3597 {
3598 coord[0] = (((real_t) x + 0.5) / nx) * sx;
3599 AddVertex(coord);
3600 }
3601 }
3602 }
3603 }
3604
3605#define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
3606#define VTXP(XC, YC, ZC) ((nx+1)*(ny+1)*(nz+1)+(XC)+((YC)+(ZC)*ny)*nx)
3607
3608 // Sets elements and the corresponding indices of vertices
3609 if (sfc_ordering && type == Element::HEXAHEDRON)
3610 {
3611 Array<int> sfc;
3612 NCMesh::GridSfcOrdering3D(nx, ny, nz, sfc);
3613 MFEM_VERIFY(sfc.Size() == 3*nx*ny*nz, "");
3614
3615 for (int k = 0; k < nx*ny*nz; k++)
3616 {
3617 x = sfc[3*k + 0];
3618 y = sfc[3*k + 1];
3619 z = sfc[3*k + 2];
3620
3621 // *INDENT-OFF*
3622 ind[0] = VTX(x , y , z );
3623 ind[1] = VTX(x+1, y , z );
3624 ind[2] = VTX(x+1, y+1, z );
3625 ind[3] = VTX(x , y+1, z );
3626 ind[4] = VTX(x , y , z+1);
3627 ind[5] = VTX(x+1, y , z+1);
3628 ind[6] = VTX(x+1, y+1, z+1);
3629 ind[7] = VTX(x , y+1, z+1);
3630 // *INDENT-ON*
3631
3632 AddHex(ind, 1);
3633 }
3634 }
3635 else
3636 {
3637 for (z = 0; z < nz; z++)
3638 {
3639 for (y = 0; y < ny; y++)
3640 {
3641 for (x = 0; x < nx; x++)
3642 {
3643 // *INDENT-OFF*
3644 ind[0] = VTX(x , y , z );
3645 ind[1] = VTX(x+1, y , z );
3646 ind[2] = VTX(x+1, y+1, z );
3647 ind[3] = VTX(x , y+1, z );
3648 ind[4] = VTX(x , y , z+1);
3649 ind[5] = VTX(x+1, y , z+1);
3650 ind[6] = VTX(x+1, y+1, z+1);
3651 ind[7] = VTX( x, y+1, z+1);
3652 // *INDENT-ON*
3653 if (type == Element::TETRAHEDRON)
3654 {
3655 AddHexAsTets(ind, 1);
3656 }
3657 else if (type == Element::WEDGE)
3658 {
3659 AddHexAsWedges(ind, 1);
3660 }
3661 else if (type == Element::PYRAMID)
3662 {
3663 ind[8] = VTXP(x, y, z);
3664 AddHexAsPyramids(ind, 1);
3665 }
3666 else
3667 {
3668 AddHex(ind, 1);
3669 }
3670 }
3671 }
3672 }
3673 }
3674
3675 // Sets boundary elements and the corresponding indices of vertices
3676 // bottom, bdr. attribute 1
3677 for (y = 0; y < ny; y++)
3678 {
3679 for (x = 0; x < nx; x++)
3680 {
3681 // *INDENT-OFF*
3682 ind[0] = VTX(x , y , 0);
3683 ind[1] = VTX(x , y+1, 0);
3684 ind[2] = VTX(x+1, y+1, 0);
3685 ind[3] = VTX(x+1, y , 0);
3686 // *INDENT-ON*
3687 if (type == Element::TETRAHEDRON)
3688 {
3689 AddBdrQuadAsTriangles(ind, 1);
3690 }
3691 else if (type == Element::WEDGE)
3692 {
3693 AddBdrQuadAsTriangles(ind, 1);
3694 }
3695 else
3696 {
3697 AddBdrQuad(ind, 1);
3698 }
3699 }
3700 }
3701 // top, bdr. attribute 6
3702 for (y = 0; y < ny; y++)
3703 {
3704 for (x = 0; x < nx; x++)
3705 {
3706 // *INDENT-OFF*
3707 ind[0] = VTX(x , y , nz);
3708 ind[1] = VTX(x+1, y , nz);
3709 ind[2] = VTX(x+1, y+1, nz);
3710 ind[3] = VTX(x , y+1, nz);
3711 // *INDENT-ON*
3712 if (type == Element::TETRAHEDRON)
3713 {
3714 AddBdrQuadAsTriangles(ind, 6);
3715 }
3716 else if (type == Element::WEDGE)
3717 {
3718 AddBdrQuadAsTriangles(ind, 6);
3719 }
3720 else
3721 {
3722 AddBdrQuad(ind, 6);
3723 }
3724 }
3725 }
3726 // left, bdr. attribute 5
3727 for (z = 0; z < nz; z++)
3728 {
3729 for (y = 0; y < ny; y++)
3730 {
3731 // *INDENT-OFF*
3732 ind[0] = VTX(0 , y , z );
3733 ind[1] = VTX(0 , y , z+1);
3734 ind[2] = VTX(0 , y+1, z+1);
3735 ind[3] = VTX(0 , y+1, z );
3736 // *INDENT-ON*
3737 if (type == Element::TETRAHEDRON)
3738 {
3739 AddBdrQuadAsTriangles(ind, 5);
3740 }
3741 else
3742 {
3743 AddBdrQuad(ind, 5);
3744 }
3745 }
3746 }
3747 // right, bdr. attribute 3
3748 for (z = 0; z < nz; z++)
3749 {
3750 for (y = 0; y < ny; y++)
3751 {
3752 // *INDENT-OFF*
3753 ind[0] = VTX(nx, y , z );
3754 ind[1] = VTX(nx, y+1, z );
3755 ind[2] = VTX(nx, y+1, z+1);
3756 ind[3] = VTX(nx, y , z+1);
3757 // *INDENT-ON*
3758 if (type == Element::TETRAHEDRON)
3759 {
3760 AddBdrQuadAsTriangles(ind, 3);
3761 }
3762 else
3763 {
3764 AddBdrQuad(ind, 3);
3765 }
3766 }
3767 }
3768 // front, bdr. attribute 2
3769 for (x = 0; x < nx; x++)
3770 {
3771 for (z = 0; z < nz; z++)
3772 {
3773 // *INDENT-OFF*
3774 ind[0] = VTX(x , 0, z );
3775 ind[1] = VTX(x+1, 0, z );
3776 ind[2] = VTX(x+1, 0, z+1);
3777 ind[3] = VTX(x , 0, z+1);
3778 // *INDENT-ON*
3779 if (type == Element::TETRAHEDRON)
3780 {
3781 AddBdrQuadAsTriangles(ind, 2);
3782 }
3783 else
3784 {
3785 AddBdrQuad(ind, 2);
3786 }
3787 }
3788 }
3789 // back, bdr. attribute 4
3790 for (x = 0; x < nx; x++)
3791 {
3792 for (z = 0; z < nz; z++)
3793 {
3794 // *INDENT-OFF*
3795 ind[0] = VTX(x , ny, z );
3796 ind[1] = VTX(x , ny, z+1);
3797 ind[2] = VTX(x+1, ny, z+1);
3798 ind[3] = VTX(x+1, ny, z );
3799 // *INDENT-ON*
3800 if (type == Element::TETRAHEDRON)
3801 {
3802 AddBdrQuadAsTriangles(ind, 4);
3803 }
3804 else
3805 {
3806 AddBdrQuad(ind, 4);
3807 }
3808 }
3809 }
3810
3811#undef VTX
3812#undef VTXP
3813
3814#if 0
3815 ofstream test_stream("debug.mesh");
3816 Print(test_stream);
3817 test_stream.close();
3818#endif
3819
3821
3822 // Finalize(...) can be called after this method, if needed
3823}
3824
3825
3826void Mesh::Make2D4TrisFromQuad(int nx, int ny, real_t sx, real_t sy)
3827{
3828 SetEmpty();
3829
3830 Dim = 2;
3831 spaceDim = 2;
3832
3833 NumOfVertices = (nx+1) * (ny+1);
3834 NumOfElements = nx * ny * 4;
3835 NumOfBdrElements = (2 * nx + 2 * ny);
3836 vertices.SetSize(NumOfVertices);
3837 elements.SetSize(NumOfElements);
3838 boundary.SetSize(NumOfBdrElements);
3839 NumOfElements = 0;
3840
3841 int ind[4];
3842
3843 // Sets vertices and the corresponding coordinates
3844 int k = 0;
3845 for (real_t j = 0; j < ny+1; j++)
3846 {
3847 real_t cy = (j / ny) * sy;
3848 for (real_t i = 0; i < nx+1; i++)
3849 {
3850 real_t cx = (i / nx) * sx;
3851 vertices[k](0) = cx;
3852 vertices[k](1) = cy;
3853 k++;
3854 }
3855 }
3856
3857 for (int y = 0; y < ny; y++)
3858 {
3859 for (int x = 0; x < nx; x++)
3860 {
3861 ind[0] = x + y*(nx+1);
3862 ind[1] = x + 1 +y*(nx+1);
3863 ind[2] = x + 1 + (y+1)*(nx+1);
3864 ind[3] = x + (y+1)*(nx+1);
3866 }
3867 }
3868
3869 int m = (nx+1)*ny;
3870 for (int i = 0; i < nx; i++)
3871 {
3872 boundary[i] = new Segment(i, i+1, 1);
3873 boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3874 }
3875 m = nx+1;
3876 for (int j = 0; j < ny; j++)
3877 {
3878 boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3879 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3880 }
3881
3882 SetMeshGen();
3884
3885 el_to_edge = new Table;
3887 GenerateFaces();
3889
3890 NumOfFaces = 0;
3891
3892 attributes.Append(1);
3895
3897}
3898
3899void Mesh::Make2D5QuadsFromQuad(int nx, int ny,
3900 real_t sx, real_t sy)
3901{
3902 SetEmpty();
3903
3904 Dim = 2;
3905 spaceDim = 2;
3906
3907 NumOfElements = nx * ny * 5;
3908 NumOfVertices = (nx+1) * (ny+1); //it will be enlarged later on
3909 NumOfBdrElements = (2 * nx + 2 * ny);
3910 vertices.SetSize(NumOfVertices);
3911 elements.SetSize(NumOfElements);
3912 boundary.SetSize(NumOfBdrElements);
3913 NumOfElements = 0;
3914
3915 int ind[4];
3916
3917 // Sets vertices and the corresponding coordinates
3918 int k = 0;
3919 for (real_t j = 0; j < ny+1; j++)
3920 {
3921 real_t cy = (j / ny) * sy;
3922 for (real_t i = 0; i < nx+1; i++)
3923 {
3924 real_t cx = (i / nx) * sx;
3925 vertices[k](0) = cx;
3926 vertices[k](1) = cy;
3927 k++;
3928 }
3929 }
3930
3931 for (int y = 0; y < ny; y++)
3932 {
3933 for (int x = 0; x < nx; x++)
3934 {
3935 ind[0] = x + y*(nx+1);
3936 ind[1] = x + 1 +y*(nx+1);
3937 ind[2] = x + 1 + (y+1)*(nx+1);
3938 ind[3] = x + (y+1)*(nx+1);
3940 }
3941 }
3942
3943 int m = (nx+1)*ny;
3944 for (int i = 0; i < nx; i++)
3945 {
3946 boundary[i] = new Segment(i, i+1, 1);
3947 boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3948 }
3949 m = nx+1;
3950 for (int j = 0; j < ny; j++)
3951 {
3952 boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3953 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3954 }
3955
3956 SetMeshGen();
3958
3959 el_to_edge = new Table;
3961 GenerateFaces();
3963
3964 NumOfFaces = 0;
3965
3966 attributes.Append(1);
3969
3971}
3972
3973void Mesh::Make3D24TetsFromHex(int nx, int ny, int nz,
3974 real_t sx, real_t sy, real_t sz)
3975{
3976 const int NVert = (nx+1) * (ny+1) * (nz+1);
3977 const int NElem = nx * ny * nz * 24;
3978 const int NBdrElem = 2*(nx*ny+nx*nz+ny*nz)*4;
3979
3980 InitMesh(3, 3, NVert, NElem, NBdrElem);
3981
3982 real_t coord[3];
3983
3984 // Sets vertices and the corresponding coordinates
3985 for (real_t z = 0; z <= nz; z++)
3986 {
3987 coord[2] = ( z / nz) * sz;
3988 for (real_t y = 0; y <= ny; y++)
3989 {
3990 coord[1] = (y / ny) * sy;
3991 for (real_t x = 0; x <= nx; x++)
3992 {
3993 coord[0] = (x / nx) * sx;
3994 AddVertex(coord);
3995 }
3996 }
3997 }
3998
3999 std::map<std::array<int, 4>, int> hex_face_verts;
4000 auto VertexIndex = [nx, ny](int xc, int yc, int zc)
4001 {
4002 return xc + (yc + zc*(ny+1))*(nx+1);
4003 };
4004
4005 int ind[9];
4006 for (int z = 0; z < nz; z++)
4007 {
4008 for (int y = 0; y < ny; y++)
4009 {
4010 for (int x = 0; x < nx; x++)
4011 {
4012 // *INDENT-OFF*
4013 ind[0] = VertexIndex(x , y , z );
4014 ind[1] = VertexIndex(x+1, y , z );
4015 ind[2] = VertexIndex(x+1, y+1, z );
4016 ind[3] = VertexIndex(x , y+1, z );
4017 ind[4] = VertexIndex(x , y , z+1);
4018 ind[5] = VertexIndex(x+1, y , z+1);
4019 ind[6] = VertexIndex(x+1, y+1, z+1);
4020 ind[7] = VertexIndex( x, y+1, z+1);
4021 AddHexAs24TetsWithPoints(ind, hex_face_verts, 1);
4022 }
4023 }
4024 }
4025
4026 hex_face_verts.clear();
4028
4029 // Done adding Tets
4030 // Now figure out elements that are on the boundary
4031 GetElementToFaceTable(false);
4032 GenerateFaces();
4033
4034 // Map to count number of tets sharing a face
4035 std::map<std::array<int, 3>, int> tet_face_count;
4036 // Map from tet face defined by three vertices to the local face number
4037 std::map<std::array<int, 3>, int> face_count_map;
4038
4039 auto get3array = [](Array<int> v)
4040 {
4041 v.Sort();
4042 return std::array<int, 3>{v[0], v[1], v[2]};
4043 };
4044
4045 Array<int> el_faces;
4046 Array<int> ori;
4047 Array<int> vertidxs;
4048 for (int i = 0; i < el_to_face->Size(); i++)
4049 {
4050 el_to_face->GetRow(i, el_faces);
4051 for (int j = 0; j < el_faces.Size(); j++)
4052 {
4053 GetFaceVertices(el_faces[j], vertidxs);
4054 auto t = get3array(vertidxs);
4055 auto it = tet_face_count.find(t);
4056 if (it == tet_face_count.end()) //edge does not already exist
4057 {
4058 tet_face_count.insert({t, 1});
4059 face_count_map.insert({t, el_faces[j]});
4060 }
4061 else
4062 {
4063 it->second++; // increase edge count value by 1.
4064 }
4065 }
4066 }
4067
4068 for (const auto &edge : tet_face_count)
4069 {
4070 if (edge.second == 1) //if this only appears once, it is a boundary edge
4071 {
4072 int facenum = (face_count_map.find(edge.first))->second;
4073 GetFaceVertices(facenum, vertidxs);
4074 AddBdrTriangle(vertidxs, 1);
4075 }
4076 }
4077
4078#if 0
4079 ofstream test_stream("debug.mesh");
4080 Print(test_stream);
4081 test_stream.close();
4082#endif
4083
4085 // Finalize(...) can be called after this method, if needed
4086}
4087
4088void Mesh::Make2D(int nx, int ny, Element::Type type,
4089 real_t sx, real_t sy,
4090 bool generate_edges, bool sfc_ordering)
4091{
4092 int i, j, k;
4093
4094 SetEmpty();
4095
4096 Dim = spaceDim = 2;
4097
4098 // Creates quadrilateral mesh
4099 if (type == Element::QUADRILATERAL)
4100 {
4101 NumOfVertices = (nx+1) * (ny+1);
4102 NumOfElements = nx * ny;
4103 NumOfBdrElements = 2 * nx + 2 * ny;
4104
4105 vertices.SetSize(NumOfVertices);
4106 elements.SetSize(NumOfElements);
4107 boundary.SetSize(NumOfBdrElements);
4108
4109 real_t cx, cy;
4110 int ind[4];
4111
4112 // Sets vertices and the corresponding coordinates
4113 k = 0;
4114 for (j = 0; j < ny+1; j++)
4115 {
4116 cy = ((real_t) j / ny) * sy;
4117 for (i = 0; i < nx+1; i++)
4118 {
4119 cx = ((real_t) i / nx) * sx;
4120 vertices[k](0) = cx;
4121 vertices[k](1) = cy;
4122 k++;
4123 }
4124 }
4125
4126 // Sets elements and the corresponding indices of vertices
4127 if (sfc_ordering)
4128 {
4129 Array<int> sfc;
4130 NCMesh::GridSfcOrdering2D(nx, ny, sfc);
4131 MFEM_VERIFY(sfc.Size() == 2*nx*ny, "");
4132
4133 for (k = 0; k < nx*ny; k++)
4134 {
4135 i = sfc[2*k + 0];
4136 j = sfc[2*k + 1];
4137 ind[0] = i + j*(nx+1);
4138 ind[1] = i + 1 +j*(nx+1);
4139 ind[2] = i + 1 + (j+1)*(nx+1);
4140 ind[3] = i + (j+1)*(nx+1);
4141 elements[k] = new Quadrilateral(ind);
4142 }
4143 }
4144 else
4145 {
4146 k = 0;
4147 for (j = 0; j < ny; j++)
4148 {
4149 for (i = 0; i < nx; i++)
4150 {
4151 ind[0] = i + j*(nx+1);
4152 ind[1] = i + 1 +j*(nx+1);
4153 ind[2] = i + 1 + (j+1)*(nx+1);
4154 ind[3] = i + (j+1)*(nx+1);
4155 elements[k] = new Quadrilateral(ind);
4156 k++;
4157 }
4158 }
4159 }
4160
4161 // Sets boundary elements and the corresponding indices of vertices
4162 int m = (nx+1)*ny;
4163 for (i = 0; i < nx; i++)
4164 {
4165 boundary[i] = new Segment(i, i+1, 1);
4166 boundary[nx+i] = new Segment(m+i+1, m+i, 3);
4167 }
4168 m = nx+1;
4169 for (j = 0; j < ny; j++)
4170 {
4171 boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
4172 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
4173 }
4174 }
4175 // Creates triangular mesh
4176 else if (type == Element::TRIANGLE)
4177 {
4178 NumOfVertices = (nx+1) * (ny+1);
4179 NumOfElements = 2 * nx * ny;
4180 NumOfBdrElements = 2 * nx + 2 * ny;
4181
4182 vertices.SetSize(NumOfVertices);
4183 elements.SetSize(NumOfElements);
4184 boundary.SetSize(NumOfBdrElements);
4185
4186 real_t cx, cy;
4187 int ind[3];
4188
4189 // Sets vertices and the corresponding coordinates
4190 k = 0;
4191 for (j = 0; j < ny+1; j++)
4192 {
4193 cy = ((real_t) j / ny) * sy;
4194 for (i = 0; i < nx+1; i++)
4195 {
4196 cx = ((real_t) i / nx) * sx;
4197 vertices[k](0) = cx;
4198 vertices[k](1) = cy;
4199 k++;
4200 }
4201 }
4202
4203 // Sets the elements and the corresponding indices of vertices
4204 k = 0;
4205 for (j = 0; j < ny; j++)
4206 {
4207 for (i = 0; i < nx; i++)
4208 {
4209 ind[0] = i + j*(nx+1);
4210 ind[1] = i + 1 + (j+1)*(nx+1);
4211 ind[2] = i + (j+1)*(nx+1);
4212 elements[k] = new Triangle(ind);
4213 k++;
4214 ind[1] = i + 1 + j*(nx+1);
4215 ind[2] = i + 1 + (j+1)*(nx+1);
4216 elements[k] = new Triangle(ind);
4217 k++;
4218 }
4219 }
4220
4221 // Sets boundary elements and the corresponding indices of vertices
4222 int m = (nx+1)*ny;
4223 for (i = 0; i < nx; i++)
4224 {
4225 boundary[i] = new Segment(i, i+1, 1);
4226 boundary[nx+i] = new Segment(m+i+1, m+i, 3);
4227 }
4228 m = nx+1;
4229 for (j = 0; j < ny; j++)
4230 {
4231 boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
4232 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
4233 }
4234
4235 // MarkTriMeshForRefinement(); // done in Finalize(...)
4236 }
4237 else
4238 {
4239 MFEM_ABORT("Unsupported element type.");
4240 }
4241
4242 SetMeshGen();
4244
4245 if (generate_edges == 1)
4246 {
4247 el_to_edge = new Table;
4249 GenerateFaces();
4251 }
4252 else
4253 {
4254 NumOfEdges = 0;
4255 }
4256
4257 NumOfFaces = 0;
4258
4259 attributes.Append(1);
4262
4263 // Finalize(...) can be called after this method, if needed
4264}
4265
4266void Mesh::Make1D(int n, real_t sx)
4267{
4268 int j, ind[1];
4269
4270 SetEmpty();
4271
4272 Dim = 1;
4273 spaceDim = 1;
4274
4275 NumOfVertices = n + 1;
4276 NumOfElements = n;
4277 NumOfBdrElements = 2;
4278 vertices.SetSize(NumOfVertices);
4279 elements.SetSize(NumOfElements);
4280 boundary.SetSize(NumOfBdrElements);
4281
4282 // Sets vertices and the corresponding coordinates
4283 for (j = 0; j < n+1; j++)
4284 {
4285 vertices[j](0) = ((real_t) j / n) * sx;
4286 }
4287
4288 // Sets elements and the corresponding indices of vertices
4289 for (j = 0; j < n; j++)
4290 {
4291 elements[j] = new Segment(j, j+1, 1);
4292 }
4293
4294 // Sets the boundary elements
4295 ind[0] = 0;
4296 boundary[0] = new Point(ind, 1);
4297 ind[0] = n;
4298 boundary[1] = new Point(ind, 2);
4299
4300 NumOfEdges = 0;
4301 NumOfFaces = 0;
4302
4303 SetMeshGen();
4304 GenerateFaces();
4305
4306 // Set be_to_face
4308 be_to_face[0] = 0;
4309 be_to_face[1] = n;
4310
4311 attributes.Append(1);
4313}
4314
4315Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
4316 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4317{
4318 Dim = mesh.Dim;
4319 spaceDim = mesh.spaceDim;
4320
4324 NumOfEdges = mesh.NumOfEdges;
4325 NumOfFaces = mesh.NumOfFaces;
4328
4329 meshgen = mesh.meshgen;
4330 mesh_geoms = mesh.mesh_geoms;
4331
4332 // Create the new Mesh instance without a record of its refinement history
4333 sequence = 0;
4334 nodes_sequence = 0;
4336
4337 // Duplicate the elements
4338 elements.SetSize(NumOfElements);
4339 for (int i = 0; i < NumOfElements; i++)
4340 {
4341 elements[i] = mesh.elements[i]->Duplicate(this);
4342 }
4343
4344 // Copy the vertices
4345 mesh.vertices.Copy(vertices);
4346
4347 // Duplicate the boundary
4348 boundary.SetSize(NumOfBdrElements);
4349 for (int i = 0; i < NumOfBdrElements; i++)
4350 {
4351 boundary[i] = mesh.boundary[i]->Duplicate(this);
4352 }
4353
4354 // Copy the element-to-face Table, el_to_face
4355 el_to_face = (mesh.el_to_face) ? new Table(*mesh.el_to_face) : NULL;
4356
4357 // Copy the boundary-to-face Array, be_to_face.
4359
4360 // Copy the element-to-edge Table, el_to_edge
4361 el_to_edge = (mesh.el_to_edge) ? new Table(*mesh.el_to_edge) : NULL;
4362
4363 // Copy the boundary-to-edge Table, bel_to_edge (3D)
4364 bel_to_edge = (mesh.bel_to_edge) ? new Table(*mesh.bel_to_edge) : NULL;
4365
4366 // Duplicate the faces and faces_info.
4367 faces.SetSize(mesh.faces.Size());
4368 for (int i = 0; i < faces.Size(); i++)
4369 {
4370 Element *face = mesh.faces[i]; // in 1D the faces are NULL
4371 faces[i] = (face) ? face->Duplicate(this) : NULL;
4372 }
4373 mesh.faces_info.Copy(faces_info);
4374 mesh.nc_faces_info.Copy(nc_faces_info);
4375
4376 // Do NOT copy the element-to-element Table, el_to_el
4377 el_to_el = NULL;
4378
4379 // Do NOT copy the face-to-edge Table, face_edge
4380 face_edge = NULL;
4381 face_to_elem = NULL;
4382
4383 // Copy the edge-to-vertex Table, edge_vertex
4384 edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
4385
4386 // Copy the attributes and bdr_attributes
4389
4390 // Copy attribute and bdr_attribute names
4393
4394 // Deep copy the NURBSExtension.
4395#ifdef MFEM_USE_MPI
4396 ParNURBSExtension *pNURBSext =
4397 dynamic_cast<ParNURBSExtension *>(mesh.NURBSext);
4398 if (pNURBSext)
4399 {
4400 NURBSext = new ParNURBSExtension(*pNURBSext);
4401 }
4402 else
4403#endif
4404 {
4405 NURBSext = mesh.NURBSext ? new NURBSExtension(*mesh.NURBSext) : NULL;
4406 }
4407
4408 // Deep copy the NCMesh.
4409#ifdef MFEM_USE_MPI
4410 if (dynamic_cast<const ParMesh*>(&mesh))
4411 {
4412 ncmesh = NULL; // skip; will be done in ParMesh copy ctor
4413 }
4414 else
4415#endif
4416 {
4417 ncmesh = mesh.ncmesh ? new NCMesh(*mesh.ncmesh) : NULL;
4418 }
4419
4420 // Duplicate the Nodes, including the FiniteElementCollection and the
4421 // FiniteElementSpace
4422 if (mesh.Nodes && copy_nodes)
4423 {
4424 FiniteElementSpace *fes = mesh.Nodes->FESpace();
4425 const FiniteElementCollection *fec = fes->FEColl();
4426 FiniteElementCollection *fec_copy =
4428 FiniteElementSpace *fes_copy =
4429 new FiniteElementSpace(*fes, this, fec_copy);
4430 Nodes = new GridFunction(fes_copy);
4431 Nodes->MakeOwner(fec_copy);
4432 *Nodes = *mesh.Nodes;
4433 own_nodes = 1;
4434 }
4435 else
4436 {
4437 Nodes = mesh.Nodes;
4438 own_nodes = 0;
4439 }
4440}
4441
4443{
4444 Swap(mesh, true);
4445}
4446
4448{
4449 Swap(mesh, true);
4450 return *this;
4451}
4452
4453Mesh Mesh::LoadFromFile(const std::string &filename, int generate_edges,
4454 int refine, bool fix_orientation)
4455{
4456 Mesh mesh;
4457 named_ifgzstream imesh(filename);
4458 if (!imesh) { MFEM_ABORT("Mesh file not found: " << filename << '\n'); }
4459 else { mesh.Load(imesh, generate_edges, refine, fix_orientation); }
4460 return mesh;
4461}
4462
4464{
4465 Mesh mesh;
4466 mesh.Make1D(n, sx);
4467 // mesh.Finalize(); not needed in this case
4468 return mesh;
4469}
4470
4472 int nx, int ny, Element::Type type, bool generate_edges,
4473 real_t sx, real_t sy, bool sfc_ordering)
4474{
4475 Mesh mesh;
4476 mesh.Make2D(nx, ny, type, sx, sy, generate_edges, sfc_ordering);
4477 mesh.Finalize(true); // refine = true
4478 return mesh;
4479}
4480
4482 int nx, int ny, int nz, Element::Type type,
4483 real_t sx, real_t sy, real_t sz, bool sfc_ordering)
4484{
4485 Mesh mesh;
4486 mesh.Make3D(nx, ny, nz, type, sx, sy, sz, sfc_ordering);
4487 mesh.Finalize(true); // refine = true
4488 return mesh;
4489}
4490
4492 real_t sx, real_t sy, real_t sz)
4493{
4494 Mesh mesh;
4495 mesh.Make3D24TetsFromHex(nx, ny, nz, sx, sy, sz);
4496 mesh.Finalize(false, false);
4497 return mesh;
4498}
4499
4501 real_t sx, real_t sy)
4502{
4503 Mesh mesh;
4504 mesh.Make2D4TrisFromQuad(nx, ny, sx, sy);
4505 mesh.Finalize(false, false);
4506 return mesh;
4507}
4508
4510 real_t sx, real_t sy)
4511{
4512 Mesh mesh;
4513 mesh.Make2D5QuadsFromQuad(nx, ny, sx, sy);
4514 mesh.Finalize(false, false);
4515 return mesh;
4516}
4517
4518Mesh Mesh::MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
4519{
4520 Mesh mesh;
4521 Array<int> ref_factors(orig_mesh.GetNE());
4522 ref_factors = ref_factor;
4523 mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
4524 return mesh;
4525}
4526
4527Mesh Mesh::MakeRefined(Mesh &orig_mesh, const Array<int> &ref_factors,
4528 int ref_type)
4529{
4530 Mesh mesh;
4531 mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
4532 return mesh;
4533}
4534
4535Mesh::Mesh(const std::string &filename, int generate_edges, int refine,
4536 bool fix_orientation)
4537 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4538{
4539 // Initialization as in the default constructor
4540 SetEmpty();
4541
4542 named_ifgzstream imesh(filename);
4543 if (!imesh)
4544 {
4545 // Abort with an error message.
4546 MFEM_ABORT("Mesh file not found: " << filename << '\n');
4547 }
4548 else
4549 {
4550 Load(imesh, generate_edges, refine, fix_orientation);
4551 }
4552}
4553
4554Mesh::Mesh(std::istream &input, int generate_edges, int refine,
4555 bool fix_orientation)
4556 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4557{
4558 SetEmpty();
4559 Load(input, generate_edges, refine, fix_orientation);
4560}
4561
4562void Mesh::ChangeVertexDataOwnership(real_t *vertex_data, int len_vertex_data,
4563 bool zerocopy)
4564{
4565 // A dimension of 3 is now required since we use mfem::Vertex objects as PODs
4566 // and these object have a hardcoded double[3] entry
4567 MFEM_VERIFY(len_vertex_data >= NumOfVertices * 3,
4568 "Not enough vertices in external array : "
4569 "len_vertex_data = "<< len_vertex_data << ", "
4570 "NumOfVertices * 3 = " << NumOfVertices * 3);
4571 // Allow multiple calls to this method with the same vertex_data
4572 if (vertex_data == (real_t *)(vertices.GetData()))
4573 {
4574 MFEM_ASSERT(!vertices.OwnsData(), "invalid ownership");
4575 return;
4576 }
4577 if (!zerocopy)
4578 {
4579 memcpy(vertex_data, vertices.GetData(),
4580 NumOfVertices * 3 * sizeof(real_t));
4581 }
4582 // Vertex is POD double[3]
4583 vertices.MakeRef(reinterpret_cast<Vertex*>(vertex_data), NumOfVertices);
4584}
4585
4586Mesh::Mesh(real_t *vertices_, int num_vertices,
4587 int *element_indices, Geometry::Type element_type,
4588 int *element_attributes, int num_elements,
4589 int *boundary_indices, Geometry::Type boundary_type,
4590 int *boundary_attributes, int num_boundary_elements,
4591 int dimension, int space_dimension)
4592 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4593{
4594 if (space_dimension == -1)
4595 {
4596 space_dimension = dimension;
4597 }
4598
4599 InitMesh(dimension, space_dimension, /*num_vertices*/ 0, num_elements,
4600 num_boundary_elements);
4601
4602 int element_index_stride = Geometry::NumVerts[element_type];
4603 int boundary_index_stride = num_boundary_elements > 0 ?
4604 Geometry::NumVerts[boundary_type] : 0;
4605
4606 // assuming Vertex is POD
4607 vertices.MakeRef(reinterpret_cast<Vertex*>(vertices_), num_vertices);
4608 NumOfVertices = num_vertices;
4609
4610 for (int i = 0; i < num_elements; i++)
4611 {
4612 elements[i] = NewElement(element_type);
4613 elements[i]->SetVertices(element_indices + i * element_index_stride);
4614 elements[i]->SetAttribute(element_attributes[i]);
4615 }
4616 NumOfElements = num_elements;
4617
4618 for (int i = 0; i < num_boundary_elements; i++)
4619 {
4620 boundary[i] = NewElement(boundary_type);
4621 boundary[i]->SetVertices(boundary_indices + i * boundary_index_stride);
4622 boundary[i]->SetAttribute(boundary_attributes[i]);
4623 }
4624 NumOfBdrElements = num_boundary_elements;
4625
4627}
4628
4630 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4631{
4632 SetEmpty();
4633 /// make an internal copy of the NURBSExtension
4634 NURBSext = new NURBSExtension( ext );
4635
4636 Dim = NURBSext->Dimension();
4640
4643
4644 vertices.SetSize(NumOfVertices);
4645 if (NURBSext->HavePatches())
4646 {
4648 FiniteElementSpace *fes = new FiniteElementSpace(this, fec, Dim,
4650 Nodes = new GridFunction(fes);
4651 Nodes->MakeOwner(fec);
4653 own_nodes = 1;
4655 for (int i = 0; i < spaceDim; i++)
4656 {
4657 Vector vert_val;
4658 Nodes->GetNodalValues(vert_val, i+1);
4659 for (int j = 0; j < NumOfVertices; j++)
4660 {
4661 vertices[j](i) = vert_val(j);
4662 }
4663 }
4664 }
4665 else
4666 {
4667 MFEM_ABORT("NURBS mesh has no patches.");
4668 }
4669 FinalizeMesh();
4670}
4671
4673{
4674 switch (geom)
4675 {
4676 case Geometry::POINT: return (new Point);
4677 case Geometry::SEGMENT: return (new Segment);
4678 case Geometry::TRIANGLE: return (new Triangle);
4679 case Geometry::SQUARE: return (new Quadrilateral);
4681#ifdef MFEM_USE_MEMALLOC
4682 return TetMemory.Alloc();
4683#else
4684 return (new Tetrahedron);
4685#endif
4686 case Geometry::CUBE: return (new Hexahedron);
4687 case Geometry::PRISM: return (new Wedge);
4688 case Geometry::PYRAMID: return (new Pyramid);
4689 default:
4690 MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
4691 }
4692
4693 return NULL;
4694}
4695
4697{
4698 int geom, nv, *v;
4699 Element *el;
4700
4701 input >> geom;
4702 el = NewElement(geom);
4703 MFEM_VERIFY(el, "Unsupported element type: " << geom);
4704 nv = el->GetNVertices();
4705 v = el->GetVertices();
4706 for (int i = 0; i < nv; i++)
4707 {
4708 input >> v[i];
4709 }
4710
4711 return el;
4712}
4713
4714void Mesh::PrintElementWithoutAttr(const Element *el, std::ostream &os)
4715{
4716 os << el->GetGeometryType();
4717 const int nv = el->GetNVertices();
4718 const int *v = el->GetVertices();
4719 for (int j = 0; j < nv; j++)
4720 {
4721 os << ' ' << v[j];
4722 }
4723 os << '\n';
4724}
4725
4726Element *Mesh::ReadElement(std::istream &input)
4727{
4728 int attr;
4729 Element *el;
4730
4731 input >> attr;
4732 el = ReadElementWithoutAttr(input);
4733 el->SetAttribute(attr);
4734
4735 return el;
4736}
4737
4738void Mesh::PrintElement(const Element *el, std::ostream &os)
4739{
4740 os << el->GetAttribute() << ' ';
4742}
4743
4745{
4746 meshgen = mesh_geoms = 0;
4747 for (int i = 0; i < NumOfElements; i++)
4748 {
4749 const Element::Type type = GetElement(i)->GetType();
4750 switch (type)
4751 {
4754 case Element::TRIANGLE:
4756 case Element::SEGMENT:
4757 mesh_geoms |= (1 << Geometry::SEGMENT);
4758 case Element::POINT:
4759 mesh_geoms |= (1 << Geometry::POINT);
4760 meshgen |= 1;
4761 break;
4762
4764 mesh_geoms |= (1 << Geometry::CUBE);
4766 mesh_geoms |= (1 << Geometry::SQUARE);
4767 mesh_geoms |= (1 << Geometry::SEGMENT);
4768 mesh_geoms |= (1 << Geometry::POINT);
4769 meshgen |= 2;
4770 break;
4771
4772 case Element::WEDGE:
4773 mesh_geoms |= (1 << Geometry::PRISM);
4774 mesh_geoms |= (1 << Geometry::SQUARE);
4776 mesh_geoms |= (1 << Geometry::SEGMENT);
4777 mesh_geoms |= (1 << Geometry::POINT);
4778 meshgen |= 4;
4779 break;
4780
4781 case Element::PYRAMID:
4782 mesh_geoms |= (1 << Geometry::PYRAMID);
4783 mesh_geoms |= (1 << Geometry::SQUARE);
4785 mesh_geoms |= (1 << Geometry::SEGMENT);
4786 mesh_geoms |= (1 << Geometry::POINT);
4787 meshgen |= 8;
4788 break;
4789
4790 default:
4791 MFEM_ABORT("invalid element type: " << type);
4792 break;
4793 }
4794 }
4795}
4796
4797void Mesh::Loader(std::istream &input, int generate_edges,
4798 std::string parse_tag)
4799{
4800 int curved = 0, read_gf = 1;
4801 bool finalize_topo = true;
4802
4803 if (!input)
4804 {
4805 MFEM_ABORT("Input stream is not open");
4806 }
4807
4808 Clear();
4809
4810 string mesh_type;
4811 input >> ws;
4812 getline(input, mesh_type);
4813 filter_dos(mesh_type);
4814
4815 // MFEM's conforming mesh formats
4816 int mfem_version = 0;
4817 if (mesh_type == "MFEM mesh v1.0") { mfem_version = 10; } // serial
4818 else if (mesh_type == "MFEM mesh v1.2") { mfem_version = 12; } // parallel
4819 else if (mesh_type == "MFEM mesh v1.3") { mfem_version = 13; } // attr sets
4820
4821 // MFEM nonconforming mesh format
4822 // (NOTE: previous v1.1 is now under this branch for backward compatibility)
4823 int mfem_nc_version = 0;
4824 if (mesh_type == "MFEM NC mesh v1.0") { mfem_nc_version = 10; }
4825 else if (mesh_type == "MFEM NC mesh v1.1") { mfem_nc_version = 11; }
4826 else if (mesh_type == "MFEM mesh v1.1") { mfem_nc_version = 1 /*legacy*/; }
4827
4828 if (mfem_version)
4829 {
4830 // Formats mfem_v12 and newer have a tag indicating the end of the mesh
4831 // section in the stream. A user provided parse tag can also be provided
4832 // via the arguments. For example, if this is called from parallel mesh
4833 // object, it can indicate to read until parallel mesh section begins.
4834 if (mfem_version >= 12 && parse_tag.empty())
4835 {
4836 parse_tag = "mfem_mesh_end";
4837 }
4838 ReadMFEMMesh(input, mfem_version, curved);
4839 }
4840 else if (mfem_nc_version)
4841 {
4842 MFEM_ASSERT(ncmesh == NULL, "internal error");
4843 int is_nc = 1;
4844
4845#ifdef MFEM_USE_MPI
4846 ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
4847 if (pmesh)
4848 {
4849 MFEM_VERIFY(mfem_nc_version >= 10,
4850 "Legacy nonconforming format (MFEM mesh v1.1) cannot be "
4851 "used to load a parallel nonconforming mesh, sorry.");
4852
4853 ncmesh = new ParNCMesh(pmesh->GetComm(),
4854 input, mfem_nc_version, curved, is_nc);
4855 }
4856 else
4857#endif
4858 {
4859 ncmesh = new NCMesh(input, mfem_nc_version, curved, is_nc);
4860 }
4862
4863 if (!is_nc)
4864 {
4865 // special case for backward compatibility with MFEM <=4.2:
4866 // if the "vertex_parents" section is missing in the v1.1 format,
4867 // the mesh is treated as conforming
4868 delete ncmesh;
4869 ncmesh = NULL;
4870 }
4871 }
4872 else if (mesh_type == "linemesh") // 1D mesh
4873 {
4874 ReadLineMesh(input);
4875 }
4876 else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2")
4877 {
4878 if (mesh_type == "curved_areamesh2")
4879 {
4880 curved = 1;
4881 }
4882 ReadNetgen2DMesh(input, curved);
4883 }
4884 else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format")
4885 {
4886 ReadNetgen3DMesh(input);
4887 }
4888 else if (mesh_type == "TrueGrid")
4889 {
4890 ReadTrueGridMesh(input);
4891 }
4892 else if (mesh_type.rfind("# vtk DataFile Version") == 0)
4893 {
4894 int major_vtk_version = mesh_type[mesh_type.length()-3] - '0';
4895 // int minor_vtk_version = mesh_type[mesh_type.length()-1] - '0';
4896 MFEM_VERIFY(major_vtk_version >= 2 && major_vtk_version <= 4,
4897 "Unsupported VTK format");
4898 ReadVTKMesh(input, curved, read_gf, finalize_topo);
4899 }
4900 else if (mesh_type.rfind("<VTKFile ") == 0 || mesh_type.rfind("<?xml") == 0)
4901 {
4902 ReadXML_VTKMesh(input, curved, read_gf, finalize_topo, mesh_type);
4903 }
4904 else if (mesh_type == "MFEM NURBS mesh v1.0")
4905 {
4906 ReadNURBSMesh(input, curved, read_gf);
4907 }
4908 else if (mesh_type == "MFEM NURBS mesh v1.1")
4909 {
4910 ReadNURBSMesh(input, curved, read_gf, true);
4911 }
4912 else if (mesh_type == "MFEM INLINE mesh v1.0")
4913 {
4914 ReadInlineMesh(input, generate_edges);
4915 return; // done with inline mesh construction
4916 }
4917 else if (mesh_type == "$MeshFormat") // Gmsh
4918 {
4919 ReadGmshMesh(input, curved, read_gf);
4920 }
4921 else if
4922 ((mesh_type.size() > 2 &&
4923 mesh_type[0] == 'C' && mesh_type[1] == 'D' && mesh_type[2] == 'F') ||
4924 (mesh_type.size() > 3 &&
4925 mesh_type[1] == 'H' && mesh_type[2] == 'D' && mesh_type[3] == 'F'))
4926 {
4927 named_ifgzstream *mesh_input = dynamic_cast<named_ifgzstream *>(&input);
4928 if (mesh_input)
4929 {
4930#ifdef MFEM_USE_NETCDF
4931 ReadCubit(mesh_input->filename, curved, read_gf);
4932#else
4933 MFEM_ABORT("NetCDF support requires configuration with"
4934 " MFEM_USE_NETCDF=YES");
4935 return;
4936#endif
4937 }
4938 else
4939 {
4940 MFEM_ABORT("Can not determine Cubit mesh filename!"
4941 " Use mfem::named_ifgzstream for input.");
4942 return;
4943 }
4944 }
4945 else
4946 {
4947 MFEM_ABORT("Unknown input mesh format: " << mesh_type);
4948 return;
4949 }
4950
4951 // at this point the following should be defined:
4952 // 1) Dim
4953 // 2) NumOfElements, elements
4954 // 3) NumOfBdrElements, boundary
4955 // 4) NumOfVertices, with allocated space in vertices
4956 // 5) curved
4957 // 5a) if curved == 0, vertices must be defined
4958 // 5b) if curved != 0 and read_gf != 0,
4959 // 'input' must point to a GridFunction
4960 // 5c) if curved != 0 and read_gf == 0,
4961 // vertices and Nodes must be defined
4962 // optional:
4963 // 1) el_to_edge may be allocated (as in the case of P2 VTK meshes)
4964 // 2) ncmesh may be allocated
4965
4966 // FinalizeTopology() will:
4967 // - assume that generate_edges is true
4968 // - assume that refine is false
4969 // - does not check the orientation of regular and boundary elements
4970 if (finalize_topo)
4971 {
4972 // don't generate any boundary elements, especially in parallel
4973 bool generate_bdr = false;
4974
4975 FinalizeTopology(generate_bdr);
4976 }
4977
4978 if (curved && read_gf)
4979 {
4980 Nodes = new GridFunction(this, input);
4981
4982 own_nodes = 1;
4984 if (ncmesh) { ncmesh->spaceDim = spaceDim; }
4985
4986 // Set vertex coordinates from the 'Nodes'
4988 }
4989
4990 // If a parse tag was supplied, keep reading the stream until the tag is
4991 // encountered.
4992 if (mfem_version >= 12)
4993 {
4994 string line;
4995 do
4996 {
4997 skip_comment_lines(input, '#');
4998 MFEM_VERIFY(input.good(), "Required mesh-end tag not found");
4999 getline(input, line);
5000 filter_dos(line);
5001 // mfem v1.2 may not have parse_tag in it, e.g. if trying to read a
5002 // serial mfem v1.2 mesh as parallel with "mfem_serial_mesh_end" as
5003 // parse_tag. That's why, regardless of parse_tag, we stop reading if
5004 // we find "mfem_mesh_end" which is required by mfem v1.2 format.
5005 if (line == "mfem_mesh_end") { break; }
5006 }
5007 while (line != parse_tag);
5008 }
5009 else if (mfem_nc_version >= 10)
5010 {
5011 string ident;
5012 skip_comment_lines(input, '#');
5013 input >> ident;
5014 MFEM_VERIFY(ident == "mfem_mesh_end",
5015 "invalid mesh: end of file tag not found");
5016 }
5017
5018 // Finalize(...) should be called after this, if needed.
5019}
5020
5021Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
5022 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
5023{
5024 int i, j, ie, ib, iv, *v, nv;
5025 Element *el;
5026 Mesh *m;
5027
5028 SetEmpty();
5029
5030 Dim = mesh_array[0]->Dimension();
5031 spaceDim = mesh_array[0]->SpaceDimension();
5032
5033 if (mesh_array[0]->NURBSext)
5034 {
5035 // assuming the pieces form a partition of a NURBS mesh
5036 NURBSext = new NURBSExtension(mesh_array, num_pieces);
5037
5040
5042
5043 // NumOfBdrElements = NURBSext->GetNBE();
5044 // NURBSext->GetBdrElementTopo(boundary);
5045
5046 Array<int> lvert_vert, lelem_elem;
5047
5048 // Here, for visualization purposes, we copy the boundary elements from
5049 // the individual pieces which include the interior boundaries. This
5050 // creates 'boundary' array that is different from the one generated by
5051 // the NURBSExtension which, in particular, makes the boundary-dof table
5052 // invalid. This, in turn, causes GetBdrElementTransformation to not
5053 // function properly.
5054 NumOfBdrElements = 0;
5055 for (i = 0; i < num_pieces; i++)
5056 {
5057 NumOfBdrElements += mesh_array[i]->GetNBE();
5058 }
5059 boundary.SetSize(NumOfBdrElements);
5060 vertices.SetSize(NumOfVertices);
5061 ib = 0;
5062 for (i = 0; i < num_pieces; i++)
5063 {
5064 m = mesh_array[i];
5065 m->NURBSext->GetVertexLocalToGlobal(lvert_vert);
5066 m->NURBSext->GetElementLocalToGlobal(lelem_elem);
5067 // copy the element attributes
5068 for (j = 0; j < m->GetNE(); j++)
5069 {
5070 elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j));
5071 }
5072 // copy the boundary
5073 for (j = 0; j < m->GetNBE(); j++)
5074 {
5075 el = m->GetBdrElement(j)->Duplicate(this);
5076 v = el->GetVertices();
5077 nv = el->GetNVertices();
5078 for (int k = 0; k < nv; k++)
5079 {
5080 v[k] = lvert_vert[v[k]];
5081 }
5082 boundary[ib++] = el;
5083 }
5084 // copy the vertices
5085 for (j = 0; j < m->GetNV(); j++)
5086 {
5087 vertices[lvert_vert[j]].SetCoords(m->SpaceDimension(),
5088 m->GetVertex(j));
5089 }
5090 }
5091 }
5092 else // not a NURBS mesh
5093 {
5094 NumOfElements = 0;
5095 NumOfBdrElements = 0;
5096 NumOfVertices = 0;
5097 for (i = 0; i < num_pieces; i++)
5098 {
5099 m = mesh_array[i];
5100 NumOfElements += m->GetNE();
5101 NumOfBdrElements += m->GetNBE();
5102 NumOfVertices += m->GetNV();
5103 }
5104 elements.SetSize(NumOfElements);
5105 boundary.SetSize(NumOfBdrElements);
5106 vertices.SetSize(NumOfVertices);
5107 ie = ib = iv = 0;
5108 for (i = 0; i < num_pieces; i++)
5109 {
5110 m = mesh_array[i];
5111 // copy the elements
5112 for (j = 0; j < m->GetNE(); j++)
5113 {
5114 el = m->GetElement(j)->Duplicate(this);
5115 v = el->GetVertices();
5116 nv = el->GetNVertices();
5117 for (int k = 0; k < nv; k++)
5118 {
5119 v[k] += iv;
5120 }
5121 elements[ie++] = el;
5122 }
5123 // copy the boundary elements
5124 for (j = 0; j < m->GetNBE(); j++)
5125 {
5126 el = m->GetBdrElement(j)->Duplicate(this);
5127 v = el->GetVertices();
5128 nv = el->GetNVertices();
5129 for (int k = 0; k < nv; k++)
5130 {
5131 v[k] += iv;
5132 }
5133 boundary[ib++] = el;
5134 }
5135 // copy the vertices
5136 for (j = 0; j < m->GetNV(); j++)
5137 {
5138 vertices[iv++].SetCoords(m->SpaceDimension(), m->GetVertex(j));
5139 }
5140 }
5141 }
5142
5144
5145 // copy the nodes (curvilinear meshes)
5146 GridFunction *g = mesh_array[0]->GetNodes();
5147 if (g)
5148 {
5149 Array<GridFunction *> gf_array(num_pieces);
5150 for (i = 0; i < num_pieces; i++)
5151 {
5152 gf_array[i] = mesh_array[i]->GetNodes();
5153 }
5154 Nodes = new GridFunction(this, gf_array, num_pieces);
5155 own_nodes = 1;
5156 }
5157
5158#ifdef MFEM_DEBUG
5161#endif
5162}
5163
5164Mesh::Mesh(Mesh *orig_mesh, int ref_factor, int ref_type)
5165 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
5166{
5167 Array<int> ref_factors(orig_mesh->GetNE());
5168 ref_factors = ref_factor;
5169 MakeRefined_(*orig_mesh, ref_factors, ref_type);
5170}
5171
5172void Mesh::MakeRefined_(Mesh &orig_mesh, const Array<int> &ref_factors,
5173 int ref_type)
5174{
5175 SetEmpty();
5176 Dim = orig_mesh.Dimension();
5177 spaceDim = orig_mesh.SpaceDimension();
5178
5179 int orig_ne = orig_mesh.GetNE();
5180 MFEM_VERIFY(ref_factors.Size() == orig_ne,
5181 "Number of refinement factors must equal number of elements")
5182 MFEM_VERIFY(orig_ne == 0 ||
5183 ref_factors.Min() >= 1, "Refinement factor must be >= 1");
5184 const int q_type = BasisType::GetQuadrature1D(ref_type);
5185 MFEM_VERIFY(Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid,
5186 "Invalid refinement type. Must use closed basis type.");
5187
5188 int min_ref = orig_ne > 0 ? ref_factors.Min() : 1;
5189 int max_ref = orig_ne > 0 ? ref_factors.Max() : 1;
5190
5191 bool var_order = (min_ref != max_ref);
5192
5193 // variable order space can only be constructed over an NC mesh
5194 if (var_order) { orig_mesh.EnsureNCMesh(true); }
5195
5196 // Construct a scalar H1 FE space of order ref_factor and use its dofs as
5197 // the indices of the new, refined vertices.
5198 H1_FECollection rfec(min_ref, Dim, ref_type);
5199 FiniteElementSpace rfes(&orig_mesh, &rfec);
5200
5201 if (var_order)
5202 {
5203 rfes.SetRelaxedHpConformity(false);
5204 for (int i = 0; i < orig_ne; i++)
5205 {
5206 rfes.SetElementOrder(i, ref_factors[i]);
5207 }
5208 rfes.Update(false);
5209 }
5210
5211 // Set the number of vertices, set the actual coordinates later
5212 NumOfVertices = rfes.GetNDofs();
5213 vertices.SetSize(NumOfVertices);
5214
5215 Array<int> rdofs;
5216 DenseMatrix phys_pts;
5217 GeometryRefiner refiner(q_type);
5218
5219 // Add refined elements and set vertex coordinates
5220 for (int el = 0; el < orig_ne; el++)
5221 {
5222 Geometry::Type geom = orig_mesh.GetElementGeometry(el);
5223 int attrib = orig_mesh.GetAttribute(el);
5224 int nvert = Geometry::NumVerts[geom];
5225 RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el]);
5226
5227 rfes.GetElementDofs(el, rdofs);
5228 MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
5229 const FiniteElement *rfe = rfes.GetFE(el);
5230 orig_mesh.GetElementTransformation(el)->Transform(rfe->GetNodes(),
5231 phys_pts);
5232 const int *c2h_map = rfec.GetDofMap(geom, ref_factors[el]);
5233 for (int i = 0; i < phys_pts.Width(); i++)
5234 {
5235 vertices[rdofs[i]].SetCoords(spaceDim, phys_pts.GetColumn(i));
5236 }
5237 for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
5238 {
5239 Element *elem = NewElement(geom);
5240 elem->SetAttribute(attrib);
5241 int *v = elem->GetVertices();
5242 for (int k = 0; k < nvert; k++)
5243 {
5244 int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
5245 v[k] = rdofs[c2h_map[cid]];
5246 }
5247 AddElement(elem);
5248 }
5249 }
5250
5251 if (Dim > 2)
5252 {
5253 GetElementToFaceTable(false);
5254 GenerateFaces();
5255 }
5256
5257 // Add refined boundary elements
5258 for (int el = 0; el < orig_mesh.GetNBE(); el++)
5259 {
5260 int i, info;
5261 orig_mesh.GetBdrElementAdjacentElement(el, i, info);
5262 Geometry::Type geom = orig_mesh.GetBdrElementGeometry(el);
5263 int attrib = orig_mesh.GetBdrAttribute(el);
5264 int nvert = Geometry::NumVerts[geom];
5265 RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[i]);
5266
5267 rfes.GetBdrElementDofs(el, rdofs);
5268 MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
5269 const int *c2h_map = rfec.GetDofMap(geom, ref_factors[i]);
5270 for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
5271 {
5272 Element *elem = NewElement(geom);
5273 elem->SetAttribute(attrib);
5274 int *v = elem->GetVertices();
5275 for (int k = 0; k < nvert; k++)
5276 {
5277 int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
5278 v[k] = rdofs[c2h_map[cid]];
5279 }
5280 AddBdrElement(elem);
5281 }
5282 }
5283 FinalizeTopology(false);
5284 sequence = orig_mesh.GetSequence() + 1;
5286
5287 // Set up the nodes of the new mesh (if the original mesh has nodes). The new
5288 // mesh is always straight-sided (i.e. degree 1 finite element space), but
5289 // the nodes are required for e.g. periodic meshes.
5290 if (orig_mesh.GetNodes())
5291 {
5292 bool discont = orig_mesh.GetNodalFESpace()->IsDGSpace();
5293 Ordering::Type dof_ordering = orig_mesh.GetNodalFESpace()->GetOrdering();
5294 Mesh::SetCurvature(1, discont, spaceDim, dof_ordering);
5295 FiniteElementSpace *nodal_fes = Nodes->FESpace();
5296 const FiniteElementCollection *nodal_fec = nodal_fes->FEColl();
5297 H1_FECollection vertex_fec(1, Dim);
5298 Array<int> dofs;
5299 int el_counter = 0;
5300 for (int iel = 0; iel < orig_ne; iel++)
5301 {
5302 Geometry::Type geom = orig_mesh.GetElementBaseGeometry(iel);
5303 int nvert = Geometry::NumVerts[geom];
5304 RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[iel]);
5305 rfes.GetElementDofs(iel, rdofs);
5306 const FiniteElement *rfe = rfes.GetFE(iel);
5307 orig_mesh.GetElementTransformation(iel)->Transform(rfe->GetNodes(),
5308 phys_pts);
5309 const int *node_map = NULL;
5310 const H1_FECollection *h1_fec =
5311 dynamic_cast<const H1_FECollection *>(nodal_fec);
5312 if (h1_fec != NULL) { node_map = h1_fec->GetDofMap(geom); }
5313 const int *vertex_map = vertex_fec.GetDofMap(geom);
5314 const int *c2h_map = rfec.GetDofMap(geom, ref_factors[iel]);
5315 for (int jel = 0; jel < RG.RefGeoms.Size()/nvert; jel++)
5316 {
5317 nodal_fes->GetElementVDofs(el_counter++, dofs);
5318 for (int iv_lex=0; iv_lex<nvert; ++iv_lex)
5319 {
5320 // convert from lexicographic to vertex index
5321 int iv = vertex_map[iv_lex];
5322 // index of vertex of current element in phys_pts matrix
5323 int pt_idx = c2h_map[RG.RefGeoms[iv+nvert*jel]];
5324 // index of current vertex into DOF array
5325 int node_idx = node_map ? node_map[iv_lex] : iv_lex;
5326 for (int d=0; d<spaceDim; ++d)
5327 {
5328 (*Nodes)[dofs[node_idx + d*nvert]] = phys_pts(d,pt_idx);
5329 }
5330 }
5331 }
5332 }
5333 }
5334
5335 // Setup the data for the coarse-fine refinement transformations
5336 CoarseFineTr.embeddings.SetSize(GetNE());
5337 // First, compute total number of point matrices that we need per geometry
5338 // and the offsets into that array
5339 using GeomRef = std::pair<Geometry::Type, int>;
5340 std::map<GeomRef, int> point_matrices_offsets;
5341 int n_point_matrices[Geometry::NumGeom] = {}; // initialize to zero
5342 for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
5343 {
5344 Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
5345 // Have we seen this pair of (goemetry, refinement level) before?
5346 GeomRef id(geom, ref_factors[el_coarse]);
5347 if (point_matrices_offsets.find(id) == point_matrices_offsets.end())
5348 {
5349 RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el_coarse]);
5350 int nvert = Geometry::NumVerts[geom];
5351 int nref_el = RG.RefGeoms.Size()/nvert;
5352 // If not, then store the offset and add to the size required
5353 point_matrices_offsets[id] = n_point_matrices[geom];
5354 n_point_matrices[geom] += nref_el;
5355 }
5356 }
5357
5358 // Set up the sizes
5359 for (int geom = 0; geom < Geometry::NumGeom; ++geom)
5360 {
5361 int nmatrices = n_point_matrices[geom];
5362 int nvert = Geometry::NumVerts[geom];
5363 CoarseFineTr.point_matrices[geom].SetSize(Dim, nvert, nmatrices);
5364 }
5365
5366 // Compute the point matrices and embeddings
5367 int el_fine = 0;
5368 for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
5369 {
5370 Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
5371 int ref = ref_factors[el_coarse];
5372 int offset = point_matrices_offsets[GeomRef(geom, ref)];
5373 int nvert = Geometry::NumVerts[geom];
5374 RefinedGeometry &RG = *refiner.Refine(geom, ref);
5375 for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
5376 {
5377 DenseMatrix &Pj = CoarseFineTr.point_matrices[geom](offset + j);
5378 for (int k = 0; k < nvert; k++)
5379 {
5380 int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
5381 const IntegrationPoint &ip = RG.RefPts[cid];
5382 ip.Get(Pj.GetColumn(k), Dim);
5383 }
5384
5385 Embedding &emb = CoarseFineTr.embeddings[el_fine];
5386 emb.geom = geom;
5387 emb.parent = el_coarse;
5388 emb.matrix = offset + j;
5389 ++el_fine;
5390 }
5391 }
5392
5393 MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
5394
5395 // The check below is disabled because is fails for parallel meshes with
5396 // interior "boundary" element that, when such "boundary" element is between
5397 // two elements on different processors.
5398 // MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
5399}
5400
5402{
5403 Mesh mesh;
5404 mesh.MakeSimplicial_(orig_mesh, NULL);
5405 return mesh;
5406}
5407
5408void Mesh::MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
5409{
5410 MFEM_VERIFY(const_cast<Mesh&>(orig_mesh).CheckElementOrientation(false) == 0,
5411 "Mesh::MakeSimplicial requires a properly oriented input mesh");
5412 MFEM_VERIFY(orig_mesh.Conforming(),
5413 "Mesh::MakeSimplicial does not support non-conforming meshes.")
5414
5415 int dim = orig_mesh.Dimension();
5416 int sdim = orig_mesh.SpaceDimension();
5417
5418 if (dim == 1)
5419 {
5420 Mesh copy(orig_mesh);
5421 Swap(copy, true);
5422 return;
5423 }
5424
5425 int nv = orig_mesh.GetNV();
5426 int ne = orig_mesh.GetNE();
5427 int nbe = orig_mesh.GetNBE();
5428
5429 static int num_subdivisions[Geometry::NUM_GEOMETRIES];
5430 num_subdivisions[Geometry::POINT] = 1;
5431 num_subdivisions[Geometry::SEGMENT] = 1;
5432 num_subdivisions[Geometry::TRIANGLE] = 1;
5433 num_subdivisions[Geometry::TETRAHEDRON] = 1;
5434 num_subdivisions[Geometry::SQUARE] = 2;
5435 num_subdivisions[Geometry::PRISM] = 3;
5436 num_subdivisions[Geometry::CUBE] = 6;
5437 // NOTE: some hexes may be subdivided into only 5 tets, so this is an
5438 // estimate only. The actual number of created tets may be less, so the
5439 // elements array will need to be shrunk after mesh creation.
5440 int new_ne = 0, new_nbe = 0;
5441 for (int i=0; i<ne; ++i)
5442 {
5443 new_ne += num_subdivisions[orig_mesh.GetElementBaseGeometry(i)];
5444 }
5445 for (int i=0; i<nbe; ++i)
5446 {
5447 new_nbe += num_subdivisions[orig_mesh.GetBdrElementGeometry(i)];
5448 }
5449
5450 InitMesh(dim, sdim, nv, new_ne, new_nbe);
5451
5452 // Vertices of the new mesh are same as the original mesh
5453 NumOfVertices = nv;
5454 for (int i=0; i<nv; ++i)
5455 {
5456 vertices[i].SetCoords(dim, orig_mesh.vertices[i]());
5457 }
5458
5459 // We need a global vertex numbering to identify which diagonals to split
5460 // (quad faces are split using the diagonal originating from the smallest
5461 // global vertex number). Use the supplied global numbering, if it is
5462 // non-NULL, otherwise use the local numbering.
5463 Array<int> vglobal_id;
5464 if (vglobal == NULL)
5465 {
5466 vglobal_id.SetSize(nv);
5467 for (int i=0; i<nv; ++i) { vglobal_id[i] = i; }
5468 vglobal = vglobal_id.GetData();
5469 }
5470
5471 constexpr int nv_tri = 3, nv_quad = 4, nv_tet = 4, nv_prism = 6, nv_hex = 8;
5472 constexpr int quad_ntris = 2, prism_ntets = 3;
5473 static const int quad_trimap[2][nv_tri*quad_ntris] =
5474 {
5475 {
5476 0, 0,
5477 1, 2,
5478 2, 3
5479 },{
5480 0, 1,
5481 1, 2,
5482 3, 3
5483 }
5484 };
5485 static const int prism_rot[nv_prism*nv_prism] =
5486 {
5487 0, 1, 2, 3, 4, 5,
5488 1, 2, 0, 4, 5, 3,
5489 2, 0, 1, 5, 3, 4,
5490 3, 5, 4, 0, 2, 1,
5491 4, 3, 5, 1, 0, 2,
5492 5, 4, 3, 2, 1, 0
5493 };
5494 static const int prism_f[nv_quad] = {1, 2, 5, 4};
5495 static const int prism_tetmaps[2][nv_prism*prism_ntets] =
5496 {
5497 {
5498 0, 0, 0,
5499 1, 1, 4,
5500 2, 5, 5,
5501 5, 4, 3
5502 },{
5503 0, 0, 0,
5504 1, 4, 4,
5505 2, 2, 5,
5506 4, 5, 3
5507 }
5508 };
5509 static const int hex_rot[nv_hex*nv_hex] =
5510 {
5511 0, 1, 2, 3, 4, 5, 6, 7,
5512 1, 0, 4, 5, 2, 3, 7, 6,
5513 2, 1, 5, 6, 3, 0, 4, 7,
5514 3, 0, 1, 2, 7, 4, 5, 6,
5515 4, 0, 3, 7, 5, 1, 2, 6,
5516 5, 1, 0, 4, 6, 2, 3, 7,
5517 6, 2, 1, 5, 7, 3, 0, 4,
5518 7, 3, 2, 6, 4, 0, 1, 5
5519 };
5520 static const int hex_f0[nv_quad] = {1, 2, 6, 5};
5521 static const int hex_f1[nv_quad] = {2, 3, 7, 6};
5522 static const int hex_f2[nv_quad] = {4, 5, 6, 7};
5523 static const int num_rot[8] = {0, 1, 2, 0, 0, 2, 1, 0};
5524 static const int hex_tetmap0[nv_tet*5] =
5525 {
5526 0, 0, 0, 0, 2,
5527 1, 2, 2, 5, 7,
5528 2, 7, 3, 7, 5,
5529 5, 5, 7, 4, 6
5530 };
5531 static const int hex_tetmap1[nv_tet*6] =
5532 {
5533 0, 0, 1, 0, 0, 1,
5534 5, 1, 6, 7, 7, 7,
5535 7, 7, 7, 2, 1, 6,
5536 4, 5, 5, 3, 2, 2
5537 };
5538 static const int hex_tetmap2[nv_tet*6] =
5539 {
5540 0, 0, 0, 0, 0, 0,
5541 4, 3, 7, 1, 3, 6,
5542 5, 7, 4, 2, 6, 5,
5543 6, 6, 6, 5, 2, 2
5544 };
5545 static const int hex_tetmap3[nv_tet*6] =
5546 {
5547 0, 0, 0, 0, 1, 1,
5548 2, 3, 7, 5, 5, 6,
5549 3, 7, 4, 6, 6, 2,
5550 6, 6, 6, 4, 0, 0
5551 };
5552 static const int *hex_tetmaps[4] =
5553 {
5554 hex_tetmap0, hex_tetmap1, hex_tetmap2, hex_tetmap3
5555 };
5556
5557 auto find_min = [](const int*a, int n) { return std::min_element(a,a+n)-a; };
5558
5559 for (int i=0; i<ne; ++i)
5560 {
5561 const int *v = orig_mesh.elements[i]->GetVertices();
5562 const int attrib = orig_mesh.GetAttribute(i);
5563 const Geometry::Type orig_geom = orig_mesh.GetElementBaseGeometry(i);
5564
5565 if (num_subdivisions[orig_geom] == 1)
5566 {
5567 // (num_subdivisions[orig_geom] == 1) implies that the element does
5568 // not need to be further split (it is either a segment, triangle,
5569 // or tetrahedron), and so it is left unchanged.
5570 Element *e = NewElement(orig_geom);
5571 e->SetAttribute(attrib);
5572 e->SetVertices(v);
5573 AddElement(e);
5574 }
5575 else if (orig_geom == Geometry::SQUARE)
5576 {
5577 for (int itri=0; itri<quad_ntris; ++itri)
5578 {
5580 e->SetAttribute(attrib);
5581 int *v2 = e->GetVertices();
5582 for (int iv=0; iv<nv_tri; ++iv)
5583 {
5584 v2[iv] = v[quad_trimap[0][itri + iv*quad_ntris]];
5585 }
5586 AddElement(e);
5587 }
5588 }
5589 else if (orig_geom == Geometry::PRISM)
5590 {
5591 int vg[nv_prism];
5592 for (int iv=0; iv<nv_prism; ++iv) { vg[iv] = vglobal[v[iv]]; }
5593 // Rotate the vertices of the prism so that the smallest vertex index
5594 // is in the first place
5595 int irot = find_min(vg, nv_prism);
5596 for (int iv=0; iv<nv_prism; ++iv)
5597 {
5598 int jv = prism_rot[iv + irot*nv_prism];
5599 vg[iv] = v[jv];
5600 }
5601 // Two cases according to which diagonal splits third quad face
5602 int q[nv_quad];
5603 for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[prism_f[iv]]]; }
5604 int j = find_min(q, nv_quad);
5605 const int *tetmap = (j == 0 || j == 2) ? prism_tetmaps[0] : prism_tetmaps[1];
5606 for (int itet=0; itet<prism_ntets; ++itet)
5607 {
5609 e->SetAttribute(attrib);
5610 int *v2 = e->GetVertices();
5611 for (int iv=0; iv<nv_tet; ++iv)
5612 {
5613 v2[iv] = vg[tetmap[itet + iv*prism_ntets]];
5614 }
5615 AddElement(e);
5616 }
5617 }
5618 else if (orig_geom == Geometry::CUBE)
5619 {
5620 int vg[nv_hex];
5621 for (int iv=0; iv<nv_hex; ++iv) { vg[iv] = vglobal[v[iv]]; }
5622
5623 // Rotate the vertices of the hex so that the smallest vertex index is
5624 // in the first place
5625 int irot = find_min(vg, nv_hex);
5626 for (int iv=0; iv<nv_hex; ++iv)
5627 {
5628 int jv = hex_rot[iv + irot*nv_hex];
5629 vg[iv] = v[jv];
5630 }
5631
5632 int q[nv_quad];
5633 // Bitmask is three binary digits, each digit is 1 if the diagonal of
5634 // the corresponding face goes through the 7th vertex, and 0 if not.
5635 int bitmask = 0;
5636 int j;
5637 // First quad face
5638 for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f0[iv]]]; }
5639 j = find_min(q, nv_quad);
5640 if (j == 0 || j == 2) { bitmask += 4; }
5641 // Second quad face
5642 for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f1[iv]]]; }
5643 j = find_min(q, nv_quad);
5644 if (j == 1 || j == 3) { bitmask += 2; }
5645 // Third quad face
5646 for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f2[iv]]]; }
5647 j = find_min(q, nv_quad);
5648 if (j == 0 || j == 2) { bitmask += 1; }
5649
5650 // Apply rotations
5651 int nrot = num_rot[bitmask];
5652 for (int k=0; k<nrot; ++k)
5653 {
5654 int vtemp;
5655 vtemp = vg[1];
5656 vg[1] = vg[4];
5657 vg[4] = vg[3];
5658 vg[3] = vtemp;
5659 vtemp = vg[5];
5660 vg[5] = vg[7];
5661 vg[7] = vg[2];
5662 vg[2] = vtemp;
5663 }
5664
5665 // Sum up nonzero bits in bitmask
5666 int ndiags = ((bitmask&4) >> 2) + ((bitmask&2) >> 1) + (bitmask&1);
5667 int ntets = (ndiags == 0) ? 5 : 6;
5668 const int *tetmap = hex_tetmaps[ndiags];
5669 for (int itet=0; itet<ntets; ++itet)
5670 {
5672 e->SetAttribute(attrib);
5673 int *v2 = e->GetVertices();
5674 for (int iv=0; iv<nv_tet; ++iv)
5675 {
5676 v2[iv] = vg[tetmap[itet + iv*ntets]];
5677 }
5678 AddElement(e);
5679 }
5680 }
5681 }
5682 // In 3D, shrink the element array because some hexes have only 5 tets
5683 if (dim == 3) { elements.SetSize(NumOfElements); }
5684
5685 for (int i=0; i<nbe; ++i)
5686 {
5687 const int *v = orig_mesh.boundary[i]->GetVertices();
5688 const int attrib = orig_mesh.GetBdrAttribute(i);
5689 const Geometry::Type orig_geom = orig_mesh.GetBdrElementGeometry(i);
5690 if (num_subdivisions[orig_geom] == 1)
5691 {
5692 Element *be = NewElement(orig_geom);
5693 be->SetAttribute(attrib);
5694 be->SetVertices(v);
5695 AddBdrElement(be);
5696 }
5697 else if (orig_geom == Geometry::SQUARE)
5698 {
5699 int vg[nv_quad];
5700 for (int iv=0; iv<nv_quad; ++iv) { vg[iv] = vglobal[v[iv]]; }
5701 // Split quad according the smallest (global) vertex
5702 int iv_min = find_min(vg, nv_quad);
5703 int isplit = (iv_min == 0 || iv_min == 2) ? 0 : 1;
5704 for (int itri=0; itri<quad_ntris; ++itri)
5705 {
5707 be->SetAttribute(attrib);
5708 int *v2 = be->GetVertices();
5709 for (int iv=0; iv<nv_tri; ++iv)
5710 {
5711 v2[iv] = v[quad_trimap[isplit][itri + iv*quad_ntris]];
5712 }
5713 AddBdrElement(be);
5714 }
5715 }
5716 else
5717 {
5718 MFEM_ABORT("Unreachable");
5719 }
5720 }
5721
5722 FinalizeTopology(false);
5723 sequence = orig_mesh.GetSequence();
5724 last_operation = orig_mesh.last_operation;
5725
5726 MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
5727 MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
5728}
5729
5730Mesh Mesh::MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v)
5731{
5732 Mesh periodic_mesh(orig_mesh, true); // Make a copy of the original mesh
5733 const FiniteElementSpace *nodal_fes = orig_mesh.GetNodalFESpace();
5734 int nodal_order = nodal_fes ? nodal_fes->GetMaxElementOrder() : 1;
5735 periodic_mesh.SetCurvature(nodal_order, true);
5736
5737 // renumber element vertices
5738 for (int i = 0; i < periodic_mesh.GetNE(); i++)
5739 {
5740 Element *el = periodic_mesh.GetElement(i);
5741 int *v = el->GetVertices();
5742 int nv = el->GetNVertices();
5743 for (int j = 0; j < nv; j++)
5744 {
5745 v[j] = v2v[v[j]];
5746 }
5747 }
5748 // renumber boundary element vertices
5749 for (int i = 0; i < periodic_mesh.GetNBE(); i++)
5750 {
5751 Element *el = periodic_mesh.GetBdrElement(i);
5752 int *v = el->GetVertices();
5753 int nv = el->GetNVertices();
5754 for (int j = 0; j < nv; j++)
5755 {
5756 v[j] = v2v[v[j]];
5757 }
5758 }
5759
5760 periodic_mesh.RemoveUnusedVertices();
5761 return periodic_mesh;
5762}
5763
5765 const std::vector<Vector> &translations, real_t tol) const
5766{
5767 const int sdim = SpaceDimension();
5768
5769 Vector coord(sdim), at(sdim), dx(sdim);
5770 Vector xMax(sdim), xMin(sdim), xDiff(sdim);
5771 xMax = xMin = xDiff = 0.0;
5772
5773 // Get a list of all vertices on the boundary
5774 unordered_set<int> bdr_v;
5775 for (int be = 0; be < GetNBE(); be++)
5776 {
5777 Array<int> dofs;
5778 GetBdrElementVertices(be,dofs);
5779
5780 for (int i = 0; i < dofs.Size(); i++)
5781 {
5782 bdr_v.insert(dofs[i]);
5783
5784 coord = GetVertex(dofs[i]);
5785 for (int j = 0; j < sdim; j++)
5786 {
5787 xMax[j] = max(xMax[j], coord[j]);
5788 xMin[j] = min(xMin[j], coord[j]);
5789 }
5790 }
5791 }
5792 add(xMax, -1.0, xMin, xDiff);
5793 real_t dia = xDiff.Norml2(); // compute mesh diameter
5794
5795 // We now identify coincident vertices. Several originally distinct vertices
5796 // may become coincident under the periodic mapping. One of these vertices
5797 // will be identified as the "primary" vertex, and all other coincident
5798 // vertices will be considered as "replicas".
5799
5800 // replica2primary[v] is the index of the primary vertex of replica `v`
5801 unordered_map<int, int> replica2primary;
5802 // primary2replicas[v] is a set of indices of replicas of primary vertex `v`
5803 unordered_map<int, unordered_set<int>> primary2replicas;
5804
5805 // Create a KD-tree containing all the boundary vertices
5806 std::unique_ptr<KDTreeBase<int,real_t>> kdtree;
5807 if (sdim == 1) { kdtree.reset(new KDTree1D); }
5808 else if (sdim == 2) { kdtree.reset(new KDTree2D); }
5809 else if (sdim == 3) { kdtree.reset(new KDTree3D); }
5810 else { MFEM_ABORT("Invalid space dimension."); }
5811
5812 // We begin with the assumption that all vertices are primary, and that there
5813 // are no replicas.
5814 for (const int v : bdr_v)
5815 {
5816 primary2replicas[v];
5817 kdtree->AddPoint(GetVertex(v), v);
5818 }
5819
5820 kdtree->Sort();
5821
5822 // Make `r` and all of `r`'s replicas be replicas of `p`. Delete `r` from the
5823 // list of primary vertices.
5824 auto make_replica = [&replica2primary, &primary2replicas](int r, int p)
5825 {
5826 if (r == p) { return; }
5827 primary2replicas[p].insert(r);
5828 replica2primary[r] = p;
5829 for (const int s : primary2replicas[r])
5830 {
5831 primary2replicas[p].insert(s);
5832 replica2primary[s] = p;
5833 }
5834 primary2replicas.erase(r);
5835 };
5836
5837 for (unsigned int i = 0; i < translations.size(); i++)
5838 {
5839 for (int vi : bdr_v)
5840 {
5841 coord = GetVertex(vi);
5842 add(coord, translations[i], at);
5843
5844 const int vj = kdtree->FindClosestPoint(at.GetData());
5845 coord = GetVertex(vj);
5846 add(at, -1.0, coord, dx);
5847
5848 if (dx.Norml2() > dia*tol) { continue; }
5849
5850 // The two vertices vi and vj are coincident.
5851
5852 // Are vertices `vi` and `vj` already primary?
5853 const bool pi = primary2replicas.find(vi) != primary2replicas.end();
5854 const bool pj = primary2replicas.find(vj) != primary2replicas.end();
5855
5856 if (pi && pj)
5857 {
5858 // Both vertices are currently primary
5859 // Demote `vj` to be a replica of `vi`
5860 make_replica(vj, vi);
5861 }
5862 else if (pi && !pj)
5863 {
5864 // `vi` is primary and `vj` is a replica
5865 const int owner_of_vj = replica2primary[vj];
5866 // Make `vi` and its replicas be replicas of `vj`'s owner
5867 make_replica(vi, owner_of_vj);
5868 }
5869 else if (!pi && pj)
5870 {
5871 // `vi` is currently a replica and `vj` is currently primary
5872 // Make `vj` and its replicas be replicas of `vi`'s owner
5873 const int owner_of_vi = replica2primary[vi];
5874 make_replica(vj, owner_of_vi);
5875 }
5876 else
5877 {
5878 // Both vertices are currently replicas
5879 // Make `vj`'s owner and all of its owner's replicas be replicas
5880 // of `vi`'s owner
5881 const int owner_of_vi = replica2primary[vi];
5882 const int owner_of_vj = replica2primary[vj];
5883 make_replica(owner_of_vj, owner_of_vi);
5884 }
5885 }
5886 }
5887
5888 std::vector<int> v2v(GetNV());
5889 for (size_t i = 0; i < v2v.size(); i++)
5890 {
5891 v2v[i] = static_cast<int>(i);
5892 }
5893 for (const auto &r2p : replica2primary)
5894 {
5895 v2v[r2p.first] = r2p.second;
5896 }
5897 return v2v;
5898}
5899
5900void Mesh::RefineNURBSFromFile(std::string ref_file)
5901{
5902 MFEM_VERIFY(NURBSext,"Mesh::RefineNURBSFromFile: Not a NURBS mesh!");
5903 mfem::out<<"Refining NURBS from refinement file: "<<ref_file<<endl;
5904
5905 int nkv;
5906 ifstream input(ref_file);
5907 input >> nkv;
5908
5909 // Check if the number of knot vectors in the refinement file and mesh match
5910 if ( nkv != NURBSext->GetNKV())
5911 {
5912 mfem::out<<endl;
5913 mfem::out<<"Knot vectors in ref_file: "<<nkv<<endl;
5914 mfem::out<<"Knot vectors in NURBSExt: "<<NURBSext->GetNKV()<<endl;
5915 MFEM_ABORT("Refine file does not have the correct number of knot vectors");
5916 }
5917
5918 // Read knot vectors from file
5919 Array<Vector *> knotVec(nkv);
5920 for (int kv = 0; kv < nkv; kv++)
5921 {
5922 knotVec[kv] = new Vector();
5923 knotVec[kv]-> Load(input);
5924 }
5925 input.close();
5926
5927 // Insert knots
5928 KnotInsert(knotVec);
5929
5930 // Delete knots
5931 for (int kv = 0; kv < nkv; kv++)
5932 {
5933 delete knotVec[kv];
5934 }
5935}
5936
5938{
5939 if (NURBSext == NULL)
5940 {
5941 mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5942 }
5943
5944 if (kv.Size() != NURBSext->GetNKV())
5945 {
5946 mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5947 }
5948
5950
5951 NURBSext->KnotInsert(kv);
5952
5953 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5954 sequence++;
5955
5956 UpdateNURBS();
5957}
5958
5960{
5961 if (NURBSext == NULL)
5962 {
5963 mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5964 }
5965
5966 if (kv.Size() != NURBSext->GetNKV())
5967 {
5968 mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5969 }
5970
5972
5973 NURBSext->KnotInsert(kv);
5974
5975 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5976 sequence++;
5977
5978 UpdateNURBS();
5979}
5980
5982{
5983 if (NURBSext == NULL)
5984 {
5985 mfem_error("Mesh::KnotRemove : Not a NURBS mesh!");
5986 }
5987
5988 if (kv.Size() != NURBSext->GetNKV())
5989 {
5990 mfem_error("Mesh::KnotRemove : KnotVector array size mismatch!");
5991 }
5992
5994
5995 NURBSext->KnotRemove(kv);
5996
5997 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5998 sequence++;
5999
6000 UpdateNURBS();
6001}
6002
6004{
6005 Array<int> rf_array(Dim);
6006 rf_array = rf;
6007 NURBSUniformRefinement(rf_array, tol);
6008}
6009
6011{
6012 MFEM_VERIFY(rf.Size() == Dim,
6013 "Refinement factors must be defined for each dimension");
6014
6015 MFEM_VERIFY(NURBSext, "NURBSUniformRefinement is only for NURBS meshes");
6016
6018
6019 Array<int> cf;
6021
6022 bool cf1 = true;
6023 for (auto f : cf)
6024 {
6025 cf1 = (cf1 && f == 1);
6026 }
6027
6028 if (cf1)
6029 {
6031 }
6032 else
6033 {
6034 NURBSext->Coarsen(cf, tol);
6035
6036 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
6037 sequence++;
6038
6039 UpdateNURBS();
6040
6042 for (int i=0; i<cf.Size(); ++i) { cf[i] *= rf[i]; }
6044 }
6045
6046 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
6047 sequence++;
6048
6049 UpdateNURBS();
6050}
6051
6052void Mesh::DegreeElevate(int rel_degree, int degree)
6053{
6054 if (NURBSext == NULL)
6055 {
6056 mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!");
6057 }
6058
6060
6061 NURBSext->DegreeElevate(rel_degree, degree);
6062
6063 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
6064 sequence++;
6065
6066 UpdateNURBS();
6067}
6068
6070{
6071 ResetLazyData();
6072
6074
6075 Dim = NURBSext->Dimension();
6076 spaceDim = Dim;
6077
6078 if (NumOfElements != NURBSext->GetNE())
6079 {
6080 for (int i = 0; i < elements.Size(); i++)
6081 {
6083 }
6086 }
6087
6089 {
6090 for (int i = 0; i < boundary.Size(); i++)
6091 {
6093 }
6096 }
6097
6098 Nodes->FESpace()->Update();
6099 Nodes->Update();
6100 NodesUpdated();
6102
6103 if (NumOfVertices != NURBSext->GetNV())
6104 {
6106 vertices.SetSize(NumOfVertices);
6107 int vd = Nodes->VectorDim();
6108 for (int i = 0; i < vd; i++)
6109 {
6110 Vector vert_val;
6111 Nodes->GetNodalValues(vert_val, i+1);
6112 for (int j = 0; j < NumOfVertices; j++)
6113 {
6114 vertices[j](i) = vert_val(j);
6115 }
6116 }
6117 }
6118
6119 if (el_to_edge)
6120 {
6122 }
6123
6124 if (el_to_face)
6125 {
6127 }
6128 GenerateFaces();
6129}
6130
6131void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot)
6132{
6133 SetEmpty();
6134
6135 // Read MFEM NURBS mesh v1.0 or 1.1 format
6136 string ident;
6137
6138 skip_comment_lines(input, '#');
6139
6140 input >> ident; // 'dimension'
6141 input >> Dim;
6142 spaceDim = Dim;
6143
6144 skip_comment_lines(input, '#');
6145
6146 input >> ident; // 'elements'
6147 input >> NumOfElements;
6148 elements.SetSize(NumOfElements);
6149 for (int j = 0; j < NumOfElements; j++)
6150 {
6151 elements[j] = ReadElement(input);
6152 }
6153
6154 skip_comment_lines(input, '#');
6155
6156 input >> ident; // 'boundary'
6157 input >> NumOfBdrElements;
6158 boundary.SetSize(NumOfBdrElements);
6159 for (int j = 0; j < NumOfBdrElements; j++)
6160 {
6161 boundary[j] = ReadElement(input);
6162 }
6163
6164 skip_comment_lines(input, '#');
6165
6166 input >> ident; // 'edges'
6167 input >> NumOfEdges;
6168 if (NumOfEdges > 0)
6169 {
6170 edge_vertex = new Table(NumOfEdges, 2);
6171 edge_to_knot.SetSize(NumOfEdges);
6172 for (int j = 0; j < NumOfEdges; j++)
6173 {
6174 int *v = edge_vertex->GetRow(j);
6175 input >> edge_to_knot[j] >> v[0] >> v[1];
6176 if (v[0] > v[1])
6177 {
6178 edge_to_knot[j] = -1 - edge_to_knot[j];
6179 }
6180 }
6181 }
6182 else
6183 {
6184 edge_to_knot.SetSize(0);
6185 }
6186
6187 skip_comment_lines(input, '#');
6188
6189 input >> ident; // 'vertices'
6190 input >> NumOfVertices;
6191 vertices.SetSize(0);
6192
6194 CheckBdrElementOrientation(); // check and fix boundary element orientation
6195
6196 /* Generate knot 2 edge mapping -- if edges are not specified in the mesh file
6197 See data/two-squares-nurbs-autoedge.mesh for an example */
6198 if (edge_to_knot.Size() == 0)
6199 {
6200 edge_vertex = new Table(NumOfEdges, 2);
6201 edge_to_knot.SetSize(NumOfEdges);
6202 constexpr int notset = -9999999;
6203 edge_to_knot = notset;
6204 Array<int> edges;
6205 Array<int> oedge;
6206 int knot = 0;
6207
6208 Array<int> edge0, edge1;
6209 int flip = 1;
6210 if (Dimension() == 2)
6211 {
6212 edge0.SetSize(2);
6213 edge1.SetSize(2);
6214
6215 edge0[0] = 0; edge1[0] = 2;
6216 edge0[1] = 1; edge1[1] = 3;
6217 flip = 1;
6218 }
6219 else if (Dimension() == 3)
6220 {
6221 edge0.SetSize(9);
6222 edge1.SetSize(9);
6223
6224 edge0[0] = 0; edge1[0] = 2;
6225 edge0[1] = 0; edge1[1] = 4;
6226 edge0[2] = 0; edge1[2] = 6;
6227
6228 edge0[3] = 1; edge1[3] = 3;
6229 edge0[4] = 1; edge1[4] = 5;
6230 edge0[5] = 1; edge1[5] = 7;
6231
6232 edge0[6] = 8; edge1[6] = 9;
6233 edge0[7] = 8; edge1[7] = 10;
6234 edge0[8] = 8; edge1[8] = 11;
6235 flip = -1;
6236 }
6237
6238 /* Initial assignment of knots to edges. This is an algorithm that loops over the
6239 patches and assigns knot vectors to edges. It starts with assigning knot vector 0
6240 and 1 to the edges of the first patch. Then it uses: 1) patches can share edges
6241 2) knot vectors on opposing edges in a patch are equal, to create edge_to_knot */
6242 int e0, e1, v0, v1, df;
6243 int p,j,k;
6244 for (p = 0; p < GetNE(); p++)
6245 {
6246 GetElementEdges(p, edges, oedge);
6247
6248 const int *v = elements[p]->GetVertices();
6249 for (j = 0; j < edges.Size(); j++)
6250 {
6251 int *vv = edge_vertex->GetRow(edges[j]);
6252 const int *e = elements[p]->GetEdgeVertices(j);
6253 if (oedge[j] == 1)
6254 {
6255 vv[0] = v[e[0]];
6256 vv[1] = v[e[1]];
6257 }
6258 else
6259 {
6260 vv[0] = v[e[1]];
6261 vv[1] = v[e[0]];
6262 }
6263 }
6264
6265 for (j = 0; j < edge1.Size(); j++)
6266 {
6267 e0 = edges[edge0[j]];
6268 e1 = edges[edge1[j]];
6269 v0 = edge_to_knot[e0];
6270 v1 = edge_to_knot[e1];
6271 df = flip*oedge[edge0[j]]*oedge[edge1[j]];
6272
6273 // Case 1: knot vector is not set
6274 if ((v0 == notset) && (v1 == notset))
6275 {
6276 edge_to_knot[e0] = knot;
6277 edge_to_knot[e1] = knot;
6278 knot++;
6279 }
6280 // Case 2 & 3: knot vector on one of the two edges
6281 // is set earlier (in another patch). We just have
6282 // to copy it for the opposing edge.
6283 else if ((v0 != notset) && (v1 == notset))
6284 {
6285 edge_to_knot[e1] = (df >= 0 ? -v0-1 : v0);
6286 }
6287 else if ((v0 == notset) && (v1 != notset))
6288 {
6289 edge_to_knot[e0] = (df >= 0 ? -v1-1 : v1);
6290 }
6291 }
6292 }
6293
6294 /* Verify correct assignment, make sure that corresponding edges
6295 within patch point to same knot vector. If not assign the lowest number.
6296
6297 We bound the while by GetNE() + 1 as this is probably the most unlucky
6298 case. +1 to finish without corrections. Note that this is a check and
6299 in general the initial assignment is correct. Then the while is performed
6300 only once. Only on very tricky meshes it might need corrections.*/
6301 int corrections;
6302 int passes = 0;
6303 do
6304 {
6305 corrections = 0;
6306 for (p = 0; p < GetNE(); p++)
6307 {
6308 GetElementEdges(p, edges, oedge);
6309 for (j = 0; j < edge1.Size(); j++)
6310 {
6311 e0 = edges[edge0[j]];
6312 e1 = edges[edge1[j]];
6313 v0 = edge_to_knot[e0];
6314 v1 = edge_to_knot[e1];
6315 v0 = ( v0 >= 0 ? v0 : -v0-1);
6316 v1 = ( v1 >= 0 ? v1 : -v1-1);
6317 if (v0 != v1)
6318 {
6319 corrections++;
6320 if (v0 < v1)
6321 {
6322 edge_to_knot[e1] = (oedge[edge1[j]] >= 0 ? v0 : -v0-1);
6323 }
6324 else if (v1 < v0)
6325 {
6326 edge_to_knot[e0] = (oedge[edge0[j]] >= 0 ? v1 : -v1-1);
6327 }
6328 }
6329 }
6330 }
6331
6332 passes++;
6333 }
6334 while (corrections > 0 && passes < GetNE() + 1);
6335
6336 // Check the validity of corrections applied
6337 if (corrections > 0)
6338 {
6339 mfem::err<<"Edge_to_knot mapping potentially incorrect"<<endl;
6340 mfem::err<<" passes = "<<passes<<endl;
6341 mfem::err<<" corrections = "<<corrections<<endl;
6342 }
6343
6344 /* Renumber knotvectors, such that:
6345 -- numbering is consecutive
6346 -- starts at zero */
6348 cnt = 0;
6349 for (j = 0; j < NumOfEdges; j++)
6350 {
6351 k = edge_to_knot[j];
6352 cnt[(k >= 0 ? k : -k-1)]++;
6353 }
6354
6355 k = 0;
6356 for (j = 0; j < cnt.Size(); j++)
6357 {
6358 cnt[j] = (cnt[j] > 0 ? k++ : -1);
6359 }
6360
6361 for (j = 0; j < NumOfEdges; j++)
6362 {
6363 k = edge_to_knot[j];
6364 edge_to_knot[j] = (k >= 0 ? cnt[k]:-cnt[-k-1]-1);
6365 }
6366
6367 // Print knot to edge mapping
6368 mfem::out<<"Generated edge to knot mapping:"<<endl;
6369 for (j = 0; j < NumOfEdges; j++)
6370 {
6371 int *v = edge_vertex->GetRow(j);
6372 k = edge_to_knot[j];
6373
6374 v0 = v[0];
6375 v1 = v[1];
6376 if (k < 0)
6377 {
6378 v[0] = v1;
6379 v[1] = v0;
6380 }
6381 mfem::out<<(k >= 0 ? k:-k-1)<<" "<< v[0] <<" "<<v[1]<<endl;
6382 }
6383
6384 // Terminate here upon failure after printing to have an idea of edge_to_knot.
6385 if (corrections > 0 ) {mfem_error("Mesh::LoadPatchTopo");}
6386 }
6387}
6388
6390{
6391 if (p.Size() >= v.Size())
6392 {
6393 for (int d = 0; d < v.Size(); d++)
6394 {
6395 v(d) = p(d);
6396 }
6397 }
6398 else
6399 {
6400 int d;
6401 for (d = 0; d < p.Size(); d++)
6402 {
6403 v(d) = p(d);
6404 }
6405 for ( ; d < v.Size(); d++)
6406 {
6407 v(d) = 0.0;
6408 }
6409 }
6410}
6411
6413{
6414 if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
6415 {
6416 const int newSpaceDim = nodes.FESpace()->GetVDim();
6418 nodes.ProjectCoefficient(xyz);
6419 }
6420 else
6421 {
6422 nodes = *Nodes;
6423 }
6424}
6425
6431
6433{
6434 if (Nodes)
6435 {
6437 if (dynamic_cast<const H1_FECollection*>(fec)
6438 || dynamic_cast<const L2_FECollection*>(fec))
6439 {
6440 return;
6441 }
6442 else // Mesh using a legacy FE_Collection
6443 {
6444 const int order = GetNodalFESpace()->GetMaxElementOrder();
6445 if (NURBSext)
6446 {
6447#ifndef MFEM_USE_MPI
6448 const bool warn = true;
6449#else
6450 ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
6451 const bool warn = !pmesh || pmesh->GetMyRank() == 0;
6452#endif
6453 if (warn)
6454 {
6455 MFEM_WARNING("converting NURBS mesh to order " << order <<
6456 " H1-continuous mesh!\n "
6457 "If this is the desired behavior, you can silence"
6458 " this warning by converting\n "
6459 "the NURBS mesh to high-order mesh in advance by"
6460 " calling the method\n "
6461 "Mesh::SetCurvature().");
6462 }
6463 }
6464 SetCurvature(order, false, -1, Ordering::byVDIM);
6465 }
6466 }
6467 else // First order H1 mesh
6468 {
6469 SetCurvature(1, false, -1, Ordering::byVDIM);
6470 }
6471}
6472
6474{
6475 GetNodes(*nodes);
6476 NewNodes(*nodes, make_owner);
6477}
6478
6480{
6481 return ((Nodes) ? Nodes->FESpace() : NULL);
6482}
6483
6484void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
6485{
6486 if (order <= 0)
6487 {
6488 delete Nodes;
6489 Nodes = nullptr;
6490 return;
6491 }
6492 space_dim = (space_dim == -1) ? spaceDim : space_dim;
6494 if (discont)
6495 {
6496 const int type = 1; // Gauss-Lobatto points
6497 nfec = new L2_FECollection(order, Dim, type);
6498 }
6499 else
6500 {
6501 nfec = new H1_FECollection(order, Dim);
6502 }
6503 FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
6504 ordering);
6505
6506 const int old_space_dim = spaceDim;
6507 SetNodalFESpace(nfes);
6508 Nodes->MakeOwner(nfec);
6509
6510 if (spaceDim != old_space_dim)
6511 {
6512 // Fix dimension of the vertices if the space dimension changes
6514 }
6515}
6516
6518{
6519 MFEM_ASSERT(nodes != NULL, "");
6520 for (int i = 0; i < spaceDim; i++)
6521 {
6522 Vector vert_val;
6523 nodes->GetNodalValues(vert_val, i+1);
6524 for (int j = 0; j < NumOfVertices; j++)
6525 {
6526 vertices[j](i) = vert_val(j);
6527 }
6528 }
6529}
6530
6532{
6533 switch (Dim)
6534 {
6535 case 1: return GetNV();
6536 case 2: return GetNEdges();
6537 case 3: return GetNFaces();
6538 }
6539 return 0;
6540}
6541
6543{
6544 return faces_info.Size();
6545}
6546
6548{
6549 const bool isInt = type==FaceType::Interior;
6550 int &nf = isInt ? nbInteriorFaces : nbBoundaryFaces;
6551 if (nf<0)
6552 {
6553 nf = 0;
6554 for (int f = 0; f < GetNumFacesWithGhost(); ++f)
6555 {
6557 if (face.IsOfFaceType(type))
6558 {
6559 if (face.IsNonconformingCoarse())
6560 {
6561 // We don't count nonconforming coarse faces.
6562 continue;
6563 }
6564 nf++;
6565 }
6566 }
6567 }
6568 return nf;
6569}
6570
6571#if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
6572static const char *fixed_or_not[] = { "fixed", "NOT FIXED" };
6573#endif
6574
6576{
6577 int i, j, k, wo = 0, fo = 0;
6578 real_t *v[4];
6579
6580 if (Dim == 2 && spaceDim == 2)
6581 {
6582 DenseMatrix J(2, 2);
6583
6584 for (i = 0; i < NumOfElements; i++)
6585 {
6586 int *vi = elements[i]->GetVertices();
6587 if (Nodes == NULL)
6588 {
6589 for (j = 0; j < 3; j++)
6590 {
6591 v[j] = vertices[vi[j]]();
6592 }
6593 for (j = 0; j < 2; j++)
6594 for (k = 0; k < 2; k++)
6595 {
6596 J(j, k) = v[j+1][k] - v[0][k];
6597 }
6598 }
6599 else
6600 {
6601 // only check the Jacobian at the center of the element
6602 GetElementJacobian(i, J);
6603 }
6604 if (J.Det() < 0.0)
6605 {
6606 if (fix_it)
6607 {
6608 switch (GetElementType(i))
6609 {
6610 case Element::TRIANGLE:
6611 mfem::Swap(vi[0], vi[1]);
6612 break;
6614 mfem::Swap(vi[1], vi[3]);
6615 break;
6616 default:
6617 MFEM_ABORT("Invalid 2D element type \""
6618 << GetElementType(i) << "\"");
6619 break;
6620 }
6621 fo++;
6622 }
6623 wo++;
6624 }
6625 }
6626 }
6627
6628 if (Dim == 3)
6629 {
6630 DenseMatrix J(3, 3);
6631
6632 for (i = 0; i < NumOfElements; i++)
6633 {
6634 int *vi = elements[i]->GetVertices();
6635 switch (GetElementType(i))
6636 {
6638 if (Nodes == NULL)
6639 {
6640 for (j = 0; j < 4; j++)
6641 {
6642 v[j] = vertices[vi[j]]();
6643 }
6644 for (j = 0; j < 3; j++)
6645 for (k = 0; k < 3; k++)
6646 {
6647 J(j, k) = v[j+1][k] - v[0][k];
6648 }
6649 }
6650 else
6651 {
6652 // only check the Jacobian at the center of the element
6653 GetElementJacobian(i, J);
6654 }
6655 if (J.Det() < 0.0)
6656 {
6657 wo++;
6658 if (fix_it)
6659 {
6660 mfem::Swap(vi[0], vi[1]);
6661 fo++;
6662 }
6663 }
6664 break;
6665
6666 case Element::WEDGE:
6667 // only check the Jacobian at the center of the element
6668 GetElementJacobian(i, J);
6669 if (J.Det() < 0.0)
6670 {
6671 wo++;
6672 if (fix_it)
6673 {
6674 // how?
6675 }
6676 }
6677 break;
6678
6679 case Element::PYRAMID:
6680 // only check the Jacobian at the center of the element
6681 GetElementJacobian(i, J);
6682 if (J.Det() < 0.0)
6683 {
6684 wo++;
6685 if (fix_it)
6686 {
6687 mfem::Swap(vi[1], vi[3]);
6688 fo++;
6689 }
6690 }
6691 break;
6692
6694 // only check the Jacobian at the center of the element
6695 GetElementJacobian(i, J);
6696 if (J.Det() < 0.0)
6697 {
6698 wo++;
6699 if (fix_it)
6700 {
6701 // how?
6702 }
6703 }
6704 break;
6705
6706 default:
6707 MFEM_ABORT("Invalid 3D element type \""
6708 << GetElementType(i) << "\"");
6709 break;
6710 }
6711 }
6712 }
6713#if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
6714 if (wo > 0)
6715 {
6716 mfem::out << "Elements with wrong orientation: " << wo << " / "
6717 << NumOfElements << " (" << fixed_or_not[(wo == fo) ? 0 : 1]
6718 << ")" << endl;
6719 }
6720#else
6721 MFEM_CONTRACT_VAR(fo);
6722#endif
6723 return wo;
6724}
6725
6726int Mesh::GetTriOrientation(const int *base, const int *test)
6727{
6728 // Static method.
6729 // This function computes the index 'j' of the permutation that transforms
6730 // test into base: test[tri_orientation[j][i]]=base[i].
6731 // tri_orientation = Geometry::Constants<Geometry::TRIANGLE>::Orient
6732 int orient;
6733
6734 if (test[0] == base[0])
6735 if (test[1] == base[1])
6736 {
6737 orient = 0; // (0, 1, 2)
6738 }
6739 else
6740 {
6741 orient = 5; // (0, 2, 1)
6742 }
6743 else if (test[0] == base[1])
6744 if (test[1] == base[0])
6745 {
6746 orient = 1; // (1, 0, 2)
6747 }
6748 else
6749 {
6750 orient = 2; // (1, 2, 0)
6751 }
6752 else // test[0] == base[2]
6753 if (test[1] == base[0])
6754 {
6755 orient = 4; // (2, 0, 1)
6756 }
6757 else
6758 {
6759 orient = 3; // (2, 1, 0)
6760 }
6761
6762#ifdef MFEM_DEBUG
6763 const int *aor = tri_t::Orient[orient];
6764 for (int j = 0; j < 3; j++)
6765 if (test[aor[j]] != base[j])
6766 {
6767 mfem::err << "Mesh::GetTriOrientation(...)" << endl;
6768 mfem::err << " base = [";
6769 for (int k = 0; k < 3; k++)
6770 {
6771 mfem::err << " " << base[k];
6772 }
6773 mfem::err << " ]\n test = [";
6774 for (int k = 0; k < 3; k++)
6775 {
6776 mfem::err << " " << test[k];
6777 }
6778 mfem::err << " ]" << endl;
6779 mfem_error();
6780 }
6781#endif
6782
6783 return orient;
6784}
6785
6786int Mesh::ComposeTriOrientations(int ori_a_b, int ori_b_c)
6787{
6788 // Static method.
6789 // Given three, possibly different, configurations of triangular face
6790 // vertices: va, vb, and vc. This function returns the relative orientation
6791 // GetTriOrientation(va, vc) by composing previously computed orientations
6792 // ori_a_b = GetTriOrientation(va, vb) and
6793 // ori_b_c = GetTriOrientation(vb, vc) without accessing the vertices.
6794
6795 const int oo[6][6] =
6796 {
6797 {0, 1, 2, 3, 4, 5},
6798 {1, 0, 5, 4, 3, 2},
6799 {2, 3, 4, 5, 0, 1},
6800 {3, 2, 1, 0, 5, 4},
6801 {4, 5, 0, 1, 2, 3},
6802 {5, 4, 3, 2, 1, 0}
6803 };
6804
6805 int ori_a_c = oo[ori_a_b][ori_b_c];
6806 return ori_a_c;
6807}
6808
6810{
6811 const int inv_ori[6] = {0, 1, 4, 3, 2, 5};
6812 return inv_ori[ori];
6813}
6814
6815int Mesh::GetQuadOrientation(const int *base, const int *test)
6816{
6817 int i;
6818
6819 for (i = 0; i < 4; i++)
6820 if (test[i] == base[0])
6821 {
6822 break;
6823 }
6824
6825#ifdef MFEM_DEBUG
6826 int orient;
6827 if (test[(i+1)%4] == base[1])
6828 {
6829 orient = 2*i;
6830 }
6831 else
6832 {
6833 orient = 2*i+1;
6834 }
6835 const int *aor = quad_t::Orient[orient];
6836 for (int j = 0; j < 4; j++)
6837 if (test[aor[j]] != base[j])
6838 {
6839 mfem::err << "Mesh::GetQuadOrientation(...)" << endl;
6840 mfem::err << " base = [";
6841 for (int k = 0; k < 4; k++)
6842 {
6843 mfem::err << " " << base[k];
6844 }
6845 mfem::err << " ]\n test = [";
6846 for (int k = 0; k < 4; k++)
6847 {
6848 mfem::err << " " << test[k];
6849 }
6850 mfem::err << " ]" << endl;
6851 mfem_error();
6852 }
6853#endif
6854
6855 if (test[(i+1)%4] == base[1])
6856 {
6857 return 2*i;
6858 }
6859
6860 return 2*i+1;
6861}
6862
6863int Mesh::ComposeQuadOrientations(int ori_a_b, int ori_b_c)
6864{
6865 // Static method.
6866 // Given three, possibly different, configurations of quadrilateral face
6867 // vertices: va, vb, and vc. This function returns the relative orientation
6868 // GetQuadOrientation(va, vc) by composing previously computed orientations
6869 // ori_a_b = GetQuadOrientation(va, vb) and
6870 // ori_b_c = GetQuadOrientation(vb, vc) without accessing the vertices.
6871
6872 const int oo[8][8] =
6873 {
6874 {0, 1, 2, 3, 4, 5, 6, 7},
6875 {1, 0, 3, 2, 5, 4, 7, 6},
6876 {2, 7, 4, 1, 6, 3, 0, 5},
6877 {3, 6, 5, 0, 7, 2, 1, 4},
6878 {4, 5, 6, 7, 0, 1, 2, 3},
6879 {5, 4, 7, 6, 1, 0, 3, 2},
6880 {6, 3, 0, 5, 2, 7, 4, 1},
6881 {7, 2, 1, 4, 3, 6, 5, 0}
6882 };
6883
6884 int ori_a_c = oo[ori_a_b][ori_b_c];
6885 return ori_a_c;
6886}
6887
6889{
6890 const int inv_ori[8] = {0, 1, 6, 3, 4, 5, 2, 7};
6891 return inv_ori[ori];
6892}
6893
6894int Mesh::GetTetOrientation(const int *base, const int *test)
6895{
6896 // Static method.
6897 // This function computes the index 'j' of the permutation that transforms
6898 // test into base: test[tet_orientation[j][i]]=base[i].
6899 // tet_orientation = Geometry::Constants<Geometry::TETRAHEDRON>::Orient
6900 int orient;
6901
6902 if (test[0] == base[0])
6903 if (test[1] == base[1])
6904 if (test[2] == base[2])
6905 {
6906 orient = 0; // (0, 1, 2, 3)
6907 }
6908 else
6909 {
6910 orient = 1; // (0, 1, 3, 2)
6911 }
6912 else if (test[2] == base[1])
6913 if (test[3] == base[2])
6914 {
6915 orient = 2; // (0, 2, 3, 1)
6916 }
6917 else
6918 {
6919 orient = 3; // (0, 2, 1, 3)
6920 }
6921 else // test[3] == base[1]
6922 if (test[1] == base[2])
6923 {
6924 orient = 4; // (0, 3, 1, 2)
6925 }
6926 else
6927 {
6928 orient = 5; // (0, 3, 2, 1)
6929 }
6930 else if (test[1] == base[0])
6931 if (test[2] == base[1])
6932 if (test[0] == base[2])
6933 {
6934 orient = 6; // (1, 2, 0, 3)
6935 }
6936 else
6937 {
6938 orient = 7; // (1, 2, 3, 0)
6939 }
6940 else if (test[3] == base[1])
6941 if (test[2] == base[2])
6942 {
6943 orient = 8; // (1, 3, 2, 0)
6944 }
6945 else
6946 {
6947 orient = 9; // (1, 3, 0, 2)
6948 }
6949 else // test[0] == base[1]
6950 if (test[3] == base[2])
6951 {
6952 orient = 10; // (1, 0, 3, 2)
6953 }
6954 else
6955 {
6956 orient = 11; // (1, 0, 2, 3)
6957 }
6958 else if (test[2] == base[0])
6959 if (test[3] == base[1])
6960 if (test[0] == base[2])
6961 {
6962 orient = 12; // (2, 3, 0, 1)
6963 }
6964 else
6965 {
6966 orient = 13; // (2, 3, 1, 0)
6967 }
6968 else if (test[0] == base[1])
6969 if (test[1] == base[2])
6970 {
6971 orient = 14; // (2, 0, 1, 3)
6972 }
6973 else
6974 {
6975 orient = 15; // (2, 0, 3, 1)
6976 }
6977 else // test[1] == base[1]
6978 if (test[3] == base[2])
6979 {
6980 orient = 16; // (2, 1, 3, 0)
6981 }
6982 else
6983 {
6984 orient = 17; // (2, 1, 0, 3)
6985 }
6986 else // (test[3] == base[0])
6987 if (test[0] == base[1])
6988 if (test[2] == base[2])
6989 {
6990 orient = 18; // (3, 0, 2, 1)
6991 }
6992 else
6993 {
6994 orient = 19; // (3, 0, 1, 2)
6995 }
6996 else if (test[1] == base[1])
6997 if (test[0] == base[2])
6998 {
6999 orient = 20; // (3, 1, 0, 2)
7000 }
7001 else
7002 {
7003 orient = 21; // (3, 1, 2, 0)
7004 }
7005 else // test[2] == base[1]
7006 if (test[1] == base[2])
7007 {
7008 orient = 22; // (3, 2, 1, 0)
7009 }
7010 else
7011 {
7012 orient = 23; // (3, 2, 0, 1)
7013 }
7014
7015#ifdef MFEM_DEBUG
7016 const int *aor = tet_t::Orient[orient];
7017 for (int j = 0; j < 4; j++)
7018 if (test[aor[j]] != base[j])
7019 {
7020 mfem_error("Mesh::GetTetOrientation(...)");
7021 }
7022#endif
7023
7024 return orient;
7025}
7026
7028{
7029 int wo = 0; // count wrong orientations
7030
7031 if (Dim == 2)
7032 {
7033 if (el_to_edge == NULL) // edges were not generated
7034 {
7035 el_to_edge = new Table;
7037 GenerateFaces(); // 'Faces' in 2D refers to the edges
7038 }
7039 for (int i = 0; i < NumOfBdrElements; i++)
7040 {
7041 if (faces_info[be_to_face[i]].Elem2No < 0) // boundary face
7042 {
7043 int *bv = boundary[i]->GetVertices();
7044 int *fv = faces[be_to_face[i]]->GetVertices();
7045 if (bv[0] != fv[0])
7046 {
7047 if (fix_it)
7048 {
7049 mfem::Swap<int>(bv[0], bv[1]);
7050 }
7051 wo++;
7052 }
7053 }
7054 }
7055 }
7056
7057 if (Dim == 3)
7058 {
7059 for (int i = 0; i < NumOfBdrElements; i++)
7060 {
7061 const int fi = be_to_face[i];
7062
7063 if (faces_info[fi].Elem2No >= 0) { continue; }
7064
7065 // boundary face
7066 int *bv = boundary[i]->GetVertices();
7067 // Make sure the 'faces' are generated:
7068 MFEM_ASSERT(fi < faces.Size(), "internal error");
7069 const int *fv = faces[fi]->GetVertices();
7070 int orientation; // orientation of the bdr. elem. w.r.t. the
7071 // corresponding face element (that's the base)
7072 const Element::Type bdr_type = GetBdrElementType(i);
7073 switch (bdr_type)
7074 {
7075 case Element::TRIANGLE:
7076 {
7077 orientation = GetTriOrientation(fv, bv);
7078 break;
7079 }
7081 {
7082 orientation = GetQuadOrientation(fv, bv);
7083 break;
7084 }
7085 default:
7086 MFEM_ABORT("Invalid 2D boundary element type \""
7087 << bdr_type << "\"");
7088 orientation = 0; // suppress a warning
7089 break;
7090 }
7091
7092 if (orientation % 2 == 0) { continue; }
7093 wo++;
7094 if (!fix_it) { continue; }
7095
7096 switch (bdr_type)
7097 {
7098 case Element::TRIANGLE:
7099 {
7100 // swap vertices 0 and 1 so that we don't change the marked edge:
7101 // (0,1,2) -> (1,0,2)
7102 mfem::Swap(bv[0], bv[1]);
7103 if (bel_to_edge)
7104 {
7105 int *be = bel_to_edge->GetRow(i);
7106 mfem::Swap(be[1], be[2]);
7107 }
7108 break;
7109 }
7111 {
7112 mfem::Swap(bv[0], bv[2]);
7113 if (bel_to_edge)
7114 {
7115 int *be = bel_to_edge->GetRow(i);
7116 mfem::Swap(be[0], be[1]);
7117 mfem::Swap(be[2], be[3]);
7118 }
7119 break;
7120 }
7121 default: // unreachable
7122 break;
7123 }
7124 }
7125 }
7126 // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
7127#ifdef MFEM_DEBUG
7128 if (wo > 0)
7129 {
7130 mfem::out << "Boundary elements with wrong orientation: " << wo << " / "
7131 << NumOfBdrElements << " (" << fixed_or_not[fix_it ? 0 : 1]
7132 << ")" << endl;
7133 }
7134#endif
7135 return wo;
7136}
7137
7139 const IntegrationPoint &ip)
7140{
7141 IntegrationPoint fip = ip;
7142 if (geom == Geometry::POINT)
7143 {
7144 return fip;
7145 }
7146 else if (geom == Geometry::SEGMENT)
7147 {
7148 MFEM_ASSERT(o >= 0 && o < 2, "Invalid orientation for Geometry::SEGMENT!");
7149 if (o == 0)
7150 {
7151 fip.x = ip.x;
7152 }
7153 else if (o == 1)
7154 {
7155 fip.x = 1.0 - ip.x;
7156 }
7157 }
7158 else if (geom == Geometry::TRIANGLE)
7159 {
7160 MFEM_ASSERT(o >= 0 && o < 6, "Invalid orientation for Geometry::TRIANGLE!");
7161 if (o == 0) // 0, 1, 2
7162 {
7163 fip.x = ip.x;
7164 fip.y = ip.y;
7165 }
7166 else if (o == 5) // 0, 2, 1
7167 {
7168 fip.x = ip.y;
7169 fip.y = ip.x;
7170 }
7171 else if (o == 2) // 1, 2, 0
7172 {
7173 fip.x = 1.0 - ip.x - ip.y;
7174 fip.y = ip.x;
7175 }
7176 else if (o == 1) // 1, 0, 2
7177 {
7178 fip.x = 1.0 - ip.x - ip.y;
7179 fip.y = ip.y;
7180 }
7181 else if (o == 4) // 2, 0, 1
7182 {
7183 fip.x = ip.y;
7184 fip.y = 1.0 - ip.x - ip.y;
7185 }
7186 else if (o == 3) // 2, 1, 0
7187 {
7188 fip.x = ip.x;
7189 fip.y = 1.0 - ip.x - ip.y;
7190 }
7191 }
7192 else if (geom == Geometry::SQUARE)
7193 {
7194 MFEM_ASSERT(o >= 0 && o < 8, "Invalid orientation for Geometry::SQUARE!");
7195 if (o == 0) // 0, 1, 2, 3
7196 {
7197 fip.x = ip.x;
7198 fip.y = ip.y;
7199 }
7200 else if (o == 1) // 0, 3, 2, 1
7201 {
7202 fip.x = ip.y;
7203 fip.y = ip.x;
7204 }
7205 else if (o == 2) // 1, 2, 3, 0
7206 {
7207 fip.x = ip.y;
7208 fip.y = 1.0 - ip.x;
7209 }
7210 else if (o == 3) // 1, 0, 3, 2
7211 {
7212 fip.x = 1.0 - ip.x;
7213 fip.y = ip.y;
7214 }
7215 else if (o == 4) // 2, 3, 0, 1
7216 {
7217 fip.x = 1.0 - ip.x;
7218 fip.y = 1.0 - ip.y;
7219 }
7220 else if (o == 5) // 2, 1, 0, 3
7221 {
7222 fip.x = 1.0 - ip.y;
7223 fip.y = 1.0 - ip.x;
7224 }
7225 else if (o == 6) // 3, 0, 1, 2
7226 {
7227 fip.x = 1.0 - ip.y;
7228 fip.y = ip.x;
7229 }
7230 else if (o == 7) // 3, 2, 1, 0
7231 {
7232 fip.x = ip.x;
7233 fip.y = 1.0 - ip.y;
7234 }
7235 }
7236 else
7237 {
7238 MFEM_ABORT("Unsupported face geometry for TransformBdrElementToFace!");
7239 }
7240 return fip;
7241}
7242
7244{
7245 MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
7246 int num_geoms = 0;
7247 for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
7248 {
7249 if (HasGeometry(Geometry::Type(g))) { num_geoms++; }
7250 }
7251 return num_geoms;
7252}
7253
7255{
7256 MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
7257 el_geoms.SetSize(0);
7258 for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
7259 {
7261 {
7262 el_geoms.Append(Geometry::Type(g));
7263 }
7264 }
7265}
7266
7267void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const
7268{
7269 if (el_to_edge)
7270 {
7271 el_to_edge->GetRow(i, edges);
7272 }
7273 else
7274 {
7275 mfem_error("Mesh::GetElementEdges(...) element to edge table "
7276 "is not generated.");
7277 }
7278
7279 const int *v = elements[i]->GetVertices();
7280 const int ne = elements[i]->GetNEdges();
7281 cor.SetSize(ne);
7282 for (int j = 0; j < ne; j++)
7283 {
7284 const int *e = elements[i]->GetEdgeVertices(j);
7285 cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
7286 }
7287}
7288
7289void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const
7290{
7291 if (Dim == 2)
7292 {
7293 edges.SetSize(1);
7294 cor.SetSize(1);
7295 edges[0] = be_to_face[i];
7296 const int *v = boundary[i]->GetVertices();
7297 cor[0] = (v[0] < v[1]) ? (1) : (-1);
7298 }
7299 else if (Dim == 3)
7300 {
7301 if (bel_to_edge)
7302 {
7303 bel_to_edge->GetRow(i, edges);
7304 }
7305 else
7306 {
7307 mfem_error("Mesh::GetBdrElementEdges(...)");
7308 }
7309
7310 const int *v = boundary[i]->GetVertices();
7311 const int ne = boundary[i]->GetNEdges();
7312 cor.SetSize(ne);
7313 for (int j = 0; j < ne; j++)
7314 {
7315 const int *e = boundary[i]->GetEdgeVertices(j);
7316 cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
7317 }
7318 }
7319}
7320
7321void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const
7322{
7323 if (Dim == 2)
7324 {
7325 edges.SetSize(1);
7326 edges[0] = i;
7327 o.SetSize(1);
7328 const int *v = faces[i]->GetVertices();
7329 o[0] = (v[0] < v[1]) ? (1) : (-1);
7330 }
7331
7332 if (Dim != 3)
7333 {
7334 return;
7335 }
7336
7337 GetFaceEdgeTable(); // generate face_edge Table (if not generated)
7338
7339 face_edge->GetRow(i, edges);
7340
7341 const int *v = faces[i]->GetVertices();
7342 const int ne = faces[i]->GetNEdges();
7343 o.SetSize(ne);
7344 for (int j = 0; j < ne; j++)
7345 {
7346 const int *e = faces[i]->GetEdgeVertices(j);
7347 o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
7348 }
7349}
7350
7351void Mesh::GetEdgeVertices(int i, Array<int> &vert) const
7352{
7353 // the two vertices are sorted: vert[0] < vert[1]
7354 // this is consistent with the global edge orientation
7355 // generate edge_vertex Table (if not generated)
7356 if (!edge_vertex) { GetEdgeVertexTable(); }
7357 edge_vertex->GetRow(i, vert);
7358}
7359
7361{
7362 if (face_edge)
7363 {
7364 return face_edge;
7365 }
7366
7367 if (Dim != 3)
7368 {
7369 return NULL;
7370 }
7371
7372#ifdef MFEM_DEBUG
7373 if (faces.Size() != NumOfFaces)
7374 {
7375 mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!");
7376 }
7377#endif
7378
7379 DSTable v_to_v(NumOfVertices);
7380 GetVertexToVertexTable(v_to_v);
7381
7382 face_edge = new Table;
7384
7385 return (face_edge);
7386}
7387
7389{
7390 if (edge_vertex)
7391 {
7392 return edge_vertex;
7393 }
7394
7395 DSTable v_to_v(NumOfVertices);
7396 GetVertexToVertexTable(v_to_v);
7397
7398 int nedges = v_to_v.NumberOfEntries();
7399 edge_vertex = new Table(nedges, 2);
7400 for (int i = 0; i < NumOfVertices; i++)
7401 {
7402 for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
7403 {
7404 int j = it.Index();
7405 edge_vertex->Push(j, i);
7406 edge_vertex->Push(j, it.Column());
7407 }
7408 }
7410
7411 return edge_vertex;
7412}
7413
7415{
7416 Table *vert_elem = new Table;
7417
7418 vert_elem->MakeI(NumOfVertices);
7419
7420 for (int i = 0; i < NumOfElements; i++)
7421 {
7422 const int nv = elements[i]->GetNVertices();
7423 const int *v = elements[i]->GetVertices();
7424 for (int j = 0; j < nv; j++)
7425 {
7426 vert_elem->AddAColumnInRow(v[j]);
7427 }
7428 }
7429
7430 vert_elem->MakeJ();
7431
7432 for (int i = 0; i < NumOfElements; i++)
7433 {
7434 const int nv = elements[i]->GetNVertices();
7435 const int *v = elements[i]->GetVertices();
7436 for (int j = 0; j < nv; j++)
7437 {
7438 vert_elem->AddConnection(v[j], i);
7439 }
7440 }
7441
7442 vert_elem->ShiftUpI();
7443
7444 return vert_elem;
7445}
7446
7448{
7449 Table *vert_bdr_elem = new Table;
7450
7451 vert_bdr_elem->MakeI(NumOfVertices);
7452
7453 for (int i = 0; i < NumOfBdrElements; i++)
7454 {
7455 const int nv = boundary[i]->GetNVertices();
7456 const int *v = boundary[i]->GetVertices();
7457 for (int j = 0; j < nv; j++)
7458 {
7459 vert_bdr_elem->AddAColumnInRow(v[j]);
7460 }
7461 }
7462
7463 vert_bdr_elem->MakeJ();
7464
7465 for (int i = 0; i < NumOfBdrElements; i++)
7466 {
7467 const int nv = boundary[i]->GetNVertices();
7468 const int *v = boundary[i]->GetVertices();
7469 for (int j = 0; j < nv; j++)
7470 {
7471 vert_bdr_elem->AddConnection(v[j], i);
7472 }
7473 }
7474
7475 vert_bdr_elem->ShiftUpI();
7476
7477 return vert_bdr_elem;
7478}
7479
7481{
7482 Table *face_elem = new Table;
7483
7484 face_elem->MakeI(faces_info.Size());
7485
7486 for (int i = 0; i < faces_info.Size(); i++)
7487 {
7488 if (faces_info[i].Elem2No >= 0)
7489 {
7490 face_elem->AddColumnsInRow(i, 2);
7491 }
7492 else
7493 {
7494 face_elem->AddAColumnInRow(i);
7495 }
7496 }
7497
7498 face_elem->MakeJ();
7499
7500 for (int i = 0; i < faces_info.Size(); i++)
7501 {
7502 face_elem->AddConnection(i, faces_info[i].Elem1No);
7503 if (faces_info[i].Elem2No >= 0)
7504 {
7505 face_elem->AddConnection(i, faces_info[i].Elem2No);
7506 }
7507 }
7508
7509 face_elem->ShiftUpI();
7510
7511 return face_elem;
7512}
7513
7514void Mesh::GetElementFaces(int i, Array<int> &el_faces, Array<int> &ori) const
7515{
7516 MFEM_VERIFY(el_to_face != NULL, "el_to_face not generated");
7517
7518 el_to_face->GetRow(i, el_faces);
7519
7520 int n = el_faces.Size();
7521 ori.SetSize(n);
7522
7523 for (int j = 0; j < n; j++)
7524 {
7525 if (faces_info[el_faces[j]].Elem1No == i)
7526 {
7527 ori[j] = faces_info[el_faces[j]].Elem1Inf % 64;
7528 }
7529 else
7530 {
7531 MFEM_ASSERT(faces_info[el_faces[j]].Elem2No == i, "internal error");
7532 ori[j] = faces_info[el_faces[j]].Elem2Inf % 64;
7533 }
7534 }
7535}
7536
7538{
7539 if (face_to_elem == NULL)
7540 {
7542 }
7543
7544 Array<int> elem_faces;
7545 Array<int> ori;
7546 GetElementFaces(elem, elem_faces, ori);
7547
7548 Array<int> nghb;
7549 for (auto f : elem_faces)
7550 {
7551 Array<int> row;
7552 face_to_elem->GetRow(f, row);
7553 for (auto r : row)
7554 {
7555 nghb.Append(r);
7556 }
7557 }
7558
7559 nghb.Sort();
7560 nghb.Unique();
7561
7562 return nghb;
7563}
7564
7565void Mesh::GetBdrElementFace(int i, int *f, int *o) const
7566{
7568
7569 const int *fv = (Dim > 1) ? faces[*f]->GetVertices() : NULL;
7570 const int *bv = boundary[i]->GetVertices();
7571
7572 // find the orientation of the bdr. elem. w.r.t.
7573 // the corresponding face element (that's the base)
7574 switch (GetBdrElementGeometry(i))
7575 {
7576 case Geometry::POINT: *o = 0; break;
7577 case Geometry::SEGMENT: *o = (fv[0] == bv[0]) ? 0 : 1; break;
7578 case Geometry::TRIANGLE: *o = GetTriOrientation(fv, bv); break;
7579 case Geometry::SQUARE: *o = GetQuadOrientation(fv, bv); break;
7580 default: MFEM_ABORT("invalid geometry");
7581 }
7582}
7583
7584void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
7585{
7586 int fid = GetBdrElementFaceIndex(bdr_el);
7587
7588 const FaceInfo &fi = faces_info[fid];
7589 MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
7590
7591 const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
7592 const int *bv = boundary[bdr_el]->GetVertices();
7593 int ori;
7594 switch (GetBdrElementGeometry(bdr_el))
7595 {
7596 case Geometry::POINT: ori = 0; break;
7597 case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
7598 case Geometry::TRIANGLE: ori = GetTriOrientation(fv, bv); break;
7599 case Geometry::SQUARE: ori = GetQuadOrientation(fv, bv); break;
7600 default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
7601 }
7602 el = fi.Elem1No;
7603 info = fi.Elem1Inf + ori;
7604}
7605
7607 int bdr_el, int &el, int &info) const
7608{
7609 int fid = GetBdrElementFaceIndex(bdr_el);
7610
7611 const FaceInfo &fi = faces_info[fid];
7612 MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
7613
7614 const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
7615 const int *bv = boundary[bdr_el]->GetVertices();
7616 int ori;
7617 switch (GetBdrElementGeometry(bdr_el))
7618 {
7619 case Geometry::POINT: ori = 0; break;
7620 case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
7621 case Geometry::TRIANGLE: ori = GetTriOrientation(bv, fv); break;
7622 case Geometry::SQUARE: ori = GetQuadOrientation(bv, fv); break;
7623 default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
7624 }
7625 el = fi.Elem1No;
7626 info = fi.Elem1Inf + ori;
7627}
7628
7629void Mesh::SetAttribute(int i, int attr)
7630{
7631 elements[i]->SetAttribute(attr);
7632 if (ncmesh) ncmesh->SetAttribute(i, attr);
7633}
7634
7636{
7637 return elements[i]->GetType();
7638}
7639
7641{
7642 return boundary[i]->GetType();
7643}
7644
7645void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const
7646{
7647 int k, j, nv;
7648 const int *v;
7649
7650 v = elements[i]->GetVertices();
7651 nv = elements[i]->GetNVertices();
7652
7653 pointmat.SetSize(spaceDim, nv);
7654 for (k = 0; k < spaceDim; k++)
7655 {
7656 for (j = 0; j < nv; j++)
7657 {
7658 pointmat(k, j) = vertices[v[j]](k);
7659 }
7660 }
7661}
7662
7663void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const
7664{
7665 int k, j, nv;
7666 const int *v;
7667
7668 v = boundary[i]->GetVertices();
7669 nv = boundary[i]->GetNVertices();
7670
7671 pointmat.SetSize(spaceDim, nv);
7672 for (k = 0; k < spaceDim; k++)
7673 for (j = 0; j < nv; j++)
7674 {
7675 pointmat(k, j) = vertices[v[j]](k);
7676 }
7677}
7678
7679real_t Mesh::GetLength(int i, int j) const
7680{
7681 const real_t *vi = vertices[i]();
7682 const real_t *vj = vertices[j]();
7683 real_t length = 0.;
7684
7685 for (int k = 0; k < spaceDim; k++)
7686 {
7687 length += (vi[k]-vj[k])*(vi[k]-vj[k]);
7688 }
7689
7690 return sqrt(length);
7691}
7692
7693// static method
7695 const DSTable &v_to_v, Table &el_to_edge)
7696{
7697 el_to_edge.MakeI(elem_array.Size());
7698 for (int i = 0; i < elem_array.Size(); i++)
7699 {
7700 el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges());
7701 }
7702 el_to_edge.MakeJ();
7703 for (int i = 0; i < elem_array.Size(); i++)
7704 {
7705 const int *v = elem_array[i]->GetVertices();
7706 const int ne = elem_array[i]->GetNEdges();
7707 for (int j = 0; j < ne; j++)
7708 {
7709 const int *e = elem_array[i]->GetEdgeVertices(j);
7710 el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]]));
7711 }
7712 }
7714}
7715
7717{
7718 if (edge_vertex)
7719 {
7720 for (int i = 0; i < edge_vertex->Size(); i++)
7721 {
7722 const int *v = edge_vertex->GetRow(i);
7723 v_to_v.Push(v[0], v[1]);
7724 }
7725 }
7726 else
7727 {
7728 for (int i = 0; i < NumOfElements; i++)
7729 {
7730 const int *v = elements[i]->GetVertices();
7731 const int ne = elements[i]->GetNEdges();
7732 for (int j = 0; j < ne; j++)
7733 {
7734 const int *e = elements[i]->GetEdgeVertices(j);
7735 v_to_v.Push(v[e[0]], v[e[1]]);
7736 }
7737 }
7738 }
7739}
7740
7742{
7743 int i, NumberOfEdges;
7744
7745 DSTable v_to_v(NumOfVertices);
7746 GetVertexToVertexTable(v_to_v);
7747
7748 NumberOfEdges = v_to_v.NumberOfEntries();
7749
7750 // Fill the element to edge table
7751 GetElementArrayEdgeTable(elements, v_to_v, e_to_f);
7752
7753 if (Dim == 2)
7754 {
7755 // Initialize the indices for the boundary elements.
7757 for (i = 0; i < NumOfBdrElements; i++)
7758 {
7759 const int *v = boundary[i]->GetVertices();
7760 be_to_face[i] = v_to_v(v[0], v[1]);
7761 }
7762 }
7763 else if (Dim == 3)
7764 {
7765 if (bel_to_edge == NULL)
7766 {
7767 bel_to_edge = new Table;
7768 }
7770 }
7771 else
7772 {
7773 mfem_error("1D GetElementToEdgeTable is not yet implemented.");
7774 }
7775
7776 // Return the number of edges
7777 return NumberOfEdges;
7778}
7779
7781{
7782 if (el_to_el)
7783 {
7784 return *el_to_el;
7785 }
7786
7787 // Note that, for ParNCMeshes, faces_info will contain also the ghost faces
7788 MFEM_ASSERT(faces_info.Size() >= GetNumFaces(), "faces were not generated!");
7789
7790 Array<Connection> conn;
7791 conn.Reserve(2*faces_info.Size());
7792
7793 for (int i = 0; i < faces_info.Size(); i++)
7794 {
7795 const FaceInfo &fi = faces_info[i];
7796 if (fi.Elem2No >= 0)
7797 {
7798 conn.Append(Connection(fi.Elem1No, fi.Elem2No));
7799 conn.Append(Connection(fi.Elem2No, fi.Elem1No));
7800 }
7801 else if (fi.Elem2Inf >= 0)
7802 {
7803 int nbr_elem_idx = NumOfElements - 1 - fi.Elem2No;
7804 conn.Append(Connection(fi.Elem1No, nbr_elem_idx));
7805 conn.Append(Connection(nbr_elem_idx, fi.Elem1No));
7806 }
7807 }
7808
7809 conn.Sort();
7810 conn.Unique();
7811 el_to_el = new Table(NumOfElements, conn);
7812
7813 return *el_to_el;
7814}
7815
7817{
7818 if (el_to_face == NULL)
7819 {
7820 mfem_error("Mesh::ElementToFaceTable()");
7821 }
7822 return *el_to_face;
7823}
7824
7826{
7827 if (el_to_edge == NULL)
7828 {
7829 mfem_error("Mesh::ElementToEdgeTable()");
7830 }
7831 return *el_to_edge;
7832}
7833
7834void Mesh::AddPointFaceElement(int lf, int gf, int el)
7835{
7836 if (faces[gf] == NULL) // this will be elem1
7837 {
7838 faces[gf] = new Point(&gf);
7839 faces_info[gf].Elem1No = el;
7840 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
7841 faces_info[gf].Elem2No = -1; // in case there's no other side
7842 faces_info[gf].Elem2Inf = -1; // face is not shared
7843 }
7844 else // this will be elem2
7845 {
7846 /* WARNING: Without the following check the mesh faces_info data structure
7847 may contain unreliable data. Normally, the order in which elements are
7848 processed could swap which elements appear as Elem1No and Elem2No. In
7849 branched meshes, where more than two elements can meet at a given node,
7850 the indices stored in Elem1No and Elem2No will be the first and last,
7851 respectively, elements found which touch a given node. This can lead to
7852 inconsistencies in any algorithms which rely on this data structure. To
7853 properly support branched meshes this data structure should be extended
7854 to support multiple elements per face. */
7855 /*
7856 MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
7857 "Interior point found connecting 1D elements "
7858 << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
7859 << " and " << el << ".");
7860 */
7861 faces_info[gf].Elem2No = el;
7862 faces_info[gf].Elem2Inf = 64 * lf + 1;
7863 }
7864}
7865
7866void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
7867{
7868 if (faces[gf] == NULL) // this will be elem1
7869 {
7870 faces[gf] = new Segment(v0, v1);
7871 faces_info[gf].Elem1No = el;
7872 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
7873 faces_info[gf].Elem2No = -1; // in case there's no other side
7874 faces_info[gf].Elem2Inf = -1; // face is not shared
7875 }
7876 else // this will be elem2
7877 {
7878 MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
7879 "Interior edge found between 2D elements "
7880 << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
7881 << " and " << el << ".");
7882 int *v = faces[gf]->GetVertices();
7883 faces_info[gf].Elem2No = el;
7884 if (v[1] == v0 && v[0] == v1)
7885 {
7886 faces_info[gf].Elem2Inf = 64 * lf + 1;
7887 }
7888 else if (v[0] == v0 && v[1] == v1)
7889 {
7890 // Temporarily allow even edge orientations: see the remark in
7891 // AddTriangleFaceElement().
7892 // Also, in a non-orientable surface mesh, the orientation will be even
7893 // for edges that connect elements with opposite orientations.
7894 faces_info[gf].Elem2Inf = 64 * lf;
7895 }
7896 else
7897 {
7898 MFEM_ABORT("internal error");
7899 }
7900 }
7901}
7902
7903void Mesh::AddTriangleFaceElement(int lf, int gf, int el,
7904 int v0, int v1, int v2)
7905{
7906 if (faces[gf] == NULL) // this will be elem1
7907 {
7908 faces[gf] = new Triangle(v0, v1, v2);
7909 faces_info[gf].Elem1No = el;
7910 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
7911 faces_info[gf].Elem2No = -1; // in case there's no other side
7912 faces_info[gf].Elem2Inf = -1; // face is not shared
7913 }
7914 else // this will be elem2
7915 {
7916 MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
7917 "Interior triangular face found connecting elements "
7918 << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
7919 << " and " << el << ".");
7920 int orientation, vv[3] = { v0, v1, v2 };
7921 orientation = GetTriOrientation(faces[gf]->GetVertices(), vv);
7922 // In a valid mesh, we should have (orientation % 2 != 0), however, if
7923 // one of the adjacent elements has wrong orientation, both face
7924 // orientations can be even, until the element orientations are fixed.
7925 // MFEM_ASSERT(orientation % 2 != 0, "");
7926 faces_info[gf].Elem2No = el;
7927 faces_info[gf].Elem2Inf = 64 * lf + orientation;
7928 }
7929}
7930
7931void Mesh::AddQuadFaceElement(int lf, int gf, int el,
7932 int v0, int v1, int v2, int v3)
7933{
7934 if (faces_info[gf].Elem1No < 0) // this will be elem1
7935 {
7936 faces[gf] = new Quadrilateral(v0, v1, v2, v3);
7937 faces_info[gf].Elem1No = el;
7938 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
7939 faces_info[gf].Elem2No = -1; // in case there's no other side
7940 faces_info[gf].Elem2Inf = -1; // face is not shared
7941 }
7942 else // this will be elem2
7943 {
7944 MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
7945 "Interior quadrilateral face found connecting elements "
7946 << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
7947 << " and " << el << ".");
7948 int vv[4] = { v0, v1, v2, v3 };
7949 int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv);
7950 // Temporarily allow even face orientations: see the remark in
7951 // AddTriangleFaceElement().
7952 // MFEM_ASSERT(oo % 2 != 0, "");
7953 faces_info[gf].Elem2No = el;
7954 faces_info[gf].Elem2Inf = 64 * lf + oo;
7955 }
7956}
7957
7959{
7960 int nfaces = GetNumFaces();
7961 for (auto &f : faces)
7962 {
7963 FreeElement(f);
7964 }
7965
7966 // (re)generate the interior faces and the info for them
7967 faces.SetSize(nfaces);
7968 faces_info.SetSize(nfaces);
7969 for (int i = 0; i < nfaces; ++i)
7970 {
7971 faces[i] = NULL;
7972 faces_info[i].Elem1No = -1;
7973 faces_info[i].NCFace = -1;
7974 }
7975
7976 Array<int> v;
7977 for (int i = 0; i < NumOfElements; ++i)
7978 {
7979 elements[i]->GetVertices(v);
7980 if (Dim == 1)
7981 {
7982 AddPointFaceElement(0, v[0], i);
7983 AddPointFaceElement(1, v[1], i);
7984 }
7985 else if (Dim == 2)
7986 {
7987 const int * const ef = el_to_edge->GetRow(i);
7988 const int ne = elements[i]->GetNEdges();
7989 for (int j = 0; j < ne; j++)
7990 {
7991 const int *e = elements[i]->GetEdgeVertices(j);
7992 AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]);
7993 }
7994 }
7995 else
7996 {
7997 const int * const ef = el_to_face->GetRow(i);
7998 switch (GetElementType(i))
7999 {
8001 {
8002 for (int j = 0; j < 4; j++)
8003 {
8004 const int *fv = tet_t::FaceVert[j];
8005 AddTriangleFaceElement(j, ef[j], i,
8006 v[fv[0]], v[fv[1]], v[fv[2]]);
8007 }
8008 break;
8009 }
8010 case Element::WEDGE:
8011 {
8012 for (int j = 0; j < 2; j++)
8013 {
8014 const int *fv = pri_t::FaceVert[j];
8015 AddTriangleFaceElement(j, ef[j], i,
8016 v[fv[0]], v[fv[1]], v[fv[2]]);
8017 }
8018 for (int j = 2; j < 5; j++)
8019 {
8020 const int *fv = pri_t::FaceVert[j];
8021 AddQuadFaceElement(j, ef[j], i,
8022 v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
8023 }
8024 break;
8025 }
8026 case Element::PYRAMID:
8027 {
8028 for (int j = 0; j < 1; j++)
8029 {
8030 const int *fv = pyr_t::FaceVert[j];
8031 AddQuadFaceElement(j, ef[j], i,
8032 v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
8033 }
8034 for (int j = 1; j < 5; j++)
8035 {
8036 const int *fv = pyr_t::FaceVert[j];
8037 AddTriangleFaceElement(j, ef[j], i,
8038 v[fv[0]], v[fv[1]], v[fv[2]]);
8039 }
8040 break;
8041 }
8043 {
8044 for (int j = 0; j < 6; j++)
8045 {
8046 const int *fv = hex_t::FaceVert[j];
8047 AddQuadFaceElement(j, ef[j], i,
8048 v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
8049 }
8050 break;
8051 }
8052 default:
8053 MFEM_ABORT("Unexpected type of Element.");
8054 }
8055 }
8056 }
8057}
8058
8060{
8061 MFEM_VERIFY(ncmesh, "missing NCMesh.");
8062
8063 for (auto &x : faces_info)
8064 {
8065 x.NCFace = -1;
8066 }
8067
8068 const NCMesh::NCList &list =
8069 (Dim == 2) ? ncmesh->GetEdgeList() : ncmesh->GetFaceList();
8070
8071 nc_faces_info.SetSize(0);
8072 nc_faces_info.Reserve(list.masters.Size() + list.slaves.Size());
8073
8074 int nfaces = GetNumFaces();
8075
8076 // add records for master faces
8077 for (const NCMesh::Master &master : list.masters)
8078 {
8079 if (master.index >= nfaces) { continue; }
8080
8081 FaceInfo &master_fi = faces_info[master.index];
8082 master_fi.NCFace = nc_faces_info.Size();
8083 nc_faces_info.Append(NCFaceInfo(false, master.local, NULL));
8084 // NOTE: one of the unused members stores local face no. to be used below
8085 MFEM_ASSERT(master_fi.Elem2No == -1, "internal error");
8086 MFEM_ASSERT(master_fi.Elem2Inf == -1, "internal error");
8087 }
8088
8089 // add records for slave faces
8090 for (const NCMesh::Slave &slave : list.slaves)
8091 {
8092 if (slave.index < 0 || // degenerate slave face
8093 slave.index >= nfaces || // ghost slave
8094 slave.master >= nfaces) // has ghost master
8095 {
8096 continue;
8097 }
8098
8099 FaceInfo &slave_fi = faces_info[slave.index];
8100 FaceInfo &master_fi = faces_info[slave.master];
8101 NCFaceInfo &master_nc = nc_faces_info[master_fi.NCFace];
8102
8103 slave_fi.NCFace = nc_faces_info.Size();
8104 slave_fi.Elem2No = master_fi.Elem1No;
8105 slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
8106 // NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
8107 // matrix. In 2D, the point matrix has the orientation of the parent
8108 // edge, so its columns need to be flipped when applying it, see
8109 // ApplyLocalSlaveTransformation.
8110
8111 nc_faces_info.Append(
8112 NCFaceInfo(true, slave.master,
8113 list.point_matrices[slave.geom][slave.matrix]));
8114 }
8115}
8116
8118{
8119 STable3D *faces_tbl = new STable3D(NumOfVertices);
8120 for (int i = 0; i < NumOfElements; i++)
8121 {
8122 const int *v = elements[i]->GetVertices();
8123 switch (GetElementType(i))
8124 {
8126 {
8127 for (int j = 0; j < 4; j++)
8128 {
8129 const int *fv = tet_t::FaceVert[j];
8130 faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
8131 }
8132 break;
8133 }
8134 case Element::PYRAMID:
8135 {
8136 for (int j = 0; j < 1; j++)
8137 {
8138 const int *fv = pyr_t::FaceVert[j];
8139 faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
8140 }
8141 for (int j = 1; j < 5; j++)
8142 {
8143 const int *fv = pyr_t::FaceVert[j];
8144 faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
8145 }
8146 break;
8147 }
8148 case Element::WEDGE:
8149 {
8150 for (int j = 0; j < 2; j++)
8151 {
8152 const int *fv = pri_t::FaceVert[j];
8153 faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
8154 }
8155 for (int j = 2; j < 5; j++)
8156 {
8157 const int *fv = pri_t::FaceVert[j];
8158 faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
8159 }
8160 break;
8161 }
8163 {
8164 // find the face by the vertices with the smallest 3 numbers
8165 // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
8166 for (int j = 0; j < 6; j++)
8167 {
8168 const int *fv = hex_t::FaceVert[j];
8169 faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
8170 }
8171 break;
8172 }
8173 default:
8174 MFEM_ABORT("Unexpected type of Element: " << GetElementType(i));
8175 }
8176 }
8177 return faces_tbl;
8178}
8179
8181{
8182 Array<int> v;
8183 STable3D *faces_tbl;
8184
8185 if (el_to_face != NULL)
8186 {
8187 delete el_to_face;
8188 }
8189 el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra
8190 faces_tbl = new STable3D(NumOfVertices);
8191 for (int i = 0; i < NumOfElements; i++)
8192 {
8193 elements[i]->GetVertices(v);
8194 switch (GetElementType(i))
8195 {
8197 {
8198 for (int j = 0; j < 4; j++)
8199 {
8200 const int *fv = tet_t::FaceVert[j];
8202 i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
8203 }
8204 break;
8205 }
8206 case Element::WEDGE:
8207 {
8208 for (int j = 0; j < 2; j++)
8209 {
8210 const int *fv = pri_t::FaceVert[j];
8212 i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
8213 }
8214 for (int j = 2; j < 5; j++)
8215 {
8216 const int *fv = pri_t::FaceVert[j];
8218 i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
8219 }
8220 break;
8221 }
8222 case Element::PYRAMID:
8223 {
8224 for (int j = 0; j < 1; j++)
8225 {
8226 const int *fv = pyr_t::FaceVert[j];
8228 i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
8229 }
8230 for (int j = 1; j < 5; j++)
8231 {
8232 const int *fv = pyr_t::FaceVert[j];
8234 i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
8235 }
8236 break;
8237 }
8239 {
8240 // find the face by the vertices with the smallest 3 numbers
8241 // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
8242 for (int j = 0; j < 6; j++)
8243 {
8244 const int *fv = hex_t::FaceVert[j];
8246 i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
8247 }
8248 break;
8249 }
8250 default:
8251 MFEM_ABORT("Unexpected type of Element.");
8252 }
8253 }
8255 NumOfFaces = faces_tbl->NumberOfElements();
8257
8258 for (int i = 0; i < NumOfBdrElements; i++)
8259 {
8260 boundary[i]->GetVertices(v);
8261 switch (GetBdrElementType(i))
8262 {
8263 case Element::TRIANGLE:
8264 {
8265 be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]);
8266 break;
8267 }
8269 {
8270 be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
8271 break;
8272 }
8273 default:
8274 MFEM_ABORT("Unexpected type of boundary Element.");
8275 }
8276 }
8277
8278 if (ret_ftbl)
8279 {
8280 return faces_tbl;
8281 }
8282 delete faces_tbl;
8283 return NULL;
8284}
8285
8286// shift cyclically 3 integers so that the smallest is first
8287static inline
8288void Rotate3(int &a, int &b, int &c)
8289{
8290 if (a < b)
8291 {
8292 if (a > c)
8293 {
8294 ShiftRight(a, b, c);
8295 }
8296 }
8297 else
8298 {
8299 if (b < c)
8300 {
8301 ShiftRight(c, b, a);
8302 }
8303 else
8304 {
8305 ShiftRight(a, b, c);
8306 }
8307 }
8308}
8309
8311{
8312 if (Dim != 3 || !(meshgen & 1))
8313 {
8314 return;
8315 }
8316
8317 ResetLazyData();
8318
8319 DSTable *old_v_to_v = NULL;
8320 Table *old_elem_vert = NULL;
8321
8322 if (Nodes)
8323 {
8324 PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
8325 }
8326
8327 for (int i = 0; i < NumOfElements; i++)
8328 {
8330 {
8331 int *v = elements[i]->GetVertices();
8332
8333 Rotate3(v[0], v[1], v[2]);
8334 if (v[0] < v[3])
8335 {
8336 Rotate3(v[1], v[2], v[3]);
8337 }
8338 else
8339 {
8340 ShiftRight(v[0], v[1], v[3]);
8341 }
8342 }
8343 }
8344
8345 for (int i = 0; i < NumOfBdrElements; i++)
8346 {
8348 {
8349 int *v = boundary[i]->GetVertices();
8350
8351 Rotate3(v[0], v[1], v[2]);
8352 }
8353 }
8354
8355 if (!Nodes)
8356 {
8358 GenerateFaces();
8359 if (el_to_edge)
8360 {
8362 }
8363 }
8364 else
8365 {
8366 DoNodeReorder(old_v_to_v, old_elem_vert);
8367 delete old_elem_vert;
8368 delete old_v_to_v;
8369 }
8370}
8371
8373{
8374 int *partitioning;
8375 real_t pmin[3] = { infinity(), infinity(), infinity() };
8376 real_t pmax[3] = { -infinity(), -infinity(), -infinity() };
8377 // find a bounding box using the vertices
8378 for (int vi = 0; vi < NumOfVertices; vi++)
8379 {
8380 const real_t *p = vertices[vi]();
8381 for (int i = 0; i < spaceDim; i++)
8382 {
8383 if (p[i] < pmin[i]) { pmin[i] = p[i]; }
8384 if (p[i] > pmax[i]) { pmax[i] = p[i]; }
8385 }
8386 }
8387
8388 partitioning = new int[NumOfElements];
8389
8390 // determine the partitioning using the centers of the elements
8391 real_t ppt[3];
8392 Vector pt(ppt, spaceDim);
8393 for (int el = 0; el < NumOfElements; el++)
8394 {
8395 GetElementTransformation(el)->Transform(
8397 int part = 0;
8398 for (int i = spaceDim-1; i >= 0; i--)
8399 {
8400 int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i])));
8401 if (idx < 0) { idx = 0; }
8402 if (idx >= nxyz[i]) { idx = nxyz[i]-1; }
8403 part = part * nxyz[i] + idx;
8404 }
8405 partitioning[el] = part;
8406 }
8407
8408 return partitioning;
8409}
8410
8411void FindPartitioningComponents(Table &elem_elem,
8412 const Array<int> &partitioning,
8413 Array<int> &component,
8414 Array<int> &num_comp);
8415
8416int *Mesh::GeneratePartitioning(int nparts, int part_method)
8417{
8418#ifdef MFEM_USE_METIS
8419
8420 int print_messages = 1;
8421 // If running in parallel, print messages only from rank 0.
8422#ifdef MFEM_USE_MPI
8423 int init_flag, fin_flag;
8424 MPI_Initialized(&init_flag);
8425 MPI_Finalized(&fin_flag);
8426 if (init_flag && !fin_flag)
8427 {
8428 int rank;
8429 MPI_Comm_rank(GetGlobalMPI_Comm(), &rank);
8430 if (rank != 0) { print_messages = 0; }
8431 }
8432#endif
8433
8434 int i, *partitioning;
8435
8437
8438 partitioning = new int[NumOfElements];
8439
8440 if (nparts == 1)
8441 {
8442 for (i = 0; i < NumOfElements; i++)
8443 {
8444 partitioning[i] = 0;
8445 }
8446 }
8447 else if (NumOfElements <= nparts)
8448 {
8449 for (i = 0; i < NumOfElements; i++)
8450 {
8451 partitioning[i] = i;
8452 }
8453 }
8454 else
8455 {
8456 idx_t *I, *J, n;
8457#ifndef MFEM_USE_METIS_5
8458 idx_t wgtflag = 0;
8459 idx_t numflag = 0;
8460 idx_t options[5];
8461#else
8462 idx_t ncon = 1;
8463 idx_t errflag;
8464 idx_t options[40];
8465#endif
8466 idx_t edgecut;
8467
8468 // In case METIS have been compiled with 64bit indices
8469 bool freedata = false;
8470 idx_t mparts = (idx_t) nparts;
8471 idx_t *mpartitioning;
8472
8473 n = NumOfElements;
8474 if (sizeof(idx_t) == sizeof(int))
8475 {
8476 I = (idx_t*) el_to_el->GetI();
8477 J = (idx_t*) el_to_el->GetJ();
8478 mpartitioning = (idx_t*) partitioning;
8479 }
8480 else
8481 {
8482 int *iI = el_to_el->GetI();
8483 int *iJ = el_to_el->GetJ();
8484 int m = iI[n];
8485 I = new idx_t[n+1];
8486 J = new idx_t[m];
8487 for (int k = 0; k < n+1; k++) { I[k] = iI[k]; }
8488 for (int k = 0; k < m; k++) { J[k] = iJ[k]; }
8489 mpartitioning = new idx_t[n];
8490 freedata = true;
8491 }
8492#ifndef MFEM_USE_METIS_5
8493 options[0] = 0;
8494#else
8495 METIS_SetDefaultOptions(options);
8496 options[METIS_OPTION_CONTIG] = 1; // set METIS_OPTION_CONTIG
8497 // If the mesh is disconnected, disable METIS_OPTION_CONTIG.
8498 {
8499 Array<int> part(partitioning, NumOfElements);
8500 part = 0; // single part for the whole mesh
8501 Array<int> component; // size will be set to num. elem.
8502 Array<int> num_comp; // size will be set to num. parts (1)
8503 FindPartitioningComponents(*el_to_el, part, component, num_comp);
8504 if (num_comp[0] > 1) { options[METIS_OPTION_CONTIG] = 0; }
8505 }
8506#endif
8507
8508 // Sort the neighbor lists
8509 if (part_method >= 0 && part_method <= 2)
8510 {
8511 for (i = 0; i < n; i++)
8512 {
8513 // Sort in increasing order.
8514 // std::sort(J+I[i], J+I[i+1]);
8515
8516 // Sort in decreasing order, as in previous versions of MFEM.
8517 std::sort(J+I[i], J+I[i+1], std::greater<idx_t>());
8518 }
8519 }
8520
8521 // This function should be used to partition a graph into a small
8522 // number of partitions (less than 8).
8523 if (part_method == 0 || part_method == 3)
8524 {
8525#ifndef MFEM_USE_METIS_5
8527 I,
8528 J,
8529 NULL,
8530 NULL,
8531 &wgtflag,
8532 &numflag,
8533 &mparts,
8534 options,
8535 &edgecut,
8536 mpartitioning);
8537#else
8538 errflag = METIS_PartGraphRecursive(&n,
8539 &ncon,
8540 I,
8541 J,
8542 NULL,
8543 NULL,
8544 NULL,
8545 &mparts,
8546 NULL,
8547 NULL,
8548 options,
8549 &edgecut,
8550 mpartitioning);
8551 if (errflag != 1)
8552 {
8553 mfem_error("Mesh::GeneratePartitioning: "
8554 " error in METIS_PartGraphRecursive!");
8555 }
8556#endif
8557 }
8558
8559 // This function should be used to partition a graph into a large
8560 // number of partitions (greater than 8).
8561 if (part_method == 1 || part_method == 4)
8562 {
8563#ifndef MFEM_USE_METIS_5
8565 I,
8566 J,
8567 NULL,
8568 NULL,
8569 &wgtflag,
8570 &numflag,
8571 &mparts,
8572 options,
8573 &edgecut,
8574 mpartitioning);
8575#else
8576 errflag = METIS_PartGraphKway(&n,
8577 &ncon,
8578 I,
8579 J,
8580 NULL,
8581 NULL,
8582 NULL,
8583 &mparts,
8584 NULL,
8585 NULL,
8586 options,
8587 &edgecut,
8588 mpartitioning);
8589 if (errflag != 1)
8590 {
8591 mfem_error("Mesh::GeneratePartitioning: "
8592 " error in METIS_PartGraphKway!");
8593 }
8594#endif
8595 }
8596
8597 // The objective of this partitioning is to minimize the total
8598 // communication volume
8599 if (part_method == 2 || part_method == 5)
8600 {
8601#ifndef MFEM_USE_METIS_5
8603 I,
8604 J,
8605 NULL,
8606 NULL,
8607 &wgtflag,
8608 &numflag,
8609 &mparts,
8610 options,
8611 &edgecut,
8612 mpartitioning);
8613#else
8614 options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
8615 errflag = METIS_PartGraphKway(&n,
8616 &ncon,
8617 I,
8618 J,
8619 NULL,
8620 NULL,
8621 NULL,
8622 &mparts,
8623 NULL,
8624 NULL,
8625 options,
8626 &edgecut,
8627 mpartitioning);
8628 if (errflag != 1)
8629 {
8630 mfem_error("Mesh::GeneratePartitioning: "
8631 " error in METIS_PartGraphKway!");
8632 }
8633#endif
8634 }
8635
8636#ifdef MFEM_DEBUG
8637 if (print_messages)
8638 {
8639 mfem::out << "Mesh::GeneratePartitioning(...): edgecut = "
8640 << edgecut << endl;
8641 }
8642#endif
8643 nparts = (int) mparts;
8644 if (mpartitioning != (idx_t*)partitioning)
8645 {
8646 for (int k = 0; k<NumOfElements; k++)
8647 {
8648 partitioning[k] = mpartitioning[k];
8649 }
8650 }
8651 if (freedata)
8652 {
8653 delete[] I;
8654 delete[] J;
8655 delete[] mpartitioning;
8656 }
8657 }
8658
8659 delete el_to_el;
8660 el_to_el = NULL;
8661
8662 // Check for empty partitionings (a "feature" in METIS)
8663 if (nparts > 1 && NumOfElements > nparts)
8664 {
8665 Array< Pair<int,int> > psize(nparts);
8666 int empty_parts;
8667
8668 // Count how many elements are in each partition, and store the result in
8669 // psize, where psize[i].one is the number of elements, and psize[i].two
8670 // is partition index. Keep track of the number of empty parts.
8671 auto count_partition_elements = [&]()
8672 {
8673 for (i = 0; i < nparts; i++)
8674 {
8675 psize[i].one = 0;
8676 psize[i].two = i;
8677 }
8678
8679 for (i = 0; i < NumOfElements; i++)
8680 {
8681 psize[partitioning[i]].one++;
8682 }
8683
8684 empty_parts = 0;
8685 for (i = 0; i < nparts; i++)
8686 {
8687 if (psize[i].one == 0) { empty_parts++; }
8688 }
8689 };
8690
8691 count_partition_elements();
8692
8693 // This code just split the largest partitionings in two.
8694 // Do we need to replace it with something better?
8695 while (empty_parts)
8696 {
8697 if (print_messages)
8698 {
8699 mfem::err << "Mesh::GeneratePartitioning(...): METIS returned "
8700 << empty_parts << " empty parts!"
8701 << " Applying a simple fix ..." << endl;
8702 }
8703
8704 SortPairs<int,int>(psize, nparts);
8705
8706 for (i = nparts-1; i > nparts-1-empty_parts; i--)
8707 {
8708 psize[i].one /= 2;
8709 }
8710
8711 for (int j = 0; j < NumOfElements; j++)
8712 {
8713 for (i = nparts-1; i > nparts-1-empty_parts; i--)
8714 {
8715 if (psize[i].one == 0 || partitioning[j] != psize[i].two)
8716 {
8717 continue;
8718 }
8719 else
8720 {
8721 partitioning[j] = psize[nparts-1-i].two;
8722 psize[i].one--;
8723 }
8724 }
8725 }
8726
8727 // Check for empty partitionings again
8728 count_partition_elements();
8729 }
8730 }
8731
8732 return partitioning;
8733
8734#else
8735
8736 mfem_error("Mesh::GeneratePartitioning(...): "
8737 "MFEM was compiled without Metis.");
8738
8739 return NULL;
8740
8741#endif
8742}
8743
8744/* required: 0 <= partitioning[i] < num_part */
8746 const Array<int> &partitioning,
8747 Array<int> &component,
8748 Array<int> &num_comp)
8749{
8750 int i, j, k;
8751 int num_elem, *i_elem_elem, *j_elem_elem;
8752
8753 num_elem = elem_elem.Size();
8754 i_elem_elem = elem_elem.GetI();
8755 j_elem_elem = elem_elem.GetJ();
8756
8757 component.SetSize(num_elem);
8758
8759 Array<int> elem_stack(num_elem);
8760 int stack_p, stack_top_p, elem;
8761 int num_part;
8762
8763 num_part = -1;
8764 for (i = 0; i < num_elem; i++)
8765 {
8766 if (partitioning[i] > num_part)
8767 {
8768 num_part = partitioning[i];
8769 }
8770 component[i] = -1;
8771 }
8772 num_part++;
8773
8774 num_comp.SetSize(num_part);
8775 for (i = 0; i < num_part; i++)
8776 {
8777 num_comp[i] = 0;
8778 }
8779
8780 stack_p = 0;
8781 stack_top_p = 0; // points to the first unused element in the stack
8782 for (elem = 0; elem < num_elem; elem++)
8783 {
8784 if (component[elem] >= 0)
8785 {
8786 continue;
8787 }
8788
8789 component[elem] = num_comp[partitioning[elem]]++;
8790
8791 elem_stack[stack_top_p++] = elem;
8792
8793 for ( ; stack_p < stack_top_p; stack_p++)
8794 {
8795 i = elem_stack[stack_p];
8796 for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++)
8797 {
8798 k = j_elem_elem[j];
8799 if (partitioning[k] == partitioning[i])
8800 {
8801 if (component[k] < 0)
8802 {
8803 component[k] = component[i];
8804 elem_stack[stack_top_p++] = k;
8805 }
8806 else if (component[k] != component[i])
8807 {
8808 mfem_error("FindPartitioningComponents");
8809 }
8810 }
8811 }
8812 }
8813 }
8814}
8815
8816void Mesh::CheckPartitioning(int *partitioning_)
8817{
8818 int i, n_empty, n_mcomp;
8819 Array<int> component, num_comp;
8820 const Array<int> partitioning(partitioning_, GetNE());
8821
8823
8824 FindPartitioningComponents(*el_to_el, partitioning, component, num_comp);
8825
8826 n_empty = n_mcomp = 0;
8827 for (i = 0; i < num_comp.Size(); i++)
8828 if (num_comp[i] == 0)
8829 {
8830 n_empty++;
8831 }
8832 else if (num_comp[i] > 1)
8833 {
8834 n_mcomp++;
8835 }
8836
8837 if (n_empty > 0)
8838 {
8839 mfem::out << "Mesh::CheckPartitioning(...) :\n"
8840 << "The following subdomains are empty :\n";
8841 for (i = 0; i < num_comp.Size(); i++)
8842 if (num_comp[i] == 0)
8843 {
8844 mfem::out << ' ' << i;
8845 }
8846 mfem::out << endl;
8847 }
8848 if (n_mcomp > 0)
8849 {
8850 mfem::out << "Mesh::CheckPartitioning(...) :\n"
8851 << "The following subdomains are NOT connected :\n";
8852 for (i = 0; i < num_comp.Size(); i++)
8853 if (num_comp[i] > 1)
8854 {
8855 mfem::out << ' ' << i;
8856 }
8857 mfem::out << endl;
8858 }
8859 if (n_empty == 0 && n_mcomp == 0)
8860 mfem::out << "Mesh::CheckPartitioning(...) : "
8861 "All subdomains are connected." << endl;
8862
8863 if (el_to_el)
8864 {
8865 delete el_to_el;
8866 }
8867 el_to_el = NULL;
8868}
8869
8870// compute the coefficients of the polynomial in t:
8871// c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B)
8872// where A, B are (d x d), d=2,3
8873void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
8874{
8875 const real_t *a = A.Data();
8876 const real_t *b = B.Data();
8877
8878 c.SetSize(A.Width()+1);
8879 switch (A.Width())
8880 {
8881 case 2:
8882 {
8883 // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ |b0 b2|
8884 // |a1 a3| + \ |a1 b3| |b1 a3| / * t + |b1 b3| * t^2
8885 c(0) = a[0]*a[3]-a[1]*a[2];
8886 c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2];
8887 c(2) = b[0]*b[3]-b[1]*b[2];
8888 }
8889 break;
8890
8891 case 3:
8892 {
8893 /* |a0 a3 a6|
8894 * det(A+t*B) = |a1 a4 a7| +
8895 * |a2 a5 a8|
8896
8897 * / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \
8898 * + | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t +
8899 * \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| /
8900
8901 * / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \
8902 * + | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 +
8903 * \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| /
8904
8905 * |b0 b3 b6|
8906 * + |b1 b4 b7| * t^3
8907 * |b2 b5 b8| */
8908 c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) +
8909 a[1] * (a[5] * a[6] - a[3] * a[8]) +
8910 a[2] * (a[3] * a[7] - a[4] * a[6]));
8911
8912 c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) +
8913 b[1] * (a[5] * a[6] - a[3] * a[8]) +
8914 b[2] * (a[3] * a[7] - a[4] * a[6]) +
8915
8916 a[0] * (b[4] * a[8] - b[5] * a[7]) +
8917 a[1] * (b[5] * a[6] - b[3] * a[8]) +
8918 a[2] * (b[3] * a[7] - b[4] * a[6]) +
8919
8920 a[0] * (a[4] * b[8] - a[5] * b[7]) +
8921 a[1] * (a[5] * b[6] - a[3] * b[8]) +
8922 a[2] * (a[3] * b[7] - a[4] * b[6]));
8923
8924 c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) +
8925 a[1] * (b[5] * b[6] - b[3] * b[8]) +
8926 a[2] * (b[3] * b[7] - b[4] * b[6]) +
8927
8928 b[0] * (a[4] * b[8] - a[5] * b[7]) +
8929 b[1] * (a[5] * b[6] - a[3] * b[8]) +
8930 b[2] * (a[3] * b[7] - a[4] * b[6]) +
8931
8932 b[0] * (b[4] * a[8] - b[5] * a[7]) +
8933 b[1] * (b[5] * a[6] - b[3] * a[8]) +
8934 b[2] * (b[3] * a[7] - b[4] * a[6]));
8935
8936 c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) +
8937 b[1] * (b[5] * b[6] - b[3] * b[8]) +
8938 b[2] * (b[3] * b[7] - b[4] * b[6]));
8939 }
8940 break;
8941
8942 default:
8943 mfem_error("DetOfLinComb(...)");
8944 }
8945}
8946
8947// compute the real roots of
8948// z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3;
8949// the roots are returned in x, sorted in increasing order;
8950// it is assumed that x is at least of size d;
8951// return the number of roots counting multiplicity;
8952// return -1 if all z(i) are 0.
8953int FindRoots(const Vector &z, Vector &x)
8954{
8955 int d = z.Size()-1;
8956 if (d > 3 || d < 0)
8957 {
8958 mfem_error("FindRoots(...)");
8959 }
8960
8961 while (z(d) == 0.0)
8962 {
8963 if (d == 0)
8964 {
8965 return (-1);
8966 }
8967 d--;
8968 }
8969 switch (d)
8970 {
8971 case 0:
8972 {
8973 return 0;
8974 }
8975
8976 case 1:
8977 {
8978 x(0) = -z(0)/z(1);
8979 return 1;
8980 }
8981
8982 case 2:
8983 {
8984 real_t a = z(2), b = z(1), c = z(0);
8985 real_t D = b*b-4*a*c;
8986 if (D < 0.0)
8987 {
8988 return 0;
8989 }
8990 if (D == 0.0)
8991 {
8992 x(0) = x(1) = -0.5 * b / a;
8993 return 2; // root with multiplicity 2
8994 }
8995 if (b == 0.0)
8996 {
8997 x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a));
8998 return 2;
8999 }
9000 else
9001 {
9002 real_t t;
9003 if (b > 0.0)
9004 {
9005 t = -0.5 * (b + sqrt(D));
9006 }
9007 else
9008 {
9009 t = -0.5 * (b - sqrt(D));
9010 }
9011 x(0) = t / a;
9012 x(1) = c / t;
9013 if (x(0) > x(1))
9014 {
9015 Swap<real_t>(x(0), x(1));
9016 }
9017 return 2;
9018 }
9019 }
9020
9021 case 3:
9022 {
9023 real_t a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3);
9024
9025 // find the real roots of x^3 + a x^2 + b x + c = 0
9026 real_t Q = (a * a - 3 * b) / 9;
9027 real_t R = (2 * a * a * a - 9 * a * b + 27 * c) / 54;
9028 real_t Q3 = Q * Q * Q;
9029 real_t R2 = R * R;
9030
9031 if (R2 == Q3)
9032 {
9033 if (Q == 0)
9034 {
9035 x(0) = x(1) = x(2) = - a / 3;
9036 }
9037 else
9038 {
9039 real_t sqrtQ = sqrt(Q);
9040
9041 if (R > 0)
9042 {
9043 x(0) = -2 * sqrtQ - a / 3;
9044 x(1) = x(2) = sqrtQ - a / 3;
9045 }
9046 else
9047 {
9048 x(0) = x(1) = - sqrtQ - a / 3;
9049 x(2) = 2 * sqrtQ - a / 3;
9050 }
9051 }
9052 return 3;
9053 }
9054 else if (R2 < Q3)
9055 {
9056 real_t theta = acos(R / sqrt(Q3));
9057 real_t A = -2 * sqrt(Q);
9058 real_t x0, x1, x2;
9059 x0 = A * cos(theta / 3) - a / 3;
9060 x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3;
9061 x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3;
9062
9063 /* Sort x0, x1, x2 */
9064 if (x0 > x1)
9065 {
9066 Swap<real_t>(x0, x1);
9067 }
9068 if (x1 > x2)
9069 {
9070 Swap<real_t>(x1, x2);
9071 if (x0 > x1)
9072 {
9073 Swap<real_t>(x0, x1);
9074 }
9075 }
9076 x(0) = x0;
9077 x(1) = x1;
9078 x(2) = x2;
9079 return 3;
9080 }
9081 else
9082 {
9083 real_t A;
9084 if (R >= 0.0)
9085 {
9086 A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0);
9087 }
9088 else
9089 {
9090 A = pow(sqrt(R2 - Q3) - R, 1.0/3.0);
9091 }
9092 x(0) = A + Q / A - a / 3;
9093 return 1;
9094 }
9095 }
9096 }
9097 return 0;
9098}
9099
9100void FindTMax(Vector &c, Vector &x, real_t &tmax,
9101 const real_t factor, const int Dim)
9102{
9103 const real_t c0 = c(0);
9104 c(0) = c0 * (1.0 - pow(factor, -Dim));
9105 int nr = FindRoots(c, x);
9106 for (int j = 0; j < nr; j++)
9107 {
9108 if (x(j) > tmax)
9109 {
9110 break;
9111 }
9112 if (x(j) >= 0.0)
9113 {
9114 tmax = x(j);
9115 break;
9116 }
9117 }
9118 c(0) = c0 * (1.0 - pow(factor, Dim));
9119 nr = FindRoots(c, x);
9120 for (int j = 0; j < nr; j++)
9121 {
9122 if (x(j) > tmax)
9123 {
9124 break;
9125 }
9126 if (x(j) >= 0.0)
9127 {
9128 tmax = x(j);
9129 break;
9130 }
9131 }
9132}
9133
9134void Mesh::CheckDisplacements(const Vector &displacements, real_t &tmax)
9135{
9136 int nvs = vertices.Size();
9137 DenseMatrix P, V, DS, PDS(spaceDim), VDS(spaceDim);
9138 Vector c(spaceDim+1), x(spaceDim);
9139 const real_t factor = 2.0;
9140
9141 // check for tangling assuming constant speed
9142 if (tmax < 1.0)
9143 {
9144 tmax = 1.0;
9145 }
9146 for (int i = 0; i < NumOfElements; i++)
9147 {
9148 Element *el = elements[i];
9149 int nv = el->GetNVertices();
9150 int *v = el->GetVertices();
9151 P.SetSize(spaceDim, nv);
9152 V.SetSize(spaceDim, nv);
9153 for (int j = 0; j < spaceDim; j++)
9154 for (int k = 0; k < nv; k++)
9155 {
9156 P(j, k) = vertices[v[k]](j);
9157 V(j, k) = displacements(v[k]+j*nvs);
9158 }
9159 DS.SetSize(nv, spaceDim);
9160 const FiniteElement *fe =
9162 // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1
9163 switch (el->GetType())
9164 {
9165 case Element::TRIANGLE:
9167 {
9168 // DS is constant
9170 Mult(P, DS, PDS);
9171 Mult(V, DS, VDS);
9172 DetOfLinComb(PDS, VDS, c);
9173 if (c(0) <= 0.0)
9174 {
9175 tmax = 0.0;
9176 }
9177 else
9178 {
9179 FindTMax(c, x, tmax, factor, Dim);
9180 }
9181 }
9182 break;
9183
9185 {
9186 const IntegrationRule &ir = fe->GetNodes();
9187 for (int j = 0; j < nv; j++)
9188 {
9189 fe->CalcDShape(ir.IntPoint(j), DS);
9190 Mult(P, DS, PDS);
9191 Mult(V, DS, VDS);
9192 DetOfLinComb(PDS, VDS, c);
9193 if (c(0) <= 0.0)
9194 {
9195 tmax = 0.0;
9196 }
9197 else
9198 {
9199 FindTMax(c, x, tmax, factor, Dim);
9200 }
9201 }
9202 }
9203 break;
9204
9205 default:
9206 mfem_error("Mesh::CheckDisplacements(...)");
9207 }
9208 }
9209}
9210
9211void Mesh::MoveVertices(const Vector &displacements)
9212{
9213 for (int i = 0, nv = vertices.Size(); i < nv; i++)
9214 for (int j = 0; j < spaceDim; j++)
9215 {
9216 vertices[i](j) += displacements(j*nv+i);
9217 }
9218}
9219
9220void Mesh::GetVertices(Vector &vert_coord) const
9221{
9222 int nv = vertices.Size();
9223 vert_coord.SetSize(nv*spaceDim);
9224 for (int i = 0; i < nv; i++)
9225 for (int j = 0; j < spaceDim; j++)
9226 {
9227 vert_coord(j*nv+i) = vertices[i](j);
9228 }
9229}
9230
9231void Mesh::SetVertices(const Vector &vert_coord)
9232{
9233 for (int i = 0, nv = vertices.Size(); i < nv; i++)
9234 for (int j = 0; j < spaceDim; j++)
9235 {
9236 vertices[i](j) = vert_coord(j*nv+i);
9237 }
9238}
9239
9240void Mesh::GetNode(int i, real_t *coord) const
9241{
9242 if (Nodes)
9243 {
9245 for (int j = 0; j < spaceDim; j++)
9246 {
9247 coord[j] = AsConst(*Nodes)(fes->DofToVDof(i, j));
9248 }
9249 }
9250 else
9251 {
9252 for (int j = 0; j < spaceDim; j++)
9253 {
9254 coord[j] = vertices[i](j);
9255 }
9256 }
9257}
9258
9259void Mesh::SetNode(int i, const real_t *coord)
9260{
9261 if (Nodes)
9262 {
9264 for (int j = 0; j < spaceDim; j++)
9265 {
9266 (*Nodes)(fes->DofToVDof(i, j)) = coord[j];
9267 }
9268 }
9269 else
9270 {
9271 for (int j = 0; j < spaceDim; j++)
9272 {
9273 vertices[i](j) = coord[j];
9274 }
9275
9276 }
9277}
9278
9279void Mesh::MoveNodes(const Vector &displacements)
9280{
9281 if (Nodes)
9282 {
9283 (*Nodes) += displacements;
9284 }
9285 else
9286 {
9287 MoveVertices(displacements);
9288 }
9289
9290 // Invalidate the old geometric factors
9291 NodesUpdated();
9292}
9293
9294void Mesh::GetNodes(Vector &node_coord) const
9295{
9296 if (Nodes)
9297 {
9298 node_coord = (*Nodes);
9299 }
9300 else
9301 {
9302 GetVertices(node_coord);
9303 }
9304}
9305
9306void Mesh::SetNodes(const Vector &node_coord)
9307{
9308 if (Nodes)
9309 {
9310 (*Nodes) = node_coord;
9311 }
9312 else
9313 {
9314 SetVertices(node_coord);
9315 }
9316
9317 // Invalidate the old geometric factors
9318 NodesUpdated();
9319}
9320
9321void Mesh::NewNodes(GridFunction &nodes, bool make_owner)
9322{
9323 if (own_nodes) { delete Nodes; }
9324 Nodes = &nodes;
9325 spaceDim = Nodes->FESpace()->GetVDim();
9326 own_nodes = (int)make_owner;
9327
9328 if (NURBSext != nodes.FESpace()->GetNURBSext())
9329 {
9330 delete NURBSext;
9331 NURBSext = nodes.FESpace()->StealNURBSext();
9332 }
9333
9334 if (ncmesh)
9335 {
9337 }
9338
9339 // Invalidate the old geometric factors
9340 NodesUpdated();
9341}
9342
9343void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_)
9344{
9345 // If this is a nonconforming mesh without nodes, ncmesh->coordinates will
9346 // be non-empty; so if the 'nodes' argument is not NULL, we will create an
9347 // inconsistent state where the Mesh has nodes and ncmesh->coordinates is not
9348 // empty. This was creating an issue for Mesh::Print() since both the
9349 // "coordinates" and "nodes" sections were written, leading to crashes during
9350 // loading. This issue is now fixed in Mesh::Printer() by temporarily
9351 // swapping ncmesh->coordinates with an empty array when the Mesh has nodes.
9352
9354 mfem::Swap<int>(own_nodes, own_nodes_);
9355 // TODO:
9356 // if (nodes)
9357 // nodes->FESpace()->MakeNURBSextOwner();
9358 // NURBSext = (Nodes) ? Nodes->FESpace()->StealNURBSext() : NULL;
9359
9360 // Invalidate the old geometric factors
9361 NodesUpdated();
9362}
9363
9364void Mesh::AverageVertices(const int *indexes, int n, int result)
9365{
9366 int j, k;
9367
9368 for (k = 0; k < spaceDim; k++)
9369 {
9370 vertices[result](k) = vertices[indexes[0]](k);
9371 }
9372
9373 for (j = 1; j < n; j++)
9374 for (k = 0; k < spaceDim; k++)
9375 {
9376 vertices[result](k) += vertices[indexes[j]](k);
9377 }
9378
9379 for (k = 0; k < spaceDim; k++)
9380 {
9381 vertices[result](k) *= (1.0 / n);
9382 }
9383}
9384
9386{
9387 if (Nodes)
9388 {
9389 Nodes->FESpace()->Update();
9390 Nodes->Update();
9391
9392 // update vertex coordinates for compatibility (e.g., GetVertex())
9394
9395 // Invalidate the old geometric factors
9396 NodesUpdated();
9397 }
9398}
9399
9400void Mesh::UniformRefinement2D_base(bool update_nodes)
9401{
9402 ResetLazyData();
9403
9404 if (el_to_edge == NULL)
9405 {
9406 el_to_edge = new Table;
9408 }
9409
9410 int quad_counter = 0;
9411 for (int i = 0; i < NumOfElements; i++)
9412 {
9413 if (elements[i]->GetType() == Element::QUADRILATERAL)
9414 {
9415 quad_counter++;
9416 }
9417 }
9418
9419 const int oedge = NumOfVertices;
9420 const int oelem = oedge + NumOfEdges;
9421
9422 Array<Element*> new_elements;
9423 Array<Element*> new_boundary;
9424
9425 vertices.SetSize(oelem + quad_counter);
9426 new_elements.SetSize(4 * NumOfElements);
9427 quad_counter = 0;
9428
9429 for (int i = 0, j = 0; i < NumOfElements; i++)
9430 {
9431 const Element::Type el_type = elements[i]->GetType();
9432 const int attr = elements[i]->GetAttribute();
9433 int *v = elements[i]->GetVertices();
9434 const int *e = el_to_edge->GetRow(i);
9435 int vv[2];
9436
9437 if (el_type == Element::TRIANGLE)
9438 {
9439 for (int ei = 0; ei < 3; ei++)
9440 {
9441 for (int k = 0; k < 2; k++)
9442 {
9443 vv[k] = v[tri_t::Edges[ei][k]];
9444 }
9445 AverageVertices(vv, 2, oedge+e[ei]);
9446 }
9447
9448 new_elements[j++] =
9449 new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
9450 new_elements[j++] =
9451 new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
9452 new_elements[j++] =
9453 new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
9454 new_elements[j++] =
9455 new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
9456 }
9457 else if (el_type == Element::QUADRILATERAL)
9458 {
9459 const int qe = quad_counter;
9460 quad_counter++;
9461 AverageVertices(v, 4, oelem+qe);
9462
9463 for (int ei = 0; ei < 4; ei++)
9464 {
9465 for (int k = 0; k < 2; k++)
9466 {
9467 vv[k] = v[quad_t::Edges[ei][k]];
9468 }
9469 AverageVertices(vv, 2, oedge+e[ei]);
9470 }
9471
9472 new_elements[j++] =
9473 new Quadrilateral(v[0], oedge+e[0], oelem+qe, oedge+e[3], attr);
9474 new_elements[j++] =
9475 new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oelem+qe, attr);
9476 new_elements[j++] =
9477 new Quadrilateral(oelem+qe, oedge+e[1], v[2], oedge+e[2], attr);
9478 new_elements[j++] =
9479 new Quadrilateral(oedge+e[3], oelem+qe, oedge+e[2], v[3], attr);
9480 }
9481 else
9482 {
9483 MFEM_ABORT("unknown element type: " << el_type);
9484 }
9486 }
9487 mfem::Swap(elements, new_elements);
9488
9489 // refine boundary elements
9490 new_boundary.SetSize(2 * NumOfBdrElements);
9491 for (int i = 0, j = 0; i < NumOfBdrElements; i++)
9492 {
9493 const int attr = boundary[i]->GetAttribute();
9494 int *v = boundary[i]->GetVertices();
9495
9496 new_boundary[j++] = new Segment(v[0], oedge+be_to_face[i], attr);
9497 new_boundary[j++] = new Segment(oedge+be_to_face[i], v[1], attr);
9498
9500 }
9501 mfem::Swap(boundary, new_boundary);
9502
9503 static const real_t A = 0.0, B = 0.5, C = 1.0;
9504 static real_t tri_children[2*3*4] =
9505 {
9506 A,A, B,A, A,B,
9507 B,B, A,B, B,A,
9508 B,A, C,A, B,B,
9509 A,B, B,B, A,C
9510 };
9511 static real_t quad_children[2*4*4] =
9512 {
9513 A,A, B,A, B,B, A,B, // lower-left
9514 B,A, C,A, C,B, B,B, // lower-right
9515 B,B, C,B, C,C, B,C, // upper-right
9516 A,B, B,B, B,C, A,C // upper-left
9517 };
9518
9520 .UseExternalData(tri_children, 2, 3, 4);
9522 .UseExternalData(quad_children, 2, 4, 4);
9523 CoarseFineTr.embeddings.SetSize(elements.Size());
9524
9525 for (int i = 0; i < elements.Size(); i++)
9526 {
9528 emb.parent = i / 4;
9529 emb.matrix = i % 4;
9530 }
9531
9532 NumOfVertices = vertices.Size();
9535 NumOfFaces = 0;
9536
9538 GenerateFaces();
9539
9541 sequence++;
9542
9543 if (update_nodes) { UpdateNodes(); }
9544
9545#ifdef MFEM_DEBUG
9546 if (!Nodes || update_nodes)
9547 {
9549 }
9551#endif
9552}
9553
9554static inline real_t sqr(const real_t &x)
9555{
9556 return x*x;
9557}
9558
9560 bool update_nodes)
9561{
9562 ResetLazyData();
9563
9564 if (el_to_edge == NULL)
9565 {
9566 el_to_edge = new Table;
9568 }
9569
9570 if (el_to_face == NULL)
9571 {
9573 }
9574
9575 Array<int> f2qf_loc;
9576 Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
9577 f2qf.SetSize(0);
9578
9579 int NumOfQuadFaces = 0;
9581 {
9583 {
9584 f2qf.SetSize(faces.Size());
9585 for (int i = 0; i < faces.Size(); i++)
9586 {
9587 if (faces[i]->GetType() == Element::QUADRILATERAL)
9588 {
9589 f2qf[i] = NumOfQuadFaces;
9590 NumOfQuadFaces++;
9591 }
9592 }
9593 }
9594 else
9595 {
9596 NumOfQuadFaces = faces.Size();
9597 }
9598 }
9599
9600 int hex_counter = 0;
9602 {
9603 for (int i = 0; i < elements.Size(); i++)
9604 {
9605 if (elements[i]->GetType() == Element::HEXAHEDRON)
9606 {
9607 hex_counter++;
9608 }
9609 }
9610 }
9611
9612 int pyr_counter = 0;
9614 {
9615 for (int i = 0; i < elements.Size(); i++)
9616 {
9617 if (elements[i]->GetType() == Element::PYRAMID)
9618 {
9619 pyr_counter++;
9620 }
9621 }
9622 }
9623
9624 // Map from edge-index to vertex-index, needed for ReorientTetMesh() for
9625 // parallel meshes.
9626 // Note: with the removal of ReorientTetMesh() this may no longer
9627 // be needed. Unfortunately, it's hard to be sure.
9628 Array<int> e2v;
9630 {
9631 e2v.SetSize(NumOfEdges);
9632
9633 DSTable *v_to_v_ptr = v_to_v_p;
9634 if (!v_to_v_p)
9635 {
9636 v_to_v_ptr = new DSTable(NumOfVertices);
9637 GetVertexToVertexTable(*v_to_v_ptr);
9638 }
9639
9640 Array<Pair<int,int> > J_v2v(NumOfEdges); // (second vertex id, edge id)
9641 J_v2v.SetSize(0);
9642 for (int i = 0; i < NumOfVertices; i++)
9643 {
9644 Pair<int,int> *row_start = J_v2v.end();
9645 for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
9646 {
9647 J_v2v.Append(Pair<int,int>(it.Column(), it.Index()));
9648 }
9649 std::sort(row_start, J_v2v.end());
9650 }
9651
9652 for (int i = 0; i < J_v2v.Size(); i++)
9653 {
9654 e2v[J_v2v[i].two] = i;
9655 }
9656
9657 if (!v_to_v_p)
9658 {
9659 delete v_to_v_ptr;
9660 }
9661 else
9662 {
9663 for (int i = 0; i < NumOfVertices; i++)
9664 {
9665 for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
9666 {
9667 it.SetIndex(e2v[it.Index()]);
9668 }
9669 }
9670 }
9671 }
9672
9673 // Offsets for new vertices from edges, faces (quads only), and elements
9674 // (hexes only); each of these entities generates one new vertex.
9675 const int oedge = NumOfVertices;
9676 const int oface = oedge + NumOfEdges;
9677 const int oelem = oface + NumOfQuadFaces;
9678
9679 Array<Element*> new_elements;
9680 Array<Element*> new_boundary;
9681
9682 vertices.SetSize(oelem + hex_counter);
9683 new_elements.SetSize(8 * NumOfElements + 2 * pyr_counter);
9684 CoarseFineTr.embeddings.SetSize(new_elements.Size());
9685
9686 hex_counter = 0;
9687 for (int i = 0, j = 0; i < NumOfElements; i++)
9688 {
9689 const Element::Type el_type = elements[i]->GetType();
9690 const int attr = elements[i]->GetAttribute();
9691 int *v = elements[i]->GetVertices();
9692 const int *e = el_to_edge->GetRow(i);
9693 int vv[4], ev[12];
9694
9695 if (e2v.Size())
9696 {
9697 const int ne = el_to_edge->RowSize(i);
9698 for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
9699 e = ev;
9700 }
9701
9702 switch (el_type)
9703 {
9705 {
9706 for (int ei = 0; ei < 6; ei++)
9707 {
9708 for (int k = 0; k < 2; k++)
9709 {
9710 vv[k] = v[tet_t::Edges[ei][k]];
9711 }
9712 AverageVertices(vv, 2, oedge+e[ei]);
9713 }
9714
9715 // Algorithm for choosing refinement type:
9716 // 0: smallest octahedron diagonal
9717 // 1: best aspect ratio
9718 const int rt_algo = 1;
9719 // Refinement type:
9720 // 0: (v0,v1)-(v2,v3), 1: (v0,v2)-(v1,v3), 2: (v0,v3)-(v1,v2)
9721 // 0: e0-e5, 1: e1-e4, 2: e2-e3
9722 int rt;
9725 const DenseMatrix &J = T->Jacobian();
9726 if (rt_algo == 0)
9727 {
9728 // smallest octahedron diagonal
9729 real_t len_sqr, min_len;
9730
9731 min_len = sqr(J(0,0)-J(0,1)-J(0,2)) +
9732 sqr(J(1,0)-J(1,1)-J(1,2)) +
9733 sqr(J(2,0)-J(2,1)-J(2,2));
9734 rt = 0;
9735
9736 len_sqr = sqr(J(0,1)-J(0,0)-J(0,2)) +
9737 sqr(J(1,1)-J(1,0)-J(1,2)) +
9738 sqr(J(2,1)-J(2,0)-J(2,2));
9739 if (len_sqr < min_len) { min_len = len_sqr; rt = 1; }
9740
9741 len_sqr = sqr(J(0,2)-J(0,0)-J(0,1)) +
9742 sqr(J(1,2)-J(1,0)-J(1,1)) +
9743 sqr(J(2,2)-J(2,0)-J(2,1));
9744 if (len_sqr < min_len) { rt = 2; }
9745 }
9746 else
9747 {
9748 // best aspect ratio
9749 real_t Em_data[18], Js_data[9], Jp_data[9];
9750 DenseMatrix Em(Em_data, 3, 6);
9751 DenseMatrix Js(Js_data, 3, 3), Jp(Jp_data, 3, 3);
9752 real_t ar1, ar2, kappa, kappa_min;
9753
9754 for (int s = 0; s < 3; s++)
9755 {
9756 for (int t = 0; t < 3; t++)
9757 {
9758 Em(t,s) = 0.5*J(t,s);
9759 }
9760 }
9761 for (int t = 0; t < 3; t++)
9762 {
9763 Em(t,3) = 0.5*(J(t,0)+J(t,1));
9764 Em(t,4) = 0.5*(J(t,0)+J(t,2));
9765 Em(t,5) = 0.5*(J(t,1)+J(t,2));
9766 }
9767
9768 // rt = 0; Em: {0,5,1,2}, {0,5,2,4}
9769 for (int t = 0; t < 3; t++)
9770 {
9771 Js(t,0) = Em(t,5)-Em(t,0);
9772 Js(t,1) = Em(t,1)-Em(t,0);
9773 Js(t,2) = Em(t,2)-Em(t,0);
9774 }
9776 ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9777 for (int t = 0; t < 3; t++)
9778 {
9779 Js(t,0) = Em(t,5)-Em(t,0);
9780 Js(t,1) = Em(t,2)-Em(t,0);
9781 Js(t,2) = Em(t,4)-Em(t,0);
9782 }
9784 ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9785 kappa_min = std::max(ar1, ar2);
9786 rt = 0;
9787
9788 // rt = 1; Em: {1,0,4,2}, {1,2,4,5}
9789 for (int t = 0; t < 3; t++)
9790 {
9791 Js(t,0) = Em(t,0)-Em(t,1);
9792 Js(t,1) = Em(t,4)-Em(t,1);
9793 Js(t,2) = Em(t,2)-Em(t,1);
9794 }
9796 ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9797 for (int t = 0; t < 3; t++)
9798 {
9799 Js(t,0) = Em(t,2)-Em(t,1);
9800 Js(t,1) = Em(t,4)-Em(t,1);
9801 Js(t,2) = Em(t,5)-Em(t,1);
9802 }
9804 ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9805 kappa = std::max(ar1, ar2);
9806 if (kappa < kappa_min) { kappa_min = kappa; rt = 1; }
9807
9808 // rt = 2; Em: {2,0,1,3}, {2,1,5,3}
9809 for (int t = 0; t < 3; t++)
9810 {
9811 Js(t,0) = Em(t,0)-Em(t,2);
9812 Js(t,1) = Em(t,1)-Em(t,2);
9813 Js(t,2) = Em(t,3)-Em(t,2);
9814 }
9816 ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9817 for (int t = 0; t < 3; t++)
9818 {
9819 Js(t,0) = Em(t,1)-Em(t,2);
9820 Js(t,1) = Em(t,5)-Em(t,2);
9821 Js(t,2) = Em(t,3)-Em(t,2);
9822 }
9824 ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9825 kappa = std::max(ar1, ar2);
9826 if (kappa < kappa_min) { rt = 2; }
9827 }
9828
9829 static const int mv_all[3][4][4] =
9830 {
9831 { {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1} }, // rt = 0
9832 { {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0} }, // rt = 1
9833 { {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3} } // rt = 2
9834 };
9835 const int (&mv)[4][4] = mv_all[rt];
9836
9837#ifndef MFEM_USE_MEMALLOC
9838 new_elements[j+0] =
9839 new Tetrahedron(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
9840 new_elements[j+1] =
9841 new Tetrahedron(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
9842 new_elements[j+2] =
9843 new Tetrahedron(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
9844 new_elements[j+3] =
9845 new Tetrahedron(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
9846
9847 for (int k = 0; k < 4; k++)
9848 {
9849 new_elements[j+4+k] =
9850 new Tetrahedron(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
9851 oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
9852 }
9853#else
9854 Tetrahedron *tet;
9855 new_elements[j+0] = tet = TetMemory.Alloc();
9856 tet->Init(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
9857
9858 new_elements[j+1] = tet = TetMemory.Alloc();
9859 tet->Init(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
9860
9861 new_elements[j+2] = tet = TetMemory.Alloc();
9862 tet->Init(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
9863
9864 new_elements[j+3] = tet = TetMemory.Alloc();
9865 tet->Init(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
9866
9867 for (int k = 0; k < 4; k++)
9868 {
9869 new_elements[j+4+k] = tet = TetMemory.Alloc();
9870 tet->Init(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
9871 oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
9872 }
9873#endif
9874 for (int k = 0; k < 4; k++)
9875 {
9876 CoarseFineTr.embeddings[j+k].parent = i;
9877 CoarseFineTr.embeddings[j+k].matrix = k;
9878 }
9879 for (int k = 0; k < 4; k++)
9880 {
9881 CoarseFineTr.embeddings[j+4+k].parent = i;
9882 CoarseFineTr.embeddings[j+4+k].matrix = 4*(rt+1)+k;
9883 }
9884
9885 j += 8;
9886 }
9887 break;
9888
9889 case Element::WEDGE:
9890 {
9891 const int *f = el_to_face->GetRow(i);
9892
9893 for (int fi = 2; fi < 5; fi++)
9894 {
9895 for (int k = 0; k < 4; k++)
9896 {
9897 vv[k] = v[pri_t::FaceVert[fi][k]];
9898 }
9899 AverageVertices(vv, 4, oface + f2qf[f[fi]]);
9900 }
9901
9902 for (int ei = 0; ei < 9; ei++)
9903 {
9904 for (int k = 0; k < 2; k++)
9905 {
9906 vv[k] = v[pri_t::Edges[ei][k]];
9907 }
9908 AverageVertices(vv, 2, oedge+e[ei]);
9909 }
9910
9911 const int qf2 = f2qf[f[2]];
9912 const int qf3 = f2qf[f[3]];
9913 const int qf4 = f2qf[f[4]];
9914
9915 new_elements[j++] =
9916 new Wedge(v[0], oedge+e[0], oedge+e[2],
9917 oedge+e[6], oface+qf2, oface+qf4, attr);
9918
9919 new_elements[j++] =
9920 new Wedge(oedge+e[1], oedge+e[2], oedge+e[0],
9921 oface+qf3, oface+qf4, oface+qf2, attr);
9922
9923 new_elements[j++] =
9924 new Wedge(oedge+e[0], v[1], oedge+e[1],
9925 oface+qf2, oedge+e[7], oface+qf3, attr);
9926
9927 new_elements[j++] =
9928 new Wedge(oedge+e[2], oedge+e[1], v[2],
9929 oface+qf4, oface+qf3, oedge+e[8], attr);
9930
9931 new_elements[j++] =
9932 new Wedge(oedge+e[6], oface+qf2, oface+qf4,
9933 v[3], oedge+e[3], oedge+e[5], attr);
9934
9935 new_elements[j++] =
9936 new Wedge(oface+qf3, oface+qf4, oface+qf2,
9937 oedge+e[4], oedge+e[5], oedge+e[3], attr);
9938
9939 new_elements[j++] =
9940 new Wedge(oface+qf2, oedge+e[7], oface+qf3,
9941 oedge+e[3], v[4], oedge+e[4], attr);
9942
9943 new_elements[j++] =
9944 new Wedge(oface+qf4, oface+qf3, oedge+e[8],
9945 oedge+e[5], oedge+e[4], v[5], attr);
9946 }
9947 break;
9948
9949 case Element::PYRAMID:
9950 {
9951 const int *f = el_to_face->GetRow(i);
9952 // pyr_counter++;
9953
9954 for (int fi = 0; fi < 1; fi++)
9955 {
9956 for (int k = 0; k < 4; k++)
9957 {
9958 vv[k] = v[pyr_t::FaceVert[fi][k]];
9959 }
9960 AverageVertices(vv, 4, oface + f2qf[f[fi]]);
9961 }
9962
9963 for (int ei = 0; ei < 8; ei++)
9964 {
9965 for (int k = 0; k < 2; k++)
9966 {
9967 vv[k] = v[pyr_t::Edges[ei][k]];
9968 }
9969 AverageVertices(vv, 2, oedge+e[ei]);
9970 }
9971
9972 const int qf0 = f2qf[f[0]];
9973
9974 new_elements[j++] =
9975 new Pyramid(v[0], oedge+e[0], oface+qf0,
9976 oedge+e[3], oedge+e[4], attr);
9977
9978 new_elements[j++] =
9979 new Pyramid(oedge+e[0], v[1], oedge+e[1],
9980 oface+qf0, oedge+e[5], attr);
9981
9982 new_elements[j++] =
9983 new Pyramid(oface+qf0, oedge+e[1], v[2],
9984 oedge+e[2], oedge+e[6], attr);
9985
9986 new_elements[j++] =
9987 new Pyramid(oedge+e[3], oface+qf0, oedge+e[2],
9988 v[3], oedge+e[7], attr);
9989
9990 new_elements[j++] =
9991 new Pyramid(oedge+e[4], oedge+e[5], oedge+e[6],
9992 oedge+e[7], v[4], attr);
9993
9994 new_elements[j++] =
9995 new Pyramid(oedge+e[7], oedge+e[6], oedge+e[5],
9996 oedge+e[4], oface+qf0, attr);
9997
9998#ifndef MFEM_USE_MEMALLOC
9999 new_elements[j++] =
10000 new Tetrahedron(oedge+e[0], oedge+e[4], oedge+e[5],
10001 oface+qf0, attr);
10002
10003 new_elements[j++] =
10004 new Tetrahedron(oedge+e[1], oedge+e[5], oedge+e[6],
10005 oface+qf0, attr);
10006
10007 new_elements[j++] =
10008 new Tetrahedron(oedge+e[2], oedge+e[6], oedge+e[7],
10009 oface+qf0, attr);
10010
10011 new_elements[j++] =
10012 new Tetrahedron(oedge+e[3], oedge+e[7], oedge+e[4],
10013 oface+qf0, attr);
10014#else
10015 Tetrahedron *tet;
10016 new_elements[j++] = tet = TetMemory.Alloc();
10017 tet->Init(oedge+e[0], oedge+e[4], oedge+e[5],
10018 oface+qf0, attr);
10019
10020 new_elements[j++] = tet = TetMemory.Alloc();
10021 tet->Init(oedge+e[1], oedge+e[5], oedge+e[6],
10022 oface+qf0, attr);
10023
10024 new_elements[j++] = tet = TetMemory.Alloc();
10025 tet->Init(oedge+e[2], oedge+e[6], oedge+e[7],
10026 oface+qf0, attr);
10027
10028 new_elements[j++] = tet = TetMemory.Alloc();
10029 tet->Init(oedge+e[3], oedge+e[7], oedge+e[4],
10030 oface+qf0, attr);
10031#endif
10032 // Tetrahedral elements may be new to this mesh so ensure that
10033 // the relevant flags are switched on
10035 meshgen |= 1;
10036 }
10037 break;
10038
10040 {
10041 const int *f = el_to_face->GetRow(i);
10042 const int he = hex_counter;
10043 hex_counter++;
10044
10045 const int *qf;
10046 int qf_data[6];
10047 if (f2qf.Size() == 0)
10048 {
10049 qf = f;
10050 }
10051 else
10052 {
10053 for (int k = 0; k < 6; k++) { qf_data[k] = f2qf[f[k]]; }
10054 qf = qf_data;
10055 }
10056
10057 AverageVertices(v, 8, oelem+he);
10058
10059 for (int fi = 0; fi < 6; fi++)
10060 {
10061 for (int k = 0; k < 4; k++)
10062 {
10063 vv[k] = v[hex_t::FaceVert[fi][k]];
10064 }
10065 AverageVertices(vv, 4, oface + qf[fi]);
10066 }
10067
10068 for (int ei = 0; ei < 12; ei++)
10069 {
10070 for (int k = 0; k < 2; k++)
10071 {
10072 vv[k] = v[hex_t::Edges[ei][k]];
10073 }
10074 AverageVertices(vv, 2, oedge+e[ei]);
10075 }
10076
10077 new_elements[j++] =
10078 new Hexahedron(v[0], oedge+e[0], oface+qf[0],
10079 oedge+e[3], oedge+e[8], oface+qf[1],
10080 oelem+he, oface+qf[4], attr);
10081 new_elements[j++] =
10082 new Hexahedron(oedge+e[0], v[1], oedge+e[1],
10083 oface+qf[0], oface+qf[1], oedge+e[9],
10084 oface+qf[2], oelem+he, attr);
10085 new_elements[j++] =
10086 new Hexahedron(oface+qf[0], oedge+e[1], v[2],
10087 oedge+e[2], oelem+he, oface+qf[2],
10088 oedge+e[10], oface+qf[3], attr);
10089 new_elements[j++] =
10090 new Hexahedron(oedge+e[3], oface+qf[0], oedge+e[2],
10091 v[3], oface+qf[4], oelem+he,
10092 oface+qf[3], oedge+e[11], attr);
10093 new_elements[j++] =
10094 new Hexahedron(oedge+e[8], oface+qf[1], oelem+he,
10095 oface+qf[4], v[4], oedge+e[4],
10096 oface+qf[5], oedge+e[7], attr);
10097 new_elements[j++] =
10098 new Hexahedron(oface+qf[1], oedge+e[9], oface+qf[2],
10099 oelem+he, oedge+e[4], v[5],
10100 oedge+e[5], oface+qf[5], attr);
10101 new_elements[j++] =
10102 new Hexahedron(oelem+he, oface+qf[2], oedge+e[10],
10103 oface+qf[3], oface+qf[5], oedge+e[5],
10104 v[6], oedge+e[6], attr);
10105 new_elements[j++] =
10106 new Hexahedron(oface+qf[4], oelem+he, oface+qf[3],
10107 oedge+e[11], oedge+e[7], oface+qf[5],
10108 oedge+e[6], v[7], attr);
10109 }
10110 break;
10111
10112 default:
10113 MFEM_ABORT("Unknown 3D element type \"" << el_type << "\"");
10114 break;
10115 }
10117 }
10118 mfem::Swap(elements, new_elements);
10119
10120 // refine boundary elements
10121 new_boundary.SetSize(4 * NumOfBdrElements);
10122 for (int i = 0, j = 0; i < NumOfBdrElements; i++)
10123 {
10124 const Element::Type bdr_el_type = boundary[i]->GetType();
10125 const int attr = boundary[i]->GetAttribute();
10126 int *v = boundary[i]->GetVertices();
10127 const int *e = bel_to_edge->GetRow(i);
10128 int ev[4];
10129
10130 if (e2v.Size())
10131 {
10132 const int ne = bel_to_edge->RowSize(i);
10133 for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
10134 e = ev;
10135 }
10136
10137 if (bdr_el_type == Element::TRIANGLE)
10138 {
10139 new_boundary[j++] =
10140 new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
10141 new_boundary[j++] =
10142 new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
10143 new_boundary[j++] =
10144 new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
10145 new_boundary[j++] =
10146 new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
10147 }
10148 else if (bdr_el_type == Element::QUADRILATERAL)
10149 {
10150 const int qf =
10151 (f2qf.Size() == 0) ? be_to_face[i] : f2qf[be_to_face[i]];
10152
10153 new_boundary[j++] =
10154 new Quadrilateral(v[0], oedge+e[0], oface+qf, oedge+e[3], attr);
10155 new_boundary[j++] =
10156 new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oface+qf, attr);
10157 new_boundary[j++] =
10158 new Quadrilateral(oface+qf, oedge+e[1], v[2], oedge+e[2], attr);
10159 new_boundary[j++] =
10160 new Quadrilateral(oedge+e[3], oface+qf, oedge+e[2], v[3], attr);
10161 }
10162 else
10163 {
10164 MFEM_ABORT("boundary Element is not a triangle or a quad!");
10165 }
10167 }
10168 mfem::Swap(boundary, new_boundary);
10169
10170 static const real_t A = 0.0, B = 0.5, C = 1.0, D = -1.0;
10171 static real_t tet_children[3*4*16] =
10172 {
10173 A,A,A, B,A,A, A,B,A, A,A,B,
10174 B,A,A, C,A,A, B,B,A, B,A,B,
10175 A,B,A, B,B,A, A,C,A, A,B,B,
10176 A,A,B, B,A,B, A,B,B, A,A,C,
10177 // edge coordinates:
10178 // 0 -> B,A,A 1 -> A,B,A 2 -> A,A,B
10179 // 3 -> B,B,A 4 -> B,A,B 5 -> A,B,B
10180 // rt = 0: {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1}
10181 B,A,A, A,B,B, A,B,A, A,A,B,
10182 B,A,A, A,B,B, A,A,B, B,A,B,
10183 B,A,A, A,B,B, B,A,B, B,B,A,
10184 B,A,A, A,B,B, B,B,A, A,B,A,
10185 // rt = 1: {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0}
10186 A,B,A, B,A,A, B,A,B, A,A,B,
10187 A,B,A, A,A,B, B,A,B, A,B,B,
10188 A,B,A, A,B,B, B,A,B, B,B,A,
10189 A,B,A, B,B,A, B,A,B, B,A,A,
10190 // rt = 2: {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3}
10191 A,A,B, B,A,A, A,B,A, B,B,A,
10192 A,A,B, A,B,A, A,B,B, B,B,A,
10193 A,A,B, A,B,B, B,A,B, B,B,A,
10194 A,A,B, B,A,B, B,A,A, B,B,A
10195 };
10196 static real_t pyr_children[3*5*10] =
10197 {
10198 A,A,A, B,A,A, B,B,A, A,B,A, A,A,B,
10199 B,A,A, C,A,A, C,B,A, B,B,A, B,A,B,
10200 B,B,A, C,B,A, C,C,A, B,C,A, B,B,B,
10201 A,B,A, B,B,A, B,C,A, A,C,A, A,B,B,
10202 A,A,B, B,A,B, B,B,B, A,B,B, A,A,C,
10203 A,B,B, B,B,B, B,A,B, A,A,B, B,B,A,
10204 B,A,A, A,A,B, B,A,B, B,B,A, D,D,D,
10205 C,B,A, B,A,B, B,B,B, B,B,A, D,D,D,
10206 B,C,A, B,B,B, A,B,B, B,B,A, D,D,D,
10207 A,B,A, A,B,B, A,A,B, B,B,A, D,D,D
10208 };
10209 static real_t pri_children[3*6*8] =
10210 {
10211 A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
10212 B,B,A, A,B,A, B,A,A, B,B,B, A,B,B, B,A,B,
10213 B,A,A, C,A,A, B,B,A, B,A,B, C,A,B, B,B,B,
10214 A,B,A, B,B,A, A,C,A, A,B,B, B,B,B, A,C,B,
10215 A,A,B, B,A,B, A,B,B, A,A,C, B,A,C, A,B,C,
10216 B,B,B, A,B,B, B,A,B, B,B,C, A,B,C, B,A,C,
10217 B,A,B, C,A,B, B,B,B, B,A,C, C,A,C, B,B,C,
10218 A,B,B, B,B,B, A,C,B, A,B,C, B,B,C, A,C,C
10219 };
10220 static real_t hex_children[3*8*8] =
10221 {
10222 A,A,A, B,A,A, B,B,A, A,B,A, A,A,B, B,A,B, B,B,B, A,B,B,
10223 B,A,A, C,A,A, C,B,A, B,B,A, B,A,B, C,A,B, C,B,B, B,B,B,
10224 B,B,A, C,B,A, C,C,A, B,C,A, B,B,B, C,B,B, C,C,B, B,C,B,
10225 A,B,A, B,B,A, B,C,A, A,C,A, A,B,B, B,B,B, B,C,B, A,C,B,
10226 A,A,B, B,A,B, B,B,B, A,B,B, A,A,C, B,A,C, B,B,C, A,B,C,
10227 B,A,B, C,A,B, C,B,B, B,B,B, B,A,C, C,A,C, C,B,C, B,B,C,
10228 B,B,B, C,B,B, C,C,B, B,C,B, B,B,C, C,B,C, C,C,C, B,C,C,
10229 A,B,B, B,B,B, B,C,B, A,C,B, A,B,C, B,B,C, B,C,C, A,C,C
10230 };
10231
10233 .UseExternalData(tet_children, 3, 4, 16);
10235 .UseExternalData(pyr_children, 3, 5, 10);
10237 .UseExternalData(pri_children, 3, 6, 8);
10239 .UseExternalData(hex_children, 3, 8, 8);
10240
10241 for (int i = 0; i < elements.Size(); i++)
10242 {
10243 // tetrahedron elements are handled above:
10244 if (elements[i]->GetType() == Element::TETRAHEDRON) { continue; }
10245
10247 emb.parent = i / 8;
10248 emb.matrix = i % 8;
10249 }
10250
10251 NumOfVertices = vertices.Size();
10252 NumOfElements = 8 * NumOfElements + 2 * pyr_counter;
10254
10256 GenerateFaces();
10257
10258#ifdef MFEM_DEBUG
10260#endif
10261
10263
10265 sequence++;
10266
10267 if (update_nodes) { UpdateNodes(); }
10268}
10269
10270void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
10271{
10272 int i, j, ind, nedges;
10273 Array<int> v;
10274
10275 ResetLazyData();
10276
10277 if (ncmesh)
10278 {
10279 MFEM_ABORT("Local and nonconforming refinements cannot be mixed.");
10280 }
10281
10283
10284 if (Dim == 1) // --------------------------------------------------------
10285 {
10286 int cne = NumOfElements, cnv = NumOfVertices;
10287 NumOfVertices += marked_el.Size();
10288 NumOfElements += marked_el.Size();
10289 vertices.SetSize(NumOfVertices);
10290 elements.SetSize(NumOfElements);
10292
10293 for (j = 0; j < marked_el.Size(); j++)
10294 {
10295 i = marked_el[j];
10296 Segment *c_seg = (Segment *)elements[i];
10297 int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
10298 int new_v = cnv + j, new_e = cne + j;
10299 AverageVertices(vert, 2, new_v);
10300 elements[new_e] = new Segment(new_v, vert[1], attr);
10301 vert[1] = new_v;
10302
10305 }
10306
10307 static real_t seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
10309 UseExternalData(seg_children, 1, 2, 3);
10310
10311 GenerateFaces();
10312
10313 } // end of 'if (Dim == 1)'
10314 else if (Dim == 2) // ---------------------------------------------------
10315 {
10316 // 1. Get table of vertex to vertex connections.
10317 DSTable v_to_v(NumOfVertices);
10318 GetVertexToVertexTable(v_to_v);
10319
10320 // 2. Get edge to element connections in arrays edge1 and edge2
10321 nedges = v_to_v.NumberOfEntries();
10322 int *edge1 = new int[nedges];
10323 int *edge2 = new int[nedges];
10324 int *middle = new int[nedges];
10325
10326 for (i = 0; i < nedges; i++)
10327 {
10328 edge1[i] = edge2[i] = middle[i] = -1;
10329 }
10330
10331 for (i = 0; i < NumOfElements; i++)
10332 {
10333 elements[i]->GetVertices(v);
10334 for (j = 1; j < v.Size(); j++)
10335 {
10336 ind = v_to_v(v[j-1], v[j]);
10337 (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
10338 }
10339 ind = v_to_v(v[0], v[v.Size()-1]);
10340 (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
10341 }
10342
10343 // 3. Do the red refinement.
10344 for (i = 0; i < marked_el.Size(); i++)
10345 {
10346 RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
10347 }
10348
10349 // 4. Do the green refinement (to get conforming mesh).
10350 int need_refinement;
10351 do
10352 {
10353 need_refinement = 0;
10354 for (i = 0; i < nedges; i++)
10355 {
10356 if (middle[i] != -1 && edge1[i] != -1)
10357 {
10358 need_refinement = 1;
10359 GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
10360 }
10361 }
10362 }
10363 while (need_refinement == 1);
10364
10365 // 5. Update the boundary elements.
10366 int v1[2], v2[2], bisect, temp;
10367 temp = NumOfBdrElements;
10368 for (i = 0; i < temp; i++)
10369 {
10370 boundary[i]->GetVertices(v);
10371 bisect = v_to_v(v[0], v[1]);
10372 if (middle[bisect] != -1) // the element was refined (needs updating)
10373 {
10374 if (boundary[i]->GetType() == Element::SEGMENT)
10375 {
10376 v1[0] = v[0]; v1[1] = middle[bisect];
10377 v2[0] = middle[bisect]; v2[1] = v[1];
10378
10379 boundary[i]->SetVertices(v1);
10381 }
10382 else
10383 mfem_error("Only bisection of segment is implemented"
10384 " for bdr elem.");
10385 }
10386 }
10387 NumOfBdrElements = boundary.Size();
10388
10389 // 6. Free the allocated memory.
10390 delete [] edge1;
10391 delete [] edge2;
10392 delete [] middle;
10393
10394 if (el_to_edge != NULL)
10395 {
10397 GenerateFaces();
10398 }
10399
10400 }
10401 else if (Dim == 3) // ---------------------------------------------------
10402 {
10403 // 1. Hash table of vertex to vertex connections corresponding to refined
10404 // edges.
10405 HashTable<Hashed2> v_to_v;
10406
10407 MFEM_VERIFY(GetNE() == 0 ||
10408 ((Tetrahedron*)elements[0])->GetRefinementFlag() != 0,
10409 "tetrahedral mesh is not marked for refinement:"
10410 " call Finalize(true)");
10411
10412 // 2. Do the red refinement.
10413 int ii;
10414 switch (type)
10415 {
10416 case 1:
10417 for (i = 0; i < marked_el.Size(); i++)
10418 {
10419 Bisection(marked_el[i], v_to_v);
10420 }
10421 break;
10422 case 2:
10423 for (i = 0; i < marked_el.Size(); i++)
10424 {
10425 Bisection(marked_el[i], v_to_v);
10426
10427 Bisection(NumOfElements - 1, v_to_v);
10428 Bisection(marked_el[i], v_to_v);
10429 }
10430 break;
10431 case 3:
10432 for (i = 0; i < marked_el.Size(); i++)
10433 {
10434 Bisection(marked_el[i], v_to_v);
10435
10436 ii = NumOfElements - 1;
10437 Bisection(ii, v_to_v);
10438 Bisection(NumOfElements - 1, v_to_v);
10439 Bisection(ii, v_to_v);
10440
10441 Bisection(marked_el[i], v_to_v);
10442 Bisection(NumOfElements-1, v_to_v);
10443 Bisection(marked_el[i], v_to_v);
10444 }
10445 break;
10446 }
10447
10448 // 3. Do the green refinement (to get conforming mesh).
10449 int need_refinement;
10450 // int need_refinement, onoe, max_gen = 0;
10451 do
10452 {
10453 // int redges[2], type, flag;
10454 need_refinement = 0;
10455 // onoe = NumOfElements;
10456 // for (i = 0; i < onoe; i++)
10457 for (i = 0; i < NumOfElements; i++)
10458 {
10459 // ((Tetrahedron *)elements[i])->
10460 // ParseRefinementFlag(redges, type, flag);
10461 // if (flag > max_gen) max_gen = flag;
10462 if (elements[i]->NeedRefinement(v_to_v))
10463 {
10464 need_refinement = 1;
10465 Bisection(i, v_to_v);
10466 }
10467 }
10468 }
10469 while (need_refinement == 1);
10470
10471 // mfem::out << "Maximum generation: " << max_gen << endl;
10472
10473 // 4. Update the boundary elements.
10474 do
10475 {
10476 need_refinement = 0;
10477 for (i = 0; i < NumOfBdrElements; i++)
10478 if (boundary[i]->NeedRefinement(v_to_v))
10479 {
10480 need_refinement = 1;
10481 BdrBisection(i, v_to_v);
10482 }
10483 }
10484 while (need_refinement == 1);
10485
10486 NumOfVertices = vertices.Size();
10487 NumOfBdrElements = boundary.Size();
10488
10489 // 5. Update element-to-edge and element-to-face relations.
10490 if (el_to_edge != NULL)
10491 {
10493 }
10494 if (el_to_face != NULL)
10495 {
10497 GenerateFaces();
10498 }
10499
10500 } // end 'if (Dim == 3)'
10501
10503 sequence++;
10504
10505 UpdateNodes();
10506
10507#ifdef MFEM_DEBUG
10509#endif
10510}
10511
10513 int nc_limit)
10514{
10515 MFEM_VERIFY(!NURBSext, "Nonconforming refinement of NURBS meshes is "
10516 "not supported. Project the NURBS to Nodes first.");
10517
10518 ResetLazyData();
10519
10520 if (!ncmesh)
10521 {
10522 // start tracking refinement hierarchy
10523 ncmesh = new NCMesh(this);
10524 }
10525
10526 if (!refinements.Size())
10527 {
10529 return;
10530 }
10531
10532 // do the refinements
10534 ncmesh->Refine(refinements);
10535
10536 if (nc_limit > 0)
10537 {
10538 ncmesh->LimitNCLevel(nc_limit);
10539 }
10540
10541 // create a second mesh containing the finest elements from 'ncmesh'
10542 Mesh* mesh2 = new Mesh(*ncmesh);
10543 ncmesh->OnMeshUpdated(mesh2);
10544
10545 // now swap the meshes, the second mesh will become the old coarse mesh
10546 // and this mesh will be the new fine mesh
10547 Swap(*mesh2, false);
10548 delete mesh2;
10549
10551
10553 sequence++;
10554
10555 UpdateNodes();
10556}
10557
10559 const int *fine, int nfine, int op)
10560{
10561 real_t error = (op == 3) ? std::pow(elem_error[fine[0]],
10562 2.0) : elem_error[fine[0]];
10563
10564 for (int i = 1; i < nfine; i++)
10565 {
10566 MFEM_VERIFY(fine[i] < elem_error.Size(), "");
10567
10568 real_t err_fine = elem_error[fine[i]];
10569 switch (op)
10570 {
10571 case 0: error = std::min(error, err_fine); break;
10572 case 1: error += err_fine; break;
10573 case 2: error = std::max(error, err_fine); break;
10574 case 3: error += std::pow(err_fine, 2.0); break;
10575 default: MFEM_ABORT("Invalid operation.");
10576 }
10577 }
10578 return (op == 3) ? std::sqrt(error) : error;
10579}
10580
10582 real_t threshold, int nc_limit, int op)
10583{
10584 MFEM_VERIFY(ncmesh, "Only supported for non-conforming meshes.");
10585 MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. "
10586 "Project the NURBS to Nodes first.");
10587
10588 ResetLazyData();
10589
10590 const Table &dt = ncmesh->GetDerefinementTable();
10591
10592 Array<int> level_ok;
10593 if (nc_limit > 0)
10594 {
10595 ncmesh->CheckDerefinementNCLevel(dt, level_ok, nc_limit);
10596 }
10597
10598 Array<int> derefs;
10599 for (int i = 0; i < dt.Size(); i++)
10600 {
10601 if (nc_limit > 0 && !level_ok[i]) { continue; }
10602
10603 real_t error =
10604 AggregateError(elem_error, dt.GetRow(i), dt.RowSize(i), op);
10605
10606 if (error < threshold) { derefs.Append(i); }
10607 }
10608
10609 if (!derefs.Size()) { return false; }
10610
10611 ncmesh->Derefine(derefs);
10612
10613 Mesh* mesh2 = new Mesh(*ncmesh);
10614 ncmesh->OnMeshUpdated(mesh2);
10615
10616 Swap(*mesh2, false);
10617 delete mesh2;
10618
10620
10622 sequence++;
10623
10624 UpdateNodes();
10625
10626 return true;
10627}
10628
10629bool Mesh::DerefineByError(Array<real_t> &elem_error, real_t threshold,
10630 int nc_limit, int op)
10631{
10632 // NOTE: the error array is not const because it will be expanded in parallel
10633 // by ghost element errors
10634 if (Nonconforming())
10635 {
10636 return NonconformingDerefinement(elem_error, threshold, nc_limit, op);
10637 }
10638 else
10639 {
10640 MFEM_ABORT("Derefinement is currently supported for non-conforming "
10641 "meshes only.");
10642 return false;
10643 }
10644}
10645
10646bool Mesh::DerefineByError(const Vector &elem_error, real_t threshold,
10647 int nc_limit, int op)
10648{
10649 Array<real_t> tmp(elem_error.Size());
10650 for (int i = 0; i < tmp.Size(); i++)
10651 {
10652 tmp[i] = elem_error(i);
10653 }
10654 return DerefineByError(tmp, threshold, nc_limit, op);
10655}
10656
10657
10658void Mesh::InitFromNCMesh(const NCMesh &ncmesh_)
10659{
10660 Dim = ncmesh_.Dimension();
10661 spaceDim = ncmesh_.SpaceDimension();
10662
10663 DeleteTables();
10664
10665 ncmesh_.GetMeshComponents(*this);
10666
10667 NumOfVertices = vertices.Size();
10668 NumOfElements = elements.Size();
10669 NumOfBdrElements = boundary.Size();
10670
10671 SetMeshGen(); // set the mesh type: 'meshgen', ...
10672
10673 NumOfEdges = NumOfFaces = 0;
10675
10676 if (Dim > 1)
10677 {
10678 el_to_edge = new Table;
10680 }
10681 if (Dim > 2)
10682 {
10684 }
10685 GenerateFaces();
10686#ifdef MFEM_DEBUG
10688#endif
10689
10690 // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
10691 // outside after this method.
10692}
10693
10694Mesh::Mesh(const NCMesh &ncmesh_)
10695 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
10696{
10697 Init();
10698 InitTables();
10699 InitFromNCMesh(ncmesh_);
10700 SetAttributes();
10701}
10702
10703void Mesh::Swap(Mesh& other, bool non_geometry)
10704{
10705 mfem::Swap(Dim, other.Dim);
10707
10713
10714 mfem::Swap(meshgen, other.meshgen);
10716
10720 mfem::Swap(faces, other.faces);
10725
10734
10737
10740
10741#ifdef MFEM_USE_MEMALLOC
10742 TetMemory.Swap(other.TetMemory);
10743#endif
10744
10745 if (non_geometry)
10746 {
10748 mfem::Swap(ncmesh, other.ncmesh);
10749
10750 mfem::Swap(Nodes, other.Nodes);
10751 if (Nodes) { Nodes->FESpace()->UpdateMeshPointer(this); }
10752 if (other.Nodes) { other.Nodes->FESpace()->UpdateMeshPointer(&other); }
10754
10756
10760 }
10761}
10762
10763void Mesh::GetElementData(const Array<Element*> &elem_array, int geom,
10764 Array<int> &elem_vtx, Array<int> &attr) const
10765{
10766 // protected method
10767 const int nv = Geometry::NumVerts[geom];
10768 int num_elems = 0;
10769 for (int i = 0; i < elem_array.Size(); i++)
10770 {
10771 if (elem_array[i]->GetGeometryType() == geom)
10772 {
10773 num_elems++;
10774 }
10775 }
10776 elem_vtx.SetSize(nv*num_elems);
10777 attr.SetSize(num_elems);
10778 elem_vtx.SetSize(0);
10779 attr.SetSize(0);
10780 for (int i = 0; i < elem_array.Size(); i++)
10781 {
10782 Element *el = elem_array[i];
10783 if (el->GetGeometryType() != geom) { continue; }
10784
10785 Array<int> loc_vtx(el->GetVertices(), nv);
10786 elem_vtx.Append(loc_vtx);
10787 attr.Append(el->GetAttribute());
10788 }
10789}
10790
10791static Array<int>& AllElements(Array<int> &list, int nelem)
10792{
10793 list.SetSize(nelem);
10794 for (int i = 0; i < nelem; i++) { list[i] = i; }
10795 return list;
10796}
10797
10798void Mesh::UniformRefinement(int ref_algo)
10799{
10800 Array<int> list;
10801
10802 if (NURBSext)
10803 {
10805 }
10806 else if (ncmesh)
10807 {
10808 GeneralRefinement(AllElements(list, GetNE()));
10809 }
10810 else if (ref_algo == 1 && meshgen == 1 && Dim == 3)
10811 {
10812 // algorithm "B" for an all-tet mesh
10813 LocalRefinement(AllElements(list, GetNE()));
10814 }
10815 else
10816 {
10817 switch (Dim)
10818 {
10819 case 1: LocalRefinement(AllElements(list, GetNE())); break;
10820 case 2: UniformRefinement2D(); break;
10821 case 3: UniformRefinement3D(); break;
10822 default: MFEM_ABORT("internal error");
10823 }
10824 }
10825}
10826
10828{
10829 if (NURBSext && cf > 1)
10830 {
10832 Array<int> initialCoarsening; // Initial coarsening factors
10833 NURBSext->GetCoarseningFactors(initialCoarsening);
10834
10835 // If refinement formulas are nested, then initial coarsening is skipped.
10836 bool noInitialCoarsening = true;
10837 for (auto f : initialCoarsening)
10838 {
10839 noInitialCoarsening = (noInitialCoarsening && f == 1);
10840 }
10841
10842 if (noInitialCoarsening)
10843 {
10844 NURBSext->Coarsen(cf, tol);
10845 }
10846 else
10847 {
10848 // Perform an initial full coarsening, and then refine. This is
10849 // necessary only for non-nested refinement formulas.
10850 NURBSext->Coarsen(initialCoarsening, tol);
10851
10852 // FiniteElementSpace::Update is not supported
10854 sequence++;
10855
10856 UpdateNURBS();
10857
10858 // Prepare for refinement by factors.
10860
10861 Array<int> rf(initialCoarsening);
10862 bool divisible = true;
10863 for (int i=0; i<rf.Size(); ++i)
10864 {
10865 rf[i] /= cf;
10866 divisible = divisible && cf * rf[i] == initialCoarsening[i];
10867 }
10868
10869 MFEM_VERIFY(divisible, "Invalid coarsening");
10870
10871 // Refine from the fully coarsened mesh to the mesh coarsened by the
10872 // factor cf.
10874 }
10875
10876 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
10877 sequence++;
10878
10879 UpdateNURBS();
10880 }
10881}
10882
10884 int nonconforming, int nc_limit)
10885{
10886 if (ncmesh)
10887 {
10888 nonconforming = 1;
10889 }
10890 else if (Dim == 1 || (Dim == 3 && (meshgen & 1)))
10891 {
10892 nonconforming = 0;
10893 }
10894 else if (nonconforming < 0)
10895 {
10896 // determine if nonconforming refinement is suitable
10897 if ((meshgen & 2) || (meshgen & 4) || (meshgen & 8))
10898 {
10899 nonconforming = 1; // tensor product elements and wedges
10900 }
10901 else
10902 {
10903 nonconforming = 0; // simplices
10904 }
10905 }
10906
10907 if (nonconforming)
10908 {
10909 // non-conforming refinement (hanging nodes)
10910 NonconformingRefinement(refinements, nc_limit);
10911 }
10912 else
10913 {
10914 Array<int> el_to_refine(refinements.Size());
10915 for (int i = 0; i < refinements.Size(); i++)
10916 {
10917 el_to_refine[i] = refinements[i].index;
10918 }
10919
10920 // infer 'type' of local refinement from first element's 'ref_type'
10921 int type, rt = (refinements.Size() ? refinements[0].GetType() : 7);
10922 if (rt == 1 || rt == 2 || rt == 4)
10923 {
10924 type = 1; // bisection
10925 }
10926 else if (rt == 3 || rt == 5 || rt == 6)
10927 {
10928 type = 2; // quadrisection
10929 }
10930 else
10931 {
10932 type = 3; // octasection
10933 }
10934
10935 // red-green refinement and bisection, no hanging nodes
10936 LocalRefinement(el_to_refine, type);
10937 }
10938}
10939
10940void Mesh::GeneralRefinement(const Array<int> &el_to_refine, int nonconforming,
10941 int nc_limit)
10942{
10943 Array<Refinement> refinements(el_to_refine.Size());
10944 for (int i = 0; i < el_to_refine.Size(); i++)
10945 {
10946 refinements[i] = Refinement(el_to_refine[i]);
10947 }
10948 GeneralRefinement(refinements, nonconforming, nc_limit);
10949}
10950
10951void Mesh::EnsureNCMesh(bool simplices_nonconforming)
10952{
10953 MFEM_VERIFY(!NURBSext, "Cannot convert a NURBS mesh to an NC mesh. "
10954 "Please project the NURBS to Nodes first, with SetCurvature().");
10955
10956#ifdef MFEM_USE_MPI
10957 MFEM_VERIFY(ncmesh != NULL || dynamic_cast<const ParMesh*>(this) == NULL,
10958 "Sorry, converting a conforming ParMesh to an NC mesh is "
10959 "not possible.");
10960#endif
10961
10962 if (!ncmesh)
10963 {
10964 if ((meshgen & 0x2) /* quads/hexes */ ||
10965 (meshgen & 0x4) /* wedges */ ||
10966 (simplices_nonconforming && (meshgen & 0x1)) /* simplices */)
10967 {
10968 ncmesh = new NCMesh(this);
10969 ncmesh->OnMeshUpdated(this);
10971 }
10972 }
10973}
10974
10975void Mesh::RandomRefinement(real_t prob, bool aniso, int nonconforming,
10976 int nc_limit)
10977{
10978 Array<Refinement> refs;
10979 for (int i = 0; i < GetNE(); i++)
10980 {
10981 if ((real_t) rand() / real_t(RAND_MAX) < prob)
10982 {
10983 int type = 7;
10984 if (aniso)
10985 {
10986 type = (Dim == 3) ? (rand() % 7 + 1) : (rand() % 3 + 1);
10987 }
10988 refs.Append(Refinement(i, type));
10989 }
10990 }
10991 GeneralRefinement(refs, nonconforming, nc_limit);
10992}
10993
10994void Mesh::RefineAtVertex(const Vertex& vert, real_t eps, int nonconforming)
10995{
10996 Array<int> v;
10997 Array<Refinement> refs;
10998 for (int i = 0; i < GetNE(); i++)
10999 {
11000 GetElementVertices(i, v);
11001 bool refine = false;
11002 for (int j = 0; j < v.Size(); j++)
11003 {
11004 real_t dist = 0.0;
11005 for (int l = 0; l < spaceDim; l++)
11006 {
11007 real_t d = vert(l) - vertices[v[j]](l);
11008 dist += d*d;
11009 }
11010 if (dist <= eps*eps) { refine = true; break; }
11011 }
11012 if (refine)
11013 {
11014 refs.Append(Refinement(i));
11015 }
11016 }
11017 GeneralRefinement(refs, nonconforming);
11018}
11019
11020bool Mesh::RefineByError(const Array<real_t> &elem_error, real_t threshold,
11021 int nonconforming, int nc_limit)
11022{
11023 MFEM_VERIFY(elem_error.Size() == GetNE(), "");
11024 Array<Refinement> refs;
11025 for (int i = 0; i < GetNE(); i++)
11026 {
11027 if (elem_error[i] > threshold)
11028 {
11029 refs.Append(Refinement(i));
11030 }
11031 }
11032 if (ReduceInt(refs.Size()))
11033 {
11034 GeneralRefinement(refs, nonconforming, nc_limit);
11035 return true;
11036 }
11037 return false;
11038}
11039
11040bool Mesh::RefineByError(const Vector &elem_error, real_t threshold,
11041 int nonconforming, int nc_limit)
11042{
11043 Array<real_t> tmp(const_cast<real_t*>(elem_error.GetData()),
11044 elem_error.Size());
11045 return RefineByError(tmp, threshold, nonconforming, nc_limit);
11046}
11047
11048
11049void Mesh::Bisection(int i, const DSTable &v_to_v,
11050 int *edge1, int *edge2, int *middle)
11051{
11052 int *vert;
11053 int v[2][4], v_new, bisect, t;
11054 Element *el = elements[i];
11055 Vertex V;
11056
11057 t = el->GetType();
11058 if (t == Element::TRIANGLE)
11059 {
11060 Triangle *tri = (Triangle *) el;
11061
11062 vert = tri->GetVertices();
11063
11064 // 1. Get the index for the new vertex in v_new.
11065 bisect = v_to_v(vert[0], vert[1]);
11066 MFEM_ASSERT(bisect >= 0, "");
11067
11068 if (middle[bisect] == -1)
11069 {
11070 v_new = NumOfVertices++;
11071 for (int d = 0; d < spaceDim; d++)
11072 {
11073 V(d) = 0.5 * (vertices[vert[0]](d) + vertices[vert[1]](d));
11074 }
11075 vertices.Append(V);
11076
11077 // Put the element that may need refinement (because of this
11078 // bisection) in edge1, or -1 if no more refinement is needed.
11079 if (edge1[bisect] == i)
11080 {
11081 edge1[bisect] = edge2[bisect];
11082 }
11083
11084 middle[bisect] = v_new;
11085 }
11086 else
11087 {
11088 v_new = middle[bisect];
11089
11090 // This edge will require no more refinement.
11091 edge1[bisect] = -1;
11092 }
11093
11094 // 2. Set the node indices for the new elements in v[0] and v[1] so that
11095 // the edge marked for refinement is between the first two nodes.
11096 v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
11097 v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
11098
11099 tri->SetVertices(v[0]); // changes vert[0..2] !!!
11100
11101 Triangle* tri_new = new Triangle(v[1], tri->GetAttribute());
11102 elements.Append(tri_new);
11103
11104 int tr = tri->GetTransform();
11105 tri_new->ResetTransform(tr);
11106
11107 // record the sequence of refinements
11108 tri->PushTransform(4);
11109 tri_new->PushTransform(5);
11110
11111 int coarse = FindCoarseElement(i);
11112 CoarseFineTr.embeddings[i].parent = coarse;
11114
11115 // 3. edge1 and edge2 may have to be changed for the second triangle.
11116 if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
11117 {
11118 bisect = v_to_v(v[1][0], v[1][1]);
11119 MFEM_ASSERT(bisect >= 0, "");
11120
11121 if (edge1[bisect] == i)
11122 {
11123 edge1[bisect] = NumOfElements;
11124 }
11125 else if (edge2[bisect] == i)
11126 {
11127 edge2[bisect] = NumOfElements;
11128 }
11129 }
11130 NumOfElements++;
11131 }
11132 else
11133 {
11134 MFEM_ABORT("Bisection for now works only for triangles.");
11135 }
11136}
11137
11139{
11140 int *vert;
11141 int v[2][4], v_new, bisect, t;
11142 Element *el = elements[i];
11143 Vertex V;
11144
11145 t = el->GetType();
11146 if (t == Element::TETRAHEDRON)
11147 {
11148 Tetrahedron *tet = (Tetrahedron *) el;
11149
11150 MFEM_VERIFY(tet->GetRefinementFlag() != 0,
11151 "TETRAHEDRON element is not marked for refinement.");
11152
11153 vert = tet->GetVertices();
11154
11155 // 1. Get the index for the new vertex in v_new.
11156 bisect = v_to_v.FindId(vert[0], vert[1]);
11157 if (bisect == -1)
11158 {
11159 v_new = NumOfVertices + v_to_v.GetId(vert[0],vert[1]);
11160 for (int j = 0; j < 3; j++)
11161 {
11162 V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j));
11163 }
11164 vertices.Append(V);
11165 }
11166 else
11167 {
11168 v_new = NumOfVertices + bisect;
11169 }
11170
11171 // 2. Set the node indices for the new elements in v[2][4] so that
11172 // the edge marked for refinement is between the first two nodes.
11173 int type, old_redges[2], flag;
11174 tet->ParseRefinementFlag(old_redges, type, flag);
11175
11176 int new_type, new_redges[2][2];
11177 v[0][3] = v_new;
11178 v[1][3] = v_new;
11179 new_redges[0][0] = 2;
11180 new_redges[0][1] = 1;
11181 new_redges[1][0] = 2;
11182 new_redges[1][1] = 1;
11183 int tr1 = -1, tr2 = -1;
11184 switch (old_redges[0])
11185 {
11186 case 2:
11187 v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3];
11188 if (type == Tetrahedron::TYPE_PF) { new_redges[0][1] = 4; }
11189 tr1 = 0;
11190 break;
11191 case 3:
11192 v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2];
11193 tr1 = 2;
11194 break;
11195 case 5:
11196 v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0];
11197 tr1 = 4;
11198 }
11199 switch (old_redges[1])
11200 {
11201 case 1:
11202 v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3];
11203 if (type == Tetrahedron::TYPE_PF) { new_redges[1][0] = 3; }
11204 tr2 = 1;
11205 break;
11206 case 4:
11207 v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2];
11208 tr2 = 3;
11209 break;
11210 case 5:
11211 v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1];
11212 tr2 = 5;
11213 }
11214
11215 int attr = tet->GetAttribute();
11216 tet->SetVertices(v[0]);
11217
11218#ifdef MFEM_USE_MEMALLOC
11219 Tetrahedron *tet2 = TetMemory.Alloc();
11220 tet2->SetVertices(v[1]);
11221 tet2->SetAttribute(attr);
11222#else
11223 Tetrahedron *tet2 = new Tetrahedron(v[1], attr);
11224#endif
11225 tet2->ResetTransform(tet->GetTransform());
11226 elements.Append(tet2);
11227
11228 // record the sequence of refinements
11229 tet->PushTransform(tr1);
11230 tet2->PushTransform(tr2);
11231
11232 int coarse = FindCoarseElement(i);
11233 CoarseFineTr.embeddings[i].parent = coarse;
11235
11236 // 3. Set the bisection flag
11237 switch (type)
11238 {
11240 new_type = Tetrahedron::TYPE_PF; break;
11242 new_type = Tetrahedron::TYPE_A; break;
11243 default:
11244 new_type = Tetrahedron::TYPE_PU;
11245 }
11246
11247 tet->CreateRefinementFlag(new_redges[0], new_type, flag+1);
11248 tet2->CreateRefinementFlag(new_redges[1], new_type, flag+1);
11249
11250 NumOfElements++;
11251 }
11252 else
11253 {
11254 MFEM_ABORT("Bisection with HashTable for now works only for tetrahedra.");
11255 }
11256}
11257
11258void Mesh::BdrBisection(int i, const HashTable<Hashed2> &v_to_v)
11259{
11260 int *vert;
11261 int v[2][3], v_new, bisect, t;
11262 Element *bdr_el = boundary[i];
11263
11264 t = bdr_el->GetType();
11265 if (t == Element::TRIANGLE)
11266 {
11267 Triangle *tri = (Triangle *) bdr_el;
11268
11269 vert = tri->GetVertices();
11270
11271 // 1. Get the index for the new vertex in v_new.
11272 bisect = v_to_v.FindId(vert[0], vert[1]);
11273 MFEM_ASSERT(bisect >= 0, "");
11274 v_new = NumOfVertices + bisect;
11275 MFEM_ASSERT(v_new != -1, "");
11276
11277 // 2. Set the node indices for the new elements in v[0] and v[1] so that
11278 // the edge marked for refinement is between the first two nodes.
11279 v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
11280 v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
11281
11282 tri->SetVertices(v[0]);
11283
11284 boundary.Append(new Triangle(v[1], tri->GetAttribute()));
11285
11287 }
11288 else
11289 {
11290 MFEM_ABORT("Bisection of boundary elements with HashTable works only for"
11291 " triangles!");
11292 }
11293}
11294
11295void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
11296 int *edge1, int *edge2, int *middle)
11297{
11298 Array<int> v;
11299 int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3];
11300 Vertex V;
11301
11302 if (elements[i]->GetType() == Element::TRIANGLE)
11303 {
11304 Triangle *tri0 = (Triangle*) elements[i];
11305 tri0->GetVertices(v);
11306
11307 // 1. Get the indices for the new vertices in array v_new
11308 bisect[0] = v_to_v(v[0],v[1]);
11309 bisect[1] = v_to_v(v[1],v[2]);
11310 bisect[2] = v_to_v(v[0],v[2]);
11311 MFEM_ASSERT(bisect[0] >= 0 && bisect[1] >= 0 && bisect[2] >= 0, "");
11312
11313 for (j = 0; j < 3; j++) // for the 3 edges fix v_new
11314 {
11315 if (middle[bisect[j]] == -1)
11316 {
11317 v_new[j] = NumOfVertices++;
11318 for (int d = 0; d < spaceDim; d++)
11319 {
11320 V(d) = (vertices[v[j]](d) + vertices[v[(j+1)%3]](d))/2.;
11321 }
11322 vertices.Append(V);
11323
11324 // Put the element that may need refinement (because of this
11325 // bisection) in edge1, or -1 if no more refinement is needed.
11326 if (edge1[bisect[j]] == i)
11327 {
11328 edge1[bisect[j]] = edge2[bisect[j]];
11329 }
11330
11331 middle[bisect[j]] = v_new[j];
11332 }
11333 else
11334 {
11335 v_new[j] = middle[bisect[j]];
11336
11337 // This edge will require no more refinement.
11338 edge1[bisect[j]] = -1;
11339 }
11340 }
11341
11342 // 2. Set the node indices for the new elements in v1, v2, v3 & v4 so that
11343 // the edges marked for refinement be between the first two nodes.
11344 v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2];
11345 v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1];
11346 v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2];
11347 v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0];
11348
11349 Triangle* tri1 = new Triangle(v1, tri0->GetAttribute());
11350 Triangle* tri2 = new Triangle(v2, tri0->GetAttribute());
11351 Triangle* tri3 = new Triangle(v3, tri0->GetAttribute());
11352
11353 elements.Append(tri1);
11354 elements.Append(tri2);
11355 elements.Append(tri3);
11356
11357 tri0->SetVertices(v4);
11358
11359 // record the sequence of refinements
11360 unsigned code = tri0->GetTransform();
11361 tri1->ResetTransform(code);
11362 tri2->ResetTransform(code);
11363 tri3->ResetTransform(code);
11364
11365 tri0->PushTransform(3);
11366 tri1->PushTransform(0);
11367 tri2->PushTransform(1);
11368 tri3->PushTransform(2);
11369
11370 // set parent indices
11371 int coarse = FindCoarseElement(i);
11376
11377 NumOfElements += 3;
11378 }
11379 else
11380 {
11381 MFEM_ABORT("Uniform refinement for now works only for triangles.");
11382 }
11383}
11384
11386{
11387 // initialize CoarseFineTr
11390 for (int i = 0; i < NumOfElements; i++)
11391 {
11392 elements[i]->ResetTransform(0);
11394 }
11395}
11396
11398{
11399 int coarse;
11400 while ((coarse = CoarseFineTr.embeddings[i].parent) != i)
11401 {
11402 i = coarse;
11403 }
11404 return coarse;
11405}
11406
11408{
11409 MFEM_VERIFY(GetLastOperation() == Mesh::REFINE, "");
11410
11411 if (ncmesh)
11412 {
11414 }
11415
11416 Mesh::GeometryList elem_geoms(*this);
11417 for (int i = 0; i < elem_geoms.Size(); i++)
11418 {
11419 const Geometry::Type geom = elem_geoms[i];
11420 if (CoarseFineTr.point_matrices[geom].SizeK()) { continue; }
11421
11422 if (geom == Geometry::TRIANGLE ||
11423 geom == Geometry::TETRAHEDRON)
11424 {
11425 std::map<unsigned, int> mat_no;
11426 mat_no[0] = 1; // identity
11427
11428 // assign matrix indices to element transformations
11429 for (int j = 0; j < elements.Size(); j++)
11430 {
11431 int index = 0;
11432 unsigned code = elements[j]->GetTransform();
11433 if (code)
11434 {
11435 int &matrix = mat_no[code];
11436 if (!matrix) { matrix = static_cast<int>(mat_no.size()); }
11437 index = matrix-1;
11438 }
11439 CoarseFineTr.embeddings[j].matrix = index;
11440 }
11441
11443 pmats.SetSize(Dim, Dim+1, static_cast<int>((mat_no.size())));
11444
11445 // calculate the point matrices used
11446 std::map<unsigned, int>::iterator it;
11447 for (it = mat_no.begin(); it != mat_no.end(); ++it)
11448 {
11449 if (geom == Geometry::TRIANGLE)
11450 {
11451 Triangle::GetPointMatrix(it->first, pmats(it->second-1));
11452 }
11453 else
11454 {
11455 Tetrahedron::GetPointMatrix(it->first, pmats(it->second-1));
11456 }
11457 }
11458 }
11459 else
11460 {
11461 MFEM_ABORT("Don't know how to construct CoarseFineTransformations for"
11462 " geom = " << geom);
11463 }
11464 }
11465
11466 // NOTE: quads and hexes already have trivial transformations ready
11467 return CoarseFineTr;
11468}
11469
11470void Mesh::PrintXG(std::ostream &os) const
11471{
11472 MFEM_ASSERT(Dim==spaceDim, "2D Manifold meshes not supported");
11473 int i, j;
11474 Array<int> v;
11475
11476 if (Dim == 2)
11477 {
11478 // Print the type of the mesh.
11479 if (Nodes == NULL)
11480 {
11481 os << "areamesh2\n\n";
11482 }
11483 else
11484 {
11485 os << "curved_areamesh2\n\n";
11486 }
11487
11488 // Print the boundary elements.
11489 os << NumOfBdrElements << '\n';
11490 for (i = 0; i < NumOfBdrElements; i++)
11491 {
11492 boundary[i]->GetVertices(v);
11493
11494 os << boundary[i]->GetAttribute();
11495 for (j = 0; j < v.Size(); j++)
11496 {
11497 os << ' ' << v[j] + 1;
11498 }
11499 os << '\n';
11500 }
11501
11502 // Print the elements.
11503 os << NumOfElements << '\n';
11504 for (i = 0; i < NumOfElements; i++)
11505 {
11506 elements[i]->GetVertices(v);
11507
11508 os << elements[i]->GetAttribute() << ' ' << v.Size();
11509 for (j = 0; j < v.Size(); j++)
11510 {
11511 os << ' ' << v[j] + 1;
11512 }
11513 os << '\n';
11514 }
11515
11516 if (Nodes == NULL)
11517 {
11518 // Print the vertices.
11519 os << NumOfVertices << '\n';
11520 for (i = 0; i < NumOfVertices; i++)
11521 {
11522 os << vertices[i](0);
11523 for (j = 1; j < Dim; j++)
11524 {
11525 os << ' ' << vertices[i](j);
11526 }
11527 os << '\n';
11528 }
11529 }
11530 else
11531 {
11532 os << NumOfVertices << '\n';
11533 Nodes->Save(os);
11534 }
11535 }
11536 else // ===== Dim != 2 =====
11537 {
11538 if (Nodes)
11539 {
11540 mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D");
11541 }
11542
11543 if (meshgen == 1)
11544 {
11545 int nv;
11546 const int *ind;
11547
11548 os << "NETGEN_Neutral_Format\n";
11549 // print the vertices
11550 os << NumOfVertices << '\n';
11551 for (i = 0; i < NumOfVertices; i++)
11552 {
11553 for (j = 0; j < Dim; j++)
11554 {
11555 os << ' ' << vertices[i](j);
11556 }
11557 os << '\n';
11558 }
11559
11560 // print the elements
11561 os << NumOfElements << '\n';
11562 for (i = 0; i < NumOfElements; i++)
11563 {
11564 nv = elements[i]->GetNVertices();
11565 ind = elements[i]->GetVertices();
11566 os << elements[i]->GetAttribute();
11567 for (j = 0; j < nv; j++)
11568 {
11569 os << ' ' << ind[j]+1;
11570 }
11571 os << '\n';
11572 }
11573
11574 // print the boundary information.
11575 os << NumOfBdrElements << '\n';
11576 for (i = 0; i < NumOfBdrElements; i++)
11577 {
11578 nv = boundary[i]->GetNVertices();
11579 ind = boundary[i]->GetVertices();
11580 os << boundary[i]->GetAttribute();
11581 for (j = 0; j < nv; j++)
11582 {
11583 os << ' ' << ind[j]+1;
11584 }
11585 os << '\n';
11586 }
11587 }
11588 else if (meshgen == 2) // TrueGrid
11589 {
11590 int nv;
11591 const int *ind;
11592
11593 os << "TrueGrid\n"
11594 << "1 " << NumOfVertices << " " << NumOfElements
11595 << " 0 0 0 0 0 0 0\n"
11596 << "0 0 0 1 0 0 0 0 0 0 0\n"
11597 << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
11598 << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
11599 << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
11600
11601 for (i = 0; i < NumOfVertices; i++)
11602 os << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1)
11603 << ' ' << vertices[i](2) << " 0.0\n";
11604
11605 for (i = 0; i < NumOfElements; i++)
11606 {
11607 nv = elements[i]->GetNVertices();
11608 ind = elements[i]->GetVertices();
11609 os << i+1 << ' ' << elements[i]->GetAttribute();
11610 for (j = 0; j < nv; j++)
11611 {
11612 os << ' ' << ind[j]+1;
11613 }
11614 os << '\n';
11615 }
11616
11617 for (i = 0; i < NumOfBdrElements; i++)
11618 {
11619 nv = boundary[i]->GetNVertices();
11620 ind = boundary[i]->GetVertices();
11621 os << boundary[i]->GetAttribute();
11622 for (j = 0; j < nv; j++)
11623 {
11624 os << ' ' << ind[j]+1;
11625 }
11626 os << " 1.0 1.0 1.0 1.0\n";
11627 }
11628 }
11629 }
11630
11631 os << flush;
11632}
11633
11634void Mesh::Printer(std::ostream &os, std::string section_delimiter,
11635 const std::string &comments) const
11636{
11637 int i, j;
11638
11639 if (NURBSext)
11640 {
11641 // general format
11642 NURBSext->Print(os, comments);
11643 os << '\n';
11644 Nodes->Save(os);
11645
11646 // patch-wise format
11647 // NURBSext->ConvertToPatches(*Nodes);
11648 // NURBSext->Print(os);
11649
11650 return;
11651 }
11652
11653 if (Nonconforming())
11654 {
11655 // Workaround for inconsistent Mesh state where the Mesh has nodes and
11656 // ncmesh->coodrinates is not empty. Such state can be created with the
11657 // method Mesh::SwapNodes(), see the comment at the beginning of its
11658 // implementation.
11659 Array<real_t> coords_save;
11660 if (Nodes) { mfem::Swap(coords_save, ncmesh->coordinates); }
11661
11662 // nonconforming mesh format
11663 ncmesh->Print(os, comments);
11664
11665 if (Nodes)
11666 {
11667 mfem::Swap(coords_save, ncmesh->coordinates);
11668
11669 os << "\n# mesh curvature GridFunction";
11670 os << "\nnodes\n";
11671 Nodes->Save(os);
11672 }
11673
11674 os << "\nmfem_mesh_end" << endl;
11675 return;
11676 }
11677
11678 // serial/parallel conforming mesh format
11679 const bool set_names = attribute_sets.SetsExist() ||
11681 os << (!set_names && section_delimiter.empty()
11682 ? "MFEM mesh v1.0\n" :
11683 (!set_names ? "MFEM mesh v1.2\n" : "MFEM mesh v1.3\n"));
11684
11685 if (set_names && section_delimiter.empty())
11686 {
11687 section_delimiter = "mfem_mesh_end";
11688 }
11689
11690 // optional
11691 if (!comments.empty()) { os << '\n' << comments << '\n'; }
11692
11693 os <<
11694 "\n#\n# MFEM Geometry Types (see fem/geom.hpp):\n#\n"
11695 "# POINT = 0\n"
11696 "# SEGMENT = 1\n"
11697 "# TRIANGLE = 2\n"
11698 "# SQUARE = 3\n"
11699 "# TETRAHEDRON = 4\n"
11700 "# CUBE = 5\n"
11701 "# PRISM = 6\n"
11702 "# PYRAMID = 7\n"
11703 "#\n";
11704
11705 os << "\ndimension\n" << Dim;
11706
11707 os << "\n\nelements\n" << NumOfElements << '\n';
11708 for (i = 0; i < NumOfElements; i++)
11709 {
11710 PrintElement(elements[i], os);
11711 }
11712
11713 if (set_names)
11714 {
11715 os << "\nattribute_sets\n";
11717 }
11718
11719 os << "\nboundary\n" << NumOfBdrElements << '\n';
11720 for (i = 0; i < NumOfBdrElements; i++)
11721 {
11722 PrintElement(boundary[i], os);
11723 }
11724
11725 if (set_names)
11726 {
11727 os << "\nbdr_attribute_sets\n";
11729 }
11730
11731 os << "\nvertices\n" << NumOfVertices << '\n';
11732 if (Nodes == NULL)
11733 {
11734 os << spaceDim << '\n';
11735 for (i = 0; i < NumOfVertices; i++)
11736 {
11737 os << vertices[i](0);
11738 for (j = 1; j < spaceDim; j++)
11739 {
11740 os << ' ' << vertices[i](j);
11741 }
11742 os << '\n';
11743 }
11744 os.flush();
11745 }
11746 else
11747 {
11748 os << "\nnodes\n";
11749 Nodes->Save(os);
11750 }
11751
11752 if (!section_delimiter.empty())
11753 {
11754 os << '\n'
11755 << section_delimiter << endl; // only with formats v1.2 and above
11756 }
11757}
11758
11759void Mesh::PrintTopo(std::ostream &os, const Array<int> &e_to_k,
11760 const int version, const std::string &comments) const
11761{
11762 MFEM_VERIFY(version == 10 || version == 11, "Invalid NURBS mesh version");
11763
11764 int i;
11765 Array<int> vert;
11766
11767 os << "MFEM NURBS mesh v" << int(version / 10) << "." << version % 10 << "\n";
11768
11769 // optional
11770 if (!comments.empty()) { os << '\n' << comments << '\n'; }
11771
11772 os <<
11773 "\n#\n# MFEM Geometry Types (see fem/geom.hpp):\n#\n"
11774 "# SEGMENT = 1\n"
11775 "# SQUARE = 3\n"
11776 "# CUBE = 5\n"
11777 "#\n";
11778
11779 os << "\ndimension\n" << Dim
11780 << "\n\nelements\n" << NumOfElements << '\n';
11781 for (i = 0; i < NumOfElements; i++)
11782 {
11783 PrintElement(elements[i], os);
11784 }
11785
11786 os << "\nboundary\n" << NumOfBdrElements << '\n';
11787 for (i = 0; i < NumOfBdrElements; i++)
11788 {
11789 PrintElement(boundary[i], os);
11790 }
11791
11792 os << "\nedges\n" << NumOfEdges << '\n';
11793 for (i = 0; i < NumOfEdges; i++)
11794 {
11795 edge_vertex->GetRow(i, vert);
11796 int ki = e_to_k[i];
11797 if (ki < 0)
11798 {
11799 ki = -1 - ki;
11800 }
11801 os << ki << ' ' << vert[0] << ' ' << vert[1] << '\n';
11802 }
11803 os << "\nvertices\n" << NumOfVertices << '\n';
11804}
11805
11806void Mesh::Save(const std::string &fname, int precision) const
11807{
11808 ofstream ofs(fname);
11809 ofs.precision(precision);
11810 Print(ofs);
11811}
11812
11813#ifdef MFEM_USE_ADIOS2
11815{
11816 os.Print(*this);
11817}
11818#endif
11819
11820void Mesh::PrintVTK(std::ostream &os)
11821{
11822 os <<
11823 "# vtk DataFile Version 3.0\n"
11824 "Generated by MFEM\n"
11825 "ASCII\n"
11826 "DATASET UNSTRUCTURED_GRID\n";
11827
11828 if (Nodes == NULL)
11829 {
11830 os << "POINTS " << NumOfVertices << " double\n";
11831 for (int i = 0; i < NumOfVertices; i++)
11832 {
11833 os << vertices[i](0);
11834 int j;
11835 for (j = 1; j < spaceDim; j++)
11836 {
11837 os << ' ' << vertices[i](j);
11838 }
11839 for ( ; j < 3; j++)
11840 {
11841 os << ' ' << 0.0;
11842 }
11843 os << '\n';
11844 }
11845 }
11846 else
11847 {
11848 Array<int> vdofs(3);
11849 os << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n";
11850 for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++)
11851 {
11852 vdofs.SetSize(1);
11853 vdofs[0] = i;
11854 Nodes->FESpace()->DofsToVDofs(vdofs);
11855 os << (*Nodes)(vdofs[0]);
11856 int j;
11857 for (j = 1; j < spaceDim; j++)
11858 {
11859 os << ' ' << (*Nodes)(vdofs[j]);
11860 }
11861 for ( ; j < 3; j++)
11862 {
11863 os << ' ' << 0.0;
11864 }
11865 os << '\n';
11866 }
11867 }
11868
11869 int order = -1;
11870 if (Nodes == NULL)
11871 {
11872 int size = 0;
11873 for (int i = 0; i < NumOfElements; i++)
11874 {
11875 size += elements[i]->GetNVertices() + 1;
11876 }
11877 os << "CELLS " << NumOfElements << ' ' << size << '\n';
11878 for (int i = 0; i < NumOfElements; i++)
11879 {
11880 const int *v = elements[i]->GetVertices();
11881 const int nv = elements[i]->GetNVertices();
11882 os << nv;
11883 Geometry::Type geom = elements[i]->GetGeometryType();
11884 const int *perm = VTKGeometry::VertexPermutation[geom];
11885 for (int j = 0; j < nv; j++)
11886 {
11887 os << ' ' << v[perm ? perm[j] : j];
11888 }
11889 os << '\n';
11890 }
11891 order = 1;
11892 }
11893 else
11894 {
11895 Array<int> dofs;
11896 int size = 0;
11897 for (int i = 0; i < NumOfElements; i++)
11898 {
11899 Nodes->FESpace()->GetElementDofs(i, dofs);
11900 MFEM_ASSERT(Dim != 0 || dofs.Size() == 1,
11901 "Point meshes should have a single dof per element");
11902 size += dofs.Size() + 1;
11903 }
11904 os << "CELLS " << NumOfElements << ' ' << size << '\n';
11905 const char *fec_name = Nodes->FESpace()->FEColl()->Name();
11906
11907 if (!strcmp(fec_name, "Linear") ||
11908 !strcmp(fec_name, "H1_0D_P1") ||
11909 !strcmp(fec_name, "H1_1D_P1") ||
11910 !strcmp(fec_name, "H1_2D_P1") ||
11911 !strcmp(fec_name, "H1_3D_P1"))
11912 {
11913 order = 1;
11914 }
11915 else if (!strcmp(fec_name, "Quadratic") ||
11916 !strcmp(fec_name, "H1_1D_P2") ||
11917 !strcmp(fec_name, "H1_2D_P2") ||
11918 !strcmp(fec_name, "H1_3D_P2"))
11919 {
11920 order = 2;
11921 }
11922 if (order == -1)
11923 {
11924 mfem::err << "Mesh::PrintVTK : can not save '"
11925 << fec_name << "' elements!" << endl;
11926 mfem_error();
11927 }
11928 for (int i = 0; i < NumOfElements; i++)
11929 {
11930 Nodes->FESpace()->GetElementDofs(i, dofs);
11931 os << dofs.Size();
11932 if (order == 1)
11933 {
11934 for (int j = 0; j < dofs.Size(); j++)
11935 {
11936 os << ' ' << dofs[j];
11937 }
11938 }
11939 else if (order == 2)
11940 {
11941 const int *vtk_mfem;
11942 switch (elements[i]->GetGeometryType())
11943 {
11944 case Geometry::SEGMENT:
11945 case Geometry::TRIANGLE:
11946 case Geometry::SQUARE:
11947 vtk_mfem = vtk_quadratic_hex; break; // identity map
11949 vtk_mfem = vtk_quadratic_tet; break;
11950 case Geometry::PRISM:
11951 vtk_mfem = vtk_quadratic_wedge; break;
11952 case Geometry::CUBE:
11953 default:
11954 vtk_mfem = vtk_quadratic_hex; break;
11955 }
11956 for (int j = 0; j < dofs.Size(); j++)
11957 {
11958 os << ' ' << dofs[vtk_mfem[j]];
11959 }
11960 }
11961 os << '\n';
11962 }
11963 }
11964
11965 os << "CELL_TYPES " << NumOfElements << '\n';
11966 for (int i = 0; i < NumOfElements; i++)
11967 {
11968 int vtk_cell_type = 5;
11970 if (order == 1) { vtk_cell_type = VTKGeometry::Map[geom]; }
11971 else if (order == 2) { vtk_cell_type = VTKGeometry::QuadraticMap[geom]; }
11972 os << vtk_cell_type << '\n';
11973 }
11974
11975 // write attributes
11976 os << "CELL_DATA " << NumOfElements << '\n'
11977 << "SCALARS material int\n"
11978 << "LOOKUP_TABLE default\n";
11979 for (int i = 0; i < NumOfElements; i++)
11980 {
11981 os << elements[i]->GetAttribute() << '\n';
11982 }
11983 os.flush();
11984}
11985
11986void Mesh::PrintVTU(std::string fname,
11987 VTKFormat format,
11988 bool high_order_output,
11989 int compression_level,
11990 bool bdr)
11991{
11992 int ref = (high_order_output && Nodes)
11993 ? Nodes->FESpace()->GetMaxElementOrder() : 1;
11994
11995 fname = fname + ".vtu";
11996 std::fstream os(fname.c_str(),std::ios::out);
11997 os << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"";
11998 if (compression_level != 0)
11999 {
12000 os << " compressor=\"vtkZLibDataCompressor\"";
12001 }
12002 os << " byte_order=\"" << VTKByteOrder() << "\">\n";
12003 os << "<UnstructuredGrid>\n";
12004 PrintVTU(os, ref, format, high_order_output, compression_level, bdr);
12005 os << "</Piece>\n"; // need to close the piece open in the PrintVTU method
12006 os << "</UnstructuredGrid>\n";
12007 os << "</VTKFile>" << std::endl;
12008
12009 os.close();
12010}
12011
12012void Mesh::PrintBdrVTU(std::string fname,
12013 VTKFormat format,
12014 bool high_order_output,
12015 int compression_level)
12016{
12017 PrintVTU(fname, format, high_order_output, compression_level, true);
12018}
12019
12020void Mesh::PrintVTU(std::ostream &os, int ref, VTKFormat format,
12021 bool high_order_output, int compression_level,
12022 bool bdr_elements)
12023{
12024 RefinedGeometry *RefG;
12025 DenseMatrix pmat;
12026
12027 const char *fmt_str = (format == VTKFormat::ASCII) ? "ascii" : "binary";
12028 const char *type_str = (format != VTKFormat::BINARY32) ? "Float64" : "Float32";
12029 std::vector<char> buf;
12030
12031 auto get_geom = [&](int i)
12032 {
12033 if (bdr_elements) { return GetBdrElementGeometry(i); }
12034 else { return GetElementBaseGeometry(i); }
12035 };
12036
12037 int ne = bdr_elements ? GetNBE() : GetNE();
12038 // count the number of points and cells
12039 int np = 0, nc_ref = 0;
12040 for (int i = 0; i < ne; i++)
12041 {
12042 Geometry::Type geom = get_geom(i);
12043 int nv = Geometries.GetVertices(geom)->GetNPoints();
12044 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12045 np += RefG->RefPts.GetNPoints();
12046 nc_ref += RefG->RefGeoms.Size() / nv;
12047 }
12048
12049 os << "<Piece NumberOfPoints=\"" << np << "\" NumberOfCells=\""
12050 << (high_order_output ? ne : nc_ref) << "\">\n";
12051
12052 // print out the points
12053 os << "<Points>\n";
12054 os << "<DataArray type=\"" << type_str
12055 << "\" NumberOfComponents=\"3\" format=\"" << fmt_str << "\">\n";
12056 for (int i = 0; i < ne; i++)
12057 {
12058 RefG = GlobGeometryRefiner.Refine(get_geom(i), ref, 1);
12059
12060 if (bdr_elements)
12061 {
12063 }
12064 else
12065 {
12066 GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
12067 }
12068
12069 for (int j = 0; j < pmat.Width(); j++)
12070 {
12071 WriteBinaryOrASCII(os, buf, pmat(0,j), " ", format);
12072 if (pmat.Height() > 1)
12073 {
12074 WriteBinaryOrASCII(os, buf, pmat(1,j), " ", format);
12075 }
12076 else
12077 {
12078 WriteBinaryOrASCII(os, buf, 0.0, " ", format);
12079 }
12080 if (pmat.Height() > 2)
12081 {
12082 WriteBinaryOrASCII(os, buf, pmat(2,j), "", format);
12083 }
12084 else
12085 {
12086 WriteBinaryOrASCII(os, buf, 0.0, "", format);
12087 }
12088 if (format == VTKFormat::ASCII) { os << '\n'; }
12089 }
12090 }
12091 if (format != VTKFormat::ASCII)
12092 {
12093 WriteBase64WithSizeAndClear(os, buf, compression_level);
12094 }
12095 os << "</DataArray>" << std::endl;
12096 os << "</Points>" << std::endl;
12097
12098 os << "<Cells>" << std::endl;
12099 os << "<DataArray type=\"Int32\" Name=\"connectivity\" format=\""
12100 << fmt_str << "\">" << std::endl;
12101 // connectivity
12102 std::vector<int> offset;
12103
12104 np = 0;
12105 if (high_order_output)
12106 {
12107 Array<int> local_connectivity;
12108 for (int iel = 0; iel < ne; iel++)
12109 {
12110 Geometry::Type geom = get_geom(iel);
12111 CreateVTKElementConnectivity(local_connectivity, geom, ref);
12112 int nnodes = local_connectivity.Size();
12113 for (int i=0; i<nnodes; ++i)
12114 {
12115 WriteBinaryOrASCII(os, buf, np+local_connectivity[i], " ",
12116 format);
12117 }
12118 if (format == VTKFormat::ASCII) { os << '\n'; }
12119 np += nnodes;
12120 offset.push_back(np);
12121 }
12122 }
12123 else
12124 {
12125 int coff = 0;
12126 for (int i = 0; i < ne; i++)
12127 {
12128 Geometry::Type geom = get_geom(i);
12129 int nv = Geometries.GetVertices(geom)->GetNPoints();
12130 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12131 Array<int> &RG = RefG->RefGeoms;
12132 for (int j = 0; j < RG.Size(); )
12133 {
12134 coff = coff+nv;
12135 offset.push_back(coff);
12136 const int *p = VTKGeometry::VertexPermutation[geom];
12137 for (int k = 0; k < nv; k++, j++)
12138 {
12139 WriteBinaryOrASCII(os, buf, np + RG[p ? p[j] : j], " ",
12140 format);
12141 }
12142 if (format == VTKFormat::ASCII) { os << '\n'; }
12143 }
12144 np += RefG->RefPts.GetNPoints();
12145 }
12146 }
12147 if (format != VTKFormat::ASCII)
12148 {
12149 WriteBase64WithSizeAndClear(os, buf, compression_level);
12150 }
12151 os << "</DataArray>" << std::endl;
12152
12153 os << "<DataArray type=\"Int32\" Name=\"offsets\" format=\""
12154 << fmt_str << "\">" << std::endl;
12155 // offsets
12156 for (size_t ii=0; ii<offset.size(); ii++)
12157 {
12158 WriteBinaryOrASCII(os, buf, offset[ii], "\n", format);
12159 }
12160 if (format != VTKFormat::ASCII)
12161 {
12162 WriteBase64WithSizeAndClear(os, buf, compression_level);
12163 }
12164 os << "</DataArray>" << std::endl;
12165 os << "<DataArray type=\"UInt8\" Name=\"types\" format=\""
12166 << fmt_str << "\">" << std::endl;
12167 // cell types
12168 const int *vtk_geom_map =
12169 high_order_output ? VTKGeometry::HighOrderMap : VTKGeometry::Map;
12170 for (int i = 0; i < ne; i++)
12171 {
12172 Geometry::Type geom = get_geom(i);
12173 uint8_t vtk_cell_type = 5;
12174
12175 vtk_cell_type = vtk_geom_map[geom];
12176
12177 if (high_order_output)
12178 {
12179 WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
12180 }
12181 else
12182 {
12183 int nv = Geometries.GetVertices(geom)->GetNPoints();
12184 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12185 Array<int> &RG = RefG->RefGeoms;
12186 for (int j = 0; j < RG.Size(); j += nv)
12187 {
12188 WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
12189 }
12190 }
12191 }
12192 if (format != VTKFormat::ASCII)
12193 {
12194 WriteBase64WithSizeAndClear(os, buf, compression_level);
12195 }
12196 os << "</DataArray>" << std::endl;
12197 os << "</Cells>" << std::endl;
12198
12199 os << "<CellData Scalars=\"attribute\">" << std::endl;
12200 os << "<DataArray type=\"Int32\" Name=\"attribute\" format=\""
12201 << fmt_str << "\">" << std::endl;
12202 for (int i = 0; i < ne; i++)
12203 {
12204 int attr = bdr_elements ? GetBdrAttribute(i) : GetAttribute(i);
12205 if (high_order_output)
12206 {
12207 WriteBinaryOrASCII(os, buf, attr, "\n", format);
12208 }
12209 else
12210 {
12211 Geometry::Type geom = get_geom(i);
12212 int nv = Geometries.GetVertices(geom)->GetNPoints();
12213 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12214 for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
12215 {
12216 WriteBinaryOrASCII(os, buf, attr, "\n", format);
12217 }
12218 }
12219 }
12220 if (format != VTKFormat::ASCII)
12221 {
12222 WriteBase64WithSizeAndClear(os, buf, compression_level);
12223 }
12224 os << "</DataArray>" << std::endl;
12225 os << "</CellData>" << std::endl;
12226}
12227
12228
12229void Mesh::PrintVTK(std::ostream &os, int ref, int field_data)
12230{
12231 int np, nc, size;
12232 RefinedGeometry *RefG;
12233 DenseMatrix pmat;
12234
12235 os <<
12236 "# vtk DataFile Version 3.0\n"
12237 "Generated by MFEM\n"
12238 "ASCII\n"
12239 "DATASET UNSTRUCTURED_GRID\n";
12240
12241 // additional dataset information
12242 if (field_data)
12243 {
12244 os << "FIELD FieldData 1\n"
12245 << "MaterialIds " << 1 << " " << attributes.Size() << " int\n";
12246 for (int i = 0; i < attributes.Size(); i++)
12247 {
12248 os << ' ' << attributes[i];
12249 }
12250 os << '\n';
12251 }
12252
12253 // count the points, cells, size
12254 np = nc = size = 0;
12255 for (int i = 0; i < GetNE(); i++)
12256 {
12258 int nv = Geometries.GetVertices(geom)->GetNPoints();
12259 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12260 np += RefG->RefPts.GetNPoints();
12261 nc += RefG->RefGeoms.Size() / nv;
12262 size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
12263 }
12264 os << "POINTS " << np << " double\n";
12265 // write the points
12266 for (int i = 0; i < GetNE(); i++)
12267 {
12269 GetElementBaseGeometry(i), ref, 1);
12270
12271 GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
12272
12273 for (int j = 0; j < pmat.Width(); j++)
12274 {
12275 os << pmat(0, j) << ' ';
12276 if (pmat.Height() > 1)
12277 {
12278 os << pmat(1, j) << ' ';
12279 if (pmat.Height() > 2)
12280 {
12281 os << pmat(2, j);
12282 }
12283 else
12284 {
12285 os << 0.0;
12286 }
12287 }
12288 else
12289 {
12290 os << 0.0 << ' ' << 0.0;
12291 }
12292 os << '\n';
12293 }
12294 }
12295
12296 // write the cells
12297 os << "CELLS " << nc << ' ' << size << '\n';
12298 np = 0;
12299 for (int i = 0; i < GetNE(); i++)
12300 {
12302 int nv = Geometries.GetVertices(geom)->GetNPoints();
12303 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12304 Array<int> &RG = RefG->RefGeoms;
12305
12306 for (int j = 0; j < RG.Size(); )
12307 {
12308 os << nv;
12309 for (int k = 0; k < nv; k++, j++)
12310 {
12311 os << ' ' << np + RG[j];
12312 }
12313 os << '\n';
12314 }
12315 np += RefG->RefPts.GetNPoints();
12316 }
12317 os << "CELL_TYPES " << nc << '\n';
12318 for (int i = 0; i < GetNE(); i++)
12319 {
12321 int nv = Geometries.GetVertices(geom)->GetNPoints();
12322 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12323 Array<int> &RG = RefG->RefGeoms;
12324 int vtk_cell_type = VTKGeometry::Map[geom];
12325
12326 for (int j = 0; j < RG.Size(); j += nv)
12327 {
12328 os << vtk_cell_type << '\n';
12329 }
12330 }
12331 // write attributes (materials)
12332 os << "CELL_DATA " << nc << '\n'
12333 << "SCALARS material int\n"
12334 << "LOOKUP_TABLE default\n";
12335 for (int i = 0; i < GetNE(); i++)
12336 {
12338 int nv = Geometries.GetVertices(geom)->GetNPoints();
12339 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12340 int attr = GetAttribute(i);
12341 for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
12342 {
12343 os << attr << '\n';
12344 }
12345 }
12346
12347 if (Dim > 1)
12348 {
12349 Array<int> coloring;
12350 srand((unsigned)time(0));
12351 real_t a = rand_real();
12352 int el0 = (int)floor(a * GetNE());
12353 GetElementColoring(coloring, el0);
12354 os << "SCALARS element_coloring int\n"
12355 << "LOOKUP_TABLE default\n";
12356 for (int i = 0; i < GetNE(); i++)
12357 {
12359 int nv = Geometries.GetVertices(geom)->GetNPoints();
12360 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12361 for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
12362 {
12363 os << coloring[i] + 1 << '\n';
12364 }
12365 }
12366 }
12367
12368 // prepare to write data
12369 os << "POINT_DATA " << np << '\n' << flush;
12370}
12371
12373{
12374 int delete_el_to_el = (el_to_el) ? (0) : (1);
12375 const Table &el_el = ElementToElementTable();
12376 int num_el = GetNE(), stack_p, stack_top_p, max_num_col;
12377 Array<int> el_stack(num_el);
12378
12379 const int *i_el_el = el_el.GetI();
12380 const int *j_el_el = el_el.GetJ();
12381
12382 colors.SetSize(num_el);
12383 colors = -2;
12384 max_num_col = 1;
12385 stack_p = stack_top_p = 0;
12386 for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el)
12387 {
12388 if (colors[el] != -2)
12389 {
12390 continue;
12391 }
12392
12393 colors[el] = -1;
12394 el_stack[stack_top_p++] = el;
12395
12396 for ( ; stack_p < stack_top_p; stack_p++)
12397 {
12398 int i = el_stack[stack_p];
12399 int num_nb = i_el_el[i+1] - i_el_el[i];
12400 if (max_num_col < num_nb + 1)
12401 {
12402 max_num_col = num_nb + 1;
12403 }
12404 for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
12405 {
12406 int k = j_el_el[j];
12407 if (colors[k] == -2)
12408 {
12409 colors[k] = -1;
12410 el_stack[stack_top_p++] = k;
12411 }
12412 }
12413 }
12414 }
12415
12416 Array<int> col_marker(max_num_col);
12417
12418 for (stack_p = 0; stack_p < stack_top_p; stack_p++)
12419 {
12420 int i = el_stack[stack_p], col;
12421 col_marker = 0;
12422 for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
12423 {
12424 col = colors[j_el_el[j]];
12425 if (col != -1)
12426 {
12427 col_marker[col] = 1;
12428 }
12429 }
12430
12431 for (col = 0; col < max_num_col; col++)
12432 if (col_marker[col] == 0)
12433 {
12434 break;
12435 }
12436
12437 colors[i] = col;
12438 }
12439
12440 if (delete_el_to_el)
12441 {
12442 delete el_to_el;
12443 el_to_el = NULL;
12444 }
12445}
12446
12447void Mesh::PrintWithPartitioning(int *partitioning, std::ostream &os,
12448 int elem_attr) const
12449{
12450 if (Dim != 3 && Dim != 2) { return; }
12451
12452 int i, j, k, l, nv, nbe, *v;
12453
12454 os << "MFEM mesh v1.0\n";
12455
12456 // optional
12457 os <<
12458 "\n#\n# MFEM Geometry Types (see fem/geom.hpp):\n#\n"
12459 "# POINT = 0\n"
12460 "# SEGMENT = 1\n"
12461 "# TRIANGLE = 2\n"
12462 "# SQUARE = 3\n"
12463 "# TETRAHEDRON = 4\n"
12464 "# CUBE = 5\n"
12465 "# PRISM = 6\n"
12466 "#\n";
12467
12468 os << "\ndimension\n" << Dim
12469 << "\n\nelements\n" << NumOfElements << '\n';
12470 for (i = 0; i < NumOfElements; i++)
12471 {
12472 os << int((elem_attr) ? partitioning[i]+1 : elements[i]->GetAttribute())
12473 << ' ' << elements[i]->GetGeometryType();
12474 nv = elements[i]->GetNVertices();
12475 v = elements[i]->GetVertices();
12476 for (j = 0; j < nv; j++)
12477 {
12478 os << ' ' << v[j];
12479 }
12480 os << '\n';
12481 }
12482 nbe = 0;
12483 for (i = 0; i < faces_info.Size(); i++)
12484 {
12485 if ((l = faces_info[i].Elem2No) >= 0)
12486 {
12487 k = partitioning[faces_info[i].Elem1No];
12488 l = partitioning[l];
12489 if (k != l)
12490 {
12491 nbe++;
12492 if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
12493 {
12494 nbe++;
12495 }
12496 }
12497 }
12498 else
12499 {
12500 nbe++;
12501 }
12502 }
12503 os << "\nboundary\n" << nbe << '\n';
12504 for (i = 0; i < faces_info.Size(); i++)
12505 {
12506 if ((l = faces_info[i].Elem2No) >= 0)
12507 {
12508 k = partitioning[faces_info[i].Elem1No];
12509 l = partitioning[l];
12510 if (k != l)
12511 {
12512 nv = faces[i]->GetNVertices();
12513 v = faces[i]->GetVertices();
12514 os << k+1 << ' ' << faces[i]->GetGeometryType();
12515 for (j = 0; j < nv; j++)
12516 {
12517 os << ' ' << v[j];
12518 }
12519 os << '\n';
12520 if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
12521 {
12522 os << l+1 << ' ' << faces[i]->GetGeometryType();
12523 for (j = nv-1; j >= 0; j--)
12524 {
12525 os << ' ' << v[j];
12526 }
12527 os << '\n';
12528 }
12529 }
12530 }
12531 else
12532 {
12533 k = partitioning[faces_info[i].Elem1No];
12534 nv = faces[i]->GetNVertices();
12535 v = faces[i]->GetVertices();
12536 os << k+1 << ' ' << faces[i]->GetGeometryType();
12537 for (j = 0; j < nv; j++)
12538 {
12539 os << ' ' << v[j];
12540 }
12541 os << '\n';
12542 }
12543 }
12544 os << "\nvertices\n" << NumOfVertices << '\n';
12545 if (Nodes == NULL)
12546 {
12547 os << spaceDim << '\n';
12548 for (i = 0; i < NumOfVertices; i++)
12549 {
12550 os << vertices[i](0);
12551 for (j = 1; j < spaceDim; j++)
12552 {
12553 os << ' ' << vertices[i](j);
12554 }
12555 os << '\n';
12556 }
12557 os.flush();
12558 }
12559 else
12560 {
12561 os << "\nnodes\n";
12562 Nodes->Save(os);
12563 }
12564}
12565
12567 std::ostream &os,
12568 int interior_faces)
12569{
12570 MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported\n");
12571 if (Dim != 3 && Dim != 2) { return; }
12572
12573 int *vcount = new int[NumOfVertices];
12574 for (int i = 0; i < NumOfVertices; i++)
12575 {
12576 vcount[i] = 0;
12577 }
12578 for (int i = 0; i < NumOfElements; i++)
12579 {
12580 int nv = elements[i]->GetNVertices();
12581 const int *ind = elements[i]->GetVertices();
12582 for (int j = 0; j < nv; j++)
12583 {
12584 vcount[ind[j]]++;
12585 }
12586 }
12587
12588 int *voff = new int[NumOfVertices+1];
12589 voff[0] = 0;
12590 for (int i = 1; i <= NumOfVertices; i++)
12591 {
12592 voff[i] = vcount[i-1] + voff[i-1];
12593 }
12594
12595 int **vown = new int*[NumOfVertices];
12596 for (int i = 0; i < NumOfVertices; i++)
12597 {
12598 vown[i] = new int[vcount[i]];
12599 }
12600
12601 // 2D
12602 if (Dim == 2)
12603 {
12604 Table edge_el;
12605 Transpose(ElementToEdgeTable(), edge_el);
12606
12607 // Fake printing of the elements.
12608 for (int i = 0; i < NumOfElements; i++)
12609 {
12610 int nv = elements[i]->GetNVertices();
12611 const int *ind = elements[i]->GetVertices();
12612 for (int j = 0; j < nv; j++)
12613 {
12614 vcount[ind[j]]--;
12615 vown[ind[j]][vcount[ind[j]]] = i;
12616 }
12617 }
12618
12619 for (int i = 0; i < NumOfVertices; i++)
12620 {
12621 vcount[i] = voff[i+1] - voff[i];
12622 }
12623
12624 int nbe = 0;
12625 for (int i = 0; i < edge_el.Size(); i++)
12626 {
12627 const int *el = edge_el.GetRow(i);
12628 if (edge_el.RowSize(i) > 1)
12629 {
12630 int k = partitioning[el[0]];
12631 int l = partitioning[el[1]];
12632 if (interior_faces || k != l)
12633 {
12634 nbe += 2;
12635 }
12636 }
12637 else
12638 {
12639 nbe++;
12640 }
12641 }
12642
12643 // Print the type of the mesh and the boundary elements.
12644 os << "areamesh2\n\n" << nbe << '\n';
12645
12646 for (int i = 0; i < edge_el.Size(); i++)
12647 {
12648 const int *el = edge_el.GetRow(i);
12649 if (edge_el.RowSize(i) > 1)
12650 {
12651 int k = partitioning[el[0]];
12652 int l = partitioning[el[1]];
12653 if (interior_faces || k != l)
12654 {
12655 Array<int> ev;
12656 GetEdgeVertices(i,ev);
12657 os << k+1; // attribute
12658 for (int j = 0; j < 2; j++)
12659 for (int s = 0; s < vcount[ev[j]]; s++)
12660 if (vown[ev[j]][s] == el[0])
12661 {
12662 os << ' ' << voff[ev[j]]+s+1;
12663 }
12664 os << '\n';
12665 os << l+1; // attribute
12666 for (int j = 1; j >= 0; j--)
12667 for (int s = 0; s < vcount[ev[j]]; s++)
12668 if (vown[ev[j]][s] == el[1])
12669 {
12670 os << ' ' << voff[ev[j]]+s+1;
12671 }
12672 os << '\n';
12673 }
12674 }
12675 else
12676 {
12677 int k = partitioning[el[0]];
12678 Array<int> ev;
12679 GetEdgeVertices(i,ev);
12680 os << k+1; // attribute
12681 for (int j = 0; j < 2; j++)
12682 for (int s = 0; s < vcount[ev[j]]; s++)
12683 if (vown[ev[j]][s] == el[0])
12684 {
12685 os << ' ' << voff[ev[j]]+s+1;
12686 }
12687 os << '\n';
12688 }
12689 }
12690
12691 // Print the elements.
12692 os << NumOfElements << '\n';
12693 for (int i = 0; i < NumOfElements; i++)
12694 {
12695 int nv = elements[i]->GetNVertices();
12696 const int *ind = elements[i]->GetVertices();
12697 os << partitioning[i]+1 << ' '; // use subdomain number as attribute
12698 os << nv << ' ';
12699 for (int j = 0; j < nv; j++)
12700 {
12701 os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
12702 vown[ind[j]][vcount[ind[j]]] = i;
12703 }
12704 os << '\n';
12705 }
12706
12707 for (int i = 0; i < NumOfVertices; i++)
12708 {
12709 vcount[i] = voff[i+1] - voff[i];
12710 }
12711
12712 // Print the vertices.
12713 os << voff[NumOfVertices] << '\n';
12714 for (int i = 0; i < NumOfVertices; i++)
12715 for (int k = 0; k < vcount[i]; k++)
12716 {
12717 for (int j = 0; j < Dim; j++)
12718 {
12719 os << vertices[i](j) << ' ';
12720 }
12721 os << '\n';
12722 }
12723 }
12724 // Dim is 3
12725 else if (meshgen == 1)
12726 {
12727 os << "NETGEN_Neutral_Format\n";
12728 // print the vertices
12729 os << voff[NumOfVertices] << '\n';
12730 for (int i = 0; i < NumOfVertices; i++)
12731 for (int k = 0; k < vcount[i]; k++)
12732 {
12733 for (int j = 0; j < Dim; j++)
12734 {
12735 os << ' ' << vertices[i](j);
12736 }
12737 os << '\n';
12738 }
12739
12740 // print the elements
12741 os << NumOfElements << '\n';
12742 for (int i = 0; i < NumOfElements; i++)
12743 {
12744 int nv = elements[i]->GetNVertices();
12745 const int *ind = elements[i]->GetVertices();
12746 os << partitioning[i]+1; // use subdomain number as attribute
12747 for (int j = 0; j < nv; j++)
12748 {
12749 os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
12750 vown[ind[j]][vcount[ind[j]]] = i;
12751 }
12752 os << '\n';
12753 }
12754
12755 for (int i = 0; i < NumOfVertices; i++)
12756 {
12757 vcount[i] = voff[i+1] - voff[i];
12758 }
12759
12760 // print the boundary information.
12761 int nbe = 0;
12762 for (int i = 0; i < NumOfFaces; i++)
12763 {
12764 int l = faces_info[i].Elem2No;
12765 if (l >= 0)
12766 {
12767 int k = partitioning[faces_info[i].Elem1No];
12768 l = partitioning[l];
12769 if (interior_faces || k != l)
12770 {
12771 nbe += 2;
12772 }
12773 }
12774 else
12775 {
12776 nbe++;
12777 }
12778 }
12779
12780 os << nbe << '\n';
12781 for (int i = 0; i < NumOfFaces; i++)
12782 {
12783 int l = faces_info[i].Elem2No;
12784 if (l >= 0)
12785 {
12786 int k = partitioning[faces_info[i].Elem1No];
12787 l = partitioning[l];
12788 if (interior_faces || k != l)
12789 {
12790 int nv = faces[i]->GetNVertices();
12791 const int *ind = faces[i]->GetVertices();
12792 os << k+1; // attribute
12793 for (int j = 0; j < nv; j++)
12794 for (int s = 0; s < vcount[ind[j]]; s++)
12795 if (vown[ind[j]][s] == faces_info[i].Elem1No)
12796 {
12797 os << ' ' << voff[ind[j]]+s+1;
12798 }
12799 os << '\n';
12800 os << l+1; // attribute
12801 for (int j = nv-1; j >= 0; j--)
12802 for (int s = 0; s < vcount[ind[j]]; s++)
12803 if (vown[ind[j]][s] == faces_info[i].Elem2No)
12804 {
12805 os << ' ' << voff[ind[j]]+s+1;
12806 }
12807 os << '\n';
12808 }
12809 }
12810 else
12811 {
12812 int k = partitioning[faces_info[i].Elem1No];
12813 int nv = faces[i]->GetNVertices();
12814 const int *ind = faces[i]->GetVertices();
12815 os << k+1; // attribute
12816 for (int j = 0; j < nv; j++)
12817 for (int s = 0; s < vcount[ind[j]]; s++)
12818 if (vown[ind[j]][s] == faces_info[i].Elem1No)
12819 {
12820 os << ' ' << voff[ind[j]]+s+1;
12821 }
12822 os << '\n';
12823 }
12824 }
12825 }
12826 // Dim is 3
12827 else if (meshgen == 2) // TrueGrid
12828 {
12829 // count the number of the boundary elements.
12830 int nbe = 0;
12831 for (int i = 0; i < NumOfFaces; i++)
12832 {
12833 int l = faces_info[i].Elem2No;
12834 if (l >= 0)
12835 {
12836 int k = partitioning[faces_info[i].Elem1No];
12837 l = partitioning[l];
12838 if (interior_faces || k != l)
12839 {
12840 nbe += 2;
12841 }
12842 }
12843 else
12844 {
12845 nbe++;
12846 }
12847 }
12848
12849 os << "TrueGrid\n"
12850 << "1 " << voff[NumOfVertices] << " " << NumOfElements
12851 << " 0 0 0 0 0 0 0\n"
12852 << "0 0 0 1 0 0 0 0 0 0 0\n"
12853 << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
12854 << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
12855 << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
12856
12857 for (int i = 0; i < NumOfVertices; i++)
12858 for (int k = 0; k < vcount[i]; k++)
12859 os << voff[i]+k << " 0.0 " << vertices[i](0) << ' '
12860 << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n";
12861
12862 for (int i = 0; i < NumOfElements; i++)
12863 {
12864 int nv = elements[i]->GetNVertices();
12865 const int *ind = elements[i]->GetVertices();
12866 os << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute
12867 for (int j = 0; j < nv; j++)
12868 {
12869 os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
12870 vown[ind[j]][vcount[ind[j]]] = i;
12871 }
12872 os << '\n';
12873 }
12874
12875 for (int i = 0; i < NumOfVertices; i++)
12876 {
12877 vcount[i] = voff[i+1] - voff[i];
12878 }
12879
12880 // boundary elements
12881 for (int i = 0; i < NumOfFaces; i++)
12882 {
12883 int l = faces_info[i].Elem2No;
12884 if (l >= 0)
12885 {
12886 int k = partitioning[faces_info[i].Elem1No];
12887 l = partitioning[l];
12888 if (interior_faces || k != l)
12889 {
12890 int nv = faces[i]->GetNVertices();
12891 const int *ind = faces[i]->GetVertices();
12892 os << k+1; // attribute
12893 for (int j = 0; j < nv; j++)
12894 for (int s = 0; s < vcount[ind[j]]; s++)
12895 if (vown[ind[j]][s] == faces_info[i].Elem1No)
12896 {
12897 os << ' ' << voff[ind[j]]+s+1;
12898 }
12899 os << " 1.0 1.0 1.0 1.0\n";
12900 os << l+1; // attribute
12901 for (int j = nv-1; j >= 0; j--)
12902 for (int s = 0; s < vcount[ind[j]]; s++)
12903 if (vown[ind[j]][s] == faces_info[i].Elem2No)
12904 {
12905 os << ' ' << voff[ind[j]]+s+1;
12906 }
12907 os << " 1.0 1.0 1.0 1.0\n";
12908 }
12909 }
12910 else
12911 {
12912 int k = partitioning[faces_info[i].Elem1No];
12913 int nv = faces[i]->GetNVertices();
12914 const int *ind = faces[i]->GetVertices();
12915 os << k+1; // attribute
12916 for (int j = 0; j < nv; j++)
12917 for (int s = 0; s < vcount[ind[j]]; s++)
12918 if (vown[ind[j]][s] == faces_info[i].Elem1No)
12919 {
12920 os << ' ' << voff[ind[j]]+s+1;
12921 }
12922 os << " 1.0 1.0 1.0 1.0\n";
12923 }
12924 }
12925 }
12926
12927 os << flush;
12928
12929 for (int i = 0; i < NumOfVertices; i++)
12930 {
12931 delete [] vown[i];
12932 }
12933
12934 delete [] vcount;
12935 delete [] voff;
12936 delete [] vown;
12937}
12938
12939void Mesh::PrintSurfaces(const Table & Aface_face, std::ostream &os) const
12940{
12941 int i, j;
12942
12943 if (NURBSext)
12944 {
12945 mfem_error("Mesh::PrintSurfaces"
12946 " NURBS mesh is not supported!");
12947 return;
12948 }
12949
12950 os << "MFEM mesh v1.0\n";
12951
12952 // optional
12953 os <<
12954 "\n#\n# MFEM Geometry Types (see fem/geom.hpp):\n#\n"
12955 "# POINT = 0\n"
12956 "# SEGMENT = 1\n"
12957 "# TRIANGLE = 2\n"
12958 "# SQUARE = 3\n"
12959 "# TETRAHEDRON = 4\n"
12960 "# CUBE = 5\n"
12961 "# PRISM = 6\n"
12962 "#\n";
12963
12964 os << "\ndimension\n" << Dim
12965 << "\n\nelements\n" << NumOfElements << '\n';
12966 for (i = 0; i < NumOfElements; i++)
12967 {
12968 PrintElement(elements[i], os);
12969 }
12970
12971 os << "\nboundary\n" << Aface_face.Size_of_connections() << '\n';
12972 const int * const i_AF_f = Aface_face.GetI();
12973 const int * const j_AF_f = Aface_face.GetJ();
12974
12975 for (int iAF=0; iAF < Aface_face.Size(); ++iAF)
12976 for (const int * iface = j_AF_f + i_AF_f[iAF];
12977 iface < j_AF_f + i_AF_f[iAF+1];
12978 ++iface)
12979 {
12980 os << iAF+1 << ' ';
12981 PrintElementWithoutAttr(faces[*iface],os);
12982 }
12983
12984 os << "\nvertices\n" << NumOfVertices << '\n';
12985 if (Nodes == NULL)
12986 {
12987 os << spaceDim << '\n';
12988 for (i = 0; i < NumOfVertices; i++)
12989 {
12990 os << vertices[i](0);
12991 for (j = 1; j < spaceDim; j++)
12992 {
12993 os << ' ' << vertices[i](j);
12994 }
12995 os << '\n';
12996 }
12997 os.flush();
12998 }
12999 else
13000 {
13001 os << "\nnodes\n";
13002 Nodes->Save(os);
13003 }
13004}
13005
13007{
13008 int i,j,k;
13009 Array<int> vert;
13010 DenseMatrix pointmat;
13011 int na = attributes.Size();
13012 real_t *cg = new real_t[na*spaceDim];
13013 int *nbea = new int[na];
13014
13015 int *vn = new int[NumOfVertices];
13016 for (i = 0; i < NumOfVertices; i++)
13017 {
13018 vn[i] = 0;
13019 }
13020 for (i = 0; i < na; i++)
13021 {
13022 for (j = 0; j < spaceDim; j++)
13023 {
13024 cg[i*spaceDim+j] = 0.0;
13025 }
13026 nbea[i] = 0;
13027 }
13028
13029 for (i = 0; i < NumOfElements; i++)
13030 {
13031 GetElementVertices(i, vert);
13032 for (k = 0; k < vert.Size(); k++)
13033 {
13034 vn[vert[k]] = 1;
13035 }
13036 }
13037
13038 for (i = 0; i < NumOfElements; i++)
13039 {
13040 int bea = GetAttribute(i)-1;
13041 GetPointMatrix(i, pointmat);
13042 GetElementVertices(i, vert);
13043
13044 for (k = 0; k < vert.Size(); k++)
13045 if (vn[vert[k]] == 1)
13046 {
13047 nbea[bea]++;
13048 for (j = 0; j < spaceDim; j++)
13049 {
13050 cg[bea*spaceDim+j] += pointmat(j,k);
13051 }
13052 vn[vert[k]] = 2;
13053 }
13054 }
13055
13056 for (i = 0; i < NumOfElements; i++)
13057 {
13058 int bea = GetAttribute(i)-1;
13059 GetElementVertices (i, vert);
13060
13061 for (k = 0; k < vert.Size(); k++)
13062 if (vn[vert[k]])
13063 {
13064 for (j = 0; j < spaceDim; j++)
13065 vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
13066 (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
13067 vn[vert[k]] = 0;
13068 }
13069 }
13070
13071 delete [] cg;
13072 delete [] nbea;
13073 delete [] vn;
13074}
13075
13077{
13078 int i,j,k;
13079 Array<int> vert;
13080 DenseMatrix pointmat;
13081 int na = NumOfElements;
13082 real_t *cg = new real_t[na*spaceDim];
13083 int *nbea = new int[na];
13084
13085 int *vn = new int[NumOfVertices];
13086 for (i = 0; i < NumOfVertices; i++)
13087 {
13088 vn[i] = 0;
13089 }
13090 for (i = 0; i < na; i++)
13091 {
13092 for (j = 0; j < spaceDim; j++)
13093 {
13094 cg[i*spaceDim+j] = 0.0;
13095 }
13096 nbea[i] = 0;
13097 }
13098
13099 for (i = 0; i < NumOfElements; i++)
13100 {
13101 GetElementVertices(i, vert);
13102 for (k = 0; k < vert.Size(); k++)
13103 {
13104 vn[vert[k]] = 1;
13105 }
13106 }
13107
13108 for (i = 0; i < NumOfElements; i++)
13109 {
13110 int bea = i;
13111 GetPointMatrix(i, pointmat);
13112 GetElementVertices(i, vert);
13113
13114 for (k = 0; k < vert.Size(); k++)
13115 if (vn[vert[k]] == 1)
13116 {
13117 nbea[bea]++;
13118 for (j = 0; j < spaceDim; j++)
13119 {
13120 cg[bea*spaceDim+j] += pointmat(j,k);
13121 }
13122 vn[vert[k]] = 2;
13123 }
13124 }
13125
13126 for (i = 0; i < NumOfElements; i++)
13127 {
13128 int bea = i;
13129 GetElementVertices(i, vert);
13130
13131 for (k = 0; k < vert.Size(); k++)
13132 if (vn[vert[k]])
13133 {
13134 for (j = 0; j < spaceDim; j++)
13135 vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
13136 (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
13137 vn[vert[k]] = 0;
13138 }
13139 }
13140
13141 delete [] cg;
13142 delete [] nbea;
13143 delete [] vn;
13144}
13145
13146void Mesh::Transform(void (*f)(const Vector&, Vector&))
13147{
13148 // TODO: support for different new spaceDim.
13149 if (Nodes == NULL)
13150 {
13151 Vector vold(spaceDim), vnew(NULL, spaceDim);
13152 for (int i = 0; i < vertices.Size(); i++)
13153 {
13154 for (int j = 0; j < spaceDim; j++)
13155 {
13156 vold(j) = vertices[i](j);
13157 }
13158 vnew.SetData(vertices[i]());
13159 (*f)(vold, vnew);
13160 }
13161 }
13162 else
13163 {
13164 GridFunction xnew(Nodes->FESpace());
13166 xnew.ProjectCoefficient(f_pert);
13167 *Nodes = xnew;
13168 }
13169 NodesUpdated();
13170}
13171
13173{
13174 MFEM_VERIFY(spaceDim == deformation.GetVDim(),
13175 "incompatible vector dimensions");
13176 if (Nodes == NULL)
13177 {
13180 GridFunction xnew(&fes);
13181 xnew.ProjectCoefficient(deformation);
13182 for (int i = 0; i < NumOfVertices; i++)
13183 for (int d = 0; d < spaceDim; d++)
13184 {
13185 vertices[i](d) = xnew(d + spaceDim*i);
13186 }
13187 }
13188 else
13189 {
13190 GridFunction xnew(Nodes->FESpace());
13191 xnew.ProjectCoefficient(deformation);
13192 *Nodes = xnew;
13193 }
13194 NodesUpdated();
13195}
13196
13198{
13199 if (NURBSext || ncmesh) { return; }
13200
13201 Array<int> v2v(GetNV());
13202 v2v = -1;
13203 for (int i = 0; i < GetNE(); i++)
13204 {
13205 Element *el = GetElement(i);
13206 int nv = el->GetNVertices();
13207 int *v = el->GetVertices();
13208 for (int j = 0; j < nv; j++)
13209 {
13210 v2v[v[j]] = 0;
13211 }
13212 }
13213 for (int i = 0; i < GetNBE(); i++)
13214 {
13215 Element *el = GetBdrElement(i);
13216 int *v = el->GetVertices();
13217 int nv = el->GetNVertices();
13218 for (int j = 0; j < nv; j++)
13219 {
13220 v2v[v[j]] = 0;
13221 }
13222 }
13223 int num_vert = 0;
13224 for (int i = 0; i < v2v.Size(); i++)
13225 {
13226 if (v2v[i] == 0)
13227 {
13228 vertices[num_vert] = vertices[i];
13229 v2v[i] = num_vert++;
13230 }
13231 }
13232
13233 if (num_vert == v2v.Size()) { return; }
13234
13235 Vector nodes_by_element;
13236 Array<int> vdofs;
13237 if (Nodes)
13238 {
13239 int s = 0;
13240 for (int i = 0; i < GetNE(); i++)
13241 {
13242 Nodes->FESpace()->GetElementVDofs(i, vdofs);
13243 s += vdofs.Size();
13244 }
13245 nodes_by_element.SetSize(s);
13246 s = 0;
13247 for (int i = 0; i < GetNE(); i++)
13248 {
13249 Nodes->FESpace()->GetElementVDofs(i, vdofs);
13250 Nodes->GetSubVector(vdofs, &nodes_by_element(s));
13251 s += vdofs.Size();
13252 }
13253 }
13254 vertices.SetSize(num_vert);
13255 NumOfVertices = num_vert;
13256 for (int i = 0; i < GetNE(); i++)
13257 {
13258 Element *el = GetElement(i);
13259 int *v = el->GetVertices();
13260 int nv = el->GetNVertices();
13261 for (int j = 0; j < nv; j++)
13262 {
13263 v[j] = v2v[v[j]];
13264 }
13265 }
13266 for (int i = 0; i < GetNBE(); i++)
13267 {
13268 Element *el = GetBdrElement(i);
13269 int *v = el->GetVertices();
13270 int nv = el->GetNVertices();
13271 for (int j = 0; j < nv; j++)
13272 {
13273 v[j] = v2v[v[j]];
13274 }
13275 }
13276 DeleteTables();
13277 if (Dim > 1)
13278 {
13279 // generate el_to_edge, be_to_face (2D), bel_to_edge (3D)
13280 el_to_edge = new Table;
13282 }
13283 if (Dim > 2)
13284 {
13285 // generate el_to_face, be_to_face
13287 }
13288 // Update faces and faces_info
13289 GenerateFaces();
13290 if (Nodes)
13291 {
13292 Nodes->FESpace()->Update();
13293 Nodes->Update();
13294 int s = 0;
13295 for (int i = 0; i < GetNE(); i++)
13296 {
13297 Nodes->FESpace()->GetElementVDofs(i, vdofs);
13298 Nodes->SetSubVector(vdofs, &nodes_by_element(s));
13299 s += vdofs.Size();
13300 }
13301 }
13302}
13303
13305{
13306 if (NURBSext || ncmesh) { return; }
13307
13308 int num_bdr_elem = 0;
13309 int new_bel_to_edge_nnz = 0;
13310 for (int i = 0; i < GetNBE(); i++)
13311 {
13313 {
13315 }
13316 else
13317 {
13318 num_bdr_elem++;
13319 if (Dim == 3)
13320 {
13321 new_bel_to_edge_nnz += bel_to_edge->RowSize(i);
13322 }
13323 }
13324 }
13325
13326 if (num_bdr_elem == GetNBE()) { return; }
13327
13328 Array<Element *> new_boundary(num_bdr_elem);
13329 Array<int> new_be_to_face;
13330 Table *new_bel_to_edge = NULL;
13331 new_boundary.SetSize(0);
13332 new_be_to_face.Reserve(num_bdr_elem);
13333 if (Dim == 3)
13334 {
13335 new_bel_to_edge = new Table;
13336 new_bel_to_edge->SetDims(num_bdr_elem, new_bel_to_edge_nnz);
13337 }
13338 for (int i = 0; i < GetNBE(); i++)
13339 {
13341 {
13342 new_boundary.Append(boundary[i]);
13343 int row = new_be_to_face.Size();
13344 new_be_to_face.Append(be_to_face[i]);
13345 if (Dim == 3)
13346 {
13347 int *e = bel_to_edge->GetRow(i);
13348 int ne = bel_to_edge->RowSize(i);
13349 int *new_e = new_bel_to_edge->GetRow(row);
13350 for (int j = 0; j < ne; j++)
13351 {
13352 new_e[j] = e[j];
13353 }
13354 new_bel_to_edge->GetI()[row+1] = new_bel_to_edge->GetI()[row] + ne;
13355 }
13356 }
13357 }
13358
13359 NumOfBdrElements = new_boundary.Size();
13360 mfem::Swap(boundary, new_boundary);
13361
13362 mfem::Swap(be_to_face, new_be_to_face);
13363
13364 if (Dim == 3)
13365 {
13366 delete bel_to_edge;
13367 bel_to_edge = new_bel_to_edge;
13368 }
13369
13370 Array<int> attribs(num_bdr_elem);
13371 for (int i = 0; i < attribs.Size(); i++)
13372 {
13373 attribs[i] = GetBdrAttribute(i);
13374 }
13375 attribs.Sort();
13376 attribs.Unique();
13378 attribs.Copy(bdr_attributes);
13379}
13380
13382{
13383#ifdef MFEM_USE_MEMALLOC
13384 if (E)
13385 {
13386 if (E->GetType() == Element::TETRAHEDRON)
13387 {
13388 TetMemory.Free((Tetrahedron*) E);
13389 }
13390 else
13391 {
13392 delete E;
13393 }
13394 }
13395#else
13396 delete E;
13397#endif
13398}
13399
13400std::ostream &operator<<(std::ostream &os, const Mesh &mesh)
13401{
13402 mesh.Print(os);
13403 return os;
13404}
13405
13406int Mesh::FindPoints(DenseMatrix &point_mat, Array<int>& elem_ids,
13407 Array<IntegrationPoint>& ips, bool warn,
13409{
13410 const int npts = point_mat.Width();
13411 if (!npts) { return 0; }
13412 MFEM_VERIFY(point_mat.Height() == spaceDim,"Invalid points matrix");
13413 elem_ids.SetSize(npts);
13414 ips.SetSize(npts);
13415 elem_ids = -1;
13416 if (!GetNE()) { return 0; }
13417
13418 real_t *data = point_mat.GetData();
13419 InverseElementTransformation *inv_tr = inv_trans;
13420 inv_tr = inv_tr ? inv_tr : new InverseElementTransformation;
13421
13422 // For each point in 'point_mat', find the element whose center is closest.
13423 Vector min_dist(npts);
13424 Array<int> e_idx(npts);
13425 min_dist = std::numeric_limits<real_t>::max();
13426 e_idx = -1;
13427
13428 Vector pt(spaceDim);
13429 for (int i = 0; i < GetNE(); i++)
13430 {
13431 GetElementTransformation(i)->Transform(
13433 for (int k = 0; k < npts; k++)
13434 {
13435 real_t dist = pt.DistanceTo(data+k*spaceDim);
13436 if (dist < min_dist(k))
13437 {
13438 min_dist(k) = dist;
13439 e_idx[k] = i;
13440 }
13441 }
13442 }
13443
13444 // Checks if the points lie in the closest element
13445 int pts_found = 0;
13446 pt.NewDataAndSize(NULL, spaceDim);
13447 for (int k = 0; k < npts; k++)
13448 {
13449 pt.SetData(data+k*spaceDim);
13450 inv_tr->SetTransformation(*GetElementTransformation(e_idx[k]));
13451 int res = inv_tr->Transform(pt, ips[k]);
13453 {
13454 elem_ids[k] = e_idx[k];
13455 pts_found++;
13456 }
13457 }
13458 if (pts_found != npts)
13459 {
13460 Array<int> elvertices;
13461 Table *vtoel = GetVertexToElementTable();
13462 for (int k = 0; k < npts; k++)
13463 {
13464 if (elem_ids[k] != -1) { continue; }
13465 // Try all vertex-neighbors of element e_idx[k]
13466 pt.SetData(data+k*spaceDim);
13467 GetElementVertices(e_idx[k], elvertices);
13468 for (int v = 0; v < elvertices.Size(); v++)
13469 {
13470 int vv = elvertices[v];
13471 int ne = vtoel->RowSize(vv);
13472 const int* els = vtoel->GetRow(vv);
13473 for (int e = 0; e < ne; e++)
13474 {
13475 if (els[e] == e_idx[k]) { continue; }
13477 int res = inv_tr->Transform(pt, ips[k]);
13479 {
13480 elem_ids[k] = els[e];
13481 pts_found++;
13482 goto next_point;
13483 }
13484 }
13485 }
13486 // Try neighbors for non-conforming meshes
13487 if (ncmesh)
13488 {
13489 Array<int> neigh;
13490 int le = ncmesh->leaf_elements[e_idx[k]];
13491 ncmesh->FindNeighbors(le,neigh);
13492 for (int e = 0; e < neigh.Size(); e++)
13493 {
13494 int nn = neigh[e];
13495 if (ncmesh->IsGhost(ncmesh->elements[nn])) { continue; }
13496 int el = ncmesh->elements[nn].index;
13498 int res = inv_tr->Transform(pt, ips[k]);
13500 {
13501 elem_ids[k] = el;
13502 pts_found++;
13503 goto next_point;
13504 }
13505 }
13506 }
13507 next_point: ;
13508 }
13509 delete vtoel;
13510 }
13511 if (inv_trans == NULL) { delete inv_tr; }
13512
13513 if (warn && pts_found != npts)
13514 {
13515 MFEM_WARNING((npts-pts_found) << " points were not found");
13516 }
13517 return pts_found;
13518}
13519
13521 real_t &volume,
13522 Vector &aspr,
13523 Vector &skew,
13524 Vector &ori) const
13525{
13526 J.HostRead();
13527 aspr.HostWrite();
13528 skew.HostWrite();
13529 ori.HostWrite();
13530 MFEM_VERIFY(Dim == 2 || Dim == 3, "Only 2D/3D meshes supported right now.");
13531 MFEM_VERIFY(Dim == spaceDim, "Surface meshes not currently supported.");
13532 if (Dim == 2)
13533 {
13534 aspr.SetSize(1);
13535 skew.SetSize(1);
13536 ori.SetSize(1);
13537 Vector col1, col2;
13538 J.GetColumn(0, col1);
13539 J.GetColumn(1, col2);
13540
13541 // Area/Volume
13542 volume = J.Det();
13543
13544 // Aspect-ratio
13545 aspr(0) = col2.Norml2()/col1.Norml2();
13546
13547 // Skewness
13548 skew(0) = std::atan2(J.Det(), col1 * col2);
13549
13550 // Orientation
13551 ori(0) = std::atan2(J(1,0), J(0,0));
13552 }
13553 else if (Dim == 3)
13554 {
13555 aspr.SetSize(4);
13556 skew.SetSize(3);
13557 ori.SetSize(4);
13558 Vector col1, col2, col3;
13559 J.GetColumn(0, col1);
13560 J.GetColumn(1, col2);
13561 J.GetColumn(2, col3);
13562 real_t len1 = col1.Norml2(),
13563 len2 = col2.Norml2(),
13564 len3 = col3.Norml2();
13565
13566 Vector col1unit = col1,
13567 col2unit = col2,
13568 col3unit = col3;
13569 col1unit *= 1.0/len1;
13570 col2unit *= 1.0/len2;
13571 col3unit *= 1.0/len3;
13572
13573 // Area/Volume
13574 volume = J.Det();
13575
13576 // Aspect-ratio - non-dimensional
13577 aspr(0) = len1/std::sqrt(len2*len3),
13578 aspr(1) = len2/std::sqrt(len1*len3);
13579
13580 // Aspect-ratio - dimensional - needed for TMOP
13581 aspr(2) = std::sqrt(len1/(len2*len3)),
13582 aspr(3) = std::sqrt(len2/(len1*len3));
13583
13584 // Skewness
13585 Vector crosscol12, crosscol13;
13586 col1.cross3D(col2, crosscol12);
13587 col1.cross3D(col3, crosscol13);
13588 skew(0) = std::acos(col1unit*col2unit);
13589 skew(1) = std::acos(col1unit*col3unit);
13590 skew(2) = std::atan(len1*volume/(crosscol12*crosscol13));
13591
13592 // Orientation
13593 // First we define the rotation matrix
13594 DenseMatrix rot(Dim);
13595 // First column
13596 for (int d=0; d<Dim; d++) { rot(d, 0) = col1unit(d); }
13597 // Second column
13598 Vector rot2 = col2unit;
13599 Vector rot1 = col1unit;
13600 rot1 *= col1unit*col2unit;
13601 rot2 -= rot1;
13602 col1unit.cross3D(col2unit, rot1);
13603 rot2 /= rot1.Norml2();
13604 for (int d=0; d < Dim; d++) { rot(d, 1) = rot2(d); }
13605 // Third column
13606 rot1 /= rot1.Norml2();
13607 for (int d=0; d < Dim; d++) { rot(d, 2) = rot1(d); }
13608 real_t delta = sqrt(pow(rot(2,1)-rot(1,2), 2.0) +
13609 pow(rot(0,2)-rot(2,0), 2.0) +
13610 pow(rot(1,0)-rot(0,1), 2.0));
13611 ori = 0.0;
13612 if (delta == 0.0) // Matrix is symmetric. Check if it is Identity.
13613 {
13614 DenseMatrix Iden(Dim);
13615 for (int d = 0; d < Dim; d++) { Iden(d, d) = 1.0; };
13616 Iden -= rot;
13617 if (Iden.FNorm2() != 0)
13618 {
13619 // TODO: Handling of these cases.
13620 rot.Print();
13621 MFEM_ABORT("Invalid rotation matrix. Contact TMOP Developers.");
13622 }
13623 }
13624 else
13625 {
13626 ori(0) = (1./delta)*(rot(2,1)-rot(1,2));
13627 ori(1) = (1./delta)*(rot(0,2)-rot(2,0));
13628 ori(2) = (1./delta)*(rot(1,0)-rot(0,1));
13629 ori(3) = std::acos(0.5*(rot.Trace()-1.0));
13630 }
13631 }
13632}
13633
13634
13636 int dim_, const Array<int> (&entity_to_vertex_)[Geometry::NumGeom])
13637 : dim(dim_),
13638 entity_to_vertex(entity_to_vertex_)
13639{
13640 int geom_offset = 0;
13641 for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
13642 {
13643 geom_offsets[g] = geom_offset;
13644 geom_offset += entity_to_vertex[g].Size()/Geometry::NumVerts[g];
13645 }
13646 geom_offsets[Geometry::DimStart[dim+1]] = geom_offset;
13647 num_entities = geom_offset;
13648}
13649
13651{
13652 // Find the 'geom' that corresponds to 'bytype_entity_id'
13653 int geom = Geometry::DimStart[dim];
13654 while (geom_offsets[geom+1] <= bytype_entity_id) { geom++; }
13655 MFEM_ASSERT(geom < Geometry::NumGeom, "internal error");
13656 MFEM_ASSERT(Geometry::Dimension[geom] == dim, "internal error");
13657 const int nv = Geometry::NumVerts[geom];
13658 const int geom_elem_id = bytype_entity_id - geom_offsets[geom];
13659 const int *v = &entity_to_vertex[geom][nv*geom_elem_id];
13660 return { geom, nv, v };
13661}
13662
13663void MeshPart::Print(std::ostream &os) const
13664{
13665 os << "MFEM mesh v1.2\n";
13666
13667 // optional
13668 os <<
13669 "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
13670 "# POINT = 0\n"
13671 "# SEGMENT = 1\n"
13672 "# TRIANGLE = 2\n"
13673 "# SQUARE = 3\n"
13674 "# TETRAHEDRON = 4\n"
13675 "# CUBE = 5\n"
13676 "# PRISM = 6\n"
13677 "# PYRAMID = 7\n"
13678 "#\n";
13679
13680 const int dim = dimension;
13681 os << "\ndimension\n" << dim;
13682
13683 os << "\n\nelements\n" << num_elements << '\n';
13684 {
13685 const bool have_element_map = (element_map.Size() == num_elements);
13686 MFEM_ASSERT(have_element_map || element_map.Size() == 0,
13687 "invalid MeshPart state");
13688 EntityHelper elem_helper(dim, entity_to_vertex);
13689 MFEM_ASSERT(elem_helper.num_entities == num_elements,
13690 "invalid MeshPart state");
13691 for (int nat_elem_id = 0; nat_elem_id < num_elements; nat_elem_id++)
13692 {
13693 const int bytype_elem_id = have_element_map ?
13694 element_map[nat_elem_id] : nat_elem_id;
13695 const Entity ent = elem_helper.FindEntity(bytype_elem_id);
13696 // Print the element
13697 os << attributes[nat_elem_id] << ' ' << ent.geom;
13698 for (int i = 0; i < ent.num_verts; i++)
13699 {
13700 os << ' ' << ent.verts[i];
13701 }
13702 os << '\n';
13703 }
13704 }
13705
13706 os << "\nboundary\n" << num_bdr_elements << '\n';
13707 {
13708 const bool have_boundary_map = (boundary_map.Size() == num_bdr_elements);
13709 MFEM_ASSERT(have_boundary_map || boundary_map.Size() == 0,
13710 "invalid MeshPart state");
13711 EntityHelper bdr_helper(dim-1, entity_to_vertex);
13712 MFEM_ASSERT(bdr_helper.num_entities == num_bdr_elements,
13713 "invalid MeshPart state");
13714 for (int nat_bdr_id = 0; nat_bdr_id < num_bdr_elements; nat_bdr_id++)
13715 {
13716 const int bytype_bdr_id = have_boundary_map ?
13717 boundary_map[nat_bdr_id] : nat_bdr_id;
13718 const Entity ent = bdr_helper.FindEntity(bytype_bdr_id);
13719 // Print the boundary element
13720 os << bdr_attributes[nat_bdr_id] << ' ' << ent.geom;
13721 for (int i = 0; i < ent.num_verts; i++)
13722 {
13723 os << ' ' << ent.verts[i];
13724 }
13725 os << '\n';
13726 }
13727 }
13728
13729 os << "\nvertices\n" << num_vertices << '\n';
13730 if (!nodes)
13731 {
13732 const int sdim = space_dimension;
13733 os << sdim << '\n';
13734 for (int i = 0; i < num_vertices; i++)
13735 {
13736 os << vertex_coordinates[i*sdim];
13737 for (int d = 1; d < sdim; d++)
13738 {
13739 os << ' ' << vertex_coordinates[i*sdim+d];
13740 }
13741 os << '\n';
13742 }
13743 }
13744 else
13745 {
13746 os << "\nnodes\n";
13747 nodes->Save(os);
13748 }
13749
13750 os << "\nmfem_serial_mesh_end\n";
13751
13752 // Start: GroupTopology::Save
13753 const int num_groups = my_groups.Size();
13754 os << "\ncommunication_groups\n";
13755 os << "number_of_groups " << num_groups << "\n\n";
13756
13757 os << "# number of entities in each group, followed by ranks in group\n";
13758 for (int group_id = 0; group_id < num_groups; ++group_id)
13759 {
13760 const int group_size = my_groups.RowSize(group_id);
13761 const int *group_ptr = my_groups.GetRow(group_id);
13762 os << group_size;
13763 for (int group_member_index = 0; group_member_index < group_size;
13764 ++group_member_index)
13765 {
13766 os << ' ' << group_ptr[group_member_index];
13767 }
13768 os << '\n';
13769 }
13770 // End: GroupTopology::Save
13771
13776
13777 MFEM_VERIFY(g2v.RowSize(0) == 0, "internal erroor");
13778 os << "\ntotal_shared_vertices " << g2v.Size_of_connections() << '\n';
13779 if (dimension >= 2)
13780 {
13781 MFEM_VERIFY(g2ev.RowSize(0) == 0, "internal erroor");
13782 os << "total_shared_edges " << g2ev.Size_of_connections()/2 << '\n';
13783 }
13784 if (dimension >= 3)
13785 {
13786 MFEM_VERIFY(g2tv.RowSize(0) == 0, "internal erroor");
13787 MFEM_VERIFY(g2qv.RowSize(0) == 0, "internal erroor");
13788 const int total_shared_faces =
13789 g2tv.Size_of_connections()/3 + g2qv.Size_of_connections()/4;
13790 os << "total_shared_faces " << total_shared_faces << '\n';
13791 }
13792 os << "\n# group 0 has no shared entities\n";
13793 for (int gr = 1; gr < num_groups; gr++)
13794 {
13795 {
13796 const int nv = g2v.RowSize(gr);
13797 const int *sv = g2v.GetRow(gr);
13798 os << "\n# group " << gr << "\nshared_vertices " << nv << '\n';
13799 for (int i = 0; i < nv; i++)
13800 {
13801 os << sv[i] << '\n';
13802 }
13803 }
13804 if (dimension >= 2)
13805 {
13806 const int ne = g2ev.RowSize(gr)/2;
13807 const int *se = g2ev.GetRow(gr);
13808 os << "\nshared_edges " << ne << '\n';
13809 for (int i = 0; i < ne; i++)
13810 {
13811 const int *v = se + 2*i;
13812 os << v[0] << ' ' << v[1] << '\n';
13813 }
13814 }
13815 if (dimension >= 3)
13816 {
13817 const int nt = g2tv.RowSize(gr)/3;
13818 const int *st = g2tv.GetRow(gr);
13819 const int nq = g2qv.RowSize(gr)/4;
13820 const int *sq = g2qv.GetRow(gr);
13821 os << "\nshared_faces " << nt+nq << '\n';
13822 for (int i = 0; i < nt; i++)
13823 {
13824 os << Geometry::TRIANGLE;
13825 const int *v = st + 3*i;
13826 for (int j = 0; j < 3; j++) { os << ' ' << v[j]; }
13827 os << '\n';
13828 }
13829 for (int i = 0; i < nq; i++)
13830 {
13831 os << Geometry::SQUARE;
13832 const int *v = sq + 4*i;
13833 for (int j = 0; j < 4; j++) { os << ' ' << v[j]; }
13834 os << '\n';
13835 }
13836 }
13837 }
13838
13839 // Write out section end tag for mesh.
13840 os << "\nmfem_mesh_end" << endl;
13841}
13842
13844{
13845 if (mesh) { return *mesh; }
13846
13847 mesh.reset(new Mesh(dimension,
13852
13853 // Add elements
13854 {
13855 const bool have_element_map = (element_map.Size() == num_elements);
13856 MFEM_ASSERT(have_element_map || element_map.Size() == 0,
13857 "invalid MeshPart state");
13859 MFEM_ASSERT(elem_helper.num_entities == num_elements,
13860 "invalid MeshPart state");
13861 const bool have_tet_refine_flags = (tet_refine_flags.Size() > 0);
13862 for (int nat_elem_id = 0; nat_elem_id < num_elements; nat_elem_id++)
13863 {
13864 const int bytype_elem_id = have_element_map ?
13865 element_map[nat_elem_id] : nat_elem_id;
13866 const Entity ent = elem_helper.FindEntity(bytype_elem_id);
13867 Element *el = mesh->NewElement(ent.geom);
13868 el->SetVertices(ent.verts);
13869 el->SetAttribute(attributes[nat_elem_id]);
13870 if (ent.geom == Geometry::TETRAHEDRON && have_tet_refine_flags)
13871 {
13872 constexpr int geom_tet = Geometry::TETRAHEDRON;
13873 const int tet_id = (ent.verts - entity_to_vertex[geom_tet])/4;
13874 const int ref_flag = tet_refine_flags[tet_id];
13875 static_cast<Tetrahedron*>(el)->SetRefinementFlag(ref_flag);
13876 }
13877 mesh->AddElement(el);
13878 }
13879 }
13880
13881 // Add boundary elements
13882 {
13883 const bool have_boundary_map = (boundary_map.Size() == num_bdr_elements);
13884 MFEM_ASSERT(have_boundary_map || boundary_map.Size() == 0,
13885 "invalid MeshPart state");
13887 MFEM_ASSERT(bdr_helper.num_entities == num_bdr_elements,
13888 "invalid MeshPart state");
13889 for (int nat_bdr_id = 0; nat_bdr_id < num_bdr_elements; nat_bdr_id++)
13890 {
13891 const int bytype_bdr_id = have_boundary_map ?
13892 boundary_map[nat_bdr_id] : nat_bdr_id;
13893 const Entity ent = bdr_helper.FindEntity(bytype_bdr_id);
13894 Element *bdr = mesh->NewElement(ent.geom);
13895 bdr->SetVertices(ent.verts);
13896 bdr->SetAttribute(bdr_attributes[nat_bdr_id]);
13897 mesh->AddBdrElement(bdr);
13898 }
13899 }
13900
13901 // Add vertices
13903 {
13904 MFEM_ASSERT(!nodes, "invalid MeshPart state");
13905 for (int vert_id = 0; vert_id < num_vertices; vert_id++)
13906 {
13907 mesh->AddVertex(vertex_coordinates + space_dimension*vert_id);
13908 }
13909 }
13910 else
13911 {
13912 MFEM_ASSERT(vertex_coordinates.Size() == 0, "invalid MeshPart state");
13913 for (int vert_id = 0; vert_id < num_vertices; vert_id++)
13914 {
13915 mesh->AddVertex(0., 0., 0.);
13916 }
13917 // 'mesh.Nodes' cannot be set here -- they can be set later, if needed
13918 }
13919
13920 mesh->FinalizeTopology(/* generate_bdr: */ false);
13921
13922 return *mesh;
13923}
13924
13925
13927 int num_parts_,
13928 const int *partitioning_,
13929 int part_method)
13930 : mesh(mesh_)
13931{
13932 if (partitioning_)
13933 {
13934 partitioning.MakeRef(const_cast<int *>(partitioning_), mesh.GetNE(),
13935 false);
13936 }
13937 else
13938 {
13939 // Mesh::GeneratePartitioning always uses new[] to allocate the,
13940 // partitioning, so we need to tell the memory manager to free it with
13941 // delete[] (even if a different host memory type has been selected).
13942 constexpr MemoryType mt = MemoryType::HOST;
13943 partitioning.MakeRef(mesh.GeneratePartitioning(num_parts_, part_method),
13944 mesh.GetNE(), mt, true);
13945 }
13946
13948 // Note: the element ids in each row of 'part_to_element' are sorted.
13949
13950 const int dim = mesh.Dimension();
13951 if (dim >= 2)
13952 {
13954 }
13955
13956 Array<int> boundary_to_part(mesh.GetNBE());
13957 // Same logic as in ParMesh::BuildLocalBoundary
13958 if (dim >= 3)
13959 {
13960 for (int i = 0; i < boundary_to_part.Size(); i++)
13961 {
13962 int face, o, el1, el2;
13963 mesh.GetBdrElementFace(i, &face, &o);
13964 mesh.GetFaceElements(face, &el1, &el2);
13965 boundary_to_part[i] =
13966 partitioning[(o % 2 == 0 || el2 < 0) ? el1 : el2];
13967 }
13968 }
13969 else if (dim == 2)
13970 {
13971 for (int i = 0; i < boundary_to_part.Size(); i++)
13972 {
13973 int edge = mesh.GetBdrElementFaceIndex(i);
13974 int el1 = edge_to_element.GetRow(edge)[0];
13975 boundary_to_part[i] = partitioning[el1];
13976 }
13977 }
13978 else if (dim == 1)
13979 {
13980 for (int i = 0; i < boundary_to_part.Size(); i++)
13981 {
13982 int vert = mesh.GetBdrElementFaceIndex(i);
13983 int el1, el2;
13984 mesh.GetFaceElements(vert, &el1, &el2);
13985 boundary_to_part[i] = partitioning[el1];
13986 }
13987 }
13988 Transpose(boundary_to_part, part_to_boundary, num_parts_);
13989 // Note: the boundary element ids in each row of 'part_to_boundary' are
13990 // sorted.
13991 boundary_to_part.DeleteAll();
13992
13993 Table *vert_element = mesh.GetVertexToElementTable(); // we must delete this
13994 vertex_to_element.Swap(*vert_element);
13995 delete vert_element;
13996}
13997
13998void MeshPartitioner::ExtractPart(int part_id, MeshPart &mesh_part) const
13999{
14000 const int num_parts = part_to_element.Size();
14001
14002 MFEM_VERIFY(0 <= part_id && part_id < num_parts,
14003 "invalid part_id = " << part_id
14004 << ", num_parts = " << num_parts);
14005
14006 const int dim = mesh.Dimension();
14007 const int sdim = mesh.SpaceDimension();
14008 const int num_elems = part_to_element.RowSize(part_id);
14009 const int *elem_list = part_to_element.GetRow(part_id); // sorted
14010 const int num_bdr_elems = part_to_boundary.RowSize(part_id);
14011 const int *bdr_elem_list = part_to_boundary.GetRow(part_id); // sorted
14012
14013 // Initialize 'mesh_part'
14014 mesh_part.dimension = dim;
14015 mesh_part.space_dimension = sdim;
14016 mesh_part.num_vertices = 0;
14017 mesh_part.num_elements = num_elems;
14018 mesh_part.num_bdr_elements = num_bdr_elems;
14019 for (int g = 0; g < Geometry::NumGeom; g++)
14020 {
14021 mesh_part.entity_to_vertex[g].SetSize(0); // can reuse Array allocation
14022 }
14023 mesh_part.tet_refine_flags.SetSize(0);
14024 mesh_part.element_map.SetSize(0); // 0 or 'num_elements', if needed
14025 mesh_part.boundary_map.SetSize(0); // 0 or 'num_bdr_elements', if needed
14026 mesh_part.attributes.SetSize(num_elems);
14027 mesh_part.bdr_attributes.SetSize(num_bdr_elems);
14028 mesh_part.vertex_coordinates.SetSize(0);
14029
14030 mesh_part.num_parts = num_parts;
14031 mesh_part.my_part_id = part_id;
14032 mesh_part.my_groups.Clear();
14033 for (int g = 0; g < Geometry::NumGeom; g++)
14034 {
14035 mesh_part.group_shared_entity_to_vertex[g].Clear();
14036 }
14037 mesh_part.nodes.reset(nullptr);
14038 mesh_part.nodal_fes.reset(nullptr);
14039 mesh_part.mesh.reset(nullptr);
14040
14041 // Initialize:
14042 // - 'mesh_part.entity_to_vertex' for the elements (boundary elements are
14043 // set later); vertex ids are global at this point - they will be mapped to
14044 // local ids later
14045 // - 'mesh_part.attributes'
14046 // - 'mesh_part.tet_refine_flags' if needed
14047 int geom_marker = 0, num_geom = 0;
14048 for (int i = 0; i < num_elems; i++)
14049 {
14050 const Element *elem = mesh.GetElement(elem_list[i]);
14051 const int geom = elem->GetGeometryType();
14052 const int nv = Geometry::NumVerts[geom];
14053 const int *v = elem->GetVertices();
14054 MFEM_VERIFY(numeric_limits<int>::max() - nv >=
14055 mesh_part.entity_to_vertex[geom].Size(),
14056 "overflow in 'entity_to_vertex[geom]', geom: "
14057 << Geometry::Name[geom]);
14058 mesh_part.entity_to_vertex[geom].Append(v, nv);
14059 mesh_part.attributes[i] = elem->GetAttribute();
14060 if (geom == Geometry::TETRAHEDRON)
14061 {
14062 // Create 'mesh_part.tet_refine_flags' but only if we find at least one
14063 // non-zero flag in a tetrahedron.
14064 const Tetrahedron *tet = static_cast<const Tetrahedron*>(elem);
14065 const int ref_flag = tet->GetRefinementFlag();
14066 if (mesh_part.tet_refine_flags.Size() == 0)
14067 {
14068 if (ref_flag)
14069 {
14070 // This is the first time we encounter non-zero 'ref_flag'
14071 const int num_tets = mesh_part.entity_to_vertex[geom].Size()/nv;
14072 mesh_part.tet_refine_flags.SetSize(num_tets, 0);
14073 mesh_part.tet_refine_flags.Last() = ref_flag;
14074 }
14075 }
14076 else
14077 {
14078 mesh_part.tet_refine_flags.Append(ref_flag);
14079 }
14080 }
14081 if ((geom_marker & (1 << geom)) == 0)
14082 {
14083 geom_marker |= (1 << geom);
14084 num_geom++;
14085 }
14086 }
14087 MFEM_ASSERT(mesh_part.tet_refine_flags.Size() == 0 ||
14088 mesh_part.tet_refine_flags.Size() ==
14090 "internal error");
14091 // Initialize 'mesh_part.element_map' if needed
14092 if (num_geom > 1)
14093 {
14094 int offsets[Geometry::NumGeom];
14095 int offset = 0;
14096 for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
14097 {
14098 offsets[g] = offset;
14099 offset += mesh_part.entity_to_vertex[g].Size()/Geometry::NumVerts[g];
14100 }
14101 mesh_part.element_map.SetSize(num_elems);
14102 for (int i = 0; i < num_elems; i++)
14103 {
14104 const int geom = mesh.GetElementGeometry(elem_list[i]);
14105 mesh_part.element_map[i] = offsets[geom]++;
14106 }
14107 }
14108
14109 // Initialize:
14110 // - 'mesh_part.entity_to_vertex' for the boundary elements; vertex ids are
14111 // global at this point - they will be mapped to local ids later
14112 // - 'mesh_part.bdr_attributes'
14113 geom_marker = 0; num_geom = 0;
14114 for (int i = 0; i < num_bdr_elems; i++)
14115 {
14116 const Element *bdr_elem = mesh.GetBdrElement(bdr_elem_list[i]);
14117 const int geom = bdr_elem->GetGeometryType();
14118 const int nv = Geometry::NumVerts[geom];
14119 const int *v = bdr_elem->GetVertices();
14120 MFEM_VERIFY(numeric_limits<int>::max() - nv >=
14121 mesh_part.entity_to_vertex[geom].Size(),
14122 "overflow in 'entity_to_vertex[geom]', geom: "
14123 << Geometry::Name[geom]);
14124 mesh_part.entity_to_vertex[geom].Append(v, nv);
14125 mesh_part.bdr_attributes[i] = bdr_elem->GetAttribute();
14126 if ((geom_marker & (1 << geom)) == 0)
14127 {
14128 geom_marker |= (1 << geom);
14129 num_geom++;
14130 }
14131 }
14132 // Initialize 'mesh_part.boundary_map' if needed
14133 if (num_geom > 1)
14134 {
14135 int offsets[Geometry::NumGeom];
14136 int offset = 0;
14137 for (int g = Geometry::DimStart[dim-1]; g < Geometry::DimStart[dim]; g++)
14138 {
14139 offsets[g] = offset;
14140 offset += mesh_part.entity_to_vertex[g].Size()/Geometry::NumVerts[g];
14141 }
14142 mesh_part.boundary_map.SetSize(num_bdr_elems);
14143 for (int i = 0; i < num_bdr_elems; i++)
14144 {
14145 const int geom = mesh.GetBdrElementGeometry(bdr_elem_list[i]);
14146 mesh_part.boundary_map[i] = offsets[geom]++;
14147 }
14148 }
14149
14150 // Create the vertex id map, 'vertex_loc_to_glob', which maps local ids to
14151 // global ones; the map is sorted, preserving the global ordering.
14152 Array<int> vertex_loc_to_glob;
14153 {
14154 std::unordered_set<int> vertex_set;
14155 for (int i = 0; i < num_elems; i++)
14156 {
14157 const Element *elem = mesh.GetElement(elem_list[i]);
14158 const int geom = elem->GetGeometryType();
14159 const int nv = Geometry::NumVerts[geom];
14160 const int *v = elem->GetVertices();
14161 vertex_set.insert(v, v + nv);
14162 }
14163 vertex_loc_to_glob.SetSize(static_cast<int>(vertex_set.size()));
14164 std::copy(vertex_set.begin(), vertex_set.end(), // src
14165 vertex_loc_to_glob.begin()); // dest
14166 }
14167 vertex_loc_to_glob.Sort();
14168
14169 // Initialize 'mesh_part.num_vertices'
14170 mesh_part.num_vertices = vertex_loc_to_glob.Size();
14171
14172 // Update the vertex ids in the arrays 'mesh_part.entity_to_vertex' from
14173 // global to local.
14174 for (int g = 0; g < Geometry::NumGeom; g++)
14175 {
14176 Array<int> &vert_array = mesh_part.entity_to_vertex[g];
14177 for (int i = 0; i < vert_array.Size(); i++)
14178 {
14179 const int glob_id = vert_array[i];
14180 const int loc_id = vertex_loc_to_glob.FindSorted(glob_id);
14181 MFEM_ASSERT(loc_id >= 0, "internal error: global vertex id not found");
14182 vert_array[i] = loc_id;
14183 }
14184 }
14185
14186 // Initialize one of 'mesh_part.vertex_coordinates' or 'mesh_part.nodes'
14187 if (!mesh.GetNodes())
14188 {
14189 MFEM_VERIFY(numeric_limits<int>::max()/sdim >= vertex_loc_to_glob.Size(),
14190 "overflow in 'vertex_coordinates', num_vertices = "
14191 << vertex_loc_to_glob.Size() << ", sdim = " << sdim);
14192 mesh_part.vertex_coordinates.SetSize(sdim*vertex_loc_to_glob.Size());
14193 for (int i = 0; i < vertex_loc_to_glob.Size(); i++)
14194 {
14195 const real_t *coord = mesh.GetVertex(vertex_loc_to_glob[i]);
14196 for (int d = 0; d < sdim; d++)
14197 {
14198 mesh_part.vertex_coordinates[i*sdim+d] = coord[d];
14199 }
14200 }
14201 }
14202 else
14203 {
14204 const GridFunction &glob_nodes = *mesh.GetNodes();
14205 mesh_part.nodal_fes = ExtractFESpace(mesh_part, *glob_nodes.FESpace());
14206 // Initialized 'mesh_part.mesh'.
14207 // Note: the nodes of 'mesh_part.mesh' are not set.
14208
14209 mesh_part.nodes = ExtractGridFunction(mesh_part, glob_nodes,
14210 *mesh_part.nodal_fes);
14211
14212 // Attach the 'mesh_part.nodes' to the 'mesh_part.mesh'.
14213 mesh_part.mesh->NewNodes(*mesh_part.nodes, /* make_owner: */ false);
14214 // Note: the vertices of 'mesh_part.mesh' are not set.
14215 }
14216
14217 // Begin constructing the "neighbor" groups, i.e. the groups that contain
14218 // 'part_id'.
14219 ListOfIntegerSets groups;
14220 {
14221 // the first group is the local one
14222 IntegerSet group;
14223 group.Recreate(1, &part_id);
14224 groups.Insert(group);
14225 }
14226
14227 // 'shared_faces' : shared face id -> (global_face_id, group_id)
14228 // Note: 'shared_faces' will be sorted by 'global_face_id'.
14229 Array<Pair<int,int>> shared_faces;
14230
14231 // Add "neighbor" groups defined by faces
14232 // Construct 'shared_faces'.
14233 if (dim >= 3)
14234 {
14235 std::unordered_set<int> face_set;
14236 // Construct 'face_set'
14237 const Table &elem_to_face = mesh.ElementToFaceTable();
14238 for (int loc_elem_id = 0; loc_elem_id < num_elems; loc_elem_id++)
14239 {
14240 const int glob_elem_id = elem_list[loc_elem_id];
14241 const int nfaces = elem_to_face.RowSize(glob_elem_id);
14242 const int *faces = elem_to_face.GetRow(glob_elem_id);
14243 face_set.insert(faces, faces + nfaces);
14244 }
14245 // Construct 'shared_faces'; add "neighbor" groups defined by faces.
14246 IntegerSet group;
14247 for (int glob_face_id : face_set)
14248 {
14249 int el[2];
14250 mesh.GetFaceElements(glob_face_id, &el[0], &el[1]);
14251 if (el[1] < 0) { continue; }
14252 el[0] = partitioning[el[0]];
14253 el[1] = partitioning[el[1]];
14254 MFEM_ASSERT(el[0] == part_id || el[1] == part_id, "internal error");
14255 if (el[0] != part_id || el[1] != part_id)
14256 {
14257 group.Recreate(2, el);
14258 const int group_id = groups.Insert(group);
14259 shared_faces.Append(Pair<int,int>(glob_face_id, group_id));
14260 }
14261 }
14262 shared_faces.Sort(); // sort the shared faces by 'glob_face_id'
14263 }
14264
14265 // 'shared_edges' : shared edge id -> (global_edge_id, group_id)
14266 // Note: 'shared_edges' will be sorted by 'global_edge_id'.
14267 Array<Pair<int,int>> shared_edges;
14268
14269 // Add "neighbor" groups defined by edges.
14270 // Construct 'shared_edges'.
14271 if (dim >= 2)
14272 {
14273 std::unordered_set<int> edge_set;
14274 // Construct 'edge_set'
14275 const Table &elem_to_edge = mesh.ElementToEdgeTable();
14276 for (int loc_elem_id = 0; loc_elem_id < num_elems; loc_elem_id++)
14277 {
14278 const int glob_elem_id = elem_list[loc_elem_id];
14279 const int nedges = elem_to_edge.RowSize(glob_elem_id);
14280 const int *edges = elem_to_edge.GetRow(glob_elem_id);
14281 edge_set.insert(edges, edges + nedges);
14282 }
14283 // Construct 'shared_edges'; add "neighbor" groups defined by edges.
14284 IntegerSet group;
14285 for (int glob_edge_id : edge_set)
14286 {
14287 const int nelem = edge_to_element.RowSize(glob_edge_id);
14288 const int *elem = edge_to_element.GetRow(glob_edge_id);
14289 Array<int> &gr = group; // reference to the 'group' internal Array
14290 gr.SetSize(nelem);
14291 for (int j = 0; j < nelem; j++)
14292 {
14293 gr[j] = partitioning[elem[j]];
14294 }
14295 gr.Sort();
14296 gr.Unique();
14297 MFEM_ASSERT(gr.FindSorted(part_id) >= 0, "internal error");
14298 if (group.Size() > 1)
14299 {
14300 const int group_id = groups.Insert(group);
14301 shared_edges.Append(Pair<int,int>(glob_edge_id, group_id));
14302 }
14303 }
14304 shared_edges.Sort(); // sort the shared edges by 'glob_edge_id'
14305 }
14306
14307 // 'shared_verts' : shared vertex id -> (global_vertex_id, group_id)
14308 // Note: 'shared_verts' will be sorted by 'global_vertex_id'.
14309 Array<Pair<int,int>> shared_verts;
14310
14311 // Add "neighbor" groups defined by vertices.
14312 // Construct 'shared_verts'.
14313 {
14314 IntegerSet group;
14315 for (int i = 0; i < vertex_loc_to_glob.Size(); i++)
14316 {
14317 // 'vertex_to_element' maps global vertex ids to global element ids
14318 const int glob_vertex_id = vertex_loc_to_glob[i];
14319 const int nelem = vertex_to_element.RowSize(glob_vertex_id);
14320 const int *elem = vertex_to_element.GetRow(glob_vertex_id);
14321 Array<int> &gr = group; // reference to the 'group' internal Array
14322 gr.SetSize(nelem);
14323 for (int j = 0; j < nelem; j++)
14324 {
14325 gr[j] = partitioning[elem[j]];
14326 }
14327 gr.Sort();
14328 gr.Unique();
14329 MFEM_ASSERT(gr.FindSorted(part_id) >= 0, "internal error");
14330 if (group.Size() > 1)
14331 {
14332 const int group_id = groups.Insert(group);
14333 shared_verts.Append(Pair<int,int>(glob_vertex_id, group_id));
14334 }
14335 }
14336 }
14337
14338 // Done constructing the "neighbor" groups in 'groups'.
14339 const int num_groups = groups.Size();
14340
14341 // Define 'mesh_part.my_groups'
14342 groups.AsTable(mesh_part.my_groups);
14343
14344 // Construct 'mesh_part.group_shared_entity_to_vertex[Geometry::POINT]'
14345 Table &group__shared_vertex_to_vertex =
14347 group__shared_vertex_to_vertex.MakeI(num_groups);
14348 for (int sv = 0; sv < shared_verts.Size(); sv++)
14349 {
14350 const int group_id = shared_verts[sv].two;
14351 group__shared_vertex_to_vertex.AddAColumnInRow(group_id);
14352 }
14353 group__shared_vertex_to_vertex.MakeJ();
14354 for (int sv = 0; sv < shared_verts.Size(); sv++)
14355 {
14356 const int glob_vertex_id = shared_verts[sv].one;
14357 const int group_id = shared_verts[sv].two;
14358 const int loc_vertex_id = vertex_loc_to_glob.FindSorted(glob_vertex_id);
14359 MFEM_ASSERT(loc_vertex_id >= 0, "internal error");
14360 group__shared_vertex_to_vertex.AddConnection(group_id, loc_vertex_id);
14361 }
14362 group__shared_vertex_to_vertex.ShiftUpI();
14363
14364 // Construct 'mesh_part.group_shared_entity_to_vertex[Geometry::SEGMENT]'
14365 if (dim >= 2)
14366 {
14367 Table &group__shared_edge_to_vertex =
14369 group__shared_edge_to_vertex.MakeI(num_groups);
14370 for (int se = 0; se < shared_edges.Size(); se++)
14371 {
14372 const int group_id = shared_edges[se].two;
14373 group__shared_edge_to_vertex.AddColumnsInRow(group_id, 2);
14374 }
14375 group__shared_edge_to_vertex.MakeJ();
14376 const Table &edge_to_vertex = *mesh.GetEdgeVertexTable();
14377 for (int se = 0; se < shared_edges.Size(); se++)
14378 {
14379 const int glob_edge_id = shared_edges[se].one;
14380 const int group_id = shared_edges[se].two;
14381 const int *v = edge_to_vertex.GetRow(glob_edge_id);
14382 for (int i = 0; i < 2; i++)
14383 {
14384 const int loc_vertex_id = vertex_loc_to_glob.FindSorted(v[i]);
14385 MFEM_ASSERT(loc_vertex_id >= 0, "internal error");
14386 group__shared_edge_to_vertex.AddConnection(group_id, loc_vertex_id);
14387 }
14388 }
14389 group__shared_edge_to_vertex.ShiftUpI();
14390 }
14391
14392 // Construct 'mesh_part.group_shared_entity_to_vertex[Geometry::TRIANGLE]'
14393 // and 'mesh_part.group_shared_entity_to_vertex[Geometry::SQUARE]'.
14394 if (dim >= 3)
14395 {
14396 Table &group__shared_tria_to_vertex =
14398 Table &group__shared_quad_to_vertex =
14400 Array<int> vertex_ids;
14401 group__shared_tria_to_vertex.MakeI(num_groups);
14402 group__shared_quad_to_vertex.MakeI(num_groups);
14403 for (int sf = 0; sf < shared_faces.Size(); sf++)
14404 {
14405 const int glob_face_id = shared_faces[sf].one;
14406 const int group_id = shared_faces[sf].two;
14407 const int geom = mesh.GetFaceGeometry(glob_face_id);
14408 mesh_part.group_shared_entity_to_vertex[geom].
14409 AddColumnsInRow(group_id, Geometry::NumVerts[geom]);
14410 }
14411 group__shared_tria_to_vertex.MakeJ();
14412 group__shared_quad_to_vertex.MakeJ();
14413 for (int sf = 0; sf < shared_faces.Size(); sf++)
14414 {
14415 const int glob_face_id = shared_faces[sf].one;
14416 const int group_id = shared_faces[sf].two;
14417 const int geom = mesh.GetFaceGeometry(glob_face_id);
14418 mesh.GetFaceVertices(glob_face_id, vertex_ids);
14419 // Rotate shared triangles that have an adjacent tetrahedron with a
14420 // nonzero refinement flag.
14421 // See also ParMesh::BuildSharedFaceElems.
14422 if (geom == Geometry::TRIANGLE)
14423 {
14424 int glob_el_id[2];
14425 mesh.GetFaceElements(glob_face_id, &glob_el_id[0], &glob_el_id[1]);
14426 int side = 0;
14427 const Element *el = mesh.GetElement(glob_el_id[0]);
14428 const Tetrahedron *tet = nullptr;
14430 {
14431 tet = static_cast<const Tetrahedron*>(el);
14432 }
14433 else
14434 {
14435 side = 1;
14436 el = mesh.GetElement(glob_el_id[1]);
14438 {
14439 tet = static_cast<const Tetrahedron*>(el);
14440 }
14441 }
14442 if (tet && tet->GetRefinementFlag())
14443 {
14444 // mark the shared face for refinement by reorienting
14445 // it according to the refinement flag in the tetrahedron
14446 // to which this shared face belongs to.
14447 int info[2];
14448 mesh.GetFaceInfos(glob_face_id, &info[0], &info[1]);
14449 tet->GetMarkedFace(info[side]/64, &vertex_ids[0]);
14450 }
14451 }
14452 for (int i = 0; i < vertex_ids.Size(); i++)
14453 {
14454 const int glob_id = vertex_ids[i];
14455 const int loc_id = vertex_loc_to_glob.FindSorted(glob_id);
14456 MFEM_ASSERT(loc_id >= 0, "internal error");
14457 vertex_ids[i] = loc_id;
14458 }
14459 mesh_part.group_shared_entity_to_vertex[geom].
14460 AddConnections(group_id, vertex_ids, vertex_ids.Size());
14461 }
14462 group__shared_tria_to_vertex.ShiftUpI();
14463 group__shared_quad_to_vertex.ShiftUpI();
14464 }
14465}
14466
14467std::unique_ptr<FiniteElementSpace>
14469 const FiniteElementSpace &global_fespace) const
14470{
14471 mesh_part.GetMesh(); // initialize 'mesh_part.mesh'
14472 // Note: the nodes of 'mesh_part.mesh' are not set by GetMesh() unless they
14473 // were already constructed, e.g. by ExtractPart().
14474
14475 return std::unique_ptr<FiniteElementSpace>(
14476 new FiniteElementSpace(mesh_part.mesh.get(),
14477 global_fespace.FEColl(),
14478 global_fespace.GetVDim(),
14479 global_fespace.GetOrdering()));
14480}
14481
14482std::unique_ptr<GridFunction>
14484 const GridFunction &global_gf,
14485 FiniteElementSpace &local_fespace) const
14486{
14487 std::unique_ptr<GridFunction> local_gf(new GridFunction(&local_fespace));
14488
14489 // Transfer data from 'global_gf' to 'local_gf'.
14490 Array<int> gvdofs, lvdofs;
14491 Vector loc_vals;
14492 const int part_id = mesh_part.my_part_id;
14493 const int num_elems = part_to_element.RowSize(part_id);
14494 const int *elem_list = part_to_element.GetRow(part_id); // sorted
14495 for (int loc_elem_id = 0; loc_elem_id < num_elems; loc_elem_id++)
14496 {
14497 const int glob_elem_id = elem_list[loc_elem_id];
14498 auto glob_dt = global_gf.FESpace()->GetElementVDofs(glob_elem_id, gvdofs);
14499 global_gf.GetSubVector(gvdofs, loc_vals);
14500 if (glob_dt) { glob_dt->InvTransformPrimal(loc_vals); }
14501 auto local_dt = local_fespace.GetElementVDofs(loc_elem_id, lvdofs);
14502 if (local_dt) { local_dt->TransformPrimal(loc_vals); }
14503 local_gf->SetSubVector(lvdofs, loc_vals);
14504 }
14505 return local_gf;
14506}
14507
14508
14510 int flags, MemoryType d_mt)
14511{
14512 this->mesh = mesh;
14513 IntRule = &ir;
14514 computed_factors = flags;
14515
14516 MFEM_ASSERT(mesh->GetNumGeometries(mesh->Dimension()) <= 1,
14517 "mixed meshes are not supported!");
14518 MFEM_ASSERT(mesh->GetNodes(), "meshes without nodes are not supported!");
14519
14520 Compute(*mesh->GetNodes(), d_mt);
14521}
14522
14524 const IntegrationRule &ir,
14525 int flags, MemoryType d_mt)
14526{
14527 this->mesh = nodes.FESpace()->GetMesh();
14528 IntRule = &ir;
14529 computed_factors = flags;
14530
14531 Compute(nodes, d_mt);
14532}
14533
14534void GeometricFactors::Compute(const GridFunction &nodes,
14535 MemoryType d_mt)
14536{
14537
14538 const FiniteElementSpace *fespace = nodes.FESpace();
14539 const FiniteElement *fe = fespace->GetTypicalFE();
14540 const int dim = fe->GetDim();
14541 const int vdim = fespace->GetVDim();
14542 const int NE = fespace->GetNE();
14543 const int ND = fe->GetDof();
14544 const int NQ = IntRule->GetNPoints();
14545
14546 unsigned eval_flags = 0;
14547 MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
14548 Device::GetDeviceMemoryType();
14550 {
14551 X.SetSize(vdim*NQ*NE, my_d_mt); // NQ x SDIM x NE
14552 eval_flags |= QuadratureInterpolator::VALUES;
14553 }
14555 {
14556 J.SetSize(dim*vdim*NQ*NE, my_d_mt); // NQ x SDIM x DIM x NE
14558 }
14560 {
14561 detJ.SetSize(NQ*NE, my_d_mt); // NQ x NE
14563 }
14564
14565 const QuadratureInterpolator *qi = fespace->GetQuadratureInterpolator(*IntRule);
14566 // All X, J, and detJ use this layout:
14568
14569 const bool use_tensor_products = UsesTensorBasis(*fespace);
14570
14571 qi->DisableTensorProducts(!use_tensor_products);
14572 const ElementDofOrdering e_ordering = use_tensor_products ?
14575 const Operator *elem_restr = fespace->GetElementRestriction(e_ordering);
14576
14577 if (elem_restr) // Always true as of 2021-04-27
14578 {
14579 Vector Enodes(vdim*ND*NE, my_d_mt);
14580 elem_restr->Mult(nodes, Enodes);
14581 qi->Mult(Enodes, eval_flags, X, J, detJ);
14582 }
14583 else
14584 {
14585 qi->Mult(nodes, eval_flags, X, J, detJ);
14586 }
14587}
14588
14590 const IntegrationRule &ir,
14591 int flags, FaceType type,
14592 MemoryType d_mt)
14593 : type(type)
14594{
14595 this->mesh = mesh;
14596 IntRule = &ir;
14597 computed_factors = flags;
14598
14599 const GridFunction *nodes = mesh->GetNodes();
14600 const FiniteElementSpace *fespace = nodes->FESpace();
14601 const int vdim = fespace->GetVDim();
14602 const int NF = fespace->GetNFbyType(type);
14603 const int NQ = ir.GetNPoints();
14604
14605 const FaceRestriction *face_restr = fespace->GetFaceRestriction(
14607 type,
14609
14610
14611 MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
14613
14614 Vector Fnodes(face_restr->Height(), my_d_mt);
14615 face_restr->Mult(*nodes, Fnodes);
14616
14617 unsigned eval_flags = 0;
14618
14620 {
14621 X.SetSize(vdim*NQ*NF, my_d_mt);
14623 }
14625 {
14626 J.SetSize(vdim*(mesh->Dimension() - 1)*NQ*NF, my_d_mt);
14628 }
14630 {
14631 detJ.SetSize(NQ*NF, my_d_mt);
14633 }
14635 {
14636 normal.SetSize(vdim*NQ*NF, my_d_mt);
14638 }
14639
14640 const FaceQuadratureInterpolator *qi =
14641 fespace->GetFaceQuadratureInterpolator(ir, type);
14642 // All face data vectors assume layout byNODES.
14644 const bool use_tensor_products = UsesTensorBasis(*fespace);
14645 qi->DisableTensorProducts(!use_tensor_products);
14646
14647 qi->Mult(Fnodes, eval_flags, X, J, detJ, normal);
14648}
14649
14651 const real_t s_)
14652 : VectorCoefficient(dim), n(n_), s(s_), tip(p, dim-1)
14653{
14654}
14655
14657 const IntegrationPoint &ip)
14658{
14659 V.SetSize(vdim);
14660 T.Transform(ip, tip);
14661 V(0) = p[0];
14662 if (vdim == 2)
14663 {
14664 V(1) = s * ((ip.y + layer) / n);
14665 }
14666 else
14667 {
14668 V(1) = p[1];
14669 V(2) = s * ((ip.z + layer) / n);
14670 }
14671}
14672
14673
14674Mesh *Extrude1D(Mesh *mesh, const int ny, const real_t sy, const bool closed)
14675{
14676 if (mesh->Dimension() != 1)
14677 {
14678 mfem::err << "Extrude1D : Not a 1D mesh!" << endl;
14679 mfem_error();
14680 }
14681
14682 int nvy = (closed) ? (ny) : (ny + 1);
14683 int nvt = mesh->GetNV() * nvy;
14684
14685 Mesh *mesh2d;
14686
14687 if (closed)
14688 {
14689 mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny, mesh->GetNBE()*ny);
14690 }
14691 else
14692 mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny,
14693 mesh->GetNBE()*ny+2*mesh->GetNE());
14694
14695 // vertices
14696 real_t vc[2];
14697 for (int i = 0; i < mesh->GetNV(); i++)
14698 {
14699 vc[0] = mesh->GetVertex(i)[0];
14700 for (int j = 0; j < nvy; j++)
14701 {
14702 vc[1] = sy * (real_t(j) / ny);
14703 mesh2d->AddVertex(vc);
14704 }
14705 }
14706 // elements
14707 Array<int> vert;
14708 for (int i = 0; i < mesh->GetNE(); i++)
14709 {
14710 const Element *elem = mesh->GetElement(i);
14711 elem->GetVertices(vert);
14712 const int attr = elem->GetAttribute();
14713 for (int j = 0; j < ny; j++)
14714 {
14715 int qv[4];
14716 qv[0] = vert[0] * nvy + j;
14717 qv[1] = vert[1] * nvy + j;
14718 qv[2] = vert[1] * nvy + (j + 1) % nvy;
14719 qv[3] = vert[0] * nvy + (j + 1) % nvy;
14720
14721 mesh2d->AddQuad(qv, attr);
14722 }
14723 }
14724 // 2D boundary from the 1D boundary
14725 for (int i = 0; i < mesh->GetNBE(); i++)
14726 {
14727 const Element *elem = mesh->GetBdrElement(i);
14728 elem->GetVertices(vert);
14729 const int attr = elem->GetAttribute();
14730 for (int j = 0; j < ny; j++)
14731 {
14732 int sv[2];
14733 sv[0] = vert[0] * nvy + j;
14734 sv[1] = vert[0] * nvy + (j + 1) % nvy;
14735
14736 if (attr%2)
14737 {
14738 Swap<int>(sv[0], sv[1]);
14739 }
14740
14741 mesh2d->AddBdrSegment(sv, attr);
14742 }
14743 }
14744
14745 if (!closed)
14746 {
14747 // 2D boundary from the 1D elements (bottom + top)
14748 int nba = (mesh->bdr_attributes.Size() > 0 ?
14749 mesh->bdr_attributes.Max() : 0);
14750 for (int i = 0; i < mesh->GetNE(); i++)
14751 {
14752 const Element *elem = mesh->GetElement(i);
14753 elem->GetVertices(vert);
14754 const int attr = nba + elem->GetAttribute();
14755 int sv[2];
14756 sv[0] = vert[0] * nvy;
14757 sv[1] = vert[1] * nvy;
14758
14759 mesh2d->AddBdrSegment(sv, attr);
14760
14761 sv[0] = vert[1] * nvy + ny;
14762 sv[1] = vert[0] * nvy + ny;
14763
14764 mesh2d->AddBdrSegment(sv, attr);
14765 }
14766 }
14767
14768 mesh2d->FinalizeQuadMesh(1, 0, false);
14769
14770 GridFunction *nodes = mesh->GetNodes();
14771 if (nodes)
14772 {
14773 // duplicate the fec of the 1D mesh so that it can be deleted safely
14774 // along with its nodes, fes and fec
14775 FiniteElementCollection *fec2d = NULL;
14776 FiniteElementSpace *fes2d;
14777 const char *name = nodes->FESpace()->FEColl()->Name();
14778 string cname = name;
14779 if (cname == "Linear")
14780 {
14781 fec2d = new LinearFECollection;
14782 }
14783 else if (cname == "Quadratic")
14784 {
14785 fec2d = new QuadraticFECollection;
14786 }
14787 else if (cname == "Cubic")
14788 {
14789 fec2d = new CubicFECollection;
14790 }
14791 else if (!strncmp(name, "H1_", 3))
14792 {
14793 fec2d = new H1_FECollection(atoi(name + 7), 2);
14794 }
14795 else if (!strncmp(name, "L2_T", 4))
14796 {
14797 fec2d = new L2_FECollection(atoi(name + 10), 2, atoi(name + 4));
14798 }
14799 else if (!strncmp(name, "L2_", 3))
14800 {
14801 fec2d = new L2_FECollection(atoi(name + 7), 2);
14802 }
14803 else
14804 {
14805 delete mesh2d;
14806 mfem::err << "Extrude1D : The mesh uses unknown FE collection : "
14807 << cname << endl;
14808 mfem_error();
14809 }
14810 fes2d = new FiniteElementSpace(mesh2d, fec2d, 2);
14811 mesh2d->SetNodalFESpace(fes2d);
14812 GridFunction *nodes2d = mesh2d->GetNodes();
14813 nodes2d->MakeOwner(fec2d);
14814
14815 NodeExtrudeCoefficient ecoeff(2, ny, sy);
14816 Vector lnodes;
14817 Array<int> vdofs2d;
14818 for (int i = 0; i < mesh->GetNE(); i++)
14819 {
14821 for (int j = ny-1; j >= 0; j--)
14822 {
14823 fes2d->GetElementVDofs(i*ny+j, vdofs2d);
14824 lnodes.SetSize(vdofs2d.Size());
14825 ecoeff.SetLayer(j);
14826 fes2d->GetFE(i*ny+j)->Project(ecoeff, T, lnodes);
14827 nodes2d->SetSubVector(vdofs2d, lnodes);
14828 }
14829 }
14830 }
14831 return mesh2d;
14832}
14833
14834Mesh *Extrude2D(Mesh *mesh, const int nz, const real_t sz)
14835{
14836 if (mesh->Dimension() != 2)
14837 {
14838 mfem::err << "Extrude2D : Not a 2D mesh!" << endl;
14839 mfem_error();
14840 }
14841
14842 int nvz = nz + 1;
14843 int nvt = mesh->GetNV() * nvz;
14844
14845 Mesh *mesh3d = new Mesh(3, nvt, mesh->GetNE()*nz,
14846 mesh->GetNBE()*nz+2*mesh->GetNE());
14847
14848 bool wdgMesh = false;
14849 bool hexMesh = false;
14850
14851 // vertices
14852 real_t vc[3];
14853 for (int i = 0; i < mesh->GetNV(); i++)
14854 {
14855 vc[0] = mesh->GetVertex(i)[0];
14856 vc[1] = mesh->GetVertex(i)[1];
14857 for (int j = 0; j < nvz; j++)
14858 {
14859 vc[2] = sz * (real_t(j) / nz);
14860 mesh3d->AddVertex(vc);
14861 }
14862 }
14863 // elements
14864 Array<int> vert;
14865 for (int i = 0; i < mesh->GetNE(); i++)
14866 {
14867 const Element *elem = mesh->GetElement(i);
14868 elem->GetVertices(vert);
14869 const int attr = elem->GetAttribute();
14870 Geometry::Type geom = elem->GetGeometryType();
14871 switch (geom)
14872 {
14873 case Geometry::TRIANGLE:
14874 wdgMesh = true;
14875 for (int j = 0; j < nz; j++)
14876 {
14877 int pv[6];
14878 pv[0] = vert[0] * nvz + j;
14879 pv[1] = vert[1] * nvz + j;
14880 pv[2] = vert[2] * nvz + j;
14881 pv[3] = vert[0] * nvz + (j + 1) % nvz;
14882 pv[4] = vert[1] * nvz + (j + 1) % nvz;
14883 pv[5] = vert[2] * nvz + (j + 1) % nvz;
14884
14885 mesh3d->AddWedge(pv, attr);
14886 }
14887 break;
14888 case Geometry::SQUARE:
14889 hexMesh = true;
14890 for (int j = 0; j < nz; j++)
14891 {
14892 int hv[8];
14893 hv[0] = vert[0] * nvz + j;
14894 hv[1] = vert[1] * nvz + j;
14895 hv[2] = vert[2] * nvz + j;
14896 hv[3] = vert[3] * nvz + j;
14897 hv[4] = vert[0] * nvz + (j + 1) % nvz;
14898 hv[5] = vert[1] * nvz + (j + 1) % nvz;
14899 hv[6] = vert[2] * nvz + (j + 1) % nvz;
14900 hv[7] = vert[3] * nvz + (j + 1) % nvz;
14901
14902 mesh3d->AddHex(hv, attr);
14903 }
14904 break;
14905 default:
14906 mfem::err << "Extrude2D : Invalid 2D element type \'"
14907 << geom << "\'" << endl;
14908 mfem_error();
14909 break;
14910 }
14911 }
14912 // 3D boundary from the 2D boundary
14913 for (int i = 0; i < mesh->GetNBE(); i++)
14914 {
14915 const Element *elem = mesh->GetBdrElement(i);
14916 elem->GetVertices(vert);
14917 const int attr = elem->GetAttribute();
14918 for (int j = 0; j < nz; j++)
14919 {
14920 int qv[4];
14921 qv[0] = vert[0] * nvz + j;
14922 qv[1] = vert[1] * nvz + j;
14923 qv[2] = vert[1] * nvz + (j + 1) % nvz;
14924 qv[3] = vert[0] * nvz + (j + 1) % nvz;
14925
14926 mesh3d->AddBdrQuad(qv, attr);
14927 }
14928 }
14929
14930 // 3D boundary from the 2D elements (bottom + top)
14931 int nba = (mesh->bdr_attributes.Size() > 0 ?
14932 mesh->bdr_attributes.Max() : 0);
14933 for (int i = 0; i < mesh->GetNE(); i++)
14934 {
14935 const Element *elem = mesh->GetElement(i);
14936 elem->GetVertices(vert);
14937 const int attr = nba + elem->GetAttribute();
14938 Geometry::Type geom = elem->GetGeometryType();
14939 switch (geom)
14940 {
14941 case Geometry::TRIANGLE:
14942 {
14943 int tv[3];
14944 tv[0] = vert[0] * nvz;
14945 tv[1] = vert[2] * nvz;
14946 tv[2] = vert[1] * nvz;
14947
14948 mesh3d->AddBdrTriangle(tv, attr);
14949
14950 tv[0] = vert[0] * nvz + nz;
14951 tv[1] = vert[1] * nvz + nz;
14952 tv[2] = vert[2] * nvz + nz;
14953
14954 mesh3d->AddBdrTriangle(tv, attr);
14955 }
14956 break;
14957 case Geometry::SQUARE:
14958 {
14959 int qv[4];
14960 qv[0] = vert[0] * nvz;
14961 qv[1] = vert[3] * nvz;
14962 qv[2] = vert[2] * nvz;
14963 qv[3] = vert[1] * nvz;
14964
14965 mesh3d->AddBdrQuad(qv, attr);
14966
14967 qv[0] = vert[0] * nvz + nz;
14968 qv[1] = vert[1] * nvz + nz;
14969 qv[2] = vert[2] * nvz + nz;
14970 qv[3] = vert[3] * nvz + nz;
14971
14972 mesh3d->AddBdrQuad(qv, attr);
14973 }
14974 break;
14975 default:
14976 mfem::err << "Extrude2D : Invalid 2D element type \'"
14977 << geom << "\'" << endl;
14978 mfem_error();
14979 break;
14980 }
14981 }
14982
14983 if ( hexMesh && wdgMesh )
14984 {
14985 mesh3d->FinalizeMesh(0, false);
14986 }
14987 else if ( hexMesh )
14988 {
14989 mesh3d->FinalizeHexMesh(1, 0, false);
14990 }
14991 else if ( wdgMesh )
14992 {
14993 mesh3d->FinalizeWedgeMesh(1, 0, false);
14994 }
14995
14996 GridFunction *nodes = mesh->GetNodes();
14997 if (nodes)
14998 {
14999 // duplicate the fec of the 2D mesh so that it can be deleted safely
15000 // along with its nodes, fes and fec
15001 FiniteElementCollection *fec3d = NULL;
15002 FiniteElementSpace *fes3d;
15003 const char *name = nodes->FESpace()->FEColl()->Name();
15004 string cname = name;
15005 if (cname == "Linear")
15006 {
15007 fec3d = new LinearFECollection;
15008 }
15009 else if (cname == "Quadratic")
15010 {
15011 fec3d = new QuadraticFECollection;
15012 }
15013 else if (cname == "Cubic")
15014 {
15015 fec3d = new CubicFECollection;
15016 }
15017 else if (!strncmp(name, "H1_", 3))
15018 {
15019 fec3d = new H1_FECollection(atoi(name + 7), 3);
15020 }
15021 else if (!strncmp(name, "L2_T", 4))
15022 {
15023 fec3d = new L2_FECollection(atoi(name + 10), 3, atoi(name + 4));
15024 }
15025 else if (!strncmp(name, "L2_", 3))
15026 {
15027 fec3d = new L2_FECollection(atoi(name + 7), 3);
15028 }
15029 else
15030 {
15031 delete mesh3d;
15032 mfem::err << "Extrude3D : The mesh uses unknown FE collection : "
15033 << cname << endl;
15034 mfem_error();
15035 }
15036 fes3d = new FiniteElementSpace(mesh3d, fec3d, 3);
15037 mesh3d->SetNodalFESpace(fes3d);
15038 GridFunction *nodes3d = mesh3d->GetNodes();
15039 nodes3d->MakeOwner(fec3d);
15040
15041 NodeExtrudeCoefficient ecoeff(3, nz, sz);
15042 Vector lnodes;
15043 Array<int> vdofs3d;
15044 for (int i = 0; i < mesh->GetNE(); i++)
15045 {
15047 for (int j = nz-1; j >= 0; j--)
15048 {
15049 fes3d->GetElementVDofs(i*nz+j, vdofs3d);
15050 lnodes.SetSize(vdofs3d.Size());
15051 ecoeff.SetLayer(j);
15052 fes3d->GetFE(i*nz+j)->Project(ecoeff, T, lnodes);
15053 nodes3d->SetSubVector(vdofs3d, lnodes);
15054 }
15055 }
15056 }
15057 return mesh3d;
15058}
15059
15060#ifdef MFEM_DEBUG
15061void Mesh::DebugDump(std::ostream &os) const
15062{
15063 // dump vertices and edges (NCMesh "nodes")
15064 os << NumOfVertices + NumOfEdges << "\n";
15065 for (int i = 0; i < NumOfVertices; i++)
15066 {
15067 const real_t *v = GetVertex(i);
15068 os << i << " " << v[0] << " " << v[1] << " " << v[2]
15069 << " 0 0 " << i << " -1 0\n";
15070 }
15071
15072 Array<int> ev;
15073 for (int i = 0; i < NumOfEdges; i++)
15074 {
15075 GetEdgeVertices(i, ev);
15076 real_t mid[3] = {0, 0, 0};
15077 for (int j = 0; j < 2; j++)
15078 {
15079 for (int k = 0; k < spaceDim; k++)
15080 {
15081 mid[k] += GetVertex(ev[j])[k];
15082 }
15083 }
15084 os << NumOfVertices+i << " "
15085 << mid[0]/2 << " " << mid[1]/2 << " " << mid[2]/2 << " "
15086 << ev[0] << " " << ev[1] << " -1 " << i << " 0\n";
15087 }
15088
15089 // dump elements
15090 os << NumOfElements << "\n";
15091 for (int i = 0; i < NumOfElements; i++)
15092 {
15093 const Element* e = elements[i];
15094 os << e->GetNVertices() << " ";
15095 for (int j = 0; j < e->GetNVertices(); j++)
15096 {
15097 os << e->GetVertices()[j] << " ";
15098 }
15099 os << e->GetAttribute() << " 0 " << i << "\n";
15100 }
15101
15102 // dump faces
15103 os << "0\n";
15104}
15105#endif
15106
15107}
Float cost() const
Definition gecko.cpp:857
void order(Functional *functional, uint iterations=1, uint window=2, uint period=2, uint seed=0, Progress *progress=0)
Definition gecko.cpp:1232
Node::Index insert_node(Float length=1)
Definition gecko.cpp:657
Arc::Index insert_arc(Node::Index i, Node::Index j, Float w=1, Float b=1)
Definition gecko.cpp:679
uint rank(Node::Index i) const
Definition gecko.hpp:672
uint Index
Definition gecko.hpp:595
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:68
int FindSorted(const T &el) const
Do bisection search for 'el' in a sorted array; return -1 if not found.
Definition array.hpp:899
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
Definition array.hpp:278
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition array.hpp:165
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:758
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
Definition array.cpp:85
int Size() const
Return the logical size of the array.
Definition array.hpp:147
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
Definition array.cpp:103
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:943
void DeleteAll()
Delete the whole array.
Definition array.hpp:925
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:830
T * GetData()
Returns the data.
Definition array.hpp:121
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition array.hpp:935
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T.
Definition array.hpp:286
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition array.hpp:325
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition array.hpp:322
T & Last()
Return the last element in the array.
Definition array.hpp:863
bool SetsExist() const
Return true if any named sets are currently defined.
bool AttributeSetExists(const std::string &name) const
Return true is the named attribute set is present.
Array< int > GetAttributeSetMarker(const std::string &set_name) const
Return a marker array corresponding to a named attribute set.
void Print(std::ostream &out=mfem::out, int width=-1) const
Print the contents of the container to an output stream.
void Copy(AttributeSets &copy) const
Create a copy of the internal data to the provided copy.
static int GetQuadrature1D(int b_type)
Get the corresponding Quadrature1D constant, when that makes sense; otherwise return Quadrature1D::In...
Definition fe_base.hpp:65
Piecewise-(bi)cubic continuous finite elements.
Definition fe_coll.hpp:941
int NumberOfEntries() const
Definition table.hpp:279
int NumberOfRows() const
Definition table.hpp:278
int Push(int a, int b)
Definition table.hpp:280
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void MultTranspose(const real_t *x, real_t *y) const
Multiply a vector with the transpose matrix.
Definition densemat.cpp:172
const real_t * HostRead() const
Shortcut for mfem::Read(GetMemory(), TotalSize(), false).
Definition densemat.hpp:478
real_t * Data() const
Returns the matrix data array.
Definition densemat.hpp:114
real_t * GetData() const
Returns the matrix data array.
Definition densemat.hpp:118
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:108
real_t Weight() const
Definition densemat.cpp:573
real_t Trace() const
Trace of a square matrix.
Definition densemat.cpp:429
real_t CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
void Print(std::ostream &out=mfem::out, int width_=4) const override
Prints matrix to stream out.
void GetColumn(int c, Vector &col) const
real_t FNorm2() const
Compute the square of the Frobenius norm of the matrix.
Definition densemat.hpp:276
real_t Det() const
Definition densemat.cpp:516
Rank 3 tensor (array of matrices)
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
void UseExternalData(real_t *ext_data, int i, int j, int k)
int SizeK() const
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:123
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Definition device.hpp:274
void TransformPrimal(real_t *v) const
Definition doftrans.cpp:17
const Mesh * mesh
The Mesh object containing the element.
Definition eltrans.hpp:97
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition eltrans.hpp:175
real_t Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint....
Definition eltrans.hpp:144
virtual int OrderJ() const =0
Return the order of the elements of the Jacobian of the transformation.
const DenseMatrix & Jacobian()
Return the Jacobian matrix of the transformation at the currently set IntegrationPoint,...
Definition eltrans.hpp:132
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition eltrans.hpp:106
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
void Reset()
Force the reevaluation of the Jacobian in the next call.
Definition eltrans.hpp:102
Abstract data type element.
Definition element.hpp:29
Geometry::Type GetGeometryType() const
Definition element.hpp:55
virtual Element * Duplicate(Mesh *m) const =0
virtual void GetVertices(Array< int > &v) const =0
Get the indices defining the vertices.
void SetAttribute(const int attr)
Set element's attribute.
Definition element.hpp:61
virtual Type GetType() const =0
Returns element's type.
Type
Constants for the classes derived from Element.
Definition element.hpp:41
int GetAttribute() const
Return element's attribute.
Definition element.hpp:58
static Type TypeFromGeometry(const Geometry::Type geom)
Return the Element::Type associated with the given Geometry::Type.
Definition element.cpp:17
virtual int GetNVertices() const =0
virtual void SetVertices(const Array< int > &v)=0
Set the indices defining the vertices.
A specialized ElementTransformation class representing a face and its two neighboring elements.
Definition eltrans.hpp:750
ElementTransformation * Elem2
Definition eltrans.hpp:791
ElementTransformation * Elem1
Definition eltrans.hpp:791
@ HAVE_ELEM2
Element on side 2 is configured.
Definition eltrans.hpp:783
@ HAVE_LOC1
Point transformation for side 1 is configured.
Definition eltrans.hpp:784
@ HAVE_ELEM1
Element on side 1 is configured.
Definition eltrans.hpp:782
@ HAVE_FACE
Face transformation is configured.
Definition eltrans.hpp:786
@ HAVE_LOC2
Point transformation for side 2 is configured.
Definition eltrans.hpp:785
IntegrationPointTransformation Loc1
Definition eltrans.hpp:793
void SetGeometryType(Geometry::Type g)
Method to set the geometry type of the face.
Definition eltrans.hpp:805
void SetConfigurationMask(int m)
Set the mask indicating which portions of the object have been setup.
Definition eltrans.hpp:776
IntegrationPointTransformation Loc2
Definition eltrans.hpp:793
real_t CheckConsistency(int print_level=0, std::ostream &out=mfem::out)
Check for self-consistency: compares the result of mapping the reference face vertices to physical co...
Definition eltrans.cpp:687
Structure for storing face geometric factors: coordinates, Jacobians, determinants of the Jacobians,...
Definition mesh.hpp:2991
Vector normal
Normals at all quadrature points.
Definition mesh.hpp:3037
Vector J
Jacobians of the element transformations at all quadrature points.
Definition mesh.hpp:3024
const IntegrationRule * IntRule
Definition mesh.hpp:2994
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition mesh.hpp:3015
FaceGeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, FaceType type, MemoryType d_mt=MemoryType::DEFAULT)
Definition mesh.cpp:14589
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition mesh.hpp:3030
A class that performs interpolation from a face E-vector to quadrature point values and/or derivative...
@ DERIVATIVES
Evaluate the derivatives at quadrature points.
@ DETERMINANTS
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
@ VALUES
Evaluate the values at quadrature points.
void DisableTensorProducts(bool disable=true) const
Disable the use of tensor product evaluations, for tensor-product elements, e.g. quads and hexes.
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
void Mult(const Vector &e_vec, unsigned eval_flags, Vector &q_val, Vector &q_der, Vector &q_det, Vector &q_nor) const
Interpolate the E-vector e_vec to quadrature points.
Base class for operators that extracts Face degrees of freedom.
void Mult(const Vector &x, Vector &y) const override=0
Extract the face degrees of freedom from x into y.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
virtual const int * DofOrderForOrientation(Geometry::Type GeomType, int Or) const =0
Returns an array, say p, that maps a local permuted index i to a local base index: base_i = p[i].
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name.
Definition fe_coll.cpp:124
virtual const char * Name() const
Definition fe_coll.hpp:79
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:244
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Compute the full set of vdofs corresponding to each entry in dofs.
Definition fespace.cpp:258
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the interior of the specified edge.
Definition fespace.cpp:3816
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary fac...
Definition fespace.cpp:3881
DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
Definition fespace.cpp:3513
void GetEdgeVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified edge, including the DOFs for the vert...
Definition fespace.cpp:367
void GetVertexDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the specified vertices.
Definition fespace.cpp:3761
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:845
virtual void UpdateMeshPointer(Mesh *new_mesh)
Definition fespace.cpp:4327
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition fespace.cpp:1582
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i'th element. The returned indices are offsets into an ...
Definition fespace.cpp:332
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3835
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:876
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:891
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition fespace.cpp:1510
const FiniteElement * GetEdgeElement(int i, int variant=0) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th edge in the ...
Definition fespace.cpp:3944
void GetFaceVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified face, including the DOFs for the edge...
Definition fespace.cpp:361
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition fespace.cpp:4157
const FiniteElement * GetTraceElement(int i, Geometry::Type geom_type) const
Return the trace element from element 'i' to the given 'geom_type'.
Definition fespace.cpp:3953
void SetRelaxedHpConformity(bool relaxed=true)
Definition fespace.hpp:1524
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition fespace.hpp:885
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Definition fespace.cpp:3914
void SetElementOrder(int i, int p)
Sets the order of the i'th finite element.
Definition fespace.cpp:196
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition fespace.hpp:908
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:878
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:679
DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element 'bel'. The returned indices are offsets in...
Definition fespace.cpp:3617
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:841
const FaceQuadratureInterpolator * GetFaceQuadratureInterpolator(const IntegrationRule &ir, FaceType type) const
Return a FaceQuadratureInterpolator that interpolates E-vectors to quadrature point values and/or der...
Definition fespace.cpp:1611
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition fespace.hpp:1510
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the interior of the specified face.
Definition fespace.cpp:3792
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3871
virtual int GetMaxElementOrder() const
Return the maximum polynomial order over all elements.
Definition fespace.hpp:705
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the interior of the specified element.
Definition fespace.cpp:3771
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for i'th boundary element. The returned indices are offsets int...
Definition fespace.cpp:348
int DofToVDof(int dof, int vd, int ndofs=-1) const
Compute a single vdof corresponding to the index dof and the vector index vd.
Definition fespace.cpp:294
virtual const FaceRestriction * GetFaceRestriction(ElementDofOrdering f_ordering, FaceType, L2FaceValues mul=L2FaceValues::DoubleValued) const
Return an Operator that converts L-vectors to E-vectors on each face.
Definition fespace.cpp:1543
Abstract class for all finite elements.
Definition fe_base.hpp:244
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:321
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition fe_base.hpp:400
virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const =0
Evaluate the gradients of all shape functions of a scalar finite element in reference space at the gi...
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition fe_base.hpp:331
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Given a coefficient and a transformation, compute its projection (approximation) in the local finite ...
Definition fe_base.cpp:126
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:334
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition mesh.hpp:2937
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition mesh.hpp:2967
const Mesh * mesh
Definition mesh.hpp:2943
const IntegrationRule * IntRule
Definition mesh.hpp:2944
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition mesh.hpp:2982
Vector J
Jacobians of the element transformations at all quadrature points.
Definition mesh.hpp:2976
GeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, MemoryType d_mt=MemoryType::DEFAULT)
Definition mesh.cpp:14509
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
Definition geom.cpp:1136
static const int NumGeom
Definition geom.hpp:46
static const int Dimension[NumGeom]
Definition geom.hpp:51
const IntegrationPoint & GetCenter(int GeomType) const
Return the center of the given Geometry::Type, GeomType.
Definition geom.hpp:75
static const char * Name[NumGeom]
Definition geom.hpp:49
static const int NumVerts[NumGeom]
Definition geom.hpp:53
const IntegrationRule * GetVertices(int GeomType) const
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType.
Definition geom.cpp:293
void JacToPerfJac(int GeomType, const DenseMatrix &J, DenseMatrix &PJ) const
Definition geom.cpp:909
static int GetInverseOrientation(Type geom_type, int orientation)
Return the inverse of the given orientation for the specified geometry type.
Definition geom.cpp:264
static const int DimStart[MaxDim+2]
Definition geom.hpp:52
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition gridfunc.cpp:167
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec_owned and fes.
Definition gridfunc.hpp:122
FiniteElementSpace * FESpace()
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
int VectorDim() const
Shortcut for calling FiniteElementSpace::GetVectorDim() on the underlying fes.
Definition gridfunc.cpp:353
void GetNodalValues(int i, Array< real_t > &nval, int vdim=1) const
Returns the values in the vertices of i'th element for dimension vdim.
Definition gridfunc.cpp:392
void GetVectorValues(int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const
Definition gridfunc.cpp:711
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:275
const int * GetDofMap(Geometry::Type GeomType) const
Get the Cartesian to local H1 dof map.
Definition fe_coll.cpp:2067
int GetId(int p1, int p2)
Get id of item whose parents are p1, p2... Create it if it doesn't exist.
Definition hash.hpp:682
int FindId(int p1, int p2) const
Find id of item whose parents are p1, p2... Return -1 if it doesn't exist.
Definition hash.hpp:773
Data type hexahedron element.
A set of integers.
Definition sets.hpp:24
void Recreate(const int n, const int *p)
Create an integer set from C-array 'p' of 'n' integers. Overwrites any existing set data.
Definition sets.cpp:33
IsoparametricTransformation Transf
Definition eltrans.hpp:733
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition eltrans.cpp:587
Class for integration point with weight.
Definition intrules.hpp:35
void Get(real_t *p, const int dim) const
Definition intrules.hpp:60
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:259
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
The inverse transformation of a given ElementTransformation.
Definition eltrans.hpp:200
virtual int Transform(const Vector &pt, IntegrationPoint &ip)
Given a point, pt, in physical space, find its reference coordinates, ip.
Definition eltrans.cpp:338
@ Inside
The point is inside the element.
Definition eltrans.hpp:244
void SetTransformation(ElementTransformation &Trans)
Set a new forward ElementTransformation, Trans.
Definition eltrans.hpp:320
A standard isoparametric element transformation.
Definition eltrans.hpp:629
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition eltrans.hpp:668
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition eltrans.hpp:648
void SetIdentityTransformation(Geometry::Type GeomType)
Set the FiniteElement Geometry for the reference elements being used.
Definition eltrans.cpp:417
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition eltrans.hpp:671
void Transform(const IntegrationPoint &, Vector &) override
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Definition eltrans.cpp:532
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:346
Piecewise-(bi/tri)linear continuous finite elements.
Definition fe_coll.hpp:861
List of integer sets.
Definition sets.hpp:51
int Insert(const IntegerSet &s)
Check to see if set 's' is in the list. If not append it to the end of the list. Returns the index of...
Definition sets.cpp:56
void AsTable(Table &t) const
Write the list of sets into table 't'.
Definition sets.cpp:81
int Size() const
Return the number of integer sets in the list.
Definition sets.hpp:58
Class containing a minimal description of a part (a subset of the elements) of a Mesh and its connect...
Definition mesh.hpp:2626
Array< real_t > vertex_coordinates
Definition mesh.hpp:2726
int dimension
Reference space dimension of the elements.
Definition mesh.hpp:2643
int num_vertices
Number of vertices.
Definition mesh.hpp:2649
Table group_shared_entity_to_vertex[Geometry::NumGeom]
Definition mesh.hpp:2789
Array< int > entity_to_vertex[Geometry::NumGeom]
Definition mesh.hpp:2678
std::unique_ptr< Mesh > mesh
Definition mesh.hpp:2733
Array< int > boundary_map
Optional re-ordering for the boundary elements, similar to 'element_map'.
Definition mesh.hpp:2702
std::unique_ptr< FiniteElementSpace > nodal_fes
Definition mesh.hpp:2739
int num_parts
Total number of MeshParts.
Definition mesh.hpp:2753
Array< int > tet_refine_flags
Store the refinement flags for tetraheral elements. If all tets have zero refinement flags then this ...
Definition mesh.hpp:2682
int space_dimension
Dimension of the physical space into which the MeshPart is embedded.
Definition mesh.hpp:2646
int num_bdr_elements
Number of boundary elements with reference space dimension equal to 'dimension'-1.
Definition mesh.hpp:2656
int num_elements
Number of elements with reference space dimension equal to 'dimension'.
Definition mesh.hpp:2652
Mesh & GetMesh()
Construct a serial Mesh object from the MeshPart.
Definition mesh.cpp:13843
int my_part_id
Index of the part described by this MeshPart: 0 <= 'my_part_id' < 'num_parts'.
Definition mesh.hpp:2757
Array< int > element_map
Definition mesh.hpp:2699
Array< int > attributes
Definition mesh.hpp:2708
Table my_groups
Definition mesh.hpp:2770
std::unique_ptr< GridFunction > nodes
Definition mesh.hpp:2747
void Print(std::ostream &os) const
Write the MeshPart to a stream using the parallel format "MFEM mesh v1.2".
Definition mesh.cpp:13663
Array< int > bdr_attributes
Definition mesh.hpp:2715
Array< int > partitioning
Definition mesh.hpp:2857
std::unique_ptr< FiniteElementSpace > ExtractFESpace(MeshPart &mesh_part, const FiniteElementSpace &global_fespace) const
Construct a local version of the given FiniteElementSpace global_fespace corresponding to the given m...
Definition mesh.cpp:14468
MeshPartitioner(Mesh &mesh_, int num_parts_, const int *partitioning_=nullptr, int part_method=1)
Construct a MeshPartitioner.
Definition mesh.cpp:13926
std::unique_ptr< GridFunction > ExtractGridFunction(const MeshPart &mesh_part, const GridFunction &global_gf, FiniteElementSpace &local_fespace) const
Construct a local version of the given GridFunction, global_gf, corresponding to the given mesh_part....
Definition mesh.cpp:14483
void ExtractPart(int part_id, MeshPart &mesh_part) const
Construct a MeshPart corresponding to the given part_id.
Definition mesh.cpp:13998
List of mesh geometries stored as Array<Geometry::Type>.
Definition mesh.hpp:1489
Mesh data type.
Definition mesh.hpp:64
int CheckElementOrientation(bool fix_it=true)
Check (and optionally attempt to fix) the orientation of the elements.
Definition mesh.cpp:6575
Array< Vertex > vertices
Definition mesh.hpp:105
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
Definition mesh.cpp:7321
void GetEdgeOrdering(const DSTable &v_to_v, Array< int > &order)
Definition mesh.cpp:2869
void GetLocalFaceTransformation(int face_type, int elem_type, IsoparametricTransformation &Transf, int info) const
A helper method that constructs a transformation from the reference space of a face to the reference ...
Definition mesh.cpp:938
void NURBSCoarsening(int cf=2, real_t tol=1.0e-12)
Definition mesh.cpp:10827
void SetVerticesFromNodes(const GridFunction *nodes)
Helper to set vertex coordinates given a high-order curvature function.
Definition mesh.cpp:6517
void ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
int GetPatchBdrAttribute(int i) const
Return the attribute of patch boundary element i, for a NURBS mesh.
Definition mesh.cpp:3243
int GetElementToEdgeTable(Table &)
Definition mesh.cpp:7741
int meshgen
Definition mesh.hpp:88
void GetGeometries(int dim, Array< Geometry::Type > &el_geoms) const
Return all element geometries of the given dimension present in the mesh.
Definition mesh.cpp:7254
void SetVertices(const Vector &vert_coord)
Definition mesh.cpp:9231
Element * NewElement(int geom)
Definition mesh.cpp:4672
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition mesh.hpp:2381
IsoparametricTransformation Transformation2
Definition mesh.hpp:249
int GetNEdges() const
Return the number of edges.
Definition mesh.hpp:1288
void MarkForRefinement()
Definition mesh.cpp:2837
void GetBdrElementFace(int i, int *f, int *o) const
Definition mesh.cpp:7565
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Definition mesh.cpp:1850
Table * GetVertexToBdrElementTable()
Definition mesh.cpp:7447
static void PrintElement(const Element *el, std::ostream &os)
Definition mesh.cpp:4738
Array< FaceInfo > faces_info
Definition mesh.hpp:232
int EulerNumber() const
Equals 1 + num_holes - num_loops.
Definition mesh.hpp:1222
CoarseFineTransformations CoarseFineTr
Definition mesh.hpp:255
void GetElementJacobian(int i, DenseMatrix &J, const IntegrationPoint *ip=NULL)
Definition mesh.cpp:62
int AddSegment(int v1, int v2, int attr=1)
Adds a segment to the mesh given by 2 vertices v1 and v2.
Definition mesh.cpp:1930
int AddBdrElement(Element *elem)
Definition mesh.cpp:2243
void GetElementColoring(Array< int > &colors, int el0=0)
Definition mesh.cpp:12372
virtual FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition mesh.cpp:1004
void FinalizeMesh(int refine=0, bool fix_orientation=true)
Finalize the construction of any type of Mesh.
Definition mesh.cpp:3355
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:290
static void PrintElementWithoutAttr(const Element *el, std::ostream &os)
Definition mesh.cpp:4714
MemAlloc< Tetrahedron, 1024 > TetMemory
Definition mesh.hpp:270
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition mesh.hpp:402
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:298
void ReadTrueGridMesh(std::istream &input)
static const int vtk_quadratic_tet[10]
Definition mesh.hpp:263
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
Definition mesh.cpp:1463
friend class ParNCMesh
Definition mesh.hpp:69
virtual void GetExteriorFaceMarker(Array< int > &face_marker) const
Populate a marker array identifying exterior faces.
Definition mesh.cpp:1555
IsoparametricTransformation EdgeTransformation
Definition mesh.hpp:251
static FiniteElement * GetTransformationFEforElementType(Element::Type)
Return FiniteElement for reference element of the specified type.
Definition mesh.cpp:336
int AddBdrQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition mesh.cpp:2290
int * CartesianPartitioning(int nxyz[])
Definition mesh.cpp:8372
Array< int > FindFaceNeighbors(const int elem) const
Returns the sorted, unique indices of elements sharing a face with element elem, including elem.
Definition mesh.cpp:7537
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition mesh.cpp:6815
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition mesh.cpp:7635
void GetLocalSegToQuadTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:716
virtual long long ReduceInt(int value) const
Utility function: sum integers from all processors (Allreduce).
Definition mesh.hpp:2589
int NumOfBdrElements
Definition mesh.hpp:79
void BdrBisection(int i, const HashTable< Hashed2 > &)
Bisect a boundary triangle: boundary element with index i is bisected.
Definition mesh.cpp:11258
Element::Type GetBdrElementType(int i) const
Returns the type of boundary element i.
Definition mesh.cpp:7640
const Table & ElementToEdgeTable() const
Definition mesh.cpp:7825
bool Conforming() const
Return a bool indicating whether this mesh is conforming.
Definition mesh.hpp:2365
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:6531
virtual void UnmarkNamedBoundaries(const std::string &set_name, Array< int > &bdr_marker) const
Unmark boundary attributes in the named set.
Definition mesh.cpp:1619
void ReadNetgen3DMesh(std::istream &input)
void GetBdrElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of boundary element i.
Definition mesh.hpp:1512
Geometry::Type GetFaceGeometry(int i) const
Return the Geometry::Type associated with face i.
Definition mesh.cpp:1476
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition mesh.cpp:10883
Geometry::Type GetElementGeometry(int i) const
Definition mesh.hpp:1434
Geometry::Type GetBdrElementGeometry(int i) const
Definition mesh.hpp:1446
int AddTri(const int *vi, int attr=1)
Adds a triangle to the mesh given by 3 vertices vi.
Definition mesh.hpp:930
static Mesh MakeCartesian1D(int n, real_t sx=1.0)
Creates 1D mesh, divided into n equal intervals.
Definition mesh.cpp:4463
int GetAttribute(int i) const
Return the attribute of element i.
Definition mesh.hpp:1389
void NodesUpdated()
This function should be called after the mesh node coordinates have been updated externally,...
Definition mesh.hpp:2211
void EnsureNodes()
Make sure that the mesh has valid nodes, i.e. its geometry is described by a vector finite element gr...
Definition mesh.cpp:6432
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition mesh.hpp:1508
void UniformRefinement3D_base(Array< int > *f2qf=NULL, DSTable *v_to_v_p=NULL, bool update_nodes=true)
Definition mesh.cpp:9559
int AddQuad(int v1, int v2, int v3, int v4, int attr=1)
Adds a quadrilateral to the mesh given by 4 vertices v1 through v4.
Definition mesh.cpp:1958
long nodes_sequence
Counter for geometric factor invalidation.
Definition mesh.hpp:98
virtual void Load(std::istream &input, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition mesh.hpp:749
IsoparametricTransformation FaceTransformation
Definition mesh.hpp:251
Array< NCFaceInfo > nc_faces_info
Definition mesh.hpp:233
friend class NCMesh
Definition mesh.hpp:65
void MakeRefined_(Mesh &orig_mesh, const Array< int > &ref_factors, int ref_type)
Internal function used in Mesh::MakeRefined.
Definition mesh.cpp:5172
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr=1)
Adds a wedge to the mesh given by 6 vertices v1 through v6.
Definition mesh.cpp:1993
Array< int > GetFaceToBdrElMap() const
Definition mesh.cpp:1517
static Mesh MakeCartesian2DWith4TrisPerQuad(int nx, int ny, real_t sx=1.0, real_t sy=1.0)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny*4 triangles.
Definition mesh.cpp:4500
void ReadInlineMesh(std::istream &input, bool generate_edges=false)
void SetPatchAttribute(int i, int attr)
Set the attribute of patch i, for a NURBS mesh.
Definition mesh.cpp:3214
void FinalizeTetMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a tetrahedral Mesh.
Definition mesh.cpp:3249
real_t GetLength(int i, int j) const
Return the length of the segment from node i to node j.
Definition mesh.cpp:7679
const FiniteElementSpace * GetNodalFESpace() const
Definition mesh.cpp:6479
void AddBdrQuadAsTriangles(const int *vi, int attr=1)
Definition mesh.cpp:2304
int AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr=1)
Adds a pyramid to the mesh given by 5 vertices v1 through v5.
Definition mesh.cpp:2007
void Loader(std::istream &input, int generate_edges=0, std::string parse_tag="")
Definition mesh.cpp:4797
const Table & ElementToElementTable()
Definition mesh.cpp:7780
void ScaleElements(real_t sf)
Definition mesh.cpp:13076
void GenerateNCFaceInfo()
Definition mesh.cpp:8059
void ReadLineMesh(std::istream &input)
void ApplyLocalSlaveTransformation(FaceElementTransformations &FT, const FaceInfo &fi, bool is_ghost) const
Definition mesh.cpp:1154
Array< Element * > faces
Definition mesh.hpp:107
int Dim
Definition mesh.hpp:76
real_t AggregateError(const Array< real_t > &elem_error, const int *fine, int nfine, int op)
Derefinement helper.
Definition mesh.cpp:10558
void CheckPartitioning(int *partitioning_)
Definition mesh.cpp:8816
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
Definition mesh.cpp:2983
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
Definition mesh.cpp:1528
void GetLocalPtToSegTransformation(IsoparametricTransformation &, int i) const
Used in GetFaceElementTransformations (...)
Definition mesh.cpp:681
bool Nonconforming() const
Return a bool indicating whether this mesh is nonconforming.
Definition mesh.hpp:2367
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition mesh.hpp:1395
virtual void MarkExternalBoundaries(Array< int > &bdr_marker, bool excl=true) const
Mark boundary attributes of external boundaries.
Definition mesh.cpp:1640
void PrintCharacteristics(Vector *Vh=NULL, Vector *Vk=NULL, std::ostream &os=mfem::out)
Compute and print mesh characteristics such as number of vertices, number of elements,...
Definition mesh.cpp:251
void UpdateNURBS()
Definition mesh.cpp:6069
static int ComposeQuadOrientations(int ori_a_b, int ori_b_c)
Definition mesh.cpp:6863
int AddTriangle(int v1, int v2, int v3, int attr=1)
Adds a triangle to the mesh given by 3 vertices v1 through v3.
Definition mesh.cpp:1944
void GenerateFaces()
Definition mesh.cpp:7958
static const int vtk_quadratic_wedge[18]
Definition mesh.hpp:265
int EulerNumber2D() const
Equals 1 - num_holes.
Definition mesh.hpp:1225
AttributeSets bdr_attribute_sets
Named sets of boundary element attributes.
Definition mesh.hpp:296
void AddBdrElements(Array< Element * > &bdr_elems, const Array< int > &be_to_face)
Add an array of boundary elements to the mesh, along with map from the elements to their faces.
Definition mesh.cpp:2250
void Destroy()
Definition mesh.cpp:1780
int GetBdrElementFaceIndex(int be_idx) const
Return the local face (codimension-1) index for the given boundary element index.
Definition mesh.hpp:1588
void GetVertices(Vector &vert_coord) const
Definition mesh.cpp:9220
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
Definition mesh.cpp:10658
virtual int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type, does not count master nonconforming face...
Definition mesh.cpp:6547
void Make1D(int n, real_t sx=1.0)
Definition mesh.cpp:4266
friend class Tetrahedron
Definition mesh.hpp:269
void DeleteTables()
Definition mesh.hpp:316
void RefineNURBSFromFile(std::string ref_file)
Definition mesh.cpp:5900
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1339
int AddBdrPoint(int v, int attr=1)
Definition mesh.cpp:2319
void FinalizeWedgeMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a wedge Mesh.
Definition mesh.cpp:3290
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition mesh.cpp:6726
void PrintTopo(std::ostream &os, const Array< int > &e_to_k, const int version, const std::string &comment="") const
Write the beginning of a NURBS mesh to os, specifying the NURBS patch topology. Optional file comment...
Definition mesh.cpp:11759
static Mesh MakeSimplicial(const Mesh &orig_mesh)
Definition mesh.cpp:5401
void SetPatchBdrAttribute(int i, int attr)
Set the attribute of patch boundary element i, for a NURBS mesh.
Definition mesh.cpp:3231
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition mesh.hpp:1291
int AddVertexAtMeanCenter(const int *vi, const int nverts, int dim=3)
Definition mesh.cpp:1913
static int GetTetOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition mesh.cpp:6894
real_t GetGeckoElementOrdering(Array< int > &ordering, int iterations=4, int window=4, int period=2, int seed=0, bool verbose=false, real_t time_limit=0)
Definition mesh.cpp:2466
static int EncodeFaceInfo(int local_face_index, int orientation)
Given local_face_index and orientation, return the corresponding encoded "face info int".
Definition mesh.hpp:2076
bool FaceIsTrueInterior(int FaceNo) const
Definition mesh.hpp:571
long GetSequence() const
Definition mesh.hpp:2387
const CoarseFineTransformations & GetRefinementTransforms() const
Definition mesh.cpp:11407
void Make2D5QuadsFromQuad(int nx, int ny, real_t sx, real_t sy)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny*5 quadrilaterals.
Definition mesh.cpp:3899
void GetLocalQuadToWdgTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:833
ElementTransformation * GetFaceTransformation(int FaceNo)
Returns a pointer to the transformation defining the given face element.
Definition mesh.cpp:607
void SetAttribute(int i, int attr)
Set the attribute of element i.
Definition mesh.cpp:7629
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition mesh.cpp:3362
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Definition mesh.hpp:2433
void DestroyTables()
Definition mesh.cpp:1735
static Mesh MakeCartesian2DWith5QuadsPerQuad(int nx, int ny, real_t sx=1.0, real_t sy=1.0)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny*5 quadrilaterals.
Definition mesh.cpp:4509
const FaceGeometricFactors * GetFaceGeometricFactors(const IntegrationRule &ir, const int flags, FaceType type, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors for the faces corresponding to the given integration rule.
Definition mesh.cpp:900
void PrintWithPartitioning(int *partitioning, std::ostream &os, int elem_attr=0) const
Prints the mesh with boundary elements given by the boundary of the subdomains, so that the boundary ...
Definition mesh.cpp:12447
void Clear()
Clear the contents of the Mesh.
Definition mesh.hpp:761
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
Definition mesh.cpp:2917
void ReadXML_VTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo, const std::string &xml_prefix="")
int AddVertex(real_t x, real_t y=0.0, real_t z=0.0)
Definition mesh.cpp:1873
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Definition mesh.cpp:10270
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
void Make3D(int nx, int ny, int nz, Element::Type type, real_t sx, real_t sy, real_t sz, bool sfc_ordering)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz hexahedra if type =...
Definition mesh.cpp:3543
virtual void Save(const std::string &fname, int precision=16) const
Definition mesh.cpp:11806
int AddTet(int v1, int v2, int v3, int v4, int attr=1)
Adds a tetrahedron to the mesh given by 4 vertices v1 through v4.
Definition mesh.cpp:1972
void GetBoundingBox(Vector &min, Vector &max, int ref=2)
Returns the minimum and maximum corners of the mesh bounding box.
Definition mesh.cpp:138
void GetBdrPointMatrix(int i, DenseMatrix &pointmat) const
Definition mesh.cpp:7663
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1216
ElementTransformation * GetTypicalElementTransformation()
If the local mesh is not empty return GetElementTransformation(0); otherwise, return the identity tra...
Definition mesh.cpp:390
Table * el_to_face
Definition mesh.hpp:236
void RandomRefinement(real_t prob, bool aniso=false, int nonconforming=-1, int nc_limit=0)
Refine each element with given probability. Uses GeneralRefinement.
Definition mesh.cpp:10975
const Element * GetBdrElement(int i) const
Return pointer to the i'th boundary element object.
Definition mesh.hpp:1354
void CheckDisplacements(const Vector &displacements, real_t &tmax)
Definition mesh.cpp:9134
friend class NURBSExtension
Definition mesh.hpp:66
void AddTriangleFaceElement(int lf, int gf, int el, int v0, int v1, int v2)
Definition mesh.cpp:7903
void AddHexAs24TetsWithPoints(int *vi, std::map< std::array< int, 4 >, int > &hex_face_verts, int attr=1)
Adds 24 tetrahedrons to the mesh by splitting a hexahedron.
Definition mesh.cpp:2175
void GetNode(int i, real_t *coord) const
Definition mesh.cpp:9240
void ReorderElements(const Array< int > &ordering, bool reorder_vertices=true)
Definition mesh.cpp:2685
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition mesh.hpp:408
void UpdateNodes()
Update the nodes of a curved mesh after the topological part of a Mesh::Operation,...
Definition mesh.cpp:9385
void PrintElementsWithPartitioning(int *partitioning, std::ostream &os, int interior_faces=0)
Definition mesh.cpp:12566
Mesh & operator=(Mesh &&mesh)
Move assignment operator.
Definition mesh.cpp:4447
long sequence
Definition mesh.hpp:95
static int InvertQuadOrientation(int ori)
Definition mesh.cpp:6888
Array< FaceGeometricFactors * > face_geom_factors
Definition mesh.hpp:301
void GetLocalTriToPyrTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:786
Table * bel_to_edge
Definition mesh.hpp:240
static Mesh MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
Create a refined (by any factor) version of orig_mesh.
Definition mesh.cpp:4518
real_t GetElementSize(int i, int type=0)
Get the size of the i-th element relative to the perfect reference element.
Definition mesh.cpp:107
Element * ReadElementWithoutAttr(std::istream &input)
Definition mesh.cpp:4696
int AddBdrSegment(int v1, int v2, int attr=1)
Definition mesh.cpp:2262
bool DerefineByError(Array< real_t > &elem_error, real_t threshold, int nc_limit=0, int op=1)
Definition mesh.cpp:10629
void FinalizeHexMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a hexahedral Mesh.
Definition mesh.cpp:3325
int AddElement(Element *elem)
Definition mesh.cpp:2236
static int DecodeFaceInfoLocalIndex(int info)
Given a "face info int", return the local face index.
Definition mesh.hpp:2072
Table * el_to_edge
Definition mesh.hpp:235
FaceInformation GetFaceInformation(int f) const
Definition mesh.cpp:1193
int GetNumFacesWithGhost() const
Return the number of faces (3D), edges (2D) or vertices (1D) including ghost faces.
Definition mesh.cpp:6542
void GetElementTransformation(int i, IsoparametricTransformation *ElTr) const
Builds the transformation defining the i-th element in ElTr. ElTr must be allocated in advance and wi...
Definition mesh.cpp:357
void RefineAtVertex(const Vertex &vert, real_t eps=0.0, int nonconforming=-1)
Refine elements sharing the specified vertex. Uses GeneralRefinement.
Definition mesh.cpp:10994
void GetBdrElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of bdr element i.
Definition mesh.cpp:7289
static int InvertTriOrientation(int ori)
Definition mesh.cpp:6809
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition mesh.cpp:8180
void FinalizeQuadMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a quadrilateral Mesh.
Definition mesh.cpp:2404
void Make3D24TetsFromHex(int nx, int ny, int nz, real_t sx, real_t sy, real_t sz)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz*24 tetrahedrons.
Definition mesh.cpp:3973
virtual bool NonconformingDerefinement(Array< real_t > &elem_error, real_t threshold, int nc_limit=0, int op=1)
NC version of GeneralDerefinement.
Definition mesh.cpp:10581
void AddVertexParents(int i, int p1, int p2)
Mark vertex i as nonconforming, with parent vertices p1 and p2.
Definition mesh.cpp:1897
MFEM_DEPRECATED void GetBdrElementAdjacentElement2(int bdr_el, int &el, int &info) const
Deprecated.
Definition mesh.cpp:7606
int GetPatchAttribute(int i) const
Return the attribute of patch i, for a NURBS mesh.
Definition mesh.cpp:3225
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
Definition mesh.cpp:1457
void Printer(std::ostream &os=mfem::out, std::string section_delimiter="", const std::string &comments="") const
Definition mesh.cpp:11634
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition mesh.hpp:1462
ElementTransformation * GetBdrElementTransformation(int i)
Returns a pointer to the transformation defining the i-th boundary element.
Definition mesh.cpp:530
IsoparametricTransformation Transformation
Definition mesh.hpp:249
void Init()
Definition mesh.cpp:1703
void Make2D4TrisFromQuad(int nx, int ny, real_t sx, real_t sy)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny*4 triangles.
Definition mesh.cpp:3826
void GetLocalTriToWdgTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:760
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
Definition mesh.cpp:7514
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1219
void ReadNURBSMesh(std::istream &input, int &curved, int &read_gf, bool spacing=false)
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors corresponding to the given integration rule.
Definition mesh.cpp:880
static Mesh MakeCartesian3D(int nx, int ny, int nz, Element::Type type, real_t sx=1.0, real_t sy=1.0, real_t sz=1.0, bool sfc_ordering=true)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz hexahedra if type =...
Definition mesh.cpp:4481
Table * edge_vertex
Definition mesh.hpp:247
void LoadPatchTopo(std::istream &input, Array< int > &edge_to_knot)
Read NURBS patch/macro-element mesh.
Definition mesh.cpp:6131
void GetCharacteristics(real_t &h_min, real_t &h_max, real_t &kappa_min, real_t &kappa_max, Vector *Vh=NULL, Vector *Vk=NULL)
Definition mesh.cpp:202
void SetNodalGridFunction(GridFunction *nodes, bool make_owner=false)
Definition mesh.cpp:6473
void ReadCubit(const std::string &filename, int &curved, int &read_gf)
Load a mesh from a Genesis file.
void SetNode(int i, const real_t *coord)
Definition mesh.cpp:9259
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:9294
int NumOfVertices
Definition mesh.hpp:79
AttributeSets attribute_sets
Named sets of element attributes.
Definition mesh.hpp:293
virtual void UniformRefinement3D()
Refine a mixed 3D mesh uniformly.
Definition mesh.hpp:457
static int ComposeTriOrientations(int ori_a_b, int ori_b_c)
Definition mesh.cpp:6786
Array< int > be_to_face
Definition mesh.hpp:238
void PrintBdrVTU(std::string fname, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0)
Definition mesh.cpp:12012
void AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
Definition mesh.cpp:7866
FaceElementTransformations * GetBdrFaceTransformations(int BdrElemNo)
Builds the transformation defining the given boundary face.
Definition mesh.cpp:1123
int AddBdrTriangle(int v1, int v2, int v3, int attr=1)
Definition mesh.cpp:2276
void GetGeometricParametersFromJacobian(const DenseMatrix &J, real_t &volume, Vector &aspr, Vector &skew, Vector &ori) const
Computes geometric parameters associated with a Jacobian matrix in 2D/3D. These parameters are (1) Ar...
Definition mesh.cpp:13520
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1279
static int DecodeFaceInfoOrientation(int info)
Given a "face info int", return the face orientation.
Definition mesh.hpp:2069
void GetHilbertElementOrdering(Array< int > &ordering)
Definition mesh.cpp:2633
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition mesh.cpp:7351
void AddQuadAs5QuadsWithPoints(int *vi, int attr=1)
Adds 5 quadrilaterals to the mesh by splitting a quadrilateral given by 4 vertices vi.
Definition mesh.cpp:2115
void ReadVTKMesh(std::istream &input, int &curved, int &read_gf, bool &finalize_topo)
void PrintVTU(std::ostream &os, int ref=1, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0, bool bdr_elements=false)
Definition mesh.cpp:12020
virtual void UniformRefinement2D()
Refine a mixed 2D mesh uniformly.
Definition mesh.hpp:447
GridFunction * Nodes
Definition mesh.hpp:260
static Mesh MakePeriodic(const Mesh &orig_mesh, const std::vector< int > &v2v)
Create a periodic mesh by identifying vertices of orig_mesh.
Definition mesh.cpp:5730
Element::Type GetFaceElementType(int Face) const
Definition mesh.cpp:1512
int CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition mesh.cpp:7027
void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
For the given boundary element, bdr_el, return its adjacent element and its info, i....
Definition mesh.cpp:7584
Table * el_to_el
Definition mesh.hpp:237
void AverageVertices(const int *indexes, int n, int result)
Averages the vertices with given indexes and saves the result in vertices[result].
Definition mesh.cpp:9364
Table * face_edge
Definition mesh.hpp:246
real_t GetElementVolume(int i)
Definition mesh.cpp:121
static Mesh LoadFromFile(const std::string &filename, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition mesh.cpp:4453
int NumOfElements
Definition mesh.hpp:79
static const int vtk_quadratic_hex[27]
Definition mesh.hpp:266
void Swap(Mesh &other, bool non_geometry)
Definition mesh.cpp:10703
Array< Triple< int, int, int > > tmp_vertex_parents
Definition mesh.hpp:274
virtual void GenerateBoundaryElements()
Definition mesh.cpp:2326
static void GetElementArrayEdgeTable(const Array< Element * > &elem_array, const DSTable &v_to_v, Table &el_to_edge)
Definition mesh.cpp:7694
std::vector< int > CreatePeriodicVertexMapping(const std::vector< Vector > &translations, real_t tol=1e-8) const
Creates a mapping v2v from the vertex indices of the mesh such that coincident vertices under the giv...
Definition mesh.cpp:5764
void Bisection(int i, const DSTable &, int *, int *, int *)
Bisect a triangle: element with index i is bisected.
Definition mesh.cpp:11049
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
Definition mesh.hpp:1526
void ResetLazyData()
Definition mesh.cpp:1808
void UniformRefinement2D_base(bool update_nodes=true)
Definition mesh.cpp:9400
IsoparametricTransformation BdrTransformation
Definition mesh.hpp:250
void GetLocalSegToTriTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:696
void DestroyPointers()
Definition mesh.cpp:1754
void InitTables()
Definition mesh.cpp:1722
void DegreeElevate(int rel_degree, int degree=16)
Definition mesh.cpp:6052
Table * face_to_elem
Definition mesh.hpp:245
int NumOfFaces
Definition mesh.hpp:80
int spaceDim
Definition mesh.hpp:77
int FindCoarseElement(int i)
Definition mesh.cpp:11397
void FinalizeTriMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a triangular Mesh.
Definition mesh.cpp:2375
void GetElementCenter(int i, Vector &center)
Definition mesh.cpp:77
void AddHexAsPyramids(const int *vi, int attr=1)
Adds 6 pyramids to the mesh by splitting a hexahedron given by 8 vertices vi.
Definition mesh.cpp:2074
static void PrintElementsByGeometry(int dim, const Array< int > &num_elems_by_geom, std::ostream &os)
Auxiliary method used by PrintCharacteristics().
Definition mesh.cpp:237
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int attr=1)
Adds a hexahedron to the mesh given by 8 vertices v1 through v8.
Definition mesh.cpp:2021
static IntegrationPoint TransformBdrElementToFace(Geometry::Type geom, int o, const IntegrationPoint &ip)
For the vertex (1D), edge (2D), or face (3D) of a boundary element with the orientation o,...
Definition mesh.cpp:7138
void SetEmpty()
Definition mesh.cpp:1729
virtual void SetNodalFESpace(FiniteElementSpace *nfes)
Definition mesh.cpp:6426
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1285
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
Definition mesh.cpp:3468
void AddQuadFaceElement(int lf, int gf, int el, int v0, int v1, int v2, int v3)
Definition mesh.cpp:7931
void ReadMFEMMesh(std::istream &input, int version, int &curved)
void KnotRemove(Array< Vector * > &kv)
For NURBS meshes, remove the knots in kv, for each direction.
Definition mesh.cpp:5981
virtual int FindPoints(DenseMatrix &point_mat, Array< int > &elem_ids, Array< IntegrationPoint > &ips, bool warn=true, InverseElementTransformation *inv_trans=NULL)
Find the ids of the elements that contain the given points, and their corresponding reference coordin...
Definition mesh.cpp:13406
void GetEdgeTransformation(int i, IsoparametricTransformation *EdTr) const
Builds the transformation defining the i-th edge element in EdTr. EdTr must be allocated in advance a...
Definition mesh.cpp:613
int own_nodes
Definition mesh.hpp:261
void GetElementData(const Array< Element * > &elem_array, int geom, Array< int > &elem_vtx, Array< int > &attr) const
Definition mesh.cpp:10763
void PrintSurfaces(const Table &Aface_face, std::ostream &os) const
Print set of disjoint surfaces:
Definition mesh.cpp:12939
bool IsSlaveFace(const FaceInfo &fi) const
Definition mesh.cpp:1149
void FreeElement(Element *E)
Definition mesh.cpp:13381
Array< Element * > boundary
Definition mesh.hpp:106
virtual void MarkTetMeshForRefinement(const DSTable &v_to_v)
Definition mesh.cpp:2894
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition mesh.cpp:7645
FaceElementTransformations * GetInteriorFaceTransformations(int FaceNo)
See GetFaceElementTransformations().
Definition mesh.cpp:1103
void GetLocalTriToTetTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:736
virtual void PrintXG(std::ostream &os=mfem::out) const
Print the mesh to the given stream using Netgen/Truegrid format.
Definition mesh.cpp:11470
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition mesh.hpp:299
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
Definition mesh.cpp:9321
virtual void NURBSUniformRefinement(int rf=2, real_t tol=1.0e-12)
Refine NURBS mesh, with an optional refinement factor, generally anisotropic.
Definition mesh.cpp:6003
int mesh_geoms
Definition mesh.hpp:90
void DebugDump(std::ostream &os) const
Output an NCMesh-compatible debug dump.
Definition mesh.cpp:15061
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition mesh.hpp:2229
bool RefineByError(const Array< real_t > &elem_error, real_t threshold, int nonconforming=-1, int nc_limit=0)
Definition mesh.cpp:11020
static Mesh MakeCartesian3DWith24TetsPerHex(int nx, int ny, int nz, real_t sx=1.0, real_t sy=1.0, real_t sz=1.0)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz*24 tetrahedrons.
Definition mesh.cpp:4491
STable3D * GetFacesTable()
Definition mesh.cpp:8117
Table * GetFaceEdgeTable() const
Definition mesh.cpp:7360
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition mesh.cpp:10951
bool HasGeometry(Geometry::Type geom) const
Return true iff the given geom is encountered in the mesh. Geometries of dimensions lower than Dimens...
Definition mesh.hpp:1250
virtual MFEM_DEPRECATED void ReorientTetMesh()
Definition mesh.cpp:8310
void PrintVTK(std::ostream &os)
Definition mesh.cpp:11820
virtual void MarkNamedBoundaries(const std::string &set_name, Array< int > &bdr_marker) const
Mark boundary attributes in the named set.
Definition mesh.cpp:1682
void MoveNodes(const Vector &displacements)
Definition mesh.cpp:9279
Array< GeometricFactors * > geom_factors
Optional geometric factors.
Definition mesh.hpp:300
void SetMeshGen()
Determine the mesh generator bitmask meshgen, see MeshGenerator().
Definition mesh.cpp:4744
int nbBoundaryFaces
Definition mesh.hpp:85
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, real_t sx=1.0, real_t sy=1.0, bool sfc_ordering=true)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny quadrilaterals if type = QUADRILATER...
Definition mesh.cpp:4471
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Definition mesh.cpp:7267
void Make2D(int nx, int ny, Element::Type type, real_t sx, real_t sy, bool generate_edges, bool sfc_ordering)
Creates mesh for the rectangle [0,sx]x[0,sy], divided into nx*ny quadrilaterals if type = QUADRILATER...
Definition mesh.cpp:4088
void AddHexAsTets(const int *vi, int attr=1)
Adds 6 tetrahedrons to the mesh by splitting a hexahedron given by 8 vertices vi.
Definition mesh.cpp:2037
FaceElementTransformations FaceElemTr
Definition mesh.hpp:252
void SetNodes(const Vector &node_coord)
Updates the vertex/node locations. Invokes NodesUpdated().
Definition mesh.cpp:9306
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition mesh.cpp:7243
void FinalizeCheck()
Definition mesh.cpp:2361
void GetLocalQuadToPyrTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:857
void AddHexAsWedges(const int *vi, int attr=1)
Adds 2 wedges to the mesh by splitting a hexahedron given by 8 vertices vi.
Definition mesh.cpp:2056
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Definition mesh.cpp:6484
Element * ReadElement(std::istream &input)
Definition mesh.cpp:4726
virtual bool HasBoundaryElements() const
Checks if the mesh has boundary elements.
Definition mesh.hpp:1246
void ScaleSubdomains(real_t sf)
Definition mesh.cpp:13006
void GetVertexToVertexTable(DSTable &) const
Definition mesh.cpp:7716
void GetLocalQuadToHexTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:811
int NumOfEdges
Definition mesh.hpp:80
void Transform(void(*f)(const Vector &, Vector &))
Definition mesh.cpp:13146
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:11295
Geometry::Type GetTypicalFaceGeometry() const
If the local mesh is not empty, return GetFaceGeometry(0); otherwise return a typical face geometry p...
Definition mesh.cpp:1496
Geometry::Type GetElementBaseGeometry(int i) const
Definition mesh.hpp:1455
virtual void UnmarkInternalBoundaries(Array< int > &bdr_marker, bool excl=true) const
Unmark boundary attributes of internal boundaries.
Definition mesh.cpp:1574
Operation last_operation
Definition mesh.hpp:310
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Swap the internal node GridFunction pointer and ownership flag members with the given ones.
Definition mesh.cpp:9343
void SetBdrAttribute(int i, int attr)
Set the attribute of boundary element i.
Definition mesh.hpp:1398
void ChangeVertexDataOwnership(real_t *vertices, int len_vertices, bool zerocopy=false)
Set the internal Vertex array to point to the given vertices array without assuming ownership of the ...
Definition mesh.cpp:4562
int nbInteriorFaces
Definition mesh.hpp:85
Table * GetVertexToElementTable()
Definition mesh.cpp:7414
void InitRefinementTransforms()
Definition mesh.cpp:11385
Table * GetEdgeVertexTable() const
Definition mesh.cpp:7388
int * GeneratePartitioning(int nparts, int part_method=1)
Definition mesh.cpp:8416
Table * GetFaceToElementTable() const
Definition mesh.cpp:7480
void MarkTriMeshForRefinement()
Definition mesh.cpp:2854
void ReadNetgen2DMesh(std::istream &input, int &curved)
Array< Element * > elements
Definition mesh.hpp:100
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition mesh.hpp:288
void AddPointFaceElement(int lf, int gf, int el)
Used in GenerateFaces()
Definition mesh.cpp:7834
void RemoveInternalBoundaries()
Definition mesh.cpp:13304
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
Definition mesh.cpp:10512
void MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
Definition mesh.cpp:5408
void MoveVertices(const Vector &displacements)
Definition mesh.cpp:9211
virtual void SetAttributes()
Determine the sets of unique attribute values in domain and boundary elements.
Definition mesh.cpp:1819
const real_t * GetVertex(int i) const
Return pointer to vertex i's coordinates.
Definition mesh.hpp:1321
void DeleteGeometricFactors()
Destroy all GeometricFactors stored by the Mesh.
Definition mesh.cpp:922
const Table & ElementToFaceTable() const
Definition mesh.cpp:7816
void AddQuadAs4TrisWithPoints(int *vi, int attr=1)
Adds 4 triangles to the mesh by splitting a quadrilateral given by 4 vertices vi.
Definition mesh.cpp:2093
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition mesh.cpp:13197
void KnotInsert(Array< KnotVector * > &kv)
For NURBS meshes, insert the new knots in kv, for each direction.
Definition mesh.cpp:5937
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
Definition ncmesh.hpp:140
void OnMeshUpdated(Mesh *mesh)
Definition ncmesh.cpp:2885
void FindNeighbors(int elem, Array< int > &neighbors, const Array< int > *search_set=NULL)
Definition ncmesh.cpp:4320
void MakeTopologyOnly()
Definition ncmesh.hpp:520
void GetMeshComponents(Mesh &mesh) const
Fill Mesh::{vertices,elements,boundary} for the current finest level.
Definition ncmesh.cpp:2758
const CoarseFineTransformations & GetRefinementTransforms() const
Definition ncmesh.cpp:5153
int Dimension() const
Return the dimension of the NCMesh.
Definition ncmesh.hpp:164
BlockArray< Element > elements
Definition ncmesh.hpp:624
static void GridSfcOrdering3D(int width, int height, int depth, Array< int > &coords)
Definition ncmesh.cpp:5556
Array< int > leaf_elements
finest elements, in Mesh ordering (+ ghosts)
Definition ncmesh.hpp:723
virtual void LimitNCLevel(int max_nc_level)
Definition ncmesh.cpp:6039
const NCList & GetFaceList()
Return the current list of conforming and nonconforming faces.
Definition ncmesh.hpp:319
virtual void Derefine(const Array< int > &derefs)
Definition ncmesh.cpp:2307
Array< real_t > coordinates
Definition ncmesh.hpp:705
bool IsGhost(const Element &el) const
Return true if the Element el is a ghost element.
Definition ncmesh.hpp:787
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Definition ncmesh.hpp:326
void Print(std::ostream &out, const std::string &comments="") const
Definition ncmesh.cpp:6244
int spaceDim
dimensions of the elements and the vertex coordinates
Definition ncmesh.hpp:524
void MarkCoarseLevel()
Definition ncmesh.cpp:5105
virtual void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level)
Definition ncmesh.cpp:2278
const Table & GetDerefinementTable()
Definition ncmesh.cpp:2263
void SetAttribute(int i, int attr)
Set the attribute of leaf element i, which is a Mesh element index.
Definition ncmesh.hpp:464
int SpaceDimension() const
Return the space dimension of the NCMesh.
Definition ncmesh.hpp:166
virtual void Refine(const Array< Refinement > &refinements)
Definition ncmesh.cpp:1945
static void GridSfcOrdering2D(int width, int height, Array< int > &coords)
Definition ncmesh.cpp:5541
NURBSExtension generally contains multiple NURBSPatch objects spanning an entire Mesh....
Definition nurbs.hpp:449
int GetNBE() const
Return the number of active boundary elements.
Definition nurbs.hpp:771
void GetCoarseningFactors(Array< int > &f) const
Definition nurbs.cpp:4476
void SetPatchAttribute(int i, int attr)
Set the attribute for patch i, which is set to all elements in the patch.
Definition nurbs.hpp:821
const Array< int > & GetPatchElements(int patch)
Return the array of indices of all elements in patch patch.
Definition nurbs.cpp:4903
void UniformRefinement(int rf=2)
Refine with optional refinement factor rf. Uniform means refinement is done everywhere by the same fa...
Definition nurbs.cpp:4447
void Print(std::ostream &os, const std::string &comments="") const
Writes all patch data to the stream os.
Definition nurbs.cpp:2472
void SetPatchBdrAttribute(int i, int attr)
Set the attribute for patch boundary element i to attr, which is set to all boundary elements in the ...
Definition nurbs.hpp:829
void SetCoordsFromPatches(Vector &Nodes)
Set FE coordinates in Nodes, using data from patches, and erase patches.
Definition nurbs.cpp:4267
void Coarsen(int cf=2, real_t tol=1.0e-12)
Definition nurbs.cpp:4469
int GetPatchAttribute(int i) const
Get the attribute for patch i, which is set to all elements in the patch.
Definition nurbs.hpp:825
void GetElementTopo(Array< Element * > &elements) const
Generate the active mesh elements and return them in elements.
Definition nurbs.cpp:3497
const Array< int > & GetPatchBdrElements(int patch)
Return the array of indices of all boundary elements in patch patch.
Definition nurbs.cpp:4910
int GetNKV() const
Return the number of KnotVectors.
Definition nurbs.hpp:758
void GetVertexLocalToGlobal(Array< int > &lvert_vert)
Get the local to global vertex index map lvert_vert.
Definition nurbs.cpp:4192
bool HavePatches() const
Return true if at least 1 patch is defined, false otherwise.
Definition nurbs.hpp:804
void GetBdrElementTopo(Array< Element * > &boundary) const
Generate the active mesh boundary elements and return them in boundary.
Definition nurbs.cpp:3626
void KnotRemove(Array< Vector * > &kv, real_t tol=1.0e-12)
Definition nurbs.cpp:4615
void GetElementLocalToGlobal(Array< int > &lelem_elem)
Get the local to global element index map lelem_elem.
Definition nurbs.cpp:4202
void KnotInsert(Array< KnotVector * > &kv)
Insert knots from kv into all KnotVectors in all patches. The size of kv should be the same as knotVe...
Definition nurbs.cpp:4503
int GetOrder() const
If all KnotVector orders are identical, return that number. Otherwise, return NURBSFECollection::Vari...
Definition nurbs.hpp:755
int GetNV() const
Return the local number of active vertices.
Definition nurbs.hpp:763
void ConvertToPatches(const Vector &Nodes)
Define patches in IKJ (B-net) format, using FE coordinates in Nodes.
Definition nurbs.cpp:4256
int Dimension() const
Return the dimension of the reference space (not physical space).
Definition nurbs.hpp:742
void SetKnotsFromPatches()
Set KnotVectors from patches and construct mesh and space data.
Definition nurbs.cpp:4275
int GetNE() const
Return the number of active elements.
Definition nurbs.hpp:767
int GetPatchBdrAttribute(int i) const
Get the attribute for boundary patch element i, which is set to all boundary elements in the patch.
Definition nurbs.hpp:834
void DegreeElevate(int rel_degree, int degree=16)
Call DegreeElevate for all KnotVectors of all patches. For each KnotVector, the new degree is max(old...
Definition nurbs.cpp:4391
Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
Definition fe_coll.hpp:699
Class for standard nodal finite elements.
Definition fe_base.hpp:721
Class used to extrude the nodes of a mesh.
Definition mesh.hpp:3043
void SetLayer(const int l)
Definition mesh.hpp:3050
NodeExtrudeCoefficient(const int dim, const int n_, const real_t s_)
Definition mesh.cpp:14650
void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip) override
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
Definition mesh.cpp:14656
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
Type
Ordering methods:
Definition fespace.hpp:34
A pair of objects.
Class for parallel meshes.
Definition pmesh.hpp:34
MPI_Comm GetComm() const
Definition pmesh.hpp:402
int GetMyRank() const
Definition pmesh.hpp:404
Parallel version of NURBSExtension.
Definition nurbs.hpp:924
Data type point element.
Definition point.hpp:23
Data type Pyramid element.
Definition pyramid.hpp:23
Piecewise-(bi)quadratic continuous finite elements.
Definition fe_coll.hpp:889
static int CheckClosed(int type)
If the Quadrature1D type is not closed return Invalid; otherwise return type.
Definition intrules.cpp:928
@ VALUES
Evaluate the values at quadrature points.
@ DERIVATIVES
Evaluate the derivatives at quadrature points.
@ DETERMINANTS
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
Data type quadrilateral element.
IntegrationRule RefPts
Definition geom.hpp:321
Array< int > RefGeoms
Definition geom.hpp:322
Symmetric 3D Table stored as an array of rows each of which has a stack of column,...
Definition stable3d.hpp:35
int Push(int r, int c, int f)
Check to see if this entry is in the table and add it to the table if it is not there....
Definition stable3d.cpp:64
int NumberOfElements()
Return the number of elements added to the table.
Definition stable3d.hpp:70
int Push4(int r, int c, int f, int t)
Check to see if this entry is in the table and add it to the table if it is not there....
Definition stable3d.cpp:140
Data type line segment element.
Definition segment.hpp:23
void GetVertices(Array< int > &v) const override
Get the indices defining the vertices.
Definition segment.cpp:40
Timing object.
Definition tic_toc.hpp:36
void Start()
Start the stopwatch. The elapsed time is not cleared.
Definition tic_toc.cpp:411
double UserTime()
Return the number of user seconds elapsed since the stopwatch was started.
Definition tic_toc.cpp:437
int * GetJ()
Definition table.hpp:122
void AddConnections(int r, const int *c, int nc)
Definition table.cpp:176
void Swap(Table &other)
Definition table.cpp:467
int RowSize(int i) const
Definition table.hpp:116
void ShiftUpI()
Definition table.cpp:187
void Clear()
Definition table.cpp:453
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
Definition table.cpp:196
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition table.cpp:259
int Push(int i, int j)
Definition table.cpp:291
void AddConnection(int r, int c)
Definition table.hpp:88
void Finalize()
Definition table.cpp:315
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition table.cpp:153
int Size() const
Returns the number of TYPE I elements.
Definition table.hpp:100
int Size_of_connections() const
Definition table.hpp:106
void AddColumnsInRow(int r, int ncol)
Definition table.hpp:86
void MakeJ()
Definition table.cpp:163
int * GetI()
Definition table.hpp:121
void AddAColumnInRow(int r)
Definition table.hpp:85
void SetDims(int rows, int nnz)
Definition table.cpp:212
Data type tetrahedron element.
void Init(int ind1, int ind2, int ind3, int ind4, int attr=1, int ref_flag=0)
Initialize the vertex indices and the attribute of a Tetrahedron.
void PushTransform(int tr) override
Add 'tr' to the current chain of coarse-fine transformations.
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag) const
int GetRefinementFlag() const
void SetVertices(const Array< int > &v) override
Set the indices defining the vertices.
void ResetTransform(int tr) override
Set current coarse-fine transformation number.
unsigned GetTransform() const override
Return current coarse-fine transformation.
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
void GetMarkedFace(const int face, int *fv) const
void CreateRefinementFlag(int refinement_edges[2], int type, int flag=0)
void GetVertices(Array< int > &v) const override
Get the indices defining the vertices.
Data type triangle element.
Definition triangle.hpp:24
void SetVertices(const Array< int > &v) override
Set the indices defining the vertices.
Definition triangle.cpp:194
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
Definition triangle.cpp:126
void PushTransform(int tr) override
Add 'tr' to the current chain of coarse-fine transformations.
Definition triangle.hpp:62
void ResetTransform(int tr) override
Set current coarse-fine transformation number.
Definition triangle.hpp:58
unsigned GetTransform() const override
Return current coarse-fine transformation.
Definition triangle.hpp:59
void GetVertices(Array< int > &v) const override
Get the indices defining the vertices.
Definition triangle.cpp:188
A triple of objects.
Base class for vector Coefficients that optionally depend on time and space.
int GetVDim()
Returns dimension of the vector.
A general vector function coefficient.
Vector data type.
Definition vector.hpp:82
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:498
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:679
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:931
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:558
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:506
void NewDataAndSize(real_t *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition vector.hpp:189
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:235
void SetData(real_t *d)
Definition vector.hpp:176
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:653
void cross3D(const Vector &vin, Vector &vout) const
Definition vector.cpp:616
real_t DistanceTo(const real_t *p) const
Compute the Euclidean distance to another vector.
Definition vector.hpp:710
Data type for vertex.
Definition vertex.hpp:23
Data type Wedge element.
Definition wedge.hpp:23
void Print(const Mesh &mesh, const adios2stream::mode print_mode=mode::sync)
const std::string filename
Definition zstr.hpp:811
real_t kappa
Definition ex24.cpp:54
int dim
Definition ex24.cpp:53
prob_type prob
Definition ex25.cpp:156
constexpr int dimension
This example only works in 3D. Kernels for 2D are not implemented.
Definition hooke.cpp:45
int index(int i, int j, int nx, int ny)
Definition life.cpp:236
real_t b
Definition lissajous.cpp:42
real_t delta
Definition lissajous.cpp:43
real_t a
Definition lissajous.cpp:41
int idxtype
Definition mesh.cpp:46
void METIS_PartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
int idx_t
Definition mesh.cpp:45
void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
unsigned int uint
Definition gecko.hpp:204
double Float
Definition gecko.hpp:208
Linear1DFiniteElement SegmentFE
Definition segment.cpp:52
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
PointFiniteElement PointFE
Definition point.cpp:42
TriLinear3DFiniteElement HexahedronFE
void Swap(Array< T > &, Array< T > &)
Definition array.hpp:672
real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
void mfem_error(const char *msg)
Definition error.cpp:154
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:548
GeometryRefiner GlobGeometryRefiner
Definition geom.cpp:2014
int FindRoots(const Vector &z, Vector &x)
Definition mesh.cpp:8953
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
Geometry Geometries
Definition fe.cpp:49
real_t rand_real()
Generate a random real_t number in the interval [0,1) using rand().
Definition vector.hpp:61
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:391
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:486
void ShiftRight(int &a, int &b, int &c)
Definition mesh.hpp:3066
MFEM_EXPORT class Linear3DFiniteElement TetrahedronFE
Definition fe.cpp:36
void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
Definition mesh.cpp:8873
Mesh * Extrude1D(Mesh *mesh, const int ny, const real_t sy, const bool closed)
Extrude a 1D mesh.
Definition mesh.cpp:14674
MFEM_EXPORT class LinearWedgeFiniteElement WedgeFE
Definition fe.cpp:40
void WriteBase64WithSizeAndClear(std::ostream &os, std::vector< char > &buf, int compression_level)
Encode in base 64 (and potentially compress) the given data, write it to the output stream (with a he...
Definition vtk.cpp:654
Mesh * Extrude2D(Mesh *mesh, const int nz, const real_t sz)
Extrude a 2D mesh.
Definition mesh.cpp:14834
VTKFormat
Data array format for VTK and VTU files.
Definition vtk.hpp:100
@ ASCII
Data arrays will be written in ASCII format.
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition globals.hpp:71
void filter_dos(std::string &line)
Check for, and remove, a trailing '\r' from and std::string.
Definition text.hpp:45
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
Definition fespace.hpp:1555
void FindTMax(Vector &c, Vector &x, real_t &tmax, const real_t factor, const int Dim)
Definition mesh.cpp:9100
BiLinear2DFiniteElement QuadrilateralFE
void WriteBinaryOrASCII(std::ostream &os, std::vector< char > &buf, const T &val, const char *suffix, VTKFormat format)
Write either ASCII data to the stream or binary data to the buffer depending on the given format.
Definition vtk.hpp:148
MFEM_EXPORT class LinearPyramidFiniteElement PyramidFE
Definition fe.cpp:44
const T & AsConst(const T &a)
Utility function similar to std::as_const in c++17.
Definition array.hpp:380
float real_t
Definition config.hpp:43
double bisect(ElementTransformation &Tr, Coefficient *LvlSet)
const char * VTKByteOrder()
Determine the byte order and return either "BigEndian" or "LittleEndian".
Definition vtk.cpp:602
void SortPairs(Pair< A, B > *pairs, int size)
Sort an array of Pairs with respect to the first element.
MemoryType
Memory types supported by MFEM.
@ HOST
Host memory; using new[] and delete[].
void CreateVTKElementConnectivity(Array< int > &con, Geometry::Type geom, int ref)
Create the VTK element connectivity array for a given element geometry and refinement level.
Definition vtk.cpp:497
void FindPartitioningComponents(Table &elem_elem, const Array< int > &partitioning, Array< int > &component, Array< int > &num_comp)
Definition mesh.cpp:8745
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:83
@ NATIVE
Native ordering as defined by the FiniteElement.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
MFEM_EXPORT Linear2DFiniteElement TriangleFE
Definition fe.cpp:32
MPI_Comm GetGlobalMPI_Comm()
Get MFEM's "global" MPI communicator.
Definition globals.cpp:67
void XYZ_VectorFunction(const Vector &p, Vector &v)
Definition mesh.cpp:6389
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
Definition text.hpp:31
FaceType
Definition mesh.hpp:48
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:492
real_t p(const Vector &x, real_t t)
T sq(T x)
Defines the coarse-fine transformations of all fine elements.
Definition ncmesh.hpp:90
Array< Embedding > embeddings
Fine element positions in their parents.
Definition ncmesh.hpp:92
DenseTensor point_matrices[Geometry::NumGeom]
Definition ncmesh.hpp:96
Helper struct for defining a connectivity table, see Table::MakeFromList.
Definition table.hpp:28
Defines the position of a fine element within a coarse element.
Definition ncmesh.hpp:69
unsigned geom
Definition ncmesh.hpp:77
int parent
Coarse Element index in the coarse mesh.
Definition ncmesh.hpp:71
unsigned matrix
Definition ncmesh.hpp:78
static const int FaceVert[NumFaces][MaxFaceVert]
Definition geom.hpp:259
static const int Edges[NumEdges][2]
Definition geom.hpp:255
static const int FaceVert[NumFaces][MaxFaceVert]
Definition geom.hpp:281
static const int Edges[NumEdges][2]
Definition geom.hpp:277
static const int Edges[NumEdges][2]
Definition geom.hpp:299
static const int FaceVert[NumFaces][MaxFaceVert]
Definition geom.hpp:303
static const int Orient[NumOrient][NumVert]
Definition geom.hpp:162
static const int Orient[NumOrient][NumVert]
Definition geom.hpp:216
static const int Edges[NumEdges][2]
Definition geom.hpp:205
static const int Edges[NumEdges][2]
Definition geom.hpp:229
static const int FaceVert[NumFaces][MaxFaceVert]
Definition geom.hpp:233
static const int Orient[NumOrient][NumVert]
Definition geom.hpp:242
static const int Edges[NumEdges][2]
Definition geom.hpp:175
static const int Orient[NumOrient][NumVert]
Definition geom.hpp:191
EntityHelper(int dim_, const Array< int >(&entity_to_vertex_)[Geometry::NumGeom])
Definition mesh.cpp:13635
Entity FindEntity(int bytype_entity_id)
Definition mesh.cpp:13650
entity_to_vertex_type & entity_to_vertex
Definition mesh.hpp:2634
int geom_offsets[Geometry::NumGeom+1]
Definition mesh.hpp:2632
const int * verts
Definition mesh.hpp:2628
This structure stores the low level information necessary to interpret the configuration of elements ...
Definition mesh.hpp:169
This structure is used as a human readable output format that deciphers the information contained in ...
Definition mesh.hpp:1980
ElementLocation location
Definition mesh.hpp:1985
bool IsNonconformingCoarse() const
Return true if the face is a nonconforming coarse face.
Definition mesh.hpp:2058
bool IsOfFaceType(FaceType type) const
Return true if the face is of the same type as type.
Definition mesh.hpp:2027
struct mfem::Mesh::FaceInformation::@15 element[2]
ElementConformity conformity
Definition mesh.hpp:1986
const DenseMatrix * point_matrix
Definition mesh.hpp:1994
Lists all edges/faces in the nonconforming mesh.
Definition ncmesh.hpp:251
Nonconforming edge/face within a bigger edge/face.
Definition ncmesh.hpp:237
static const int HighOrderMap[Geometry::NUM_GEOMETRIES]
Map from MFEM's Geometry::Type to arbitrary-order Lagrange VTK geometries.
Definition vtk.hpp:83
static const int QuadraticMap[Geometry::NUM_GEOMETRIES]
Map from MFEM's Geometry::Type to legacy quadratic VTK geometries/.
Definition vtk.hpp:81
static const int * VertexPermutation[Geometry::NUM_GEOMETRIES]
Permutation from MFEM's vertex ordering to VTK's vertex ordering.
Definition vtk.hpp:76
static const int Map[Geometry::NUM_GEOMETRIES]
Map from MFEM's Geometry::Type to linear VTK geometries.
Definition vtk.hpp:79
std::array< int, NCMesh::MaxFaceNodes > nodes