MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
mesh.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, 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
395
396void Mesh::GetElementTransformation(int i, const Vector &nodes,
397 IsoparametricTransformation *ElTr) const
398{
399 ElTr->Attribute = GetAttribute(i);
400 ElTr->ElementNo = i;
402 ElTr->mesh = this;
403 DenseMatrix &pm = ElTr->GetPointMat();
404 ElTr->Reset();
405 nodes.HostRead();
406 if (Nodes == NULL)
407 {
408 MFEM_ASSERT(nodes.Size() == spaceDim*GetNV(), "");
409 int nv = elements[i]->GetNVertices();
410 const int *v = elements[i]->GetVertices();
411 int n = vertices.Size();
412 pm.SetSize(spaceDim, nv);
413 for (int k = 0; k < spaceDim; k++)
414 {
415 for (int j = 0; j < nv; j++)
416 {
417 pm(k, j) = nodes(k*n+v[j]);
418 }
419 }
421 }
422 else
423 {
424 MFEM_ASSERT(nodes.Size() == Nodes->Size(), "");
425 Array<int> vdofs;
426 Nodes->FESpace()->GetElementVDofs(i, vdofs);
427 int n = vdofs.Size()/spaceDim;
428 pm.SetSize(spaceDim, n);
429 for (int k = 0; k < spaceDim; k++)
430 {
431 for (int j = 0; j < n; j++)
432 {
433 pm(k,j) = nodes(vdofs[n*k+j]);
434 }
435 }
436 ElTr->SetFE(Nodes->FESpace()->GetFE(i));
437 }
438}
439
441 IsoparametricTransformation* ElTr) const
442{
443 ElTr->Attribute = GetBdrAttribute(i);
444 ElTr->ElementNo = i; // boundary element number
446 ElTr->mesh = this;
447 DenseMatrix &pm = ElTr->GetPointMat();
448 ElTr->Reset();
449 if (Nodes == NULL)
450 {
451 GetBdrPointMatrix(i, pm);
453 }
454 else
455 {
456 const FiniteElement *bdr_el = Nodes->FESpace()->GetBE(i);
457 Nodes->HostRead();
458 const GridFunction &nodes = *Nodes;
459 if (bdr_el)
460 {
461 Array<int> vdofs;
462 Nodes->FESpace()->GetBdrElementVDofs(i, vdofs);
463 int n = vdofs.Size()/spaceDim;
464 pm.SetSize(spaceDim, n);
465 for (int k = 0; k < spaceDim; k++)
466 {
467 for (int j = 0; j < n; j++)
468 {
469 pm(k,j) = nodes(vdofs[n*k+j]);
470 }
471 }
472 ElTr->SetFE(bdr_el);
473 }
474 else // L2 Nodes (e.g., periodic mesh)
475 {
476 int elem_id, face_info;
477 GetBdrElementAdjacentElement(i, elem_id, face_info);
479 face_info = EncodeFaceInfo(
480 DecodeFaceInfoLocalIndex(face_info),
482 face_geom, DecodeFaceInfoOrientation(face_info))
483 );
484
487 GetElementType(elem_id),
488 Loc1.Transf, face_info);
489 const FiniteElement *face_el =
490 Nodes->FESpace()->GetTraceElement(elem_id, face_geom);
491 MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
492 "Mesh requires nodal Finite Element.");
493
494 IntegrationRule eir(face_el->GetDof());
495 Loc1.Transf.ElementNo = elem_id;
496 Loc1.Transf.mesh = this;
498 Loc1.Transform(face_el->GetNodes(), eir);
499 Nodes->GetVectorValues(Loc1.Transf, eir, pm);
500
501 ElTr->SetFE(face_el);
502 }
503 }
504}
505
511
514{
515 FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute();
516 FTr->ElementNo = FaceNo;
518 FTr->mesh = this;
519 DenseMatrix &pm = FTr->GetPointMat();
520 FTr->Reset();
521 if (Nodes == NULL)
522 {
523 const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
524 const int nv = (Dim == 1) ? 1 : faces[FaceNo]->GetNVertices();
525 pm.SetSize(spaceDim, nv);
526 for (int i = 0; i < spaceDim; i++)
527 {
528 for (int j = 0; j < nv; j++)
529 {
530 pm(i, j) = vertices[v[j]](i);
531 }
532 }
534 }
535 else // curved mesh
536 {
537 const FiniteElement *face_el = Nodes->FESpace()->GetFaceElement(FaceNo);
538 Nodes->HostRead();
539 const GridFunction &nodes = *Nodes;
540 if (face_el)
541 {
542 Array<int> vdofs;
543 Nodes->FESpace()->GetFaceVDofs(FaceNo, vdofs);
544 int n = vdofs.Size()/spaceDim;
545 pm.SetSize(spaceDim, n);
546 for (int i = 0; i < spaceDim; i++)
547 {
548 for (int j = 0; j < n; j++)
549 {
550 pm(i, j) = nodes(vdofs[n*i+j]);
551 }
552 }
553 FTr->SetFE(face_el);
554 }
555 else // L2 Nodes (e.g., periodic mesh), go through the volume of Elem1
556 {
557 const FaceInfo &face_info = faces_info[FaceNo];
558 Geometry::Type face_geom = GetFaceGeometry(FaceNo);
559 Element::Type face_type = GetFaceElementType(FaceNo);
560
563 GetElementType(face_info.Elem1No),
564 Loc1.Transf, face_info.Elem1Inf);
565
566 face_el = Nodes->FESpace()->GetTraceElement(face_info.Elem1No,
567 face_geom);
568 MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
569 "Mesh requires nodal Finite Element.");
570
571 IntegrationRule eir(face_el->GetDof());
572 Loc1.Transf.ElementNo = face_info.Elem1No;
574 Loc1.Transf.mesh = this;
575 Loc1.Transform(face_el->GetNodes(), eir);
576 Nodes->GetVectorValues(Loc1.Transf, eir, pm);
577
578 FTr->SetFE(face_el);
579 }
580 }
581}
582
588
590 IsoparametricTransformation *EdTr) const
591{
592 if (Dim == 2)
593 {
594 GetFaceTransformation(EdgeNo, EdTr);
595 return;
596 }
597 if (Dim == 1)
598 {
599 mfem_error("Mesh::GetEdgeTransformation not defined in 1D \n");
600 }
601
602 EdTr->Attribute = 1;
603 EdTr->ElementNo = EdgeNo;
605 EdTr->mesh = this;
606 DenseMatrix &pm = EdTr->GetPointMat();
607 EdTr->Reset();
608 if (Nodes == NULL)
609 {
610 Array<int> v;
611 GetEdgeVertices(EdgeNo, v);
612 const int nv = 2;
613 pm.SetSize(spaceDim, nv);
614 for (int i = 0; i < spaceDim; i++)
615 {
616 for (int j = 0; j < nv; j++)
617 {
618 pm(i, j) = vertices[v[j]](i);
619 }
620 }
622 }
623 else
624 {
625 const FiniteElement *edge_el = Nodes->FESpace()->GetEdgeElement(EdgeNo);
626 Nodes->HostRead();
627 const GridFunction &nodes = *Nodes;
628 if (edge_el)
629 {
630 Array<int> vdofs;
631 Nodes->FESpace()->GetEdgeVDofs(EdgeNo, vdofs);
632 int n = vdofs.Size()/spaceDim;
633 pm.SetSize(spaceDim, n);
634 for (int i = 0; i < spaceDim; i++)
635 {
636 for (int j = 0; j < n; j++)
637 {
638 pm(i, j) = nodes(vdofs[n*i+j]);
639 }
640 }
641 EdTr->SetFE(edge_el);
642 }
643 else
644 {
645 MFEM_ABORT("Not implemented.");
646 }
647 }
648}
649
655
656
658 IsoparametricTransformation &Transf, int i) const
659{
660 const IntegrationRule *SegVert;
661 DenseMatrix &locpm = Transf.GetPointMat();
662 Transf.Reset();
663
664 Transf.SetFE(&PointFE);
666 locpm.SetSize(1, 1);
667 locpm(0, 0) = SegVert->IntPoint(i/64).x;
668 // (i/64) is the local face no. in the segment
669 // (i%64) is the orientation of the point (not used)
670}
671
673 IsoparametricTransformation &Transf, int i) const
674{
675 const int *tv, *so;
676 const IntegrationRule *TriVert;
677 DenseMatrix &locpm = Transf.GetPointMat();
678 Transf.Reset();
679
680 Transf.SetFE(&SegmentFE);
681 tv = tri_t::Edges[i/64]; // (i/64) is the local face no. in the triangle
682 so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
684 locpm.SetSize(2, 2);
685 for (int j = 0; j < 2; j++)
686 {
687 locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x;
688 locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y;
689 }
690}
691
693 IsoparametricTransformation &Transf, int i) const
694{
695 const int *qv, *so;
696 const IntegrationRule *QuadVert;
697 DenseMatrix &locpm = Transf.GetPointMat();
698 Transf.Reset();
699
700 Transf.SetFE(&SegmentFE);
701 qv = quad_t::Edges[i/64]; // (i/64) is the local face no. in the quad
702 so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
704 locpm.SetSize(2, 2);
705 for (int j = 0; j < 2; j++)
706 {
707 locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x;
708 locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y;
709 }
710}
711
713 IsoparametricTransformation &Transf, int i) const
714{
715 DenseMatrix &locpm = Transf.GetPointMat();
716 Transf.Reset();
717
718 Transf.SetFE(&TriangleFE);
719 // (i/64) is the local face no. in the tet
720 const int *tv = tet_t::FaceVert[i/64];
721 // (i%64) is the orientation of the tetrahedron face
722 // w.r.t. the face element
723 const int *to = tri_t::Orient[i%64];
724 const IntegrationRule *TetVert =
726 locpm.SetSize(3, 3);
727 for (int j = 0; j < 3; j++)
728 {
729 const IntegrationPoint &vert = TetVert->IntPoint(tv[to[j]]);
730 locpm(0, j) = vert.x;
731 locpm(1, j) = vert.y;
732 locpm(2, j) = vert.z;
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 pri
744 MFEM_VERIFY(i < 128, "Local face index " << i/64
745 << " is not a triangular face of a wedge.");
746 const int *pv = pri_t::FaceVert[i/64];
747 // (i%64) is the orientation of the wedge face
748 // w.r.t. the face element
749 const int *to = tri_t::Orient[i%64];
750 const IntegrationRule *PriVert =
752 locpm.SetSize(3, 3);
753 for (int j = 0; j < 3; j++)
754 {
755 const IntegrationPoint &vert = PriVert->IntPoint(pv[to[j]]);
756 locpm(0, j) = vert.x;
757 locpm(1, j) = vert.y;
758 locpm(2, j) = vert.z;
759 }
760}
761
763 IsoparametricTransformation &Transf, int i) const
764{
765 DenseMatrix &locpm = Transf.GetPointMat();
766
767 Transf.SetFE(&TriangleFE);
768 // (i/64) is the local face no. in the pyr
769 MFEM_VERIFY(i >= 64, "Local face index " << i/64
770 << " is not a triangular face of a pyramid.");
771 const int *pv = pyr_t::FaceVert[i/64];
772 // (i%64) is the orientation of the pyramid face
773 // w.r.t. the face element
774 const int *to = tri_t::Orient[i%64];
775 const IntegrationRule *PyrVert =
777 locpm.SetSize(3, 3);
778 for (int j = 0; j < 3; j++)
779 {
780 const IntegrationPoint &vert = PyrVert->IntPoint(pv[to[j]]);
781 locpm(0, j) = vert.x;
782 locpm(1, j) = vert.y;
783 locpm(2, j) = vert.z;
784 }
785}
786
788 IsoparametricTransformation &Transf, int i) const
789{
790 DenseMatrix &locpm = Transf.GetPointMat();
791 Transf.Reset();
792
793 Transf.SetFE(&QuadrilateralFE);
794 // (i/64) is the local face no. in the hex
795 const int *hv = hex_t::FaceVert[i/64];
796 // (i%64) is the orientation of the quad
797 const int *qo = quad_t::Orient[i%64];
799 locpm.SetSize(3, 4);
800 for (int j = 0; j < 4; j++)
801 {
802 const IntegrationPoint &vert = HexVert->IntPoint(hv[qo[j]]);
803 locpm(0, j) = vert.x;
804 locpm(1, j) = vert.y;
805 locpm(2, j) = vert.z;
806 }
807}
808
810 IsoparametricTransformation &Transf, int i) const
811{
812 DenseMatrix &locpm = Transf.GetPointMat();
813 Transf.Reset();
814
815 Transf.SetFE(&QuadrilateralFE);
816 // (i/64) is the local face no. in the pri
817 MFEM_VERIFY(i >= 128, "Local face index " << i/64
818 << " is not a quadrilateral face of a wedge.");
819 const int *pv = pri_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 = PriVert->IntPoint(pv[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
838 Transf.SetFE(&QuadrilateralFE);
839 // (i/64) is the local face no. in the pyr
840 MFEM_VERIFY(i < 64, "Local face index " << i/64
841 << " is not a quadrilateral face of a pyramid.");
842 const int *pv = pyr_t::FaceVert[i/64];
843 // (i%64) is the orientation of the quad
844 const int *qo = quad_t::Orient[i%64];
846 locpm.SetSize(3, 4);
847 for (int j = 0; j < 4; j++)
848 {
849 const IntegrationPoint &vert = PyrVert->IntPoint(pv[qo[j]]);
850 locpm(0, j) = vert.x;
851 locpm(1, j) = vert.y;
852 locpm(2, j) = vert.z;
853 }
854}
855
857 const int flags,
858 MemoryType d_mt)
859{
860 for (int i = 0; i < geom_factors.Size(); i++)
861 {
863 if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags)
864 {
865 return gf;
866 }
867 }
868
869 this->EnsureNodes();
870
871 GeometricFactors *gf = new GeometricFactors(this, ir, flags, d_mt);
872 geom_factors.Append(gf);
873 return gf;
874}
875
877 const IntegrationRule& ir,
878 const int flags, FaceType type, MemoryType d_mt)
879{
880 for (int i = 0; i < face_geom_factors.Size(); i++)
881 {
883 if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags &&
884 gf->type==type)
885 {
886 return gf;
887 }
888 }
889
890 this->EnsureNodes();
891
892 FaceGeometricFactors *gf = new FaceGeometricFactors(this, ir, flags, type,
893 d_mt);
894 face_geom_factors.Append(gf);
895 return gf;
896}
897
899{
900 for (int i = 0; i < geom_factors.Size(); i++)
901 {
902 delete geom_factors[i];
903 }
904 geom_factors.SetSize(0);
905 for (int i = 0; i < face_geom_factors.Size(); i++)
906 {
907 delete face_geom_factors[i];
908 }
909 face_geom_factors.SetSize(0);
910
912}
913
914void Mesh::GetLocalFaceTransformation(int face_type, int elem_type,
916 int info) const
917{
918 switch (face_type)
919 {
920 case Element::POINT:
921 GetLocalPtToSegTransformation(Transf, info);
922 break;
923
924 case Element::SEGMENT:
925 if (elem_type == Element::TRIANGLE)
926 {
927 GetLocalSegToTriTransformation(Transf, info);
928 }
929 else
930 {
931 MFEM_ASSERT(elem_type == Element::QUADRILATERAL, "");
933 }
934 break;
935
937 if (elem_type == Element::TETRAHEDRON)
938 {
939 GetLocalTriToTetTransformation(Transf, info);
940 }
941 else if (elem_type == Element::WEDGE)
942 {
943 GetLocalTriToWdgTransformation(Transf, info);
944 }
945 else if (elem_type == Element::PYRAMID)
946 {
947 GetLocalTriToPyrTransformation(Transf, info);
948 }
949 else
950 {
951 MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
952 "face type " << face_type
953 << " and element type " << elem_type << "\n");
954 }
955 break;
956
958 if (elem_type == Element::HEXAHEDRON)
959 {
961 }
962 else if (elem_type == Element::WEDGE)
963 {
965 }
966 else if (elem_type == Element::PYRAMID)
967 {
969 }
970 else
971 {
972 MFEM_ABORT("Mesh::GetLocalFaceTransformation not defined for "
973 "face type " << face_type
974 << " and element type " << elem_type << "\n");
975 }
976 break;
977 }
978}
979
987
992 int mask) const
993{
994 const FaceInfo &face_info = faces_info[FaceNo];
995
996 int cmask = 0;
997 FElTr.SetConfigurationMask(cmask);
998 FElTr.Elem1 = NULL;
999 FElTr.Elem2 = NULL;
1000
1001 // setup the transformation for the first element
1002 FElTr.Elem1No = face_info.Elem1No;
1004 {
1005 GetElementTransformation(FElTr.Elem1No, &ElTr1);
1006 FElTr.Elem1 = &ElTr1;
1007 cmask |= 1;
1008 }
1009
1010 // setup the transformation for the second element
1011 // return NULL in the Elem2 field if there's no second element, i.e.
1012 // the face is on the "boundary"
1013 FElTr.Elem2No = face_info.Elem2No;
1015 FElTr.Elem2No >= 0)
1016 {
1017#ifdef MFEM_DEBUG
1019 { MFEM_ABORT("NURBS mesh not supported!"); }
1020#endif
1021 GetElementTransformation(FElTr.Elem2No, &ElTr2);
1022 FElTr.Elem2 = &ElTr2;
1023 cmask |= 2;
1024 }
1025
1026 // setup the face transformation
1028 {
1029 GetFaceTransformation(FaceNo, &FElTr);
1030 cmask |= 16;
1031 }
1032 else
1033 {
1034 FElTr.SetGeometryType(GetFaceGeometry(FaceNo));
1035 }
1036
1037 // setup Loc1 & Loc2
1038 int face_type = GetFaceElementType(FaceNo);
1040 {
1041 int elem_type = GetElementType(face_info.Elem1No);
1042 GetLocalFaceTransformation(face_type, elem_type,
1043 FElTr.Loc1.Transf, face_info.Elem1Inf);
1044 cmask |= 4;
1045 }
1047 FElTr.Elem2No >= 0)
1048 {
1049 int elem_type = GetElementType(face_info.Elem2No);
1050 GetLocalFaceTransformation(face_type, elem_type,
1051 FElTr.Loc2.Transf, face_info.Elem2Inf);
1052
1053 // NC meshes: prepend slave edge/face transformation to Loc2
1054 if (Nonconforming() && IsSlaveFace(face_info))
1055 {
1056 ApplyLocalSlaveTransformation(FElTr, face_info, false);
1057 }
1058 cmask |= 8;
1059 }
1060
1061 FElTr.SetConfigurationMask(cmask);
1062
1063 // This check can be useful for internal debugging, however it will fail on
1064 // periodic boundary faces, so we keep it disabled in general.
1065#if 0
1066#ifdef MFEM_DEBUG
1067 real_t dist = FElTr.CheckConsistency();
1068 if (dist >= 1e-12)
1069 {
1070 mfem::out << "\nInternal error: face id = " << FaceNo
1071 << ", dist = " << dist << '\n';
1072 FElTr.CheckConsistency(1); // print coordinates
1073 MFEM_ABORT("internal error");
1074 }
1075#endif
1076#endif
1077}
1078
1085
1089 IsoparametricTransformation &ElTr2) const
1090{
1091 if (faces_info[FaceNo].Elem2No < 0)
1092 {
1094 return;
1095 }
1096 GetFaceElementTransformations(FaceNo, FElTr, ElTr1, ElTr2);
1097}
1098
1105
1109 IsoparametricTransformation &ElTr2) const
1110{
1111 // Check if the face is interior, shared, or nonconforming.
1112 int fn = GetBdrElementFaceIndex(BdrElemNo);
1113 if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
1114 {
1116 return;
1117 }
1118 GetFaceElementTransformations(fn, FElTr, ElTr1, ElTr2, 21);
1119 FElTr.Attribute = boundary[BdrElemNo]->GetAttribute();
1120 FElTr.ElementNo = BdrElemNo;
1122 FElTr.mesh = this;
1123}
1124
1125bool Mesh::IsSlaveFace(const FaceInfo &fi) const
1126{
1127 return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
1128}
1129
1131 const FaceInfo &fi, bool is_ghost) const
1132{
1133#ifdef MFEM_THREAD_SAFE
1134 DenseMatrix composition;
1135#else
1136 static DenseMatrix composition;
1137#endif
1138 MFEM_ASSERT(fi.NCFace >= 0, "");
1139 MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error");
1140 if (!is_ghost)
1141 {
1142 // side 1 -> child side, side 2 -> parent side
1144 LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1145 // In 2D, we need to flip the point matrix since it is aligned with the
1146 // parent side.
1147 if (Dim == 2)
1148 {
1149 // swap points (columns) 0 and 1
1150 std::swap(composition(0,0), composition(0,1));
1151 std::swap(composition(1,0), composition(1,1));
1152 }
1153 LT.SetPointMat(composition);
1154 }
1155 else // is_ghost == true
1156 {
1157 // side 1 -> parent side, side 2 -> child side
1159 LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
1160 // In 2D, there is no need to flip the point matrix since it is already
1161 // aligned with the parent side, see also ParNCMesh::GetFaceNeighbors.
1162 // In 3D the point matrix was flipped during construction in
1163 // ParNCMesh::GetFaceNeighbors and due to that it is already aligned with
1164 // the parent side.
1165 LT.SetPointMat(composition);
1166 }
1167}
1168
1170{
1171 FaceInformation face;
1172 int e1, e2;
1173 int inf1, inf2;
1174 int ncface;
1175 GetFaceElements(f, &e1, &e2);
1176 GetFaceInfos(f, &inf1, &inf2, &ncface);
1177 face.element[0].index = e1;
1179 face.element[0].orientation = inf1%64;
1180 face.element[0].local_face_id = inf1/64;
1181 face.element[1].local_face_id = inf2/64;
1182 face.ncface = ncface;
1183 face.point_matrix = nullptr;
1184 // The following figures out face.location, face.conformity,
1185 // face.element[1].index, and face.element[1].orientation.
1186 if (f < GetNumFaces()) // Non-ghost face
1187 {
1188 if (e2>=0)
1189 {
1190 if (ncface==-1)
1191 {
1197 face.element[1].index = e2;
1198 face.element[1].orientation = inf2%64;
1199 }
1200 else // ncface >= 0
1201 {
1207 face.element[1].index = e2;
1208 MFEM_ASSERT(inf2%64==0, "unexpected slave face orientation.");
1209 face.element[1].orientation = inf2%64;
1210 face.point_matrix = nc_faces_info[ncface].PointMatrix;
1211 }
1212 }
1213 else // e2<0
1214 {
1215 if (ncface==-1)
1216 {
1217 if (inf2<0)
1218 {
1224 face.element[1].index = -1;
1225 face.element[1].orientation = -1;
1226 }
1227 else // inf2 >= 0
1228 {
1234 face.element[1].index = -1 - e2;
1235 face.element[1].orientation = inf2%64;
1236 }
1237 }
1238 else // ncface >= 0
1239 {
1240 if (inf2 < 0)
1241 {
1247 face.element[1].index = -1;
1248 face.element[1].orientation = -1;
1249 }
1250 else
1251 {
1257 face.element[1].index = -1 - e2;
1258 face.element[1].orientation = inf2%64;
1259 }
1260 face.point_matrix = nc_faces_info[ncface].PointMatrix;
1261 }
1262 }
1263 }
1264 else // Ghost face
1265 {
1266 if (e1==-1)
1267 {
1273 face.element[1].index = -1;
1274 face.element[1].orientation = -1;
1275 }
1276 else
1277 {
1283 face.element[1].index = -1 - e2;
1284 face.element[1].orientation = inf2%64;
1285 face.point_matrix = nc_faces_info[ncface].PointMatrix;
1286 }
1287 }
1288 return face;
1289}
1290
1291Mesh::FaceInformation::operator Mesh::FaceInfo() const
1292{
1293 FaceInfo res {-1, -1, -1, -1, -1};
1294 switch (tag)
1295 {
1297 res.Elem1No = element[0].index;
1298 res.Elem2No = element[1].index;
1299 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1300 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1301 res.NCFace = ncface;
1302 break;
1304 res.Elem1No = element[0].index;
1305 res.Elem2No = element[1].index;
1306 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1307 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1308 res.NCFace = ncface;
1309 break;
1311 res.Elem1No = element[0].index;
1312 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1313 break;
1315 res.Elem1No = element[0].index;
1316 res.Elem2No = -1 - element[1].index;
1317 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1318 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1319 break;
1321 res.Elem1No = element[0].index;
1322 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1323 break;
1325 res.Elem1No = element[0].index;
1326 res.Elem2No = -1 - element[1].index;
1327 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1328 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1329 break;
1331 break;
1333 res.Elem1No = element[0].index;
1334 res.Elem2No = -1 - element[1].index;
1335 res.Elem1Inf = element[0].orientation + element[0].local_face_id*64;
1336 res.Elem2Inf = element[1].orientation + element[1].local_face_id*64;
1337 break;
1338 }
1339 return res;
1340}
1341
1342std::ostream &operator<<(std::ostream &os, const Mesh::FaceInformation& info)
1343{
1344 os << "face topology=";
1345 switch (info.topology)
1346 {
1348 os << "Boundary";
1349 break;
1351 os << "Conforming";
1352 break;
1354 os << "Non-conforming";
1355 break;
1357 os << "NA";
1358 break;
1359 }
1360 os << '\n';
1361 os << "element[0].location=";
1362 switch (info.element[0].location)
1363 {
1365 os << "Local";
1366 break;
1368 os << "FaceNbr";
1369 break;
1371 os << "NA";
1372 break;
1373 }
1374 os << '\n';
1375 os << "element[1].location=";
1376 switch (info.element[1].location)
1377 {
1379 os << "Local";
1380 break;
1382 os << "FaceNbr";
1383 break;
1385 os << "NA";
1386 break;
1387 }
1388 os << '\n';
1389 os << "element[0].conformity=";
1390 switch (info.element[0].conformity)
1391 {
1393 os << "Coincident";
1394 break;
1396 os << "Superset";
1397 break;
1399 os << "Subset";
1400 break;
1402 os << "NA";
1403 break;
1404 }
1405 os << '\n';
1406 os << "element[1].conformity=";
1407 switch (info.element[1].conformity)
1408 {
1410 os << "Coincident";
1411 break;
1413 os << "Superset";
1414 break;
1416 os << "Subset";
1417 break;
1419 os << "NA";
1420 break;
1421 }
1422 os << '\n';
1423 os << "element[0].index=" << info.element[0].index << '\n'
1424 << "element[1].index=" << info.element[1].index << '\n'
1425 << "element[0].local_face_id=" << info.element[0].local_face_id << '\n'
1426 << "element[1].local_face_id=" << info.element[1].local_face_id << '\n'
1427 << "element[0].orientation=" << info.element[0].orientation << '\n'
1428 << "element[1].orientation=" << info.element[1].orientation << '\n'
1429 << "ncface=" << info.ncface << std::endl;
1430 return os;
1431}
1432
1433void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2) const
1434{
1435 *Elem1 = faces_info[Face].Elem1No;
1436 *Elem2 = faces_info[Face].Elem2No;
1437}
1438
1439void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const
1440{
1441 *Inf1 = faces_info[Face].Elem1Inf;
1442 *Inf2 = faces_info[Face].Elem2Inf;
1443}
1444
1445void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2, int *NCFace) const
1446{
1447 *Inf1 = faces_info[Face].Elem1Inf;
1448 *Inf2 = faces_info[Face].Elem2Inf;
1449 *NCFace = faces_info[Face].NCFace;
1450}
1451
1453{
1454 switch (Dim)
1455 {
1456 case 1: return Geometry::POINT;
1457 case 2: return Geometry::SEGMENT;
1458 case 3:
1459 if (Face < NumOfFaces) // local (non-ghost) face
1460 {
1461 return faces[Face]->GetGeometryType();
1462 }
1463 // ghost face
1464 const int nc_face_id = faces_info[Face].NCFace;
1465
1466 MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported");
1467 return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType();
1468 }
1469 return Geometry::INVALID;
1470}
1471
1473{
1474 return (Dim == 1) ? Element::POINT : faces[Face]->GetType();
1475}
1476
1478{
1479 Array<int> face_to_be(Dim == 2 ? NumOfEdges : NumOfFaces);
1480 face_to_be = -1;
1481 for (int i = 0; i < NumOfBdrElements; i++)
1482 {
1483 face_to_be[GetBdrElementFaceIndex(i)] = i;
1484 }
1485 return face_to_be;
1486}
1487
1489{
1490 // in order of declaration:
1491 Dim = spaceDim = 0;
1492 NumOfVertices = -1;
1494 NumOfEdges = NumOfFaces = 0;
1495 nbInteriorFaces = -1;
1496 nbBoundaryFaces = -1;
1497 meshgen = mesh_geoms = 0;
1498 sequence = 0;
1499 nodes_sequence = 0;
1500 Nodes = NULL;
1501 own_nodes = 1;
1502 NURBSext = NULL;
1503 ncmesh = NULL;
1505}
1506
1508{
1509 el_to_edge =
1511 face_to_elem = NULL;
1512}
1513
1515{
1516 Init();
1517 InitTables();
1518}
1519
1521{
1522 delete el_to_edge;
1523 delete el_to_face;
1524 delete el_to_el;
1526
1527 if (Dim == 3)
1528 {
1529 delete bel_to_edge;
1530 }
1531
1532 delete face_edge;
1533 delete edge_vertex;
1534
1535 delete face_to_elem;
1536 face_to_elem = NULL;
1537}
1538
1540{
1541 if (own_nodes) { delete Nodes; }
1542
1543 delete ncmesh;
1544
1545 delete NURBSext;
1546
1547 for (int i = 0; i < NumOfElements; i++)
1548 {
1550 }
1551
1552 for (int i = 0; i < NumOfBdrElements; i++)
1553 {
1555 }
1556
1557 for (int i = 0; i < faces.Size(); i++)
1558 {
1559 FreeElement(faces[i]);
1560 }
1561
1562 DestroyTables();
1563}
1564
1566{
1568
1569 elements.DeleteAll();
1570 vertices.DeleteAll();
1571 boundary.DeleteAll();
1572 faces.DeleteAll();
1573 faces_info.DeleteAll();
1574 nc_faces_info.DeleteAll();
1576
1577 // TODO:
1578 // IsoparametricTransformations
1579 // Transformation, Transformation2, BdrTransformation, FaceTransformation,
1580 // EdgeTransformation;
1581 // FaceElementTransformations FaceElemTr;
1582
1584
1585#ifdef MFEM_USE_MEMALLOC
1586 TetMemory.Clear();
1587#endif
1588
1591}
1592
1594{
1595 delete el_to_el; el_to_el = NULL;
1596 delete face_edge; face_edge = NULL;
1597 delete face_to_elem; face_to_elem = NULL;
1598 delete edge_vertex; edge_vertex = NULL;
1600 nbInteriorFaces = -1;
1601 nbBoundaryFaces = -1;
1602}
1603
1605{
1606 Array<int> attribs;
1607
1608 attribs.SetSize(GetNBE());
1609 for (int i = 0; i < attribs.Size(); i++)
1610 {
1611 attribs[i] = GetBdrAttribute(i);
1612 }
1613 attribs.Sort();
1614 attribs.Unique();
1615 attribs.Copy(bdr_attributes);
1616 if (bdr_attributes.Size() > 0 && bdr_attributes[0] <= 0)
1617 {
1618 MFEM_WARNING("Non-positive attributes on the boundary!");
1619 }
1620
1621 attribs.SetSize(GetNE());
1622 for (int i = 0; i < attribs.Size(); i++)
1623 {
1624 attribs[i] = GetAttribute(i);
1625 }
1626 attribs.Sort();
1627 attribs.Unique();
1628 attribs.Copy(attributes);
1629 if (attributes.Size() > 0 && attributes[0] <= 0)
1630 {
1631 MFEM_WARNING("Non-positive attributes in the domain!");
1632 }
1633}
1634
1635void Mesh::InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
1636{
1637 SetEmpty();
1638
1639 Dim = Dim_;
1640 spaceDim = spaceDim_;
1641
1642 NumOfVertices = 0;
1643 vertices.SetSize(NVert); // just allocate space for vertices
1644
1645 NumOfElements = 0;
1646 elements.SetSize(NElem); // just allocate space for Element *
1647
1648 NumOfBdrElements = 0;
1649 boundary.SetSize(NBdrElem); // just allocate space for Element *
1650}
1651
1652template<typename T>
1653static void CheckEnlarge(Array<T> &array, int size)
1654{
1655 if (size >= array.Size()) { array.SetSize(size + 1); }
1656}
1657
1659{
1660 CheckEnlarge(vertices, NumOfVertices);
1662 v[0] = x;
1663 v[1] = y;
1664 v[2] = z;
1665 return NumOfVertices++;
1666}
1667
1668int Mesh::AddVertex(const real_t *coords)
1669{
1670 CheckEnlarge(vertices, NumOfVertices);
1671 vertices[NumOfVertices].SetCoords(spaceDim, coords);
1672 return NumOfVertices++;
1673}
1674
1675int Mesh::AddVertex(const Vector &coords)
1676{
1677 MFEM_ASSERT(coords.Size() >= spaceDim,
1678 "invalid 'coords' size: " << coords.Size());
1679 return AddVertex(coords.GetData());
1680}
1681
1682void Mesh::AddVertexParents(int i, int p1, int p2)
1683{
1684 tmp_vertex_parents.Append(Triple<int, int, int>(i, p1, p2));
1685
1686 // if vertex coordinates are defined, make sure the hanging vertex has the
1687 // correct position
1688 if (i < vertices.Size())
1689 {
1690 real_t *vi = vertices[i](), *vp1 = vertices[p1](), *vp2 = vertices[p2]();
1691 for (int j = 0; j < 3; j++)
1692 {
1693 vi[j] = (vp1[j] + vp2[j]) * 0.5;
1694 }
1695 }
1696}
1697
1698int Mesh::AddVertexAtMeanCenter(const int *vi, int nverts, int dim)
1699{
1700 Vector vii(dim);
1701 vii = 0.0;
1702 for (int i = 0; i < nverts; i++)
1703 {
1704 real_t *vp = vertices[vi[i]]();
1705 for (int j = 0; j < dim; j++)
1706 {
1707 vii(j) += vp[j];
1708 }
1709 }
1710 vii /= nverts;
1711 AddVertex(vii);
1712 return NumOfVertices;
1713}
1714
1715int Mesh::AddSegment(int v1, int v2, int attr)
1716{
1717 CheckEnlarge(elements, NumOfElements);
1718 elements[NumOfElements] = new Segment(v1, v2, attr);
1719 return NumOfElements++;
1720}
1721
1722int Mesh::AddSegment(const int *vi, int attr)
1723{
1724 CheckEnlarge(elements, NumOfElements);
1725 elements[NumOfElements] = new Segment(vi, attr);
1726 return NumOfElements++;
1727}
1728
1729int Mesh::AddTriangle(int v1, int v2, int v3, int attr)
1730{
1731 CheckEnlarge(elements, NumOfElements);
1732 elements[NumOfElements] = new Triangle(v1, v2, v3, attr);
1733 return NumOfElements++;
1734}
1735
1736int Mesh::AddTriangle(const int *vi, int attr)
1737{
1738 CheckEnlarge(elements, NumOfElements);
1739 elements[NumOfElements] = new Triangle(vi, attr);
1740 return NumOfElements++;
1741}
1742
1743int Mesh::AddQuad(int v1, int v2, int v3, int v4, int attr)
1744{
1745 CheckEnlarge(elements, NumOfElements);
1746 elements[NumOfElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1747 return NumOfElements++;
1748}
1749
1750int Mesh::AddQuad(const int *vi, int attr)
1751{
1752 CheckEnlarge(elements, NumOfElements);
1753 elements[NumOfElements] = new Quadrilateral(vi, attr);
1754 return NumOfElements++;
1755}
1756
1757int Mesh::AddTet(int v1, int v2, int v3, int v4, int attr)
1758{
1759 int vi[4] = {v1, v2, v3, v4};
1760 return AddTet(vi, attr);
1761}
1762
1763int Mesh::AddTet(const int *vi, int attr)
1764{
1765 CheckEnlarge(elements, NumOfElements);
1766#ifdef MFEM_USE_MEMALLOC
1767 Tetrahedron *tet;
1768 tet = TetMemory.Alloc();
1769 tet->SetVertices(vi);
1770 tet->SetAttribute(attr);
1771 elements[NumOfElements] = tet;
1772#else
1773 elements[NumOfElements] = new Tetrahedron(vi, attr);
1774#endif
1775 return NumOfElements++;
1776}
1777
1778int Mesh::AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr)
1779{
1780 CheckEnlarge(elements, NumOfElements);
1781 elements[NumOfElements] = new Wedge(v1, v2, v3, v4, v5, v6, attr);
1782 return NumOfElements++;
1783}
1784
1785int Mesh::AddWedge(const int *vi, int attr)
1786{
1787 CheckEnlarge(elements, NumOfElements);
1788 elements[NumOfElements] = new Wedge(vi, attr);
1789 return NumOfElements++;
1790}
1791
1792int Mesh::AddPyramid(int v1, int v2, int v3, int v4, int v5, int attr)
1793{
1794 CheckEnlarge(elements, NumOfElements);
1795 elements[NumOfElements] = new Pyramid(v1, v2, v3, v4, v5, attr);
1796 return NumOfElements++;
1797}
1798
1799int Mesh::AddPyramid(const int *vi, int attr)
1800{
1801 CheckEnlarge(elements, NumOfElements);
1802 elements[NumOfElements] = new Pyramid(vi, attr);
1803 return NumOfElements++;
1804}
1805
1806int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
1807 int attr)
1808{
1809 CheckEnlarge(elements, NumOfElements);
1811 new Hexahedron(v1, v2, v3, v4, v5, v6, v7, v8, attr);
1812 return NumOfElements++;
1813}
1814
1815int Mesh::AddHex(const int *vi, int attr)
1816{
1817 CheckEnlarge(elements, NumOfElements);
1818 elements[NumOfElements] = new Hexahedron(vi, attr);
1819 return NumOfElements++;
1820}
1821
1822void Mesh::AddHexAsTets(const int *vi, int attr)
1823{
1824 static const int hex_to_tet[6][4] =
1825 {
1826 { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
1827 { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
1828 };
1829 int ti[4];
1830
1831 for (int i = 0; i < 6; i++)
1832 {
1833 for (int j = 0; j < 4; j++)
1834 {
1835 ti[j] = vi[hex_to_tet[i][j]];
1836 }
1837 AddTet(ti, attr);
1838 }
1839}
1840
1841void Mesh::AddHexAsWedges(const int *vi, int attr)
1842{
1843 static const int hex_to_wdg[2][6] =
1844 {
1845 { 0, 1, 2, 4, 5, 6 }, { 0, 2, 3, 4, 6, 7 }
1846 };
1847 int ti[6];
1848
1849 for (int i = 0; i < 2; i++)
1850 {
1851 for (int j = 0; j < 6; j++)
1852 {
1853 ti[j] = vi[hex_to_wdg[i][j]];
1854 }
1855 AddWedge(ti, attr);
1856 }
1857}
1858
1859void Mesh::AddHexAsPyramids(const int *vi, int attr)
1860{
1861 static const int hex_to_pyr[6][5] =
1862 {
1863 { 0, 1, 2, 3, 8 }, { 0, 4, 5, 1, 8 }, { 1, 5, 6, 2, 8 },
1864 { 2, 6, 7, 3, 8 }, { 3, 7, 4, 0, 8 }, { 7, 6, 5, 4, 8 }
1865 };
1866 int ti[5];
1867
1868 for (int i = 0; i < 6; i++)
1869 {
1870 for (int j = 0; j < 5; j++)
1871 {
1872 ti[j] = vi[hex_to_pyr[i][j]];
1873 }
1874 AddPyramid(ti, attr);
1875 }
1876}
1877
1878void Mesh::AddQuadAs4TrisWithPoints(int *vi, int attr)
1879{
1880 int num_faces = 4;
1881 static const int quad_to_tri[4][2] =
1882 {
1883 {0, 1}, {1, 2}, {2, 3}, {3, 0}
1884 };
1885
1886 int elem_center_index = AddVertexAtMeanCenter(vi, 4, 2) - 1;
1887
1888 int ti[3];
1889 ti[2] = elem_center_index;
1890 for (int i = 0; i < num_faces; i++)
1891 {
1892 for (int j = 0; j < 2; j++)
1893 {
1894 ti[j] = vi[quad_to_tri[i][j]];
1895 }
1896 AddTri(ti, attr);
1897 }
1898}
1899
1900void Mesh::AddQuadAs5QuadsWithPoints(int *vi, int attr)
1901{
1902 int num_faces = 4;
1903 static const int quad_faces[4][2] =
1904 {
1905 {0, 1}, {1, 2}, {2, 3}, {3, 0}
1906 };
1907
1908 Vector px(4), py(4);
1909 for (int i = 0; i < 4; i++)
1910 {
1911 real_t *vp = vertices[vi[i]]();
1912 px(i) = vp[0];
1913 py(i) = vp[1];
1914 }
1915
1916 int vnew_index[4];
1917 real_t vnew[2];
1918 real_t r = 0.25, s = 0.25;
1919 vnew[0] = px(0)*(1-r)*(1-s) + px(1)*(r)*(1-s) + px(2)*r*s + px(3)*(1-r)*s;
1920 vnew[1] = py(0)*(1-r)*(1-s) + py(1)*(r)*(1-s) + py(2)*r*s + py(3)*(1-r)*s;
1921 AddVertex(vnew);
1922 vnew_index[0] = NumOfVertices-1;
1923
1924 r = 0.75, s = 0.25;
1925 vnew[0] = px(0)*(1-r)*(1-s) + px(1)*(r)*(1-s) + px(2)*r*s + px(3)*(1-r)*s;
1926 vnew[1] = py(0)*(1-r)*(1-s) + py(1)*(r)*(1-s) + py(2)*r*s + py(3)*(1-r)*s;
1927 AddVertex(vnew);
1928 vnew_index[1] = NumOfVertices-1;
1929
1930 r = 0.75, s = 0.75;
1931 vnew[0] = px(0)*(1-r)*(1-s) + px(1)*(r)*(1-s) + px(2)*r*s + px(3)*(1-r)*s;
1932 vnew[1] = py(0)*(1-r)*(1-s) + py(1)*(r)*(1-s) + py(2)*r*s + py(3)*(1-r)*s;
1933 AddVertex(vnew);
1934 vnew_index[2] = NumOfVertices-1;
1935
1936 r = 0.25, s = 0.75;
1937 vnew[0] = px(0)*(1-r)*(1-s) + px(1)*(r)*(1-s) + px(2)*r*s + px(3)*(1-r)*s;
1938 vnew[1] = py(0)*(1-r)*(1-s) + py(1)*(r)*(1-s) + py(2)*r*s + py(3)*(1-r)*s;
1939 AddVertex(vnew);
1940 vnew_index[3] = NumOfVertices-1;
1941
1942 static const int quad_faces_new[4][2] =
1943 {
1944 { 1, 0}, { 2, 1}, { 3, 2}, { 0, 3}
1945 };
1946
1947 int ti[4];
1948 for (int i = 0; i < num_faces; i++)
1949 {
1950 for (int j = 0; j < 2; j++)
1951 {
1952 ti[j] = vi[quad_faces[i][j]];
1953 ti[j+2] = vnew_index[quad_faces_new[i][j]];
1954 }
1955 AddQuad(ti, attr);
1956 }
1957 AddQuad(vnew_index, attr);
1958}
1959
1961 std::map<std::array<int, 4>, int> &hex_face_verts,
1962 int attr)
1963{
1964 auto get4arraysorted = [](Array<int> v)
1965 {
1966 v.Sort();
1967 return std::array<int, 4> {v[0], v[1], v[2], v[3]};
1968 };
1969
1970 int num_faces = 6;
1971 static const int hex_to_tet[6][4] =
1972 {
1973 { 0, 1, 2, 3 }, { 1, 2, 6, 5 }, { 5, 4, 7, 6},
1974 { 0, 1, 5, 4 }, { 2, 3, 7, 6 }, { 0,3, 7, 4}
1975 };
1976
1977 int elem_center_index = AddVertexAtMeanCenter(vi, 8, 3) - 1;
1978
1979 Array<int> flist(4);
1980
1981 // local vertex indices for each of the 4 edges of the face
1982 static const int tet_face[4][2] =
1983 {
1984 {0, 1}, {1, 2}, {3, 2}, {3, 0}
1985 };
1986
1987 for (int i = 0; i < num_faces; i++)
1988 {
1989 for (int j = 0; j < 4; j++)
1990 {
1991 flist[j] = vi[hex_to_tet[i][j]];
1992 }
1993 int face_center_index;
1994
1995 auto t = get4arraysorted(flist);
1996 auto it = hex_face_verts.find(t);
1997 if (it == hex_face_verts.end())
1998 {
1999 face_center_index = AddVertexAtMeanCenter(flist.GetData(),
2000 flist.Size(), 3) - 1;
2001 hex_face_verts.insert({t, face_center_index});
2002 }
2003 else
2004 {
2005 face_center_index = it->second;
2006 }
2007 int fti[4];
2008 fti[2] = face_center_index;
2009 fti[3] = elem_center_index;
2010 for (int j = 0; j < 4; j++)
2011 {
2012 for (int k = 0; k < 2; k++)
2013 {
2014 fti[k] = flist[tet_face[j][k]];
2015 }
2016 AddTet(fti, attr);
2017 }
2018 }
2019}
2020
2022{
2023 CheckEnlarge(elements, NumOfElements);
2024 elements[NumOfElements] = elem;
2025 return NumOfElements++;
2026}
2027
2029{
2030 CheckEnlarge(boundary, NumOfBdrElements);
2031 boundary[NumOfBdrElements] = elem;
2032 return NumOfBdrElements++;
2033}
2034
2035int Mesh::AddBdrSegment(int v1, int v2, int attr)
2036{
2037 CheckEnlarge(boundary, NumOfBdrElements);
2038 boundary[NumOfBdrElements] = new Segment(v1, v2, attr);
2039 return NumOfBdrElements++;
2040}
2041
2042int Mesh::AddBdrSegment(const int *vi, int attr)
2043{
2044 CheckEnlarge(boundary, NumOfBdrElements);
2045 boundary[NumOfBdrElements] = new Segment(vi, attr);
2046 return NumOfBdrElements++;
2047}
2048
2049int Mesh::AddBdrTriangle(int v1, int v2, int v3, int attr)
2050{
2051 CheckEnlarge(boundary, NumOfBdrElements);
2052 boundary[NumOfBdrElements] = new Triangle(v1, v2, v3, attr);
2053 return NumOfBdrElements++;
2054}
2055
2056int Mesh::AddBdrTriangle(const int *vi, int attr)
2057{
2058 CheckEnlarge(boundary, NumOfBdrElements);
2059 boundary[NumOfBdrElements] = new Triangle(vi, attr);
2060 return NumOfBdrElements++;
2061}
2062
2063int Mesh::AddBdrQuad(int v1, int v2, int v3, int v4, int attr)
2064{
2065 CheckEnlarge(boundary, NumOfBdrElements);
2066 boundary[NumOfBdrElements] = new Quadrilateral(v1, v2, v3, v4, attr);
2067 return NumOfBdrElements++;
2068}
2069
2070int Mesh::AddBdrQuad(const int *vi, int attr)
2071{
2072 CheckEnlarge(boundary, NumOfBdrElements);
2073 boundary[NumOfBdrElements] = new Quadrilateral(vi, attr);
2074 return NumOfBdrElements++;
2075}
2076
2077void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
2078{
2079 static const int quad_to_tri[2][3] = { { 0, 1, 2 }, { 0, 2, 3 } };
2080 int ti[3];
2081
2082 for (int i = 0; i < 2; i++)
2083 {
2084 for (int j = 0; j < 3; j++)
2085 {
2086 ti[j] = vi[quad_to_tri[i][j]];
2087 }
2088 AddBdrTriangle(ti, attr);
2089 }
2090}
2091
2092int Mesh::AddBdrPoint(int v, int attr)
2093{
2094 CheckEnlarge(boundary, NumOfBdrElements);
2095 boundary[NumOfBdrElements] = new Point(&v, attr);
2096 return NumOfBdrElements++;
2097}
2098
2100{
2101 for (auto &b : boundary)
2102 {
2103 FreeElement(b);
2104 }
2105
2106 if (Dim == 3)
2107 {
2108 delete bel_to_edge;
2109 bel_to_edge = NULL;
2110 }
2111
2112 // count the 'NumOfBdrElements'
2113 NumOfBdrElements = 0;
2114 for (const auto &fi : faces_info)
2115 {
2116 if (fi.Elem2No < 0) { ++NumOfBdrElements; }
2117 }
2118
2119 // Add the boundary elements
2122 for (int i = 0, j = 0; i < faces_info.Size(); i++)
2123 {
2124 if (faces_info[i].Elem2No < 0)
2125 {
2126 boundary[j] = faces[i]->Duplicate(this);
2127 be_to_face[j++] = i;
2128 }
2129 }
2130
2131 // Note: in 3D, 'bel_to_edge' is destroyed but it's not updated.
2132}
2133
2135{
2136 MFEM_VERIFY(vertices.Size() == NumOfVertices ||
2137 vertices.Size() == 0,
2138 "incorrect number of vertices: preallocated: " << vertices.Size()
2139 << ", actually added: " << NumOfVertices);
2140 MFEM_VERIFY(elements.Size() == NumOfElements,
2141 "incorrect number of elements: preallocated: " << elements.Size()
2142 << ", actually added: " << NumOfElements);
2143 MFEM_VERIFY(boundary.Size() == NumOfBdrElements,
2144 "incorrect number of boundary elements: preallocated: "
2145 << boundary.Size() << ", actually added: " << NumOfBdrElements);
2146}
2147
2148void Mesh::FinalizeTriMesh(int generate_edges, int refine, bool fix_orientation)
2149{
2150 FinalizeCheck();
2151 CheckElementOrientation(fix_orientation);
2152
2153 if (refine)
2154 {
2156 }
2157
2158 if (generate_edges)
2159 {
2160 el_to_edge = new Table;
2162 GenerateFaces();
2164 }
2165 else
2166 {
2167 NumOfEdges = 0;
2168 }
2169
2170 NumOfFaces = 0;
2171
2172 SetAttributes();
2173
2174 SetMeshGen();
2175}
2176
2177void Mesh::FinalizeQuadMesh(int generate_edges, int refine,
2178 bool fix_orientation)
2179{
2180 FinalizeCheck();
2181 if (fix_orientation)
2182 {
2183 CheckElementOrientation(fix_orientation);
2184 }
2185
2186 if (generate_edges)
2187 {
2188 el_to_edge = new Table;
2190 GenerateFaces();
2192 }
2193 else
2194 {
2195 NumOfEdges = 0;
2196 }
2197
2198 NumOfFaces = 0;
2199
2200 SetAttributes();
2201
2202 SetMeshGen();
2203}
2204
2205
2206class GeckoProgress : public Gecko::Progress
2207{
2208 real_t limit;
2209 mutable StopWatch sw;
2210public:
2211 GeckoProgress(real_t limit) : limit(limit) { sw.Start(); }
2212 virtual bool quit() const { return limit > 0 && sw.UserTime() > limit; }
2213};
2214
2215class GeckoVerboseProgress : public GeckoProgress
2216{
2217 using Float = Gecko::Float;
2218 using Graph = Gecko::Graph;
2219 using uint = Gecko::uint;
2220public:
2221 GeckoVerboseProgress(real_t limit) : GeckoProgress(limit) {}
2222
2223 virtual void beginorder(const Graph* graph, Float cost) const
2224 { mfem::out << "Begin Gecko ordering, cost = " << cost << std::endl; }
2225 virtual void endorder(const Graph* graph, Float cost) const
2226 { mfem::out << "End ordering, cost = " << cost << std::endl; }
2227
2228 virtual void beginiter(const Graph* graph,
2229 uint iter, uint maxiter, uint window) const
2230 {
2231 mfem::out << "Iteration " << iter << "/" << maxiter << ", window "
2232 << window << std::flush;
2233 }
2234 virtual void enditer(const Graph* graph, Float mincost, Float cost) const
2235 { mfem::out << ", cost = " << cost << endl; }
2236};
2237
2238
2240 int iterations, int window,
2241 int period, int seed, bool verbose,
2242 real_t time_limit)
2243{
2244 Gecko::Graph graph;
2245 Gecko::FunctionalGeometric functional; // edge product cost
2246
2247 GeckoProgress progress(time_limit);
2248 GeckoVerboseProgress vprogress(time_limit);
2249
2250 // insert elements as nodes in the graph
2251 for (int elemid = 0; elemid < GetNE(); ++elemid)
2252 {
2253 graph.insert_node();
2254 }
2255
2256 // insert graph edges for element neighbors
2257 // NOTE: indices in Gecko are 1 based hence the +1 on insertion
2258 const Table &my_el_to_el = ElementToElementTable();
2259 for (int elemid = 0; elemid < GetNE(); ++elemid)
2260 {
2261 const int *neighid = my_el_to_el.GetRow(elemid);
2262 for (int i = 0; i < my_el_to_el.RowSize(elemid); ++i)
2263 {
2264 graph.insert_arc(elemid + 1, neighid[i] + 1);
2265 }
2266 }
2267
2268 // get the ordering from Gecko and copy it into the Array<int>
2269 graph.order(&functional, iterations, window, period, seed,
2270 verbose ? &vprogress : &progress);
2271
2272 ordering.SetSize(GetNE());
2274 for (Gecko::Node::Index gnodeid = 1; gnodeid <= NE; ++gnodeid)
2275 {
2276 ordering[gnodeid - 1] = graph.rank(gnodeid);
2277 }
2278
2279 return graph.cost();
2280}
2281
2282
2283struct HilbertCmp
2284{
2285 int coord;
2286 bool dir;
2287 const Array<real_t> &points;
2288 real_t mid;
2289
2290 HilbertCmp(int coord, bool dir, const Array<real_t> &points, real_t mid)
2291 : coord(coord), dir(dir), points(points), mid(mid) {}
2292
2293 bool operator()(int i) const
2294 {
2295 return (points[3*i + coord] < mid) != dir;
2296 }
2297};
2298
2299static void HilbertSort2D(int coord1, // major coordinate to sort points by
2300 bool dir1, // sort coord1 ascending/descending?
2301 bool dir2, // sort coord2 ascending/descending?
2302 const Array<real_t> &points, int *beg, int *end,
2303 real_t xmin, real_t ymin, real_t xmax, real_t ymax)
2304{
2305 if (end - beg <= 1) { return; }
2306
2307 real_t xmid = (xmin + xmax)*0.5;
2308 real_t ymid = (ymin + ymax)*0.5;
2309
2310 int coord2 = (coord1 + 1) % 2; // the 'other' coordinate
2311
2312 // sort (partition) points into four quadrants
2313 int *p0 = beg, *p4 = end;
2314 int *p2 = std::partition(p0, p4, HilbertCmp(coord1, dir1, points, xmid));
2315 int *p1 = std::partition(p0, p2, HilbertCmp(coord2, dir2, points, ymid));
2316 int *p3 = std::partition(p2, p4, HilbertCmp(coord2, !dir2, points, ymid));
2317
2318 if (p1 != p4)
2319 {
2320 HilbertSort2D(coord2, dir2, dir1, points, p0, p1,
2321 ymin, xmin, ymid, xmid);
2322 }
2323 if (p1 != p0 || p2 != p4)
2324 {
2325 HilbertSort2D(coord1, dir1, dir2, points, p1, p2,
2326 xmin, ymid, xmid, ymax);
2327 }
2328 if (p2 != p0 || p3 != p4)
2329 {
2330 HilbertSort2D(coord1, dir1, dir2, points, p2, p3,
2331 xmid, ymid, xmax, ymax);
2332 }
2333 if (p3 != p0)
2334 {
2335 HilbertSort2D(coord2, !dir2, !dir1, points, p3, p4,
2336 ymid, xmax, ymin, xmid);
2337 }
2338}
2339
2340static void HilbertSort3D(int coord1, bool dir1, bool dir2, bool dir3,
2341 const Array<real_t> &points, int *beg, int *end,
2342 real_t xmin, real_t ymin, real_t zmin,
2343 real_t xmax, real_t ymax, real_t zmax)
2344{
2345 if (end - beg <= 1) { return; }
2346
2347 real_t xmid = (xmin + xmax)*0.5;
2348 real_t ymid = (ymin + ymax)*0.5;
2349 real_t zmid = (zmin + zmax)*0.5;
2350
2351 int coord2 = (coord1 + 1) % 3;
2352 int coord3 = (coord1 + 2) % 3;
2353
2354 // sort (partition) points into eight octants
2355 int *p0 = beg, *p8 = end;
2356 int *p4 = std::partition(p0, p8, HilbertCmp(coord1, dir1, points, xmid));
2357 int *p2 = std::partition(p0, p4, HilbertCmp(coord2, dir2, points, ymid));
2358 int *p6 = std::partition(p4, p8, HilbertCmp(coord2, !dir2, points, ymid));
2359 int *p1 = std::partition(p0, p2, HilbertCmp(coord3, dir3, points, zmid));
2360 int *p3 = std::partition(p2, p4, HilbertCmp(coord3, !dir3, points, zmid));
2361 int *p5 = std::partition(p4, p6, HilbertCmp(coord3, dir3, points, zmid));
2362 int *p7 = std::partition(p6, p8, HilbertCmp(coord3, !dir3, points, zmid));
2363
2364 if (p1 != p8)
2365 {
2366 HilbertSort3D(coord3, dir3, dir1, dir2, points, p0, p1,
2367 zmin, xmin, ymin, zmid, xmid, ymid);
2368 }
2369 if (p1 != p0 || p2 != p8)
2370 {
2371 HilbertSort3D(coord2, dir2, dir3, dir1, points, p1, p2,
2372 ymin, zmid, xmin, ymid, zmax, xmid);
2373 }
2374 if (p2 != p0 || p3 != p8)
2375 {
2376 HilbertSort3D(coord2, dir2, dir3, dir1, points, p2, p3,
2377 ymid, zmid, xmin, ymax, zmax, xmid);
2378 }
2379 if (p3 != p0 || p4 != p8)
2380 {
2381 HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p3, p4,
2382 xmin, ymax, zmid, xmid, ymid, zmin);
2383 }
2384 if (p4 != p0 || p5 != p8)
2385 {
2386 HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p4, p5,
2387 xmid, ymax, zmid, xmax, ymid, zmin);
2388 }
2389 if (p5 != p0 || p6 != p8)
2390 {
2391 HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p5, p6,
2392 ymax, zmid, xmax, ymid, zmax, xmid);
2393 }
2394 if (p6 != p0 || p7 != p8)
2395 {
2396 HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p6, p7,
2397 ymid, zmid, xmax, ymin, zmax, xmid);
2398 }
2399 if (p7 != p0)
2400 {
2401 HilbertSort3D(coord3, !dir3, !dir1, dir2, points, p7, p8,
2402 zmid, xmax, ymin, zmin, xmid, ymid);
2403 }
2404}
2405
2407{
2408 MFEM_VERIFY(spaceDim <= 3, "");
2409
2410 Vector min, max, center;
2411 GetBoundingBox(min, max);
2412
2413 Array<int> indices(GetNE());
2414 Array<real_t> points(3*GetNE());
2415
2416 if (spaceDim < 3) { points = 0.0; }
2417
2418 // calculate element centers
2419 for (int i = 0; i < GetNE(); i++)
2420 {
2421 GetElementCenter(i, center);
2422 for (int j = 0; j < spaceDim; j++)
2423 {
2424 points[3*i + j] = center(j);
2425 }
2426 indices[i] = i;
2427 }
2428
2429 if (spaceDim == 1)
2430 {
2431 indices.Sort([&](int a, int b)
2432 { return points[3*a] < points[3*b]; });
2433 }
2434 else if (spaceDim == 2)
2435 {
2436 // recursively partition the points in 2D
2437 HilbertSort2D(0, false, false,
2438 points, indices.begin(), indices.end(),
2439 min(0), min(1), max(0), max(1));
2440 }
2441 else
2442 {
2443 // recursively partition the points in 3D
2444 HilbertSort3D(0, false, false, false,
2445 points, indices.begin(), indices.end(),
2446 min(0), min(1), min(2), max(0), max(1), max(2));
2447 }
2448
2449 // return ordering in the format required by ReorderElements
2450 ordering.SetSize(GetNE());
2451 for (int i = 0; i < GetNE(); i++)
2452 {
2453 ordering[indices[i]] = i;
2454 }
2455}
2456
2457
2458void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
2459{
2460 if (NURBSext)
2461 {
2462 MFEM_WARNING("element reordering of NURBS meshes is not supported.");
2463 return;
2464 }
2465 if (ncmesh)
2466 {
2467 MFEM_WARNING("element reordering of non-conforming meshes is not"
2468 " supported.");
2469 return;
2470 }
2471 MFEM_VERIFY(ordering.Size() == GetNE(), "invalid reordering array.")
2472
2473 // Data members that need to be updated:
2474
2475 // - elements - reorder of the pointers and the vertex ids if reordering
2476 // the vertices
2477 // - vertices - if reordering the vertices
2478 // - boundary - update the vertex ids, if reordering the vertices
2479 // - faces - regenerate
2480 // - faces_info - regenerate
2481
2482 // Deleted by DeleteTables():
2483 // - el_to_edge - rebuild in 2D and 3D only
2484 // - el_to_face - rebuild in 3D only
2485 // - bel_to_edge - rebuild in 3D only
2486 // - el_to_el - no need to rebuild
2487 // - face_edge - no need to rebuild
2488 // - edge_vertex - no need to rebuild
2489 // - geom_factors - no need to rebuild
2490
2491 // - be_to_face
2492
2493 // - Nodes
2494
2495 // Save the locations of the Nodes so we can rebuild them later
2496 Array<Vector*> old_elem_node_vals;
2497 FiniteElementSpace *nodes_fes = NULL;
2498 if (Nodes)
2499 {
2500 old_elem_node_vals.SetSize(GetNE());
2501 nodes_fes = Nodes->FESpace();
2502 Array<int> old_dofs;
2503 Vector vals;
2504 for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2505 {
2506 nodes_fes->GetElementVDofs(old_elid, old_dofs);
2507 Nodes->GetSubVector(old_dofs, vals);
2508 old_elem_node_vals[old_elid] = new Vector(vals);
2509 }
2510 }
2511
2512 // Get the newly ordered elements
2513 Array<Element *> new_elements(GetNE());
2514 for (int old_elid = 0; old_elid < ordering.Size(); ++old_elid)
2515 {
2516 int new_elid = ordering[old_elid];
2517 new_elements[new_elid] = elements[old_elid];
2518 }
2519 mfem::Swap(elements, new_elements);
2520 new_elements.DeleteAll();
2521
2522 if (reorder_vertices)
2523 {
2524 // Get the new vertex ordering permutation vectors and fill the new
2525 // vertices
2526 Array<int> vertex_ordering(GetNV());
2527 vertex_ordering = -1;
2528 Array<Vertex> new_vertices(GetNV());
2529 int new_vertex_ind = 0;
2530 for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2531 {
2532 int *elem_vert = elements[new_elid]->GetVertices();
2533 int nv = elements[new_elid]->GetNVertices();
2534 for (int vi = 0; vi < nv; ++vi)
2535 {
2536 int old_vertex_ind = elem_vert[vi];
2537 if (vertex_ordering[old_vertex_ind] == -1)
2538 {
2539 vertex_ordering[old_vertex_ind] = new_vertex_ind;
2540 new_vertices[new_vertex_ind] = vertices[old_vertex_ind];
2541 new_vertex_ind++;
2542 }
2543 }
2544 }
2545 mfem::Swap(vertices, new_vertices);
2546 new_vertices.DeleteAll();
2547
2548 // Replace the vertex ids in the elements with the reordered vertex
2549 // numbers
2550 for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
2551 {
2552 int *elem_vert = elements[new_elid]->GetVertices();
2553 int nv = elements[new_elid]->GetNVertices();
2554 for (int vi = 0; vi < nv; ++vi)
2555 {
2556 elem_vert[vi] = vertex_ordering[elem_vert[vi]];
2557 }
2558 }
2559
2560 // Replace the vertex ids in the boundary with reordered vertex numbers
2561 for (int belid = 0; belid < GetNBE(); ++belid)
2562 {
2563 int *be_vert = boundary[belid]->GetVertices();
2564 int nv = boundary[belid]->GetNVertices();
2565 for (int vi = 0; vi < nv; ++vi)
2566 {
2567 be_vert[vi] = vertex_ordering[be_vert[vi]];
2568 }
2569 }
2570 }
2571
2572 // Destroy tables that need to be rebuild
2573 DeleteTables();
2574
2575 if (Dim > 1)
2576 {
2577 // generate el_to_edge, be_to_face (2D), bel_to_edge (3D)
2578 el_to_edge = new Table;
2580 }
2581 if (Dim > 2)
2582 {
2583 // generate el_to_face, be_to_face
2585 }
2586 // Update faces and faces_info
2587 GenerateFaces();
2588
2589 // Build the nodes from the saved locations if they were around before
2590 if (Nodes)
2591 {
2592 // To force FE space update, we need to increase 'sequence':
2593 sequence++;
2596 nodes_fes->Update(false); // want_transform = false
2597 Nodes->Update(); // just needed to update Nodes->sequence
2598 Array<int> new_dofs;
2599 for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
2600 {
2601 int new_elid = ordering[old_elid];
2602 nodes_fes->GetElementVDofs(new_elid, new_dofs);
2603 Nodes->SetSubVector(new_dofs, *(old_elem_node_vals[old_elid]));
2604 delete old_elem_node_vals[old_elid];
2605 }
2606 }
2607}
2608
2609
2611{
2612 if (meshgen & 1)
2613 {
2614 if (Dim == 2)
2615 {
2617 }
2618 else if (Dim == 3)
2619 {
2620 DSTable v_to_v(NumOfVertices);
2621 GetVertexToVertexTable(v_to_v);
2623 }
2624 }
2625}
2626
2628{
2629 // Mark the longest triangle edge by rotating the indices so that
2630 // vertex 0 - vertex 1 is the longest edge in the triangle.
2631 DenseMatrix pmat;
2632 for (int i = 0; i < NumOfElements; i++)
2633 {
2634 if (elements[i]->GetType() == Element::TRIANGLE)
2635 {
2636 GetPointMatrix(i, pmat);
2637 static_cast<Triangle*>(elements[i])->MarkEdge(pmat);
2638 }
2639 }
2640}
2641
2642void Mesh::GetEdgeOrdering(const DSTable &v_to_v, Array<int> &order)
2643{
2644 NumOfEdges = v_to_v.NumberOfEntries();
2645 order.SetSize(NumOfEdges);
2646 Array<Pair<real_t, int> > length_idx(NumOfEdges);
2647
2648 for (int i = 0; i < NumOfVertices; i++)
2649 {
2650 for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
2651 {
2652 int j = it.Index();
2653 length_idx[j].one = GetLength(i, it.Column());
2654 length_idx[j].two = j;
2655 }
2656 }
2657
2658 // Sort by increasing edge-length.
2659 length_idx.Sort();
2660
2661 for (int i = 0; i < NumOfEdges; i++)
2662 {
2663 order[length_idx[i].two] = i;
2664 }
2665}
2666
2668{
2669 // Mark the longest tetrahedral edge by rotating the indices so that
2670 // vertex 0 - vertex 1 is the longest edge in the element.
2671 Array<int> order;
2672 GetEdgeOrdering(v_to_v, order);
2673
2674 for (int i = 0; i < NumOfElements; i++)
2675 {
2676 if (elements[i]->GetType() == Element::TETRAHEDRON)
2677 {
2678 elements[i]->MarkEdge(v_to_v, order);
2679 }
2680 }
2681 for (int i = 0; i < NumOfBdrElements; i++)
2682 {
2683 if (boundary[i]->GetType() == Element::TRIANGLE)
2684 {
2685 boundary[i]->MarkEdge(v_to_v, order);
2686 }
2687 }
2688}
2689
2690void Mesh::PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
2691{
2692 if (*old_v_to_v && *old_elem_vert)
2693 {
2694 return;
2695 }
2696
2698
2699 if (*old_v_to_v == NULL)
2700 {
2701 bool need_v_to_v = false;
2702 Array<int> dofs;
2703 for (int i = 0; i < GetNEdges(); i++)
2704 {
2705 // Since edge indices may change, we need to permute edge interior dofs
2706 // any time an edge index changes and there is at least one dof on that
2707 // edge.
2708 fes->GetEdgeInteriorDofs(i, dofs);
2709 if (dofs.Size() > 0)
2710 {
2711 need_v_to_v = true;
2712 break;
2713 }
2714 }
2715 if (need_v_to_v)
2716 {
2717 *old_v_to_v = new DSTable(NumOfVertices);
2718 GetVertexToVertexTable(*(*old_v_to_v));
2719 }
2720 }
2721 if (*old_elem_vert == NULL)
2722 {
2723 bool need_elem_vert = false;
2724 Array<int> dofs;
2725 for (int i = 0; i < GetNE(); i++)
2726 {
2727 // Since element indices do not change, we need to permute element
2728 // interior dofs only when there are at least 2 interior dofs in an
2729 // element (assuming the nodal dofs are non-directional).
2730 fes->GetElementInteriorDofs(i, dofs);
2731 if (dofs.Size() > 1)
2732 {
2733 need_elem_vert = true;
2734 break;
2735 }
2736 }
2737 if (need_elem_vert)
2738 {
2739 *old_elem_vert = new Table;
2740 (*old_elem_vert)->MakeI(GetNE());
2741 for (int i = 0; i < GetNE(); i++)
2742 {
2743 (*old_elem_vert)->AddColumnsInRow(i, elements[i]->GetNVertices());
2744 }
2745 (*old_elem_vert)->MakeJ();
2746 for (int i = 0; i < GetNE(); i++)
2747 {
2748 (*old_elem_vert)->AddConnections(i, elements[i]->GetVertices(),
2749 elements[i]->GetNVertices());
2750 }
2751 (*old_elem_vert)->ShiftUpI();
2752 }
2753 }
2754}
2755
2756void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
2757{
2759 const FiniteElementCollection *fec = fes->FEColl();
2760 Array<int> old_dofs, new_dofs;
2761
2762 // assuming that all edges have the same number of dofs
2763 if (NumOfEdges) { fes->GetEdgeInteriorDofs(0, old_dofs); }
2764 const int num_edge_dofs = old_dofs.Size();
2765
2766 // Save the original nodes
2767 const Vector onodes = *Nodes;
2768
2769 // vertex dofs do not need to be moved
2770 fes->GetVertexDofs(0, old_dofs);
2771 int offset = NumOfVertices * old_dofs.Size();
2772
2773 // edge dofs:
2774 // edge enumeration may be different but edge orientation is the same
2775 if (num_edge_dofs > 0)
2776 {
2777 DSTable new_v_to_v(NumOfVertices);
2778 GetVertexToVertexTable(new_v_to_v);
2779
2780 for (int i = 0; i < NumOfVertices; i++)
2781 {
2782 for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it)
2783 {
2784 const int old_i = (*old_v_to_v)(i, it.Column());
2785 const int new_i = it.Index();
2786 if (new_i == old_i) { continue; }
2787
2788 old_dofs.SetSize(num_edge_dofs);
2789 new_dofs.SetSize(num_edge_dofs);
2790 for (int j = 0; j < num_edge_dofs; j++)
2791 {
2792 old_dofs[j] = offset + old_i * num_edge_dofs + j;
2793 new_dofs[j] = offset + new_i * num_edge_dofs + j;
2794 }
2795 fes->DofsToVDofs(old_dofs);
2796 fes->DofsToVDofs(new_dofs);
2797 for (int j = 0; j < old_dofs.Size(); j++)
2798 {
2799 (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2800 }
2801 }
2802 }
2803 offset += NumOfEdges * num_edge_dofs;
2804 }
2805
2806 // face dofs:
2807 // both enumeration and orientation of the faces may be different
2808 if (fes->GetNFDofs() > 0)
2809 {
2810 // generate the old face-vertex table using the unmodified 'faces'
2811 Table old_face_vertex;
2812 old_face_vertex.MakeI(NumOfFaces);
2813 for (int i = 0; i < NumOfFaces; i++)
2814 {
2815 old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices());
2816 }
2817 old_face_vertex.MakeJ();
2818 for (int i = 0; i < NumOfFaces; i++)
2819 old_face_vertex.AddConnections(i, faces[i]->GetVertices(),
2820 faces[i]->GetNVertices());
2821 old_face_vertex.ShiftUpI();
2822
2823 // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info'
2824 STable3D *faces_tbl = GetElementToFaceTable(1);
2825 GenerateFaces();
2826
2827 // compute the new face dof offsets
2828 Array<int> new_fdofs(NumOfFaces+1);
2829 new_fdofs[0] = 0;
2830 for (int i = 0; i < NumOfFaces; i++) // i = old face index
2831 {
2832 const int *old_v = old_face_vertex.GetRow(i);
2833 int new_i; // new face index
2834 switch (old_face_vertex.RowSize(i))
2835 {
2836 case 3:
2837 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2838 break;
2839 case 4:
2840 default:
2841 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2842 break;
2843 }
2844 fes->GetFaceInteriorDofs(i, old_dofs);
2845 new_fdofs[new_i+1] = old_dofs.Size();
2846 }
2847 new_fdofs.PartialSum();
2848
2849 // loop over the old face numbers
2850 for (int i = 0; i < NumOfFaces; i++)
2851 {
2852 const int *old_v = old_face_vertex.GetRow(i), *new_v;
2853 const int *dof_ord;
2854 int new_i, new_or;
2855 switch (old_face_vertex.RowSize(i))
2856 {
2857 case 3:
2858 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2859 new_v = faces[new_i]->GetVertices();
2860 new_or = GetTriOrientation(old_v, new_v);
2861 dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, new_or);
2862 break;
2863 case 4:
2864 default:
2865 new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2866 new_v = faces[new_i]->GetVertices();
2867 new_or = GetQuadOrientation(old_v, new_v);
2868 dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, new_or);
2869 break;
2870 }
2871
2872 fes->GetFaceInteriorDofs(i, old_dofs);
2873 new_dofs.SetSize(old_dofs.Size());
2874 for (int j = 0; j < old_dofs.Size(); j++)
2875 {
2876 // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2877 const int old_j = dof_ord[j];
2878 new_dofs[old_j] = offset + new_fdofs[new_i] + j;
2879 }
2880 fes->DofsToVDofs(old_dofs);
2881 fes->DofsToVDofs(new_dofs);
2882 for (int j = 0; j < old_dofs.Size(); j++)
2883 {
2884 (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2885 }
2886 }
2887
2888 offset += fes->GetNFDofs();
2889 delete faces_tbl;
2890 }
2891
2892 // element dofs:
2893 // element orientation may be different
2894 if (old_elem_vert) // have elements with 2 or more dofs
2895 {
2896 // matters when the 'fec' is
2897 // (this code is executed only for triangles/tets)
2898 // - Pk on triangles, k >= 4
2899 // - Qk on quads, k >= 3
2900 // - Pk on tets, k >= 5
2901 // - Qk on hexes, k >= 3
2902 // - DG spaces
2903 // - ...
2904
2905 // loop over all elements
2906 for (int i = 0; i < GetNE(); i++)
2907 {
2908 const int *old_v = old_elem_vert->GetRow(i);
2909 const int *new_v = elements[i]->GetVertices();
2910 const int *dof_ord;
2911 int new_or;
2912 const Geometry::Type geom = elements[i]->GetGeometryType();
2913 switch (geom)
2914 {
2915 case Geometry::SEGMENT:
2916 new_or = (old_v[0] == new_v[0]) ? +1 : -1;
2917 break;
2918 case Geometry::TRIANGLE:
2919 new_or = GetTriOrientation(old_v, new_v);
2920 break;
2921 case Geometry::SQUARE:
2922 new_or = GetQuadOrientation(old_v, new_v);
2923 break;
2925 new_or = GetTetOrientation(old_v, new_v);
2926 break;
2927 default:
2928 new_or = 0;
2929 MFEM_ABORT(Geometry::Name[geom] << " elements (" << fec->Name()
2930 << " FE collection) are not supported yet!");
2931 break;
2932 }
2933 dof_ord = fec->DofOrderForOrientation(geom, new_or);
2934 MFEM_VERIFY(dof_ord != NULL,
2935 "FE collection '" << fec->Name()
2936 << "' does not define reordering for "
2937 << Geometry::Name[geom] << " elements!");
2938 fes->GetElementInteriorDofs(i, old_dofs);
2939 new_dofs.SetSize(old_dofs.Size());
2940 for (int j = 0; j < new_dofs.Size(); j++)
2941 {
2942 // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2943 const int old_j = dof_ord[j];
2944 new_dofs[old_j] = offset + j;
2945 }
2946 offset += new_dofs.Size();
2947 fes->DofsToVDofs(old_dofs);
2948 fes->DofsToVDofs(new_dofs);
2949 for (int j = 0; j < old_dofs.Size(); j++)
2950 {
2951 (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2952 }
2953 }
2954 }
2955
2956 // Update Tables, faces, etc
2957 if (Dim > 2)
2958 {
2959 if (fes->GetNFDofs() == 0)
2960 {
2961 // needed for FE spaces that have face dofs, even if
2962 // the 'Nodes' do not have face dofs.
2964 GenerateFaces();
2965 }
2967 }
2968 if (el_to_edge)
2969 {
2970 // update 'el_to_edge', 'be_to_face' (2D), 'bel_to_edge' (3D)
2972 if (Dim == 2)
2973 {
2974 // update 'faces' and 'faces_info'
2975 GenerateFaces();
2977 }
2978 }
2979 // To force FE space update, we need to increase 'sequence':
2980 sequence++;
2983 fes->Update(false); // want_transform = false
2984 Nodes->Update(); // just needed to update Nodes->sequence
2985}
2986
2987void Mesh::SetPatchAttribute(int i, int attr)
2988{
2989 MFEM_ASSERT(NURBSext, "SetPatchAttribute is only for NURBS meshes");
2990 NURBSext->SetPatchAttribute(i, attr);
2991 const Array<int>& elems = NURBSext->GetPatchElements(i);
2992 for (auto e : elems)
2993 {
2994 SetAttribute(e, attr);
2995 }
2996}
2997
2999{
3000 MFEM_ASSERT(NURBSext, "GetPatchAttribute is only for NURBS meshes");
3001 return NURBSext->GetPatchAttribute(i);
3002}
3003
3004void Mesh::SetPatchBdrAttribute(int i, int attr)
3005{
3006 MFEM_ASSERT(NURBSext, "SetPatchBdrAttribute is only for NURBS meshes");
3008
3009 const Array<int>& bdryelems = NURBSext->GetPatchBdrElements(i);
3010 for (auto be : bdryelems)
3011 {
3012 SetBdrAttribute(be, attr);
3013 }
3014}
3015
3017{
3018 MFEM_ASSERT(NURBSext, "GetBdrPatchBdrAttribute is only for NURBS meshes");
3019 return NURBSext->GetPatchBdrAttribute(i);
3020}
3021
3022void Mesh::FinalizeTetMesh(int generate_edges, int refine, bool fix_orientation)
3023{
3024 FinalizeCheck();
3025 CheckElementOrientation(fix_orientation);
3026
3027 if (!HasBoundaryElements())
3028 {
3030 GenerateFaces();
3032 }
3033
3034 if (refine)
3035 {
3036 DSTable v_to_v(NumOfVertices);
3037 GetVertexToVertexTable(v_to_v);
3039 }
3040
3042 GenerateFaces();
3043
3045
3046 if (generate_edges == 1)
3047 {
3048 el_to_edge = new Table;
3050 }
3051 else
3052 {
3053 el_to_edge = NULL; // Not really necessary -- InitTables was called
3054 bel_to_edge = NULL;
3055 NumOfEdges = 0;
3056 }
3057
3058 SetAttributes();
3059
3060 SetMeshGen();
3061}
3062
3063void Mesh::FinalizeWedgeMesh(int generate_edges, int refine,
3064 bool fix_orientation)
3065{
3066 FinalizeCheck();
3067 CheckElementOrientation(fix_orientation);
3068
3069 if (!HasBoundaryElements())
3070 {
3072 GenerateFaces();
3074 }
3075
3077 GenerateFaces();
3078
3080
3081 if (generate_edges == 1)
3082 {
3083 el_to_edge = new Table;
3085 }
3086 else
3087 {
3088 el_to_edge = NULL; // Not really necessary -- InitTables was called
3089 bel_to_edge = NULL;
3090 NumOfEdges = 0;
3091 }
3092
3093 SetAttributes();
3094
3095 SetMeshGen();
3096}
3097
3098void Mesh::FinalizeHexMesh(int generate_edges, int refine, bool fix_orientation)
3099{
3100 FinalizeCheck();
3101 CheckElementOrientation(fix_orientation);
3102
3104 GenerateFaces();
3105
3106 if (!HasBoundaryElements())
3107 {
3109 }
3110
3112
3113 if (generate_edges)
3114 {
3115 el_to_edge = new Table;
3117 }
3118 else
3119 {
3120 NumOfEdges = 0;
3121 }
3122
3123 SetAttributes();
3124
3125 SetMeshGen();
3126}
3127
3128void Mesh::FinalizeMesh(int refine, bool fix_orientation)
3129{
3131
3132 Finalize(refine, fix_orientation);
3133}
3134
3135void Mesh::FinalizeTopology(bool generate_bdr)
3136{
3137 // Requirements: the following should be defined:
3138 // 1) Dim
3139 // 2) NumOfElements, elements
3140 // 3) NumOfBdrElements, boundary
3141 // 4) NumOfVertices
3142 // Optional:
3143 // 2) ncmesh may be defined
3144 // 3) el_to_edge may be allocated (it will be re-computed)
3145
3146 FinalizeCheck();
3147 bool generate_edges = true;
3148
3149 if (spaceDim == 0) { spaceDim = Dim; }
3150 if (ncmesh) { ncmesh->spaceDim = spaceDim; }
3151
3152 // if the user defined any hanging nodes (see AddVertexParent),
3153 // we're initializing a non-conforming mesh
3154 if (tmp_vertex_parents.Size())
3155 {
3156 MFEM_VERIFY(ncmesh == NULL, "");
3157 ncmesh = new NCMesh(this);
3158
3159 // we need to recreate the Mesh because NCMesh reorders the vertices
3160 // (see NCMesh::UpdateVertices())
3162 ncmesh->OnMeshUpdated(this);
3164
3165 SetAttributes();
3166
3167 tmp_vertex_parents.DeleteAll();
3168 return;
3169 }
3170
3171 // set the mesh type: 'meshgen', ...
3172 SetMeshGen();
3173
3174 // generate the faces
3175 if (Dim > 2)
3176 {
3178 GenerateFaces();
3179 if (!HasBoundaryElements() && generate_bdr)
3180 {
3182 GetElementToFaceTable(); // update be_to_face
3183 }
3184 }
3185 else
3186 {
3187 NumOfFaces = 0;
3188 }
3189
3190 // generate edges if requested
3191 if (Dim > 1 && generate_edges)
3192 {
3193 // el_to_edge may already be allocated (P2 VTK meshes)
3194 if (!el_to_edge) { el_to_edge = new Table; }
3196 if (Dim == 2)
3197 {
3198 GenerateFaces(); // 'Faces' in 2D refers to the edges
3199 if (!HasBoundaryElements() && generate_bdr)
3200 {
3202 }
3203 }
3204 }
3205 else
3206 {
3207 NumOfEdges = 0;
3208 }
3209
3210 if (Dim == 1)
3211 {
3212 GenerateFaces();
3213 if (!HasBoundaryElements() && generate_bdr)
3214 {
3215 // be_to_face will be set inside GenerateBoundaryElements
3217 }
3218 else
3219 {
3221 for (int i = 0; i < NumOfBdrElements; ++i)
3222 {
3223 be_to_face[i] = boundary[i]->GetVertices()[0];
3224 }
3225 }
3226 }
3227
3228 if (ncmesh)
3229 {
3230 // tell NCMesh the numbering of edges/faces
3231 ncmesh->OnMeshUpdated(this);
3232
3233 // update faces_info with NC relations
3235 }
3236
3237 // generate the arrays 'attributes' and 'bdr_attributes'
3238 SetAttributes();
3239}
3240
3241void Mesh::Finalize(bool refine, bool fix_orientation)
3242{
3243 if (NURBSext || ncmesh)
3244 {
3245 MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
3246 MFEM_ASSERT(CheckBdrElementOrientation() == 0, "");
3247 return;
3248 }
3249
3250 // Requirements:
3251 // 1) FinalizeTopology() or equivalent was called
3252 // 2) if (Nodes == NULL), vertices must be defined
3253 // 3) if (Nodes != NULL), Nodes must be defined
3254
3255 const bool check_orientation = true; // for regular elements, not boundary
3256 const bool curved = (Nodes != NULL);
3257 const bool may_change_topology =
3258 ( refine && (Dim > 1 && (meshgen & 1)) ) ||
3259 ( check_orientation && fix_orientation &&
3260 (Dim == 2 || (Dim == 3 && (meshgen & 1))) );
3261
3262 DSTable *old_v_to_v = NULL;
3263 Table *old_elem_vert = NULL;
3264
3265 if (curved && may_change_topology)
3266 {
3267 PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
3268 }
3269
3270 if (check_orientation)
3271 {
3272 // check and optionally fix element orientation
3273 CheckElementOrientation(fix_orientation);
3274 }
3275 if (refine)
3276 {
3277 MarkForRefinement(); // may change topology!
3278 }
3279
3280 if (may_change_topology)
3281 {
3282 if (curved)
3283 {
3284 DoNodeReorder(old_v_to_v, old_elem_vert); // updates the mesh topology
3285 delete old_elem_vert;
3286 delete old_v_to_v;
3287 }
3288 else
3289 {
3290 FinalizeTopology(); // Re-computes some data unnecessarily.
3291 }
3292
3293 // TODO: maybe introduce Mesh::NODE_REORDER operation and FESpace::
3294 // NodeReorderMatrix and do Nodes->Update() instead of DoNodeReorder?
3295 }
3296
3297 // check and fix boundary element orientation
3299
3300#ifdef MFEM_DEBUG
3301 // For non-orientable surfaces/manifolds, the check below will fail, so we
3302 // only perform it when Dim == spaceDim.
3303 if (Dim >= 2 && Dim == spaceDim)
3304 {
3305 const int num_faces = GetNumFaces();
3306 for (int i = 0; i < num_faces; i++)
3307 {
3308 MFEM_VERIFY(faces_info[i].Elem2No < 0 ||
3309 faces_info[i].Elem2Inf%2 != 0, "Invalid mesh topology."
3310 " Interior face with incompatible orientations.");
3311 }
3312 }
3313#endif
3314}
3315
3316void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
3317 real_t sx, real_t sy, real_t sz, bool sfc_ordering)
3318{
3319 int x, y, z;
3320
3321 int NVert, NElem, NBdrElem;
3322
3323 NVert = (nx+1) * (ny+1) * (nz+1);
3324 NElem = nx * ny * nz;
3325 NBdrElem = 2*(nx*ny+nx*nz+ny*nz);
3326 if (type == Element::TETRAHEDRON)
3327 {
3328 NElem *= 6;
3329 NBdrElem *= 2;
3330 }
3331 else if (type == Element::WEDGE)
3332 {
3333 NElem *= 2;
3334 NBdrElem += 2*nx*ny;
3335 }
3336 else if (type == Element::PYRAMID)
3337 {
3338 NElem *= 6;
3339 NVert += nx * ny * nz;
3340 }
3341
3342 InitMesh(3, 3, NVert, NElem, NBdrElem);
3343
3344 real_t coord[3];
3345 int ind[9];
3346
3347 // Sets vertices and the corresponding coordinates
3348 for (z = 0; z <= nz; z++)
3349 {
3350 coord[2] = ((real_t) z / nz) * sz;
3351 for (y = 0; y <= ny; y++)
3352 {
3353 coord[1] = ((real_t) y / ny) * sy;
3354 for (x = 0; x <= nx; x++)
3355 {
3356 coord[0] = ((real_t) x / nx) * sx;
3357 AddVertex(coord);
3358 }
3359 }
3360 }
3361 if (type == Element::PYRAMID)
3362 {
3363 for (z = 0; z < nz; z++)
3364 {
3365 coord[2] = (((real_t) z + 0.5) / nz) * sz;
3366 for (y = 0; y < ny; y++)
3367 {
3368 coord[1] = (((real_t) y + 0.5) / ny) * sy;
3369 for (x = 0; x < nx; x++)
3370 {
3371 coord[0] = (((real_t) x + 0.5) / nx) * sx;
3372 AddVertex(coord);
3373 }
3374 }
3375 }
3376 }
3377
3378#define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
3379#define VTXP(XC, YC, ZC) ((nx+1)*(ny+1)*(nz+1)+(XC)+((YC)+(ZC)*ny)*nx)
3380
3381 // Sets elements and the corresponding indices of vertices
3382 if (sfc_ordering && type == Element::HEXAHEDRON)
3383 {
3384 Array<int> sfc;
3385 NCMesh::GridSfcOrdering3D(nx, ny, nz, sfc);
3386 MFEM_VERIFY(sfc.Size() == 3*nx*ny*nz, "");
3387
3388 for (int k = 0; k < nx*ny*nz; k++)
3389 {
3390 x = sfc[3*k + 0];
3391 y = sfc[3*k + 1];
3392 z = sfc[3*k + 2];
3393
3394 // *INDENT-OFF*
3395 ind[0] = VTX(x , y , z );
3396 ind[1] = VTX(x+1, y , z );
3397 ind[2] = VTX(x+1, y+1, z );
3398 ind[3] = VTX(x , y+1, z );
3399 ind[4] = VTX(x , y , z+1);
3400 ind[5] = VTX(x+1, y , z+1);
3401 ind[6] = VTX(x+1, y+1, z+1);
3402 ind[7] = VTX(x , y+1, z+1);
3403 // *INDENT-ON*
3404
3405 AddHex(ind, 1);
3406 }
3407 }
3408 else
3409 {
3410 for (z = 0; z < nz; z++)
3411 {
3412 for (y = 0; y < ny; y++)
3413 {
3414 for (x = 0; x < nx; x++)
3415 {
3416 // *INDENT-OFF*
3417 ind[0] = VTX(x , y , z );
3418 ind[1] = VTX(x+1, y , z );
3419 ind[2] = VTX(x+1, y+1, z );
3420 ind[3] = VTX(x , y+1, z );
3421 ind[4] = VTX(x , y , z+1);
3422 ind[5] = VTX(x+1, y , z+1);
3423 ind[6] = VTX(x+1, y+1, z+1);
3424 ind[7] = VTX( x, y+1, z+1);
3425 // *INDENT-ON*
3426 if (type == Element::TETRAHEDRON)
3427 {
3428 AddHexAsTets(ind, 1);
3429 }
3430 else if (type == Element::WEDGE)
3431 {
3432 AddHexAsWedges(ind, 1);
3433 }
3434 else if (type == Element::PYRAMID)
3435 {
3436 ind[8] = VTXP(x, y, z);
3437 AddHexAsPyramids(ind, 1);
3438 }
3439 else
3440 {
3441 AddHex(ind, 1);
3442 }
3443 }
3444 }
3445 }
3446 }
3447
3448 // Sets boundary elements and the corresponding indices of vertices
3449 // bottom, bdr. attribute 1
3450 for (y = 0; y < ny; y++)
3451 {
3452 for (x = 0; x < nx; x++)
3453 {
3454 // *INDENT-OFF*
3455 ind[0] = VTX(x , y , 0);
3456 ind[1] = VTX(x , y+1, 0);
3457 ind[2] = VTX(x+1, y+1, 0);
3458 ind[3] = VTX(x+1, y , 0);
3459 // *INDENT-ON*
3460 if (type == Element::TETRAHEDRON)
3461 {
3462 AddBdrQuadAsTriangles(ind, 1);
3463 }
3464 else if (type == Element::WEDGE)
3465 {
3466 AddBdrQuadAsTriangles(ind, 1);
3467 }
3468 else
3469 {
3470 AddBdrQuad(ind, 1);
3471 }
3472 }
3473 }
3474 // top, bdr. attribute 6
3475 for (y = 0; y < ny; y++)
3476 {
3477 for (x = 0; x < nx; x++)
3478 {
3479 // *INDENT-OFF*
3480 ind[0] = VTX(x , y , nz);
3481 ind[1] = VTX(x+1, y , nz);
3482 ind[2] = VTX(x+1, y+1, nz);
3483 ind[3] = VTX(x , y+1, nz);
3484 // *INDENT-ON*
3485 if (type == Element::TETRAHEDRON)
3486 {
3487 AddBdrQuadAsTriangles(ind, 6);
3488 }
3489 else if (type == Element::WEDGE)
3490 {
3491 AddBdrQuadAsTriangles(ind, 6);
3492 }
3493 else
3494 {
3495 AddBdrQuad(ind, 6);
3496 }
3497 }
3498 }
3499 // left, bdr. attribute 5
3500 for (z = 0; z < nz; z++)
3501 {
3502 for (y = 0; y < ny; y++)
3503 {
3504 // *INDENT-OFF*
3505 ind[0] = VTX(0 , y , z );
3506 ind[1] = VTX(0 , y , z+1);
3507 ind[2] = VTX(0 , y+1, z+1);
3508 ind[3] = VTX(0 , y+1, z );
3509 // *INDENT-ON*
3510 if (type == Element::TETRAHEDRON)
3511 {
3512 AddBdrQuadAsTriangles(ind, 5);
3513 }
3514 else
3515 {
3516 AddBdrQuad(ind, 5);
3517 }
3518 }
3519 }
3520 // right, bdr. attribute 3
3521 for (z = 0; z < nz; z++)
3522 {
3523 for (y = 0; y < ny; y++)
3524 {
3525 // *INDENT-OFF*
3526 ind[0] = VTX(nx, y , z );
3527 ind[1] = VTX(nx, y+1, z );
3528 ind[2] = VTX(nx, y+1, z+1);
3529 ind[3] = VTX(nx, y , z+1);
3530 // *INDENT-ON*
3531 if (type == Element::TETRAHEDRON)
3532 {
3533 AddBdrQuadAsTriangles(ind, 3);
3534 }
3535 else
3536 {
3537 AddBdrQuad(ind, 3);
3538 }
3539 }
3540 }
3541 // front, bdr. attribute 2
3542 for (x = 0; x < nx; x++)
3543 {
3544 for (z = 0; z < nz; z++)
3545 {
3546 // *INDENT-OFF*
3547 ind[0] = VTX(x , 0, z );
3548 ind[1] = VTX(x+1, 0, z );
3549 ind[2] = VTX(x+1, 0, z+1);
3550 ind[3] = VTX(x , 0, z+1);
3551 // *INDENT-ON*
3552 if (type == Element::TETRAHEDRON)
3553 {
3554 AddBdrQuadAsTriangles(ind, 2);
3555 }
3556 else
3557 {
3558 AddBdrQuad(ind, 2);
3559 }
3560 }
3561 }
3562 // back, bdr. attribute 4
3563 for (x = 0; x < nx; x++)
3564 {
3565 for (z = 0; z < nz; z++)
3566 {
3567 // *INDENT-OFF*
3568 ind[0] = VTX(x , ny, z );
3569 ind[1] = VTX(x , ny, z+1);
3570 ind[2] = VTX(x+1, ny, z+1);
3571 ind[3] = VTX(x+1, ny, z );
3572 // *INDENT-ON*
3573 if (type == Element::TETRAHEDRON)
3574 {
3575 AddBdrQuadAsTriangles(ind, 4);
3576 }
3577 else
3578 {
3579 AddBdrQuad(ind, 4);
3580 }
3581 }
3582 }
3583
3584#undef VTX
3585
3586#if 0
3587 ofstream test_stream("debug.mesh");
3588 Print(test_stream);
3589 test_stream.close();
3590#endif
3591
3593
3594 // Finalize(...) can be called after this method, if needed
3595}
3596
3597
3598void Mesh::Make2D4TrisFromQuad(int nx, int ny, real_t sx, real_t sy)
3599{
3600 SetEmpty();
3601
3602 Dim = 2;
3603 spaceDim = 2;
3604
3605 NumOfVertices = (nx+1) * (ny+1);
3606 NumOfElements = nx * ny * 4;
3607 NumOfBdrElements = (2 * nx + 2 * ny);
3608 vertices.SetSize(NumOfVertices);
3609 elements.SetSize(NumOfElements);
3610 boundary.SetSize(NumOfBdrElements);
3611 NumOfElements = 0;
3612
3613 int ind[4];
3614
3615 // Sets vertices and the corresponding coordinates
3616 int k = 0;
3617 for (real_t j = 0; j < ny+1; j++)
3618 {
3619 real_t cy = (j / ny) * sy;
3620 for (real_t i = 0; i < nx+1; i++)
3621 {
3622 real_t cx = (i / nx) * sx;
3623 vertices[k](0) = cx;
3624 vertices[k](1) = cy;
3625 k++;
3626 }
3627 }
3628
3629 for (int y = 0; y < ny; y++)
3630 {
3631 for (int x = 0; x < nx; x++)
3632 {
3633 ind[0] = x + y*(nx+1);
3634 ind[1] = x + 1 +y*(nx+1);
3635 ind[2] = x + 1 + (y+1)*(nx+1);
3636 ind[3] = x + (y+1)*(nx+1);
3638 }
3639 }
3640
3641 int m = (nx+1)*ny;
3642 for (int i = 0; i < nx; i++)
3643 {
3644 boundary[i] = new Segment(i, i+1, 1);
3645 boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3646 }
3647 m = nx+1;
3648 for (int j = 0; j < ny; j++)
3649 {
3650 boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3651 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3652 }
3653
3654 SetMeshGen();
3656
3657 el_to_edge = new Table;
3659 GenerateFaces();
3661
3662 NumOfFaces = 0;
3663
3664 attributes.Append(1);
3667
3669}
3670
3671void Mesh::Make2D5QuadsFromQuad(int nx, int ny,
3672 real_t sx, real_t sy)
3673{
3674 SetEmpty();
3675
3676 Dim = 2;
3677 spaceDim = 2;
3678
3679 NumOfElements = nx * ny * 5;
3680 NumOfVertices = (nx+1) * (ny+1); //it will be enlarged later on
3681 NumOfBdrElements = (2 * nx + 2 * ny);
3682 vertices.SetSize(NumOfVertices);
3683 elements.SetSize(NumOfElements);
3684 boundary.SetSize(NumOfBdrElements);
3685 NumOfElements = 0;
3686
3687 int ind[4];
3688
3689 // Sets vertices and the corresponding coordinates
3690 int k = 0;
3691 for (real_t j = 0; j < ny+1; j++)
3692 {
3693 real_t cy = (j / ny) * sy;
3694 for (real_t i = 0; i < nx+1; i++)
3695 {
3696 real_t cx = (i / nx) * sx;
3697 vertices[k](0) = cx;
3698 vertices[k](1) = cy;
3699 k++;
3700 }
3701 }
3702
3703 for (int y = 0; y < ny; y++)
3704 {
3705 for (int x = 0; x < nx; x++)
3706 {
3707 ind[0] = x + y*(nx+1);
3708 ind[1] = x + 1 +y*(nx+1);
3709 ind[2] = x + 1 + (y+1)*(nx+1);
3710 ind[3] = x + (y+1)*(nx+1);
3712 }
3713 }
3714
3715 int m = (nx+1)*ny;
3716 for (int i = 0; i < nx; i++)
3717 {
3718 boundary[i] = new Segment(i, i+1, 1);
3719 boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3720 }
3721 m = nx+1;
3722 for (int j = 0; j < ny; j++)
3723 {
3724 boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3725 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3726 }
3727
3728 SetMeshGen();
3730
3731 el_to_edge = new Table;
3733 GenerateFaces();
3735
3736 NumOfFaces = 0;
3737
3738 attributes.Append(1);
3741
3743}
3744
3745void Mesh::Make3D24TetsFromHex(int nx, int ny, int nz,
3746 real_t sx, real_t sy, real_t sz)
3747{
3748 const int NVert = (nx+1) * (ny+1) * (nz+1);
3749 const int NElem = nx * ny * nz * 24;
3750 const int NBdrElem = 2*(nx*ny+nx*nz+ny*nz)*4;
3751
3752 InitMesh(3, 3, NVert, NElem, NBdrElem);
3753
3754 real_t coord[3];
3755
3756 // Sets vertices and the corresponding coordinates
3757 for (real_t z = 0; z <= nz; z++)
3758 {
3759 coord[2] = ( z / nz) * sz;
3760 for (real_t y = 0; y <= ny; y++)
3761 {
3762 coord[1] = (y / ny) * sy;
3763 for (real_t x = 0; x <= nx; x++)
3764 {
3765 coord[0] = (x / nx) * sx;
3766 AddVertex(coord);
3767 }
3768 }
3769 }
3770
3771 std::map<std::array<int, 4>, int> hex_face_verts;
3772 auto VertexIndex = [nx, ny](int xc, int yc, int zc)
3773 {
3774 return xc + (yc + zc*(ny+1))*(nx+1);
3775 };
3776
3777 int ind[9];
3778 for (int z = 0; z < nz; z++)
3779 {
3780 for (int y = 0; y < ny; y++)
3781 {
3782 for (int x = 0; x < nx; x++)
3783 {
3784 // *INDENT-OFF*
3785 ind[0] = VertexIndex(x , y , z );
3786 ind[1] = VertexIndex(x+1, y , z );
3787 ind[2] = VertexIndex(x+1, y+1, z );
3788 ind[3] = VertexIndex(x , y+1, z );
3789 ind[4] = VertexIndex(x , y , z+1);
3790 ind[5] = VertexIndex(x+1, y , z+1);
3791 ind[6] = VertexIndex(x+1, y+1, z+1);
3792 ind[7] = VertexIndex( x, y+1, z+1);
3793 AddHexAs24TetsWithPoints(ind, hex_face_verts, 1);
3794 }
3795 }
3796 }
3797
3798 hex_face_verts.clear();
3800
3801 // Done adding Tets
3802 // Now figure out elements that are on the boundary
3803 GetElementToFaceTable(false);
3804 GenerateFaces();
3805
3806 // Map to count number of tets sharing a face
3807 std::map<std::array<int, 3>, int> tet_face_count;
3808 // Map from tet face defined by three vertices to the local face number
3809 std::map<std::array<int, 3>, int> face_count_map;
3810
3811 auto get3array = [](Array<int> v)
3812 {
3813 v.Sort();
3814 return std::array<int, 3>{v[0], v[1], v[2]};
3815 };
3816
3817 Array<int> el_faces;
3818 Array<int> ori;
3819 Array<int> vertidxs;
3820 for (int i = 0; i < el_to_face->Size(); i++)
3821 {
3822 el_to_face->GetRow(i, el_faces);
3823 for (int j = 0; j < el_faces.Size(); j++)
3824 {
3825 GetFaceVertices(el_faces[j], vertidxs);
3826 auto t = get3array(vertidxs);
3827 auto it = tet_face_count.find(t);
3828 if (it == tet_face_count.end()) //edge does not already exist
3829 {
3830 tet_face_count.insert({t, 1});
3831 face_count_map.insert({t, el_faces[j]});
3832 }
3833 else
3834 {
3835 it->second++; // increase edge count value by 1.
3836 }
3837 }
3838 }
3839
3840 for (const auto &edge : tet_face_count)
3841 {
3842 if (edge.second == 1) //if this only appears once, it is a boundary edge
3843 {
3844 int facenum = (face_count_map.find(edge.first))->second;
3845 GetFaceVertices(facenum, vertidxs);
3846 AddBdrTriangle(vertidxs, 1);
3847 }
3848 }
3849
3850#if 0
3851 ofstream test_stream("debug.mesh");
3852 Print(test_stream);
3853 test_stream.close();
3854#endif
3855
3857 // Finalize(...) can be called after this method, if needed
3858}
3859
3860void Mesh::Make2D(int nx, int ny, Element::Type type,
3861 real_t sx, real_t sy,
3862 bool generate_edges, bool sfc_ordering)
3863{
3864 int i, j, k;
3865
3866 SetEmpty();
3867
3868 Dim = spaceDim = 2;
3869
3870 // Creates quadrilateral mesh
3871 if (type == Element::QUADRILATERAL)
3872 {
3873 NumOfVertices = (nx+1) * (ny+1);
3874 NumOfElements = nx * ny;
3875 NumOfBdrElements = 2 * nx + 2 * ny;
3876
3877 vertices.SetSize(NumOfVertices);
3878 elements.SetSize(NumOfElements);
3879 boundary.SetSize(NumOfBdrElements);
3880
3881 real_t cx, cy;
3882 int ind[4];
3883
3884 // Sets vertices and the corresponding coordinates
3885 k = 0;
3886 for (j = 0; j < ny+1; j++)
3887 {
3888 cy = ((real_t) j / ny) * sy;
3889 for (i = 0; i < nx+1; i++)
3890 {
3891 cx = ((real_t) i / nx) * sx;
3892 vertices[k](0) = cx;
3893 vertices[k](1) = cy;
3894 k++;
3895 }
3896 }
3897
3898 // Sets elements and the corresponding indices of vertices
3899 if (sfc_ordering)
3900 {
3901 Array<int> sfc;
3902 NCMesh::GridSfcOrdering2D(nx, ny, sfc);
3903 MFEM_VERIFY(sfc.Size() == 2*nx*ny, "");
3904
3905 for (k = 0; k < nx*ny; k++)
3906 {
3907 i = sfc[2*k + 0];
3908 j = sfc[2*k + 1];
3909 ind[0] = i + j*(nx+1);
3910 ind[1] = i + 1 +j*(nx+1);
3911 ind[2] = i + 1 + (j+1)*(nx+1);
3912 ind[3] = i + (j+1)*(nx+1);
3913 elements[k] = new Quadrilateral(ind);
3914 }
3915 }
3916 else
3917 {
3918 k = 0;
3919 for (j = 0; j < ny; j++)
3920 {
3921 for (i = 0; i < nx; i++)
3922 {
3923 ind[0] = i + j*(nx+1);
3924 ind[1] = i + 1 +j*(nx+1);
3925 ind[2] = i + 1 + (j+1)*(nx+1);
3926 ind[3] = i + (j+1)*(nx+1);
3927 elements[k] = new Quadrilateral(ind);
3928 k++;
3929 }
3930 }
3931 }
3932
3933 // Sets boundary elements and the corresponding indices of vertices
3934 int m = (nx+1)*ny;
3935 for (i = 0; i < nx; i++)
3936 {
3937 boundary[i] = new Segment(i, i+1, 1);
3938 boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3939 }
3940 m = nx+1;
3941 for (j = 0; j < ny; j++)
3942 {
3943 boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3944 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3945 }
3946 }
3947 // Creates triangular mesh
3948 else if (type == Element::TRIANGLE)
3949 {
3950 NumOfVertices = (nx+1) * (ny+1);
3951 NumOfElements = 2 * nx * ny;
3952 NumOfBdrElements = 2 * nx + 2 * ny;
3953
3954 vertices.SetSize(NumOfVertices);
3955 elements.SetSize(NumOfElements);
3956 boundary.SetSize(NumOfBdrElements);
3957
3958 real_t cx, cy;
3959 int ind[3];
3960
3961 // Sets vertices and the corresponding coordinates
3962 k = 0;
3963 for (j = 0; j < ny+1; j++)
3964 {
3965 cy = ((real_t) j / ny) * sy;
3966 for (i = 0; i < nx+1; i++)
3967 {
3968 cx = ((real_t) i / nx) * sx;
3969 vertices[k](0) = cx;
3970 vertices[k](1) = cy;
3971 k++;
3972 }
3973 }
3974
3975 // Sets the elements and the corresponding indices of vertices
3976 k = 0;
3977 for (j = 0; j < ny; j++)
3978 {
3979 for (i = 0; i < nx; i++)
3980 {
3981 ind[0] = i + j*(nx+1);
3982 ind[1] = i + 1 + (j+1)*(nx+1);
3983 ind[2] = i + (j+1)*(nx+1);
3984 elements[k] = new Triangle(ind);
3985 k++;
3986 ind[1] = i + 1 + j*(nx+1);
3987 ind[2] = i + 1 + (j+1)*(nx+1);
3988 elements[k] = new Triangle(ind);
3989 k++;
3990 }
3991 }
3992
3993 // Sets boundary elements and the corresponding indices of vertices
3994 int m = (nx+1)*ny;
3995 for (i = 0; i < nx; i++)
3996 {
3997 boundary[i] = new Segment(i, i+1, 1);
3998 boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3999 }
4000 m = nx+1;
4001 for (j = 0; j < ny; j++)
4002 {
4003 boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
4004 boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
4005 }
4006
4007 // MarkTriMeshForRefinement(); // done in Finalize(...)
4008 }
4009 else
4010 {
4011 MFEM_ABORT("Unsupported element type.");
4012 }
4013
4014 SetMeshGen();
4016
4017 if (generate_edges == 1)
4018 {
4019 el_to_edge = new Table;
4021 GenerateFaces();
4023 }
4024 else
4025 {
4026 NumOfEdges = 0;
4027 }
4028
4029 NumOfFaces = 0;
4030
4031 attributes.Append(1);
4034
4035 // Finalize(...) can be called after this method, if needed
4036}
4037
4038void Mesh::Make1D(int n, real_t sx)
4039{
4040 int j, ind[1];
4041
4042 SetEmpty();
4043
4044 Dim = 1;
4045 spaceDim = 1;
4046
4047 NumOfVertices = n + 1;
4048 NumOfElements = n;
4049 NumOfBdrElements = 2;
4050 vertices.SetSize(NumOfVertices);
4051 elements.SetSize(NumOfElements);
4052 boundary.SetSize(NumOfBdrElements);
4053
4054 // Sets vertices and the corresponding coordinates
4055 for (j = 0; j < n+1; j++)
4056 {
4057 vertices[j](0) = ((real_t) j / n) * sx;
4058 }
4059
4060 // Sets elements and the corresponding indices of vertices
4061 for (j = 0; j < n; j++)
4062 {
4063 elements[j] = new Segment(j, j+1, 1);
4064 }
4065
4066 // Sets the boundary elements
4067 ind[0] = 0;
4068 boundary[0] = new Point(ind, 1);
4069 ind[0] = n;
4070 boundary[1] = new Point(ind, 2);
4071
4072 NumOfEdges = 0;
4073 NumOfFaces = 0;
4074
4075 SetMeshGen();
4076 GenerateFaces();
4077
4078 // Set be_to_face
4080 be_to_face[0] = 0;
4081 be_to_face[1] = n;
4082
4083 attributes.Append(1);
4085}
4086
4087Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
4088 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4089{
4090 Dim = mesh.Dim;
4091 spaceDim = mesh.spaceDim;
4092
4096 NumOfEdges = mesh.NumOfEdges;
4097 NumOfFaces = mesh.NumOfFaces;
4100
4101 meshgen = mesh.meshgen;
4102 mesh_geoms = mesh.mesh_geoms;
4103
4104 // Create the new Mesh instance without a record of its refinement history
4105 sequence = 0;
4106 nodes_sequence = 0;
4108
4109 // Duplicate the elements
4110 elements.SetSize(NumOfElements);
4111 for (int i = 0; i < NumOfElements; i++)
4112 {
4113 elements[i] = mesh.elements[i]->Duplicate(this);
4114 }
4115
4116 // Copy the vertices
4117 mesh.vertices.Copy(vertices);
4118
4119 // Duplicate the boundary
4120 boundary.SetSize(NumOfBdrElements);
4121 for (int i = 0; i < NumOfBdrElements; i++)
4122 {
4123 boundary[i] = mesh.boundary[i]->Duplicate(this);
4124 }
4125
4126 // Copy the element-to-face Table, el_to_face
4127 el_to_face = (mesh.el_to_face) ? new Table(*mesh.el_to_face) : NULL;
4128
4129 // Copy the boundary-to-face Array, be_to_face.
4131
4132 // Copy the element-to-edge Table, el_to_edge
4133 el_to_edge = (mesh.el_to_edge) ? new Table(*mesh.el_to_edge) : NULL;
4134
4135 // Copy the boundary-to-edge Table, bel_to_edge (3D)
4136 bel_to_edge = (mesh.bel_to_edge) ? new Table(*mesh.bel_to_edge) : NULL;
4137
4138 // Duplicate the faces and faces_info.
4139 faces.SetSize(mesh.faces.Size());
4140 for (int i = 0; i < faces.Size(); i++)
4141 {
4142 Element *face = mesh.faces[i]; // in 1D the faces are NULL
4143 faces[i] = (face) ? face->Duplicate(this) : NULL;
4144 }
4145 mesh.faces_info.Copy(faces_info);
4146 mesh.nc_faces_info.Copy(nc_faces_info);
4147
4148 // Do NOT copy the element-to-element Table, el_to_el
4149 el_to_el = NULL;
4150
4151 // Do NOT copy the face-to-edge Table, face_edge
4152 face_edge = NULL;
4153 face_to_elem = NULL;
4154
4155 // Copy the edge-to-vertex Table, edge_vertex
4156 edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
4157
4158 // Copy the attributes and bdr_attributes
4161
4162 // Copy attribute and bdr_attribute names
4165
4166 // Deep copy the NURBSExtension.
4167#ifdef MFEM_USE_MPI
4168 ParNURBSExtension *pNURBSext =
4169 dynamic_cast<ParNURBSExtension *>(mesh.NURBSext);
4170 if (pNURBSext)
4171 {
4172 NURBSext = new ParNURBSExtension(*pNURBSext);
4173 }
4174 else
4175#endif
4176 {
4177 NURBSext = mesh.NURBSext ? new NURBSExtension(*mesh.NURBSext) : NULL;
4178 }
4179
4180 // Deep copy the NCMesh.
4181#ifdef MFEM_USE_MPI
4182 if (dynamic_cast<const ParMesh*>(&mesh))
4183 {
4184 ncmesh = NULL; // skip; will be done in ParMesh copy ctor
4185 }
4186 else
4187#endif
4188 {
4189 ncmesh = mesh.ncmesh ? new NCMesh(*mesh.ncmesh) : NULL;
4190 }
4191
4192 // Duplicate the Nodes, including the FiniteElementCollection and the
4193 // FiniteElementSpace
4194 if (mesh.Nodes && copy_nodes)
4195 {
4196 FiniteElementSpace *fes = mesh.Nodes->FESpace();
4197 const FiniteElementCollection *fec = fes->FEColl();
4198 FiniteElementCollection *fec_copy =
4200 FiniteElementSpace *fes_copy =
4201 new FiniteElementSpace(*fes, this, fec_copy);
4202 Nodes = new GridFunction(fes_copy);
4203 Nodes->MakeOwner(fec_copy);
4204 *Nodes = *mesh.Nodes;
4205 own_nodes = 1;
4206 }
4207 else
4208 {
4209 Nodes = mesh.Nodes;
4210 own_nodes = 0;
4211 }
4212}
4213
4215{
4216 Swap(mesh, true);
4217}
4218
4220{
4221 Swap(mesh, true);
4222 return *this;
4223}
4224
4225Mesh Mesh::LoadFromFile(const std::string &filename, int generate_edges,
4226 int refine, bool fix_orientation)
4227{
4228 Mesh mesh;
4229 named_ifgzstream imesh(filename);
4230 if (!imesh) { MFEM_ABORT("Mesh file not found: " << filename << '\n'); }
4231 else { mesh.Load(imesh, generate_edges, refine, fix_orientation); }
4232 return mesh;
4233}
4234
4236{
4237 Mesh mesh;
4238 mesh.Make1D(n, sx);
4239 // mesh.Finalize(); not needed in this case
4240 return mesh;
4241}
4242
4244 int nx, int ny, Element::Type type, bool generate_edges,
4245 real_t sx, real_t sy, bool sfc_ordering)
4246{
4247 Mesh mesh;
4248 mesh.Make2D(nx, ny, type, sx, sy, generate_edges, sfc_ordering);
4249 mesh.Finalize(true); // refine = true
4250 return mesh;
4251}
4252
4254 int nx, int ny, int nz, Element::Type type,
4255 real_t sx, real_t sy, real_t sz, bool sfc_ordering)
4256{
4257 Mesh mesh;
4258 mesh.Make3D(nx, ny, nz, type, sx, sy, sz, sfc_ordering);
4259 mesh.Finalize(true); // refine = true
4260 return mesh;
4261}
4262
4264 real_t sx, real_t sy, real_t sz)
4265{
4266 Mesh mesh;
4267 mesh.Make3D24TetsFromHex(nx, ny, nz, sx, sy, sz);
4268 mesh.Finalize(false, false);
4269 return mesh;
4270}
4271
4273 real_t sx, real_t sy)
4274{
4275 Mesh mesh;
4276 mesh.Make2D4TrisFromQuad(nx, ny, sx, sy);
4277 mesh.Finalize(false, false);
4278 return mesh;
4279}
4280
4282 real_t sx, real_t sy)
4283{
4284 Mesh mesh;
4285 mesh.Make2D5QuadsFromQuad(nx, ny, sx, sy);
4286 mesh.Finalize(false, false);
4287 return mesh;
4288}
4289
4290Mesh Mesh::MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
4291{
4292 Mesh mesh;
4293 Array<int> ref_factors(orig_mesh.GetNE());
4294 ref_factors = ref_factor;
4295 mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
4296 return mesh;
4297}
4298
4299Mesh Mesh::MakeRefined(Mesh &orig_mesh, const Array<int> &ref_factors,
4300 int ref_type)
4301{
4302 Mesh mesh;
4303 mesh.MakeRefined_(orig_mesh, ref_factors, ref_type);
4304 return mesh;
4305}
4306
4307Mesh::Mesh(const std::string &filename, int generate_edges, int refine,
4308 bool fix_orientation)
4309 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4310{
4311 // Initialization as in the default constructor
4312 SetEmpty();
4313
4314 named_ifgzstream imesh(filename);
4315 if (!imesh)
4316 {
4317 // Abort with an error message.
4318 MFEM_ABORT("Mesh file not found: " << filename << '\n');
4319 }
4320 else
4321 {
4322 Load(imesh, generate_edges, refine, fix_orientation);
4323 }
4324}
4325
4326Mesh::Mesh(std::istream &input, int generate_edges, int refine,
4327 bool fix_orientation)
4328 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4329{
4330 SetEmpty();
4331 Load(input, generate_edges, refine, fix_orientation);
4332}
4333
4334void Mesh::ChangeVertexDataOwnership(real_t *vertex_data, int len_vertex_data,
4335 bool zerocopy)
4336{
4337 // A dimension of 3 is now required since we use mfem::Vertex objects as PODs
4338 // and these object have a hardcoded double[3] entry
4339 MFEM_VERIFY(len_vertex_data >= NumOfVertices * 3,
4340 "Not enough vertices in external array : "
4341 "len_vertex_data = "<< len_vertex_data << ", "
4342 "NumOfVertices * 3 = " << NumOfVertices * 3);
4343 // Allow multiple calls to this method with the same vertex_data
4344 if (vertex_data == (real_t *)(vertices.GetData()))
4345 {
4346 MFEM_ASSERT(!vertices.OwnsData(), "invalid ownership");
4347 return;
4348 }
4349 if (!zerocopy)
4350 {
4351 memcpy(vertex_data, vertices.GetData(),
4352 NumOfVertices * 3 * sizeof(real_t));
4353 }
4354 // Vertex is POD double[3]
4355 vertices.MakeRef(reinterpret_cast<Vertex*>(vertex_data), NumOfVertices);
4356}
4357
4358Mesh::Mesh(real_t *vertices_, int num_vertices,
4359 int *element_indices, Geometry::Type element_type,
4360 int *element_attributes, int num_elements,
4361 int *boundary_indices, Geometry::Type boundary_type,
4362 int *boundary_attributes, int num_boundary_elements,
4363 int dimension, int space_dimension)
4364 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4365{
4366 if (space_dimension == -1)
4367 {
4368 space_dimension = dimension;
4369 }
4370
4371 InitMesh(dimension, space_dimension, /*num_vertices*/ 0, num_elements,
4372 num_boundary_elements);
4373
4374 int element_index_stride = Geometry::NumVerts[element_type];
4375 int boundary_index_stride = num_boundary_elements > 0 ?
4376 Geometry::NumVerts[boundary_type] : 0;
4377
4378 // assuming Vertex is POD
4379 vertices.MakeRef(reinterpret_cast<Vertex*>(vertices_), num_vertices);
4380 NumOfVertices = num_vertices;
4381
4382 for (int i = 0; i < num_elements; i++)
4383 {
4384 elements[i] = NewElement(element_type);
4385 elements[i]->SetVertices(element_indices + i * element_index_stride);
4386 elements[i]->SetAttribute(element_attributes[i]);
4387 }
4388 NumOfElements = num_elements;
4389
4390 for (int i = 0; i < num_boundary_elements; i++)
4391 {
4392 boundary[i] = NewElement(boundary_type);
4393 boundary[i]->SetVertices(boundary_indices + i * boundary_index_stride);
4394 boundary[i]->SetAttribute(boundary_attributes[i]);
4395 }
4396 NumOfBdrElements = num_boundary_elements;
4397
4399}
4400
4402{
4403 switch (geom)
4404 {
4405 case Geometry::POINT: return (new Point);
4406 case Geometry::SEGMENT: return (new Segment);
4407 case Geometry::TRIANGLE: return (new Triangle);
4408 case Geometry::SQUARE: return (new Quadrilateral);
4410#ifdef MFEM_USE_MEMALLOC
4411 return TetMemory.Alloc();
4412#else
4413 return (new Tetrahedron);
4414#endif
4415 case Geometry::CUBE: return (new Hexahedron);
4416 case Geometry::PRISM: return (new Wedge);
4417 case Geometry::PYRAMID: return (new Pyramid);
4418 default:
4419 MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
4420 }
4421
4422 return NULL;
4423}
4424
4426{
4427 int geom, nv, *v;
4428 Element *el;
4429
4430 input >> geom;
4431 el = NewElement(geom);
4432 MFEM_VERIFY(el, "Unsupported element type: " << geom);
4433 nv = el->GetNVertices();
4434 v = el->GetVertices();
4435 for (int i = 0; i < nv; i++)
4436 {
4437 input >> v[i];
4438 }
4439
4440 return el;
4441}
4442
4443void Mesh::PrintElementWithoutAttr(const Element *el, std::ostream &os)
4444{
4445 os << el->GetGeometryType();
4446 const int nv = el->GetNVertices();
4447 const int *v = el->GetVertices();
4448 for (int j = 0; j < nv; j++)
4449 {
4450 os << ' ' << v[j];
4451 }
4452 os << '\n';
4453}
4454
4455Element *Mesh::ReadElement(std::istream &input)
4456{
4457 int attr;
4458 Element *el;
4459
4460 input >> attr;
4461 el = ReadElementWithoutAttr(input);
4462 el->SetAttribute(attr);
4463
4464 return el;
4465}
4466
4467void Mesh::PrintElement(const Element *el, std::ostream &os)
4468{
4469 os << el->GetAttribute() << ' ';
4471}
4472
4474{
4475 meshgen = mesh_geoms = 0;
4476 for (int i = 0; i < NumOfElements; i++)
4477 {
4478 const Element::Type type = GetElement(i)->GetType();
4479 switch (type)
4480 {
4483 case Element::TRIANGLE:
4485 case Element::SEGMENT:
4486 mesh_geoms |= (1 << Geometry::SEGMENT);
4487 case Element::POINT:
4488 mesh_geoms |= (1 << Geometry::POINT);
4489 meshgen |= 1;
4490 break;
4491
4493 mesh_geoms |= (1 << Geometry::CUBE);
4495 mesh_geoms |= (1 << Geometry::SQUARE);
4496 mesh_geoms |= (1 << Geometry::SEGMENT);
4497 mesh_geoms |= (1 << Geometry::POINT);
4498 meshgen |= 2;
4499 break;
4500
4501 case Element::WEDGE:
4502 mesh_geoms |= (1 << Geometry::PRISM);
4503 mesh_geoms |= (1 << Geometry::SQUARE);
4505 mesh_geoms |= (1 << Geometry::SEGMENT);
4506 mesh_geoms |= (1 << Geometry::POINT);
4507 meshgen |= 4;
4508 break;
4509
4510 case Element::PYRAMID:
4511 mesh_geoms |= (1 << Geometry::PYRAMID);
4512 mesh_geoms |= (1 << Geometry::SQUARE);
4514 mesh_geoms |= (1 << Geometry::SEGMENT);
4515 mesh_geoms |= (1 << Geometry::POINT);
4516 meshgen |= 8;
4517 break;
4518
4519 default:
4520 MFEM_ABORT("invalid element type: " << type);
4521 break;
4522 }
4523 }
4524}
4525
4526void Mesh::Loader(std::istream &input, int generate_edges,
4527 std::string parse_tag)
4528{
4529 int curved = 0, read_gf = 1;
4530 bool finalize_topo = true;
4531
4532 if (!input)
4533 {
4534 MFEM_ABORT("Input stream is not open");
4535 }
4536
4537 Clear();
4538
4539 string mesh_type;
4540 input >> ws;
4541 getline(input, mesh_type);
4542 filter_dos(mesh_type);
4543
4544 // MFEM's conforming mesh formats
4545 int mfem_version = 0;
4546 if (mesh_type == "MFEM mesh v1.0") { mfem_version = 10; } // serial
4547 else if (mesh_type == "MFEM mesh v1.2") { mfem_version = 12; } // parallel
4548 else if (mesh_type == "MFEM mesh v1.3") { mfem_version = 13; } // attr sets
4549
4550 // MFEM nonconforming mesh format
4551 // (NOTE: previous v1.1 is now under this branch for backward compatibility)
4552 int mfem_nc_version = 0;
4553 if (mesh_type == "MFEM NC mesh v1.0") { mfem_nc_version = 10; }
4554 else if (mesh_type == "MFEM mesh v1.1") { mfem_nc_version = 1 /*legacy*/; }
4555
4556 if (mfem_version)
4557 {
4558 // Formats mfem_v12 and newer have a tag indicating the end of the mesh
4559 // section in the stream. A user provided parse tag can also be provided
4560 // via the arguments. For example, if this is called from parallel mesh
4561 // object, it can indicate to read until parallel mesh section begins.
4562 if (mfem_version >= 12 && parse_tag.empty())
4563 {
4564 parse_tag = "mfem_mesh_end";
4565 }
4566 ReadMFEMMesh(input, mfem_version, curved);
4567 }
4568 else if (mfem_nc_version)
4569 {
4570 MFEM_ASSERT(ncmesh == NULL, "internal error");
4571 int is_nc = 1;
4572
4573#ifdef MFEM_USE_MPI
4574 ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
4575 if (pmesh)
4576 {
4577 MFEM_VERIFY(mfem_nc_version >= 10,
4578 "Legacy nonconforming format (MFEM mesh v1.1) cannot be "
4579 "used to load a parallel nonconforming mesh, sorry.");
4580
4581 ncmesh = new ParNCMesh(pmesh->GetComm(),
4582 input, mfem_nc_version, curved, is_nc);
4583 }
4584 else
4585#endif
4586 {
4587 ncmesh = new NCMesh(input, mfem_nc_version, curved, is_nc);
4588 }
4590
4591 if (!is_nc)
4592 {
4593 // special case for backward compatibility with MFEM <=4.2:
4594 // if the "vertex_parents" section is missing in the v1.1 format,
4595 // the mesh is treated as conforming
4596 delete ncmesh;
4597 ncmesh = NULL;
4598 }
4599 }
4600 else if (mesh_type == "linemesh") // 1D mesh
4601 {
4602 ReadLineMesh(input);
4603 }
4604 else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2")
4605 {
4606 if (mesh_type == "curved_areamesh2")
4607 {
4608 curved = 1;
4609 }
4610 ReadNetgen2DMesh(input, curved);
4611 }
4612 else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format")
4613 {
4614 ReadNetgen3DMesh(input);
4615 }
4616 else if (mesh_type == "TrueGrid")
4617 {
4618 ReadTrueGridMesh(input);
4619 }
4620 else if (mesh_type.rfind("# vtk DataFile Version") == 0)
4621 {
4622 int major_vtk_version = mesh_type[mesh_type.length()-3] - '0';
4623 // int minor_vtk_version = mesh_type[mesh_type.length()-1] - '0';
4624 MFEM_VERIFY(major_vtk_version >= 2 && major_vtk_version <= 4,
4625 "Unsupported VTK format");
4626 ReadVTKMesh(input, curved, read_gf, finalize_topo);
4627 }
4628 else if (mesh_type.rfind("<VTKFile ") == 0 || mesh_type.rfind("<?xml") == 0)
4629 {
4630 ReadXML_VTKMesh(input, curved, read_gf, finalize_topo, mesh_type);
4631 }
4632 else if (mesh_type == "MFEM NURBS mesh v1.0")
4633 {
4634 ReadNURBSMesh(input, curved, read_gf);
4635 }
4636 else if (mesh_type == "MFEM NURBS mesh v1.1")
4637 {
4638 ReadNURBSMesh(input, curved, read_gf, true);
4639 }
4640 else if (mesh_type == "MFEM INLINE mesh v1.0")
4641 {
4642 ReadInlineMesh(input, generate_edges);
4643 return; // done with inline mesh construction
4644 }
4645 else if (mesh_type == "$MeshFormat") // Gmsh
4646 {
4647 ReadGmshMesh(input, curved, read_gf);
4648 }
4649 else if
4650 ((mesh_type.size() > 2 &&
4651 mesh_type[0] == 'C' && mesh_type[1] == 'D' && mesh_type[2] == 'F') ||
4652 (mesh_type.size() > 3 &&
4653 mesh_type[1] == 'H' && mesh_type[2] == 'D' && mesh_type[3] == 'F'))
4654 {
4655 named_ifgzstream *mesh_input = dynamic_cast<named_ifgzstream *>(&input);
4656 if (mesh_input)
4657 {
4658#ifdef MFEM_USE_NETCDF
4659 ReadCubit(mesh_input->filename, curved, read_gf);
4660#else
4661 MFEM_ABORT("NetCDF support requires configuration with"
4662 " MFEM_USE_NETCDF=YES");
4663 return;
4664#endif
4665 }
4666 else
4667 {
4668 MFEM_ABORT("Can not determine Cubit mesh filename!"
4669 " Use mfem::named_ifgzstream for input.");
4670 return;
4671 }
4672 }
4673 else
4674 {
4675 MFEM_ABORT("Unknown input mesh format: " << mesh_type);
4676 return;
4677 }
4678
4679 // at this point the following should be defined:
4680 // 1) Dim
4681 // 2) NumOfElements, elements
4682 // 3) NumOfBdrElements, boundary
4683 // 4) NumOfVertices, with allocated space in vertices
4684 // 5) curved
4685 // 5a) if curved == 0, vertices must be defined
4686 // 5b) if curved != 0 and read_gf != 0,
4687 // 'input' must point to a GridFunction
4688 // 5c) if curved != 0 and read_gf == 0,
4689 // vertices and Nodes must be defined
4690 // optional:
4691 // 1) el_to_edge may be allocated (as in the case of P2 VTK meshes)
4692 // 2) ncmesh may be allocated
4693
4694 // FinalizeTopology() will:
4695 // - assume that generate_edges is true
4696 // - assume that refine is false
4697 // - does not check the orientation of regular and boundary elements
4698 if (finalize_topo)
4699 {
4700 // don't generate any boundary elements, especially in parallel
4701 bool generate_bdr = false;
4702
4703 FinalizeTopology(generate_bdr);
4704 }
4705
4706 if (curved && read_gf)
4707 {
4708 Nodes = new GridFunction(this, input);
4709
4710 own_nodes = 1;
4712 if (ncmesh) { ncmesh->spaceDim = spaceDim; }
4713
4714 // Set vertex coordinates from the 'Nodes'
4716 }
4717
4718 // If a parse tag was supplied, keep reading the stream until the tag is
4719 // encountered.
4720 if (mfem_version >= 12)
4721 {
4722 string line;
4723 do
4724 {
4725 skip_comment_lines(input, '#');
4726 MFEM_VERIFY(input.good(), "Required mesh-end tag not found");
4727 getline(input, line);
4728 filter_dos(line);
4729 // mfem v1.2 may not have parse_tag in it, e.g. if trying to read a
4730 // serial mfem v1.2 mesh as parallel with "mfem_serial_mesh_end" as
4731 // parse_tag. That's why, regardless of parse_tag, we stop reading if
4732 // we find "mfem_mesh_end" which is required by mfem v1.2 format.
4733 if (line == "mfem_mesh_end") { break; }
4734 }
4735 while (line != parse_tag);
4736 }
4737 else if (mfem_nc_version >= 10)
4738 {
4739 string ident;
4740 skip_comment_lines(input, '#');
4741 input >> ident;
4742 MFEM_VERIFY(ident == "mfem_mesh_end",
4743 "invalid mesh: end of file tag not found");
4744 }
4745
4746 // Finalize(...) should be called after this, if needed.
4747}
4748
4749Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
4750 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4751{
4752 int i, j, ie, ib, iv, *v, nv;
4753 Element *el;
4754 Mesh *m;
4755
4756 SetEmpty();
4757
4758 Dim = mesh_array[0]->Dimension();
4759 spaceDim = mesh_array[0]->SpaceDimension();
4760
4761 if (mesh_array[0]->NURBSext)
4762 {
4763 // assuming the pieces form a partition of a NURBS mesh
4764 NURBSext = new NURBSExtension(mesh_array, num_pieces);
4765
4768
4770
4771 // NumOfBdrElements = NURBSext->GetNBE();
4772 // NURBSext->GetBdrElementTopo(boundary);
4773
4774 Array<int> lvert_vert, lelem_elem;
4775
4776 // Here, for visualization purposes, we copy the boundary elements from
4777 // the individual pieces which include the interior boundaries. This
4778 // creates 'boundary' array that is different from the one generated by
4779 // the NURBSExtension which, in particular, makes the boundary-dof table
4780 // invalid. This, in turn, causes GetBdrElementTransformation to not
4781 // function properly.
4782 NumOfBdrElements = 0;
4783 for (i = 0; i < num_pieces; i++)
4784 {
4785 NumOfBdrElements += mesh_array[i]->GetNBE();
4786 }
4787 boundary.SetSize(NumOfBdrElements);
4788 vertices.SetSize(NumOfVertices);
4789 ib = 0;
4790 for (i = 0; i < num_pieces; i++)
4791 {
4792 m = mesh_array[i];
4793 m->NURBSext->GetVertexLocalToGlobal(lvert_vert);
4794 m->NURBSext->GetElementLocalToGlobal(lelem_elem);
4795 // copy the element attributes
4796 for (j = 0; j < m->GetNE(); j++)
4797 {
4798 elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j));
4799 }
4800 // copy the boundary
4801 for (j = 0; j < m->GetNBE(); j++)
4802 {
4803 el = m->GetBdrElement(j)->Duplicate(this);
4804 v = el->GetVertices();
4805 nv = el->GetNVertices();
4806 for (int k = 0; k < nv; k++)
4807 {
4808 v[k] = lvert_vert[v[k]];
4809 }
4810 boundary[ib++] = el;
4811 }
4812 // copy the vertices
4813 for (j = 0; j < m->GetNV(); j++)
4814 {
4815 vertices[lvert_vert[j]].SetCoords(m->SpaceDimension(),
4816 m->GetVertex(j));
4817 }
4818 }
4819 }
4820 else // not a NURBS mesh
4821 {
4822 NumOfElements = 0;
4823 NumOfBdrElements = 0;
4824 NumOfVertices = 0;
4825 for (i = 0; i < num_pieces; i++)
4826 {
4827 m = mesh_array[i];
4828 NumOfElements += m->GetNE();
4829 NumOfBdrElements += m->GetNBE();
4830 NumOfVertices += m->GetNV();
4831 }
4832 elements.SetSize(NumOfElements);
4833 boundary.SetSize(NumOfBdrElements);
4834 vertices.SetSize(NumOfVertices);
4835 ie = ib = iv = 0;
4836 for (i = 0; i < num_pieces; i++)
4837 {
4838 m = mesh_array[i];
4839 // copy the elements
4840 for (j = 0; j < m->GetNE(); j++)
4841 {
4842 el = m->GetElement(j)->Duplicate(this);
4843 v = el->GetVertices();
4844 nv = el->GetNVertices();
4845 for (int k = 0; k < nv; k++)
4846 {
4847 v[k] += iv;
4848 }
4849 elements[ie++] = el;
4850 }
4851 // copy the boundary elements
4852 for (j = 0; j < m->GetNBE(); j++)
4853 {
4854 el = m->GetBdrElement(j)->Duplicate(this);
4855 v = el->GetVertices();
4856 nv = el->GetNVertices();
4857 for (int k = 0; k < nv; k++)
4858 {
4859 v[k] += iv;
4860 }
4861 boundary[ib++] = el;
4862 }
4863 // copy the vertices
4864 for (j = 0; j < m->GetNV(); j++)
4865 {
4866 vertices[iv++].SetCoords(m->SpaceDimension(), m->GetVertex(j));
4867 }
4868 }
4869 }
4870
4872
4873 // copy the nodes (curvilinear meshes)
4874 GridFunction *g = mesh_array[0]->GetNodes();
4875 if (g)
4876 {
4877 Array<GridFunction *> gf_array(num_pieces);
4878 for (i = 0; i < num_pieces; i++)
4879 {
4880 gf_array[i] = mesh_array[i]->GetNodes();
4881 }
4882 Nodes = new GridFunction(this, gf_array, num_pieces);
4883 own_nodes = 1;
4884 }
4885
4886#ifdef MFEM_DEBUG
4889#endif
4890}
4891
4892Mesh::Mesh(Mesh *orig_mesh, int ref_factor, int ref_type)
4893 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
4894{
4895 Array<int> ref_factors(orig_mesh->GetNE());
4896 ref_factors = ref_factor;
4897 MakeRefined_(*orig_mesh, ref_factors, ref_type);
4898}
4899
4900void Mesh::MakeRefined_(Mesh &orig_mesh, const Array<int> &ref_factors,
4901 int ref_type)
4902{
4903 SetEmpty();
4904 Dim = orig_mesh.Dimension();
4905 spaceDim = orig_mesh.SpaceDimension();
4906
4907 int orig_ne = orig_mesh.GetNE();
4908 MFEM_VERIFY(ref_factors.Size() == orig_ne,
4909 "Number of refinement factors must equal number of elements")
4910 MFEM_VERIFY(orig_ne == 0 ||
4911 ref_factors.Min() >= 1, "Refinement factor must be >= 1");
4912 const int q_type = BasisType::GetQuadrature1D(ref_type);
4913 MFEM_VERIFY(Quadrature1D::CheckClosed(q_type) != Quadrature1D::Invalid,
4914 "Invalid refinement type. Must use closed basis type.");
4915
4916 int min_ref = orig_ne > 0 ? ref_factors.Min() : 1;
4917 int max_ref = orig_ne > 0 ? ref_factors.Max() : 1;
4918
4919 bool var_order = (min_ref != max_ref);
4920
4921 // variable order space can only be constructed over an NC mesh
4922 if (var_order) { orig_mesh.EnsureNCMesh(true); }
4923
4924 // Construct a scalar H1 FE space of order ref_factor and use its dofs as
4925 // the indices of the new, refined vertices.
4926 H1_FECollection rfec(min_ref, Dim, ref_type);
4927 FiniteElementSpace rfes(&orig_mesh, &rfec);
4928
4929 if (var_order)
4930 {
4931 rfes.SetRelaxedHpConformity(false);
4932 for (int i = 0; i < orig_ne; i++)
4933 {
4934 rfes.SetElementOrder(i, ref_factors[i]);
4935 }
4936 rfes.Update(false);
4937 }
4938
4939 // Set the number of vertices, set the actual coordinates later
4940 NumOfVertices = rfes.GetNDofs();
4941 vertices.SetSize(NumOfVertices);
4942
4943 Array<int> rdofs;
4944 DenseMatrix phys_pts;
4945 GeometryRefiner refiner(q_type);
4946
4947 // Add refined elements and set vertex coordinates
4948 for (int el = 0; el < orig_ne; el++)
4949 {
4950 Geometry::Type geom = orig_mesh.GetElementGeometry(el);
4951 int attrib = orig_mesh.GetAttribute(el);
4952 int nvert = Geometry::NumVerts[geom];
4953 RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el]);
4954
4955 rfes.GetElementDofs(el, rdofs);
4956 MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4957 const FiniteElement *rfe = rfes.GetFE(el);
4958 orig_mesh.GetElementTransformation(el)->Transform(rfe->GetNodes(),
4959 phys_pts);
4960 const int *c2h_map = rfec.GetDofMap(geom, ref_factors[el]);
4961 for (int i = 0; i < phys_pts.Width(); i++)
4962 {
4963 vertices[rdofs[i]].SetCoords(spaceDim, phys_pts.GetColumn(i));
4964 }
4965 for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4966 {
4967 Element *elem = NewElement(geom);
4968 elem->SetAttribute(attrib);
4969 int *v = elem->GetVertices();
4970 for (int k = 0; k < nvert; k++)
4971 {
4972 int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
4973 v[k] = rdofs[c2h_map[cid]];
4974 }
4975 AddElement(elem);
4976 }
4977 }
4978
4979 if (Dim > 2)
4980 {
4981 GetElementToFaceTable(false);
4982 GenerateFaces();
4983 }
4984
4985 // Add refined boundary elements
4986 for (int el = 0; el < orig_mesh.GetNBE(); el++)
4987 {
4988 int i, info;
4989 orig_mesh.GetBdrElementAdjacentElement(el, i, info);
4990 Geometry::Type geom = orig_mesh.GetBdrElementGeometry(el);
4991 int attrib = orig_mesh.GetBdrAttribute(el);
4992 int nvert = Geometry::NumVerts[geom];
4993 RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[i]);
4994
4995 rfes.GetBdrElementDofs(el, rdofs);
4996 MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
4997 const int *c2h_map = rfec.GetDofMap(geom, ref_factors[i]);
4998 for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
4999 {
5000 Element *elem = NewElement(geom);
5001 elem->SetAttribute(attrib);
5002 int *v = elem->GetVertices();
5003 for (int k = 0; k < nvert; k++)
5004 {
5005 int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
5006 v[k] = rdofs[c2h_map[cid]];
5007 }
5008 AddBdrElement(elem);
5009 }
5010 }
5011 FinalizeTopology(false);
5012 sequence = orig_mesh.GetSequence() + 1;
5014
5015 // Set up the nodes of the new mesh (if the original mesh has nodes). The new
5016 // mesh is always straight-sided (i.e. degree 1 finite element space), but
5017 // the nodes are required for e.g. periodic meshes.
5018 if (orig_mesh.GetNodes())
5019 {
5020 bool discont = orig_mesh.GetNodalFESpace()->IsDGSpace();
5021 Ordering::Type dof_ordering = orig_mesh.GetNodalFESpace()->GetOrdering();
5022 Mesh::SetCurvature(1, discont, spaceDim, dof_ordering);
5023 FiniteElementSpace *nodal_fes = Nodes->FESpace();
5024 const FiniteElementCollection *nodal_fec = nodal_fes->FEColl();
5025 H1_FECollection vertex_fec(1, Dim);
5026 Array<int> dofs;
5027 int el_counter = 0;
5028 for (int iel = 0; iel < orig_ne; iel++)
5029 {
5030 Geometry::Type geom = orig_mesh.GetElementBaseGeometry(iel);
5031 int nvert = Geometry::NumVerts[geom];
5032 RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[iel]);
5033 rfes.GetElementDofs(iel, rdofs);
5034 const FiniteElement *rfe = rfes.GetFE(iel);
5035 orig_mesh.GetElementTransformation(iel)->Transform(rfe->GetNodes(),
5036 phys_pts);
5037 const int *node_map = NULL;
5038 const H1_FECollection *h1_fec =
5039 dynamic_cast<const H1_FECollection *>(nodal_fec);
5040 if (h1_fec != NULL) { node_map = h1_fec->GetDofMap(geom); }
5041 const int *vertex_map = vertex_fec.GetDofMap(geom);
5042 const int *c2h_map = rfec.GetDofMap(geom, ref_factors[iel]);
5043 for (int jel = 0; jel < RG.RefGeoms.Size()/nvert; jel++)
5044 {
5045 nodal_fes->GetElementVDofs(el_counter++, dofs);
5046 for (int iv_lex=0; iv_lex<nvert; ++iv_lex)
5047 {
5048 // convert from lexicographic to vertex index
5049 int iv = vertex_map[iv_lex];
5050 // index of vertex of current element in phys_pts matrix
5051 int pt_idx = c2h_map[RG.RefGeoms[iv+nvert*jel]];
5052 // index of current vertex into DOF array
5053 int node_idx = node_map ? node_map[iv_lex] : iv_lex;
5054 for (int d=0; d<spaceDim; ++d)
5055 {
5056 (*Nodes)[dofs[node_idx + d*nvert]] = phys_pts(d,pt_idx);
5057 }
5058 }
5059 }
5060 }
5061 }
5062
5063 // Setup the data for the coarse-fine refinement transformations
5064 CoarseFineTr.embeddings.SetSize(GetNE());
5065 // First, compute total number of point matrices that we need per geometry
5066 // and the offsets into that array
5067 using GeomRef = std::pair<Geometry::Type, int>;
5068 std::map<GeomRef, int> point_matrices_offsets;
5069 int n_point_matrices[Geometry::NumGeom] = {}; // initialize to zero
5070 for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
5071 {
5072 Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
5073 // Have we seen this pair of (goemetry, refinement level) before?
5074 GeomRef id(geom, ref_factors[el_coarse]);
5075 if (point_matrices_offsets.find(id) == point_matrices_offsets.end())
5076 {
5077 RefinedGeometry &RG = *refiner.Refine(geom, ref_factors[el_coarse]);
5078 int nvert = Geometry::NumVerts[geom];
5079 int nref_el = RG.RefGeoms.Size()/nvert;
5080 // If not, then store the offset and add to the size required
5081 point_matrices_offsets[id] = n_point_matrices[geom];
5082 n_point_matrices[geom] += nref_el;
5083 }
5084 }
5085
5086 // Set up the sizes
5087 for (int geom = 0; geom < Geometry::NumGeom; ++geom)
5088 {
5089 int nmatrices = n_point_matrices[geom];
5090 int nvert = Geometry::NumVerts[geom];
5091 CoarseFineTr.point_matrices[geom].SetSize(Dim, nvert, nmatrices);
5092 }
5093
5094 // Compute the point matrices and embeddings
5095 int el_fine = 0;
5096 for (int el_coarse = 0; el_coarse < orig_ne; ++el_coarse)
5097 {
5098 Geometry::Type geom = orig_mesh.GetElementBaseGeometry(el_coarse);
5099 int ref = ref_factors[el_coarse];
5100 int offset = point_matrices_offsets[GeomRef(geom, ref)];
5101 int nvert = Geometry::NumVerts[geom];
5102 RefinedGeometry &RG = *refiner.Refine(geom, ref);
5103 for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
5104 {
5105 DenseMatrix &Pj = CoarseFineTr.point_matrices[geom](offset + j);
5106 for (int k = 0; k < nvert; k++)
5107 {
5108 int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
5109 const IntegrationPoint &ip = RG.RefPts[cid];
5110 ip.Get(Pj.GetColumn(k), Dim);
5111 }
5112
5113 Embedding &emb = CoarseFineTr.embeddings[el_fine];
5114 emb.parent = el_coarse;
5115 emb.matrix = offset + j;
5116 ++el_fine;
5117 }
5118 }
5119
5120 MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
5121
5122 // The check below is disabled because is fails for parallel meshes with
5123 // interior "boundary" element that, when such "boundary" element is between
5124 // two elements on different processors.
5125 // MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
5126}
5127
5129{
5130 Mesh mesh;
5131 mesh.MakeSimplicial_(orig_mesh, NULL);
5132 return mesh;
5133}
5134
5135void Mesh::MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
5136{
5137 MFEM_VERIFY(const_cast<Mesh&>(orig_mesh).CheckElementOrientation(false) == 0,
5138 "Mesh::MakeSimplicial requires a properly oriented input mesh");
5139 MFEM_VERIFY(orig_mesh.Conforming(),
5140 "Mesh::MakeSimplicial does not support non-conforming meshes.")
5141
5142 int dim = orig_mesh.Dimension();
5143 int sdim = orig_mesh.SpaceDimension();
5144
5145 if (dim == 1)
5146 {
5147 Mesh copy(orig_mesh);
5148 Swap(copy, true);
5149 return;
5150 }
5151
5152 int nv = orig_mesh.GetNV();
5153 int ne = orig_mesh.GetNE();
5154 int nbe = orig_mesh.GetNBE();
5155
5156 static int num_subdivisions[Geometry::NUM_GEOMETRIES];
5157 num_subdivisions[Geometry::POINT] = 1;
5158 num_subdivisions[Geometry::SEGMENT] = 1;
5159 num_subdivisions[Geometry::TRIANGLE] = 1;
5160 num_subdivisions[Geometry::TETRAHEDRON] = 1;
5161 num_subdivisions[Geometry::SQUARE] = 2;
5162 num_subdivisions[Geometry::PRISM] = 3;
5163 num_subdivisions[Geometry::CUBE] = 6;
5164 // NOTE: some hexes may be subdivided into only 5 tets, so this is an
5165 // estimate only. The actual number of created tets may be less, so the
5166 // elements array will need to be shrunk after mesh creation.
5167 int new_ne = 0, new_nbe = 0;
5168 for (int i=0; i<ne; ++i)
5169 {
5170 new_ne += num_subdivisions[orig_mesh.GetElementBaseGeometry(i)];
5171 }
5172 for (int i=0; i<nbe; ++i)
5173 {
5174 new_nbe += num_subdivisions[orig_mesh.GetBdrElementGeometry(i)];
5175 }
5176
5177 InitMesh(dim, sdim, nv, new_ne, new_nbe);
5178
5179 // Vertices of the new mesh are same as the original mesh
5180 NumOfVertices = nv;
5181 for (int i=0; i<nv; ++i)
5182 {
5183 vertices[i].SetCoords(dim, orig_mesh.vertices[i]());
5184 }
5185
5186 // We need a global vertex numbering to identify which diagonals to split
5187 // (quad faces are split using the diagonal originating from the smallest
5188 // global vertex number). Use the supplied global numbering, if it is
5189 // non-NULL, otherwise use the local numbering.
5190 Array<int> vglobal_id;
5191 if (vglobal == NULL)
5192 {
5193 vglobal_id.SetSize(nv);
5194 for (int i=0; i<nv; ++i) { vglobal_id[i] = i; }
5195 vglobal = vglobal_id.GetData();
5196 }
5197
5198 constexpr int nv_tri = 3, nv_quad = 4, nv_tet = 4, nv_prism = 6, nv_hex = 8;
5199 constexpr int quad_ntris = 2, prism_ntets = 3;
5200 static const int quad_trimap[2][nv_tri*quad_ntris] =
5201 {
5202 {
5203 0, 0,
5204 1, 2,
5205 2, 3
5206 },{
5207 0, 1,
5208 1, 2,
5209 3, 3
5210 }
5211 };
5212 static const int prism_rot[nv_prism*nv_prism] =
5213 {
5214 0, 1, 2, 3, 4, 5,
5215 1, 2, 0, 4, 5, 3,
5216 2, 0, 1, 5, 3, 4,
5217 3, 5, 4, 0, 2, 1,
5218 4, 3, 5, 1, 0, 2,
5219 5, 4, 3, 2, 1, 0
5220 };
5221 static const int prism_f[nv_quad] = {1, 2, 5, 4};
5222 static const int prism_tetmaps[2][nv_prism*prism_ntets] =
5223 {
5224 {
5225 0, 0, 0,
5226 1, 1, 4,
5227 2, 5, 5,
5228 5, 4, 3
5229 },{
5230 0, 0, 0,
5231 1, 4, 4,
5232 2, 2, 5,
5233 4, 5, 3
5234 }
5235 };
5236 static const int hex_rot[nv_hex*nv_hex] =
5237 {
5238 0, 1, 2, 3, 4, 5, 6, 7,
5239 1, 0, 4, 5, 2, 3, 7, 6,
5240 2, 1, 5, 6, 3, 0, 4, 7,
5241 3, 0, 1, 2, 7, 4, 5, 6,
5242 4, 0, 3, 7, 5, 1, 2, 6,
5243 5, 1, 0, 4, 6, 2, 3, 7,
5244 6, 2, 1, 5, 7, 3, 0, 4,
5245 7, 3, 2, 6, 4, 0, 1, 5
5246 };
5247 static const int hex_f0[nv_quad] = {1, 2, 6, 5};
5248 static const int hex_f1[nv_quad] = {2, 3, 7, 6};
5249 static const int hex_f2[nv_quad] = {4, 5, 6, 7};
5250 static const int num_rot[8] = {0, 1, 2, 0, 0, 2, 1, 0};
5251 static const int hex_tetmap0[nv_tet*5] =
5252 {
5253 0, 0, 0, 0, 2,
5254 1, 2, 2, 5, 7,
5255 2, 7, 3, 7, 5,
5256 5, 5, 7, 4, 6
5257 };
5258 static const int hex_tetmap1[nv_tet*6] =
5259 {
5260 0, 0, 1, 0, 0, 1,
5261 5, 1, 6, 7, 7, 7,
5262 7, 7, 7, 2, 1, 6,
5263 4, 5, 5, 3, 2, 2
5264 };
5265 static const int hex_tetmap2[nv_tet*6] =
5266 {
5267 0, 0, 0, 0, 0, 0,
5268 4, 3, 7, 1, 3, 6,
5269 5, 7, 4, 2, 6, 5,
5270 6, 6, 6, 5, 2, 2
5271 };
5272 static const int hex_tetmap3[nv_tet*6] =
5273 {
5274 0, 0, 0, 0, 1, 1,
5275 2, 3, 7, 5, 5, 6,
5276 3, 7, 4, 6, 6, 2,
5277 6, 6, 6, 4, 0, 0
5278 };
5279 static const int *hex_tetmaps[4] =
5280 {
5281 hex_tetmap0, hex_tetmap1, hex_tetmap2, hex_tetmap3
5282 };
5283
5284 auto find_min = [](const int*a, int n) { return std::min_element(a,a+n)-a; };
5285
5286 for (int i=0; i<ne; ++i)
5287 {
5288 const int *v = orig_mesh.elements[i]->GetVertices();
5289 const int attrib = orig_mesh.GetAttribute(i);
5290 const Geometry::Type orig_geom = orig_mesh.GetElementBaseGeometry(i);
5291
5292 if (num_subdivisions[orig_geom] == 1)
5293 {
5294 // (num_subdivisions[orig_geom] == 1) implies that the element does
5295 // not need to be further split (it is either a segment, triangle,
5296 // or tetrahedron), and so it is left unchanged.
5297 Element *e = NewElement(orig_geom);
5298 e->SetAttribute(attrib);
5299 e->SetVertices(v);
5300 AddElement(e);
5301 }
5302 else if (orig_geom == Geometry::SQUARE)
5303 {
5304 for (int itri=0; itri<quad_ntris; ++itri)
5305 {
5307 e->SetAttribute(attrib);
5308 int *v2 = e->GetVertices();
5309 for (int iv=0; iv<nv_tri; ++iv)
5310 {
5311 v2[iv] = v[quad_trimap[0][itri + iv*quad_ntris]];
5312 }
5313 AddElement(e);
5314 }
5315 }
5316 else if (orig_geom == Geometry::PRISM)
5317 {
5318 int vg[nv_prism];
5319 for (int iv=0; iv<nv_prism; ++iv) { vg[iv] = vglobal[v[iv]]; }
5320 // Rotate the vertices of the prism so that the smallest vertex index
5321 // is in the first place
5322 int irot = find_min(vg, nv_prism);
5323 for (int iv=0; iv<nv_prism; ++iv)
5324 {
5325 int jv = prism_rot[iv + irot*nv_prism];
5326 vg[iv] = v[jv];
5327 }
5328 // Two cases according to which diagonal splits third quad face
5329 int q[nv_quad];
5330 for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[prism_f[iv]]]; }
5331 int j = find_min(q, nv_quad);
5332 const int *tetmap = (j == 0 || j == 2) ? prism_tetmaps[0] : prism_tetmaps[1];
5333 for (int itet=0; itet<prism_ntets; ++itet)
5334 {
5336 e->SetAttribute(attrib);
5337 int *v2 = e->GetVertices();
5338 for (int iv=0; iv<nv_tet; ++iv)
5339 {
5340 v2[iv] = vg[tetmap[itet + iv*prism_ntets]];
5341 }
5342 AddElement(e);
5343 }
5344 }
5345 else if (orig_geom == Geometry::CUBE)
5346 {
5347 int vg[nv_hex];
5348 for (int iv=0; iv<nv_hex; ++iv) { vg[iv] = vglobal[v[iv]]; }
5349
5350 // Rotate the vertices of the hex so that the smallest vertex index is
5351 // in the first place
5352 int irot = find_min(vg, nv_hex);
5353 for (int iv=0; iv<nv_hex; ++iv)
5354 {
5355 int jv = hex_rot[iv + irot*nv_hex];
5356 vg[iv] = v[jv];
5357 }
5358
5359 int q[nv_quad];
5360 // Bitmask is three binary digits, each digit is 1 if the diagonal of
5361 // the corresponding face goes through the 7th vertex, and 0 if not.
5362 int bitmask = 0;
5363 int j;
5364 // First quad face
5365 for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f0[iv]]]; }
5366 j = find_min(q, nv_quad);
5367 if (j == 0 || j == 2) { bitmask += 4; }
5368 // Second quad face
5369 for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f1[iv]]]; }
5370 j = find_min(q, nv_quad);
5371 if (j == 1 || j == 3) { bitmask += 2; }
5372 // Third quad face
5373 for (int iv=0; iv<nv_quad; ++iv) { q[iv] = vglobal[vg[hex_f2[iv]]]; }
5374 j = find_min(q, nv_quad);
5375 if (j == 0 || j == 2) { bitmask += 1; }
5376
5377 // Apply rotations
5378 int nrot = num_rot[bitmask];
5379 for (int k=0; k<nrot; ++k)
5380 {
5381 int vtemp;
5382 vtemp = vg[1];
5383 vg[1] = vg[4];
5384 vg[4] = vg[3];
5385 vg[3] = vtemp;
5386 vtemp = vg[5];
5387 vg[5] = vg[7];
5388 vg[7] = vg[2];
5389 vg[2] = vtemp;
5390 }
5391
5392 // Sum up nonzero bits in bitmask
5393 int ndiags = ((bitmask&4) >> 2) + ((bitmask&2) >> 1) + (bitmask&1);
5394 int ntets = (ndiags == 0) ? 5 : 6;
5395 const int *tetmap = hex_tetmaps[ndiags];
5396 for (int itet=0; itet<ntets; ++itet)
5397 {
5399 e->SetAttribute(attrib);
5400 int *v2 = e->GetVertices();
5401 for (int iv=0; iv<nv_tet; ++iv)
5402 {
5403 v2[iv] = vg[tetmap[itet + iv*ntets]];
5404 }
5405 AddElement(e);
5406 }
5407 }
5408 }
5409 // In 3D, shrink the element array because some hexes have only 5 tets
5410 if (dim == 3) { elements.SetSize(NumOfElements); }
5411
5412 for (int i=0; i<nbe; ++i)
5413 {
5414 const int *v = orig_mesh.boundary[i]->GetVertices();
5415 const int attrib = orig_mesh.GetBdrAttribute(i);
5416 const Geometry::Type orig_geom = orig_mesh.GetBdrElementGeometry(i);
5417 if (num_subdivisions[orig_geom] == 1)
5418 {
5419 Element *be = NewElement(orig_geom);
5420 be->SetAttribute(attrib);
5421 be->SetVertices(v);
5422 AddBdrElement(be);
5423 }
5424 else if (orig_geom == Geometry::SQUARE)
5425 {
5426 int vg[nv_quad];
5427 for (int iv=0; iv<nv_quad; ++iv) { vg[iv] = vglobal[v[iv]]; }
5428 // Split quad according the smallest (global) vertex
5429 int iv_min = find_min(vg, nv_quad);
5430 int isplit = (iv_min == 0 || iv_min == 2) ? 0 : 1;
5431 for (int itri=0; itri<quad_ntris; ++itri)
5432 {
5434 be->SetAttribute(attrib);
5435 int *v2 = be->GetVertices();
5436 for (int iv=0; iv<nv_tri; ++iv)
5437 {
5438 v2[iv] = v[quad_trimap[isplit][itri + iv*quad_ntris]];
5439 }
5440 AddBdrElement(be);
5441 }
5442 }
5443 else
5444 {
5445 MFEM_ABORT("Unreachable");
5446 }
5447 }
5448
5449 FinalizeTopology(false);
5450 sequence = orig_mesh.GetSequence();
5451 last_operation = orig_mesh.last_operation;
5452
5453 MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
5454 MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
5455}
5456
5457Mesh Mesh::MakePeriodic(const Mesh &orig_mesh, const std::vector<int> &v2v)
5458{
5459 Mesh periodic_mesh(orig_mesh, true); // Make a copy of the original mesh
5460 const FiniteElementSpace *nodal_fes = orig_mesh.GetNodalFESpace();
5461 int nodal_order = nodal_fes ? nodal_fes->GetMaxElementOrder() : 1;
5462 periodic_mesh.SetCurvature(nodal_order, true);
5463
5464 // renumber element vertices
5465 for (int i = 0; i < periodic_mesh.GetNE(); i++)
5466 {
5467 Element *el = periodic_mesh.GetElement(i);
5468 int *v = el->GetVertices();
5469 int nv = el->GetNVertices();
5470 for (int j = 0; j < nv; j++)
5471 {
5472 v[j] = v2v[v[j]];
5473 }
5474 }
5475 // renumber boundary element vertices
5476 for (int i = 0; i < periodic_mesh.GetNBE(); i++)
5477 {
5478 Element *el = periodic_mesh.GetBdrElement(i);
5479 int *v = el->GetVertices();
5480 int nv = el->GetNVertices();
5481 for (int j = 0; j < nv; j++)
5482 {
5483 v[j] = v2v[v[j]];
5484 }
5485 }
5486
5487 periodic_mesh.RemoveUnusedVertices();
5488 return periodic_mesh;
5489}
5490
5492 const std::vector<Vector> &translations, real_t tol) const
5493{
5494 const int sdim = SpaceDimension();
5495
5496 Vector coord(sdim), at(sdim), dx(sdim);
5497 Vector xMax(sdim), xMin(sdim), xDiff(sdim);
5498 xMax = xMin = xDiff = 0.0;
5499
5500 // Get a list of all vertices on the boundary
5501 unordered_set<int> bdr_v;
5502 for (int be = 0; be < GetNBE(); be++)
5503 {
5504 Array<int> dofs;
5505 GetBdrElementVertices(be,dofs);
5506
5507 for (int i = 0; i < dofs.Size(); i++)
5508 {
5509 bdr_v.insert(dofs[i]);
5510
5511 coord = GetVertex(dofs[i]);
5512 for (int j = 0; j < sdim; j++)
5513 {
5514 xMax[j] = max(xMax[j], coord[j]);
5515 xMin[j] = min(xMin[j], coord[j]);
5516 }
5517 }
5518 }
5519 add(xMax, -1.0, xMin, xDiff);
5520 real_t dia = xDiff.Norml2(); // compute mesh diameter
5521
5522 // We now identify coincident vertices. Several originally distinct vertices
5523 // may become coincident under the periodic mapping. One of these vertices
5524 // will be identified as the "primary" vertex, and all other coincident
5525 // vertices will be considered as "replicas".
5526
5527 // replica2primary[v] is the index of the primary vertex of replica `v`
5528 unordered_map<int, int> replica2primary;
5529 // primary2replicas[v] is a set of indices of replicas of primary vertex `v`
5530 unordered_map<int, unordered_set<int>> primary2replicas;
5531
5532 // Create a KD-tree containing all the boundary vertices
5533 std::unique_ptr<KDTreeBase<int,real_t>> kdtree;
5534 if (sdim == 1) { kdtree.reset(new KDTree1D); }
5535 else if (sdim == 2) { kdtree.reset(new KDTree2D); }
5536 else if (sdim == 3) { kdtree.reset(new KDTree3D); }
5537 else { MFEM_ABORT("Invalid space dimension."); }
5538
5539 // We begin with the assumption that all vertices are primary, and that there
5540 // are no replicas.
5541 for (const int v : bdr_v)
5542 {
5543 primary2replicas[v];
5544 kdtree->AddPoint(GetVertex(v), v);
5545 }
5546
5547 kdtree->Sort();
5548
5549 // Make `r` and all of `r`'s replicas be replicas of `p`. Delete `r` from the
5550 // list of primary vertices.
5551 auto make_replica = [&replica2primary, &primary2replicas](int r, int p)
5552 {
5553 if (r == p) { return; }
5554 primary2replicas[p].insert(r);
5555 replica2primary[r] = p;
5556 for (const int s : primary2replicas[r])
5557 {
5558 primary2replicas[p].insert(s);
5559 replica2primary[s] = p;
5560 }
5561 primary2replicas.erase(r);
5562 };
5563
5564 for (unsigned int i = 0; i < translations.size(); i++)
5565 {
5566 for (int vi : bdr_v)
5567 {
5568 coord = GetVertex(vi);
5569 add(coord, translations[i], at);
5570
5571 const int vj = kdtree->FindClosestPoint(at.GetData());
5572 coord = GetVertex(vj);
5573 add(at, -1.0, coord, dx);
5574
5575 if (dx.Norml2() > dia*tol) { continue; }
5576
5577 // The two vertices vi and vj are coincident.
5578
5579 // Are vertices `vi` and `vj` already primary?
5580 const bool pi = primary2replicas.find(vi) != primary2replicas.end();
5581 const bool pj = primary2replicas.find(vj) != primary2replicas.end();
5582
5583 if (pi && pj)
5584 {
5585 // Both vertices are currently primary
5586 // Demote `vj` to be a replica of `vi`
5587 make_replica(vj, vi);
5588 }
5589 else if (pi && !pj)
5590 {
5591 // `vi` is primary and `vj` is a replica
5592 const int owner_of_vj = replica2primary[vj];
5593 // Make `vi` and its replicas be replicas of `vj`'s owner
5594 make_replica(vi, owner_of_vj);
5595 }
5596 else if (!pi && pj)
5597 {
5598 // `vi` is currently a replica and `vj` is currently primary
5599 // Make `vj` and its replicas be replicas of `vi`'s owner
5600 const int owner_of_vi = replica2primary[vi];
5601 make_replica(vj, owner_of_vi);
5602 }
5603 else
5604 {
5605 // Both vertices are currently replicas
5606 // Make `vj`'s owner and all of its owner's replicas be replicas
5607 // of `vi`'s owner
5608 const int owner_of_vi = replica2primary[vi];
5609 const int owner_of_vj = replica2primary[vj];
5610 make_replica(owner_of_vj, owner_of_vi);
5611 }
5612 }
5613 }
5614
5615 std::vector<int> v2v(GetNV());
5616 for (size_t i = 0; i < v2v.size(); i++)
5617 {
5618 v2v[i] = i;
5619 }
5620 for (const auto &r2p : replica2primary)
5621 {
5622 v2v[r2p.first] = r2p.second;
5623 }
5624 return v2v;
5625}
5626
5627void Mesh::RefineNURBSFromFile(std::string ref_file)
5628{
5629 MFEM_VERIFY(NURBSext,"Mesh::RefineNURBSFromFile: Not a NURBS mesh!");
5630 mfem::out<<"Refining NURBS from refinement file: "<<ref_file<<endl;
5631
5632 int nkv;
5633 ifstream input(ref_file);
5634 input >> nkv;
5635
5636 // Check if the number of knot vectors in the refinement file and mesh match
5637 if ( nkv != NURBSext->GetNKV())
5638 {
5639 mfem::out<<endl;
5640 mfem::out<<"Knot vectors in ref_file: "<<nkv<<endl;
5641 mfem::out<<"Knot vectors in NURBSExt: "<<NURBSext->GetNKV()<<endl;
5642 MFEM_ABORT("Refine file does not have the correct number of knot vectors");
5643 }
5644
5645 // Read knot vectors from file
5646 Array<Vector *> knotVec(nkv);
5647 for (int kv = 0; kv < nkv; kv++)
5648 {
5649 knotVec[kv] = new Vector();
5650 knotVec[kv]-> Load(input);
5651 }
5652 input.close();
5653
5654 // Insert knots
5655 KnotInsert(knotVec);
5656
5657 // Delete knots
5658 for (int kv = 0; kv < nkv; kv++)
5659 {
5660 delete knotVec[kv];
5661 }
5662}
5663
5665{
5666 if (NURBSext == NULL)
5667 {
5668 mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5669 }
5670
5671 if (kv.Size() != NURBSext->GetNKV())
5672 {
5673 mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5674 }
5675
5677
5678 NURBSext->KnotInsert(kv);
5679
5680 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5681 sequence++;
5682
5683 UpdateNURBS();
5684}
5685
5687{
5688 if (NURBSext == NULL)
5689 {
5690 mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
5691 }
5692
5693 if (kv.Size() != NURBSext->GetNKV())
5694 {
5695 mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
5696 }
5697
5699
5700 NURBSext->KnotInsert(kv);
5701
5702 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5703 sequence++;
5704
5705 UpdateNURBS();
5706}
5707
5709{
5710 if (NURBSext == NULL)
5711 {
5712 mfem_error("Mesh::KnotRemove : Not a NURBS mesh!");
5713 }
5714
5715 if (kv.Size() != NURBSext->GetNKV())
5716 {
5717 mfem_error("Mesh::KnotRemove : KnotVector array size mismatch!");
5718 }
5719
5721
5722 NURBSext->KnotRemove(kv);
5723
5724 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5725 sequence++;
5726
5727 UpdateNURBS();
5728}
5729
5731{
5732 Array<int> rf_array(Dim);
5733 rf_array = rf;
5734 NURBSUniformRefinement(rf_array, tol);
5735}
5736
5738{
5739 MFEM_VERIFY(rf.Size() == Dim,
5740 "Refinement factors must be defined for each dimension");
5741
5742 MFEM_VERIFY(NURBSext, "NURBSUniformRefinement is only for NURBS meshes");
5743
5745
5746 Array<int> cf;
5748
5749 bool cf1 = true;
5750 for (auto f : cf)
5751 {
5752 cf1 = (cf1 && f == 1);
5753 }
5754
5755 if (cf1)
5756 {
5758 }
5759 else
5760 {
5761 NURBSext->Coarsen(cf, tol);
5762
5763 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5764 sequence++;
5765
5766 UpdateNURBS();
5767
5769 for (int i=0; i<cf.Size(); ++i) { cf[i] *= rf[i]; }
5771 }
5772
5773 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5774 sequence++;
5775
5776 UpdateNURBS();
5777}
5778
5779void Mesh::DegreeElevate(int rel_degree, int degree)
5780{
5781 if (NURBSext == NULL)
5782 {
5783 mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!");
5784 }
5785
5787
5788 NURBSext->DegreeElevate(rel_degree, degree);
5789
5790 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
5791 sequence++;
5792
5793 UpdateNURBS();
5794}
5795
5797{
5798 ResetLazyData();
5799
5801
5802 Dim = NURBSext->Dimension();
5803 spaceDim = Dim;
5804
5805 if (NumOfElements != NURBSext->GetNE())
5806 {
5807 for (int i = 0; i < elements.Size(); i++)
5808 {
5810 }
5813 }
5814
5816 {
5817 for (int i = 0; i < boundary.Size(); i++)
5818 {
5820 }
5823 }
5824
5825 Nodes->FESpace()->Update();
5826 Nodes->Update();
5827 NodesUpdated();
5829
5830 if (NumOfVertices != NURBSext->GetNV())
5831 {
5833 vertices.SetSize(NumOfVertices);
5834 int vd = Nodes->VectorDim();
5835 for (int i = 0; i < vd; i++)
5836 {
5837 Vector vert_val;
5838 Nodes->GetNodalValues(vert_val, i+1);
5839 for (int j = 0; j < NumOfVertices; j++)
5840 {
5841 vertices[j](i) = vert_val(j);
5842 }
5843 }
5844 }
5845
5846 if (el_to_edge)
5847 {
5849 }
5850
5851 if (el_to_face)
5852 {
5854 }
5855 GenerateFaces();
5856}
5857
5858void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot)
5859{
5860 SetEmpty();
5861
5862 // Read MFEM NURBS mesh v1.0 or 1.1 format
5863 string ident;
5864
5865 skip_comment_lines(input, '#');
5866
5867 input >> ident; // 'dimension'
5868 input >> Dim;
5869 spaceDim = Dim;
5870
5871 skip_comment_lines(input, '#');
5872
5873 input >> ident; // 'elements'
5874 input >> NumOfElements;
5875 elements.SetSize(NumOfElements);
5876 for (int j = 0; j < NumOfElements; j++)
5877 {
5878 elements[j] = ReadElement(input);
5879 }
5880
5881 skip_comment_lines(input, '#');
5882
5883 input >> ident; // 'boundary'
5884 input >> NumOfBdrElements;
5885 boundary.SetSize(NumOfBdrElements);
5886 for (int j = 0; j < NumOfBdrElements; j++)
5887 {
5888 boundary[j] = ReadElement(input);
5889 }
5890
5891 skip_comment_lines(input, '#');
5892
5893 input >> ident; // 'edges'
5894 input >> NumOfEdges;
5895 if (NumOfEdges > 0)
5896 {
5897 edge_vertex = new Table(NumOfEdges, 2);
5898 edge_to_knot.SetSize(NumOfEdges);
5899 for (int j = 0; j < NumOfEdges; j++)
5900 {
5901 int *v = edge_vertex->GetRow(j);
5902 input >> edge_to_knot[j] >> v[0] >> v[1];
5903 if (v[0] > v[1])
5904 {
5905 edge_to_knot[j] = -1 - edge_to_knot[j];
5906 }
5907 }
5908 }
5909 else
5910 {
5911 edge_to_knot.SetSize(0);
5912 }
5913
5914 skip_comment_lines(input, '#');
5915
5916 input >> ident; // 'vertices'
5917 input >> NumOfVertices;
5918 vertices.SetSize(0);
5919
5921 CheckBdrElementOrientation(); // check and fix boundary element orientation
5922
5923 /* Generate knot 2 edge mapping -- if edges are not specified in the mesh file
5924 See data/two-squares-nurbs-autoedge.mesh for an example */
5925 if (edge_to_knot.Size() == 0)
5926 {
5927 edge_vertex = new Table(NumOfEdges, 2);
5928 edge_to_knot.SetSize(NumOfEdges);
5929 constexpr int notset = -9999999;
5930 edge_to_knot = notset;
5931 Array<int> edges;
5932 Array<int> oedge;
5933 int knot = 0;
5934
5935 Array<int> edge0, edge1;
5936 int flip = 1;
5937 if (Dimension() == 2)
5938 {
5939 edge0.SetSize(2);
5940 edge1.SetSize(2);
5941
5942 edge0[0] = 0; edge1[0] = 2;
5943 edge0[1] = 1; edge1[1] = 3;
5944 flip = 1;
5945 }
5946 else if (Dimension() == 3)
5947 {
5948 edge0.SetSize(9);
5949 edge1.SetSize(9);
5950
5951 edge0[0] = 0; edge1[0] = 2;
5952 edge0[1] = 0; edge1[1] = 4;
5953 edge0[2] = 0; edge1[2] = 6;
5954
5955 edge0[3] = 1; edge1[3] = 3;
5956 edge0[4] = 1; edge1[4] = 5;
5957 edge0[5] = 1; edge1[5] = 7;
5958
5959 edge0[6] = 8; edge1[6] = 9;
5960 edge0[7] = 8; edge1[7] = 10;
5961 edge0[8] = 8; edge1[8] = 11;
5962 flip = -1;
5963 }
5964
5965 /* Initial assignment of knots to edges. This is an algorithm that loops over the
5966 patches and assigns knot vectors to edges. It starts with assigning knot vector 0
5967 and 1 to the edges of the first patch. Then it uses: 1) patches can share edges
5968 2) knot vectors on opposing edges in a patch are equal, to create edge_to_knot */
5969 int e0, e1, v0, v1, df;
5970 int p,j,k;
5971 for (p = 0; p < GetNE(); p++)
5972 {
5973 GetElementEdges(p, edges, oedge);
5974
5975 const int *v = elements[p]->GetVertices();
5976 for (j = 0; j < edges.Size(); j++)
5977 {
5978 int *vv = edge_vertex->GetRow(edges[j]);
5979 const int *e = elements[p]->GetEdgeVertices(j);
5980 if (oedge[j] == 1)
5981 {
5982 vv[0] = v[e[0]];
5983 vv[1] = v[e[1]];
5984 }
5985 else
5986 {
5987 vv[0] = v[e[1]];
5988 vv[1] = v[e[0]];
5989 }
5990 }
5991
5992 for (j = 0; j < edge1.Size(); j++)
5993 {
5994 e0 = edges[edge0[j]];
5995 e1 = edges[edge1[j]];
5996 v0 = edge_to_knot[e0];
5997 v1 = edge_to_knot[e1];
5998 df = flip*oedge[edge0[j]]*oedge[edge1[j]];
5999
6000 // Case 1: knot vector is not set
6001 if ((v0 == notset) && (v1 == notset))
6002 {
6003 edge_to_knot[e0] = knot;
6004 edge_to_knot[e1] = knot;
6005 knot++;
6006 }
6007 // Case 2 & 3: knot vector on one of the two edges
6008 // is set earlier (in another patch). We just have
6009 // to copy it for the opposing edge.
6010 else if ((v0 != notset) && (v1 == notset))
6011 {
6012 edge_to_knot[e1] = (df >= 0 ? -v0-1 : v0);
6013 }
6014 else if ((v0 == notset) && (v1 != notset))
6015 {
6016 edge_to_knot[e0] = (df >= 0 ? -v1-1 : v1);
6017 }
6018 }
6019 }
6020
6021 /* Verify correct assignment, make sure that corresponding edges
6022 within patch point to same knot vector. If not assign the lowest number.
6023
6024 We bound the while by GetNE() + 1 as this is probably the most unlucky
6025 case. +1 to finish without corrections. Note that this is a check and
6026 in general the initial assignment is correct. Then the while is performed
6027 only once. Only on very tricky meshes it might need corrections.*/
6028 int corrections;
6029 int passes = 0;
6030 do
6031 {
6032 corrections = 0;
6033 for (p = 0; p < GetNE(); p++)
6034 {
6035 GetElementEdges(p, edges, oedge);
6036 for (j = 0; j < edge1.Size(); j++)
6037 {
6038 e0 = edges[edge0[j]];
6039 e1 = edges[edge1[j]];
6040 v0 = edge_to_knot[e0];
6041 v1 = edge_to_knot[e1];
6042 v0 = ( v0 >= 0 ? v0 : -v0-1);
6043 v1 = ( v1 >= 0 ? v1 : -v1-1);
6044 if (v0 != v1)
6045 {
6046 corrections++;
6047 if (v0 < v1)
6048 {
6049 edge_to_knot[e1] = (oedge[edge1[j]] >= 0 ? v0 : -v0-1);
6050 }
6051 else if (v1 < v0)
6052 {
6053 edge_to_knot[e0] = (oedge[edge0[j]] >= 0 ? v1 : -v1-1);
6054 }
6055 }
6056 }
6057 }
6058
6059 passes++;
6060 }
6061 while (corrections > 0 && passes < GetNE() + 1);
6062
6063 // Check the validity of corrections applied
6064 if (corrections > 0)
6065 {
6066 mfem::err<<"Edge_to_knot mapping potentially incorrect"<<endl;
6067 mfem::err<<" passes = "<<passes<<endl;
6068 mfem::err<<" corrections = "<<corrections<<endl;
6069 }
6070
6071 /* Renumber knotvectors, such that:
6072 -- numbering is consecutive
6073 -- starts at zero */
6075 cnt = 0;
6076 for (j = 0; j < NumOfEdges; j++)
6077 {
6078 k = edge_to_knot[j];
6079 cnt[(k >= 0 ? k : -k-1)]++;
6080 }
6081
6082 k = 0;
6083 for (j = 0; j < cnt.Size(); j++)
6084 {
6085 cnt[j] = (cnt[j] > 0 ? k++ : -1);
6086 }
6087
6088 for (j = 0; j < NumOfEdges; j++)
6089 {
6090 k = edge_to_knot[j];
6091 edge_to_knot[j] = (k >= 0 ? cnt[k]:-cnt[-k-1]-1);
6092 }
6093
6094 // Print knot to edge mapping
6095 mfem::out<<"Generated edge to knot mapping:"<<endl;
6096 for (j = 0; j < NumOfEdges; j++)
6097 {
6098 int *v = edge_vertex->GetRow(j);
6099 k = edge_to_knot[j];
6100
6101 v0 = v[0];
6102 v1 = v[1];
6103 if (k < 0)
6104 {
6105 v[0] = v1;
6106 v[1] = v0;
6107 }
6108 mfem::out<<(k >= 0 ? k:-k-1)<<" "<< v[0] <<" "<<v[1]<<endl;
6109 }
6110
6111 // Terminate here upon failure after printing to have an idea of edge_to_knot.
6112 if (corrections > 0 ) {mfem_error("Mesh::LoadPatchTopo");}
6113 }
6114}
6115
6117{
6118 if (p.Size() >= v.Size())
6119 {
6120 for (int d = 0; d < v.Size(); d++)
6121 {
6122 v(d) = p(d);
6123 }
6124 }
6125 else
6126 {
6127 int d;
6128 for (d = 0; d < p.Size(); d++)
6129 {
6130 v(d) = p(d);
6131 }
6132 for ( ; d < v.Size(); d++)
6133 {
6134 v(d) = 0.0;
6135 }
6136 }
6137}
6138
6140{
6141 if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
6142 {
6143 const int newSpaceDim = nodes.FESpace()->GetVDim();
6145 nodes.ProjectCoefficient(xyz);
6146 }
6147 else
6148 {
6149 nodes = *Nodes;
6150 }
6151}
6152
6154{
6155 GridFunction *nodes = new GridFunction(nfes);
6156 SetNodalGridFunction(nodes, true);
6157}
6158
6160{
6161 if (Nodes)
6162 {
6164 if (dynamic_cast<const H1_FECollection*>(fec)
6165 || dynamic_cast<const L2_FECollection*>(fec))
6166 {
6167 return;
6168 }
6169 else // Mesh using a legacy FE_Collection
6170 {
6171 const int order = GetNodalFESpace()->GetElementOrder(0);
6172 if (NURBSext)
6173 {
6174#ifndef MFEM_USE_MPI
6175 const bool warn = true;
6176#else
6177 ParMesh *pmesh = dynamic_cast<ParMesh*>(this);
6178 const bool warn = !pmesh || pmesh->GetMyRank() == 0;
6179#endif
6180 if (warn)
6181 {
6182 MFEM_WARNING("converting NURBS mesh to order " << order <<
6183 " H1-continuous mesh!\n "
6184 "If this is the desired behavior, you can silence"
6185 " this warning by converting\n "
6186 "the NURBS mesh to high-order mesh in advance by"
6187 " calling the method\n "
6188 "Mesh::SetCurvature().");
6189 }
6190 }
6191 SetCurvature(order, false, -1, Ordering::byVDIM);
6192 }
6193 }
6194 else // First order H1 mesh
6195 {
6196 SetCurvature(1, false, -1, Ordering::byVDIM);
6197 }
6198}
6199
6200void Mesh::SetNodalGridFunction(GridFunction *nodes, bool make_owner)
6201{
6202 GetNodes(*nodes);
6203 NewNodes(*nodes, make_owner);
6204}
6205
6207{
6208 return ((Nodes) ? Nodes->FESpace() : NULL);
6209}
6210
6211void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
6212{
6213 if (order <= 0)
6214 {
6215 delete Nodes;
6216 Nodes = nullptr;
6217 return;
6218 }
6219 space_dim = (space_dim == -1) ? spaceDim : space_dim;
6221 if (discont)
6222 {
6223 const int type = 1; // Gauss-Lobatto points
6224 nfec = new L2_FECollection(order, Dim, type);
6225 }
6226 else
6227 {
6228 nfec = new H1_FECollection(order, Dim);
6229 }
6230 FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
6231 ordering);
6232 SetNodalFESpace(nfes);
6233 Nodes->MakeOwner(nfec);
6234}
6235
6237{
6238 MFEM_ASSERT(nodes != NULL, "");
6239 for (int i = 0; i < spaceDim; i++)
6240 {
6241 Vector vert_val;
6242 nodes->GetNodalValues(vert_val, i+1);
6243 for (int j = 0; j < NumOfVertices; j++)
6244 {
6245 vertices[j](i) = vert_val(j);
6246 }
6247 }
6248}
6249
6251{
6252 switch (Dim)
6253 {
6254 case 1: return GetNV();
6255 case 2: return GetNEdges();
6256 case 3: return GetNFaces();
6257 }
6258 return 0;
6259}
6260
6262{
6263 return faces_info.Size();
6264}
6265
6267{
6268 const bool isInt = type==FaceType::Interior;
6269 int &nf = isInt ? nbInteriorFaces : nbBoundaryFaces;
6270 if (nf<0)
6271 {
6272 nf = 0;
6273 for (int f = 0; f < GetNumFacesWithGhost(); ++f)
6274 {
6276 if (face.IsOfFaceType(type))
6277 {
6278 if (face.IsNonconformingCoarse())
6279 {
6280 // We don't count nonconforming coarse faces.
6281 continue;
6282 }
6283 nf++;
6284 }
6285 }
6286 }
6287 return nf;
6288}
6289
6290#if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
6291static const char *fixed_or_not[] = { "fixed", "NOT FIXED" };
6292#endif
6293
6295{
6296 int i, j, k, wo = 0, fo = 0;
6297 real_t *v[4];
6298
6299 if (Dim == 2 && spaceDim == 2)
6300 {
6301 DenseMatrix J(2, 2);
6302
6303 for (i = 0; i < NumOfElements; i++)
6304 {
6305 int *vi = elements[i]->GetVertices();
6306 if (Nodes == NULL)
6307 {
6308 for (j = 0; j < 3; j++)
6309 {
6310 v[j] = vertices[vi[j]]();
6311 }
6312 for (j = 0; j < 2; j++)
6313 for (k = 0; k < 2; k++)
6314 {
6315 J(j, k) = v[j+1][k] - v[0][k];
6316 }
6317 }
6318 else
6319 {
6320 // only check the Jacobian at the center of the element
6321 GetElementJacobian(i, J);
6322 }
6323 if (J.Det() < 0.0)
6324 {
6325 if (fix_it)
6326 {
6327 switch (GetElementType(i))
6328 {
6329 case Element::TRIANGLE:
6330 mfem::Swap(vi[0], vi[1]);
6331 break;
6333 mfem::Swap(vi[1], vi[3]);
6334 break;
6335 default:
6336 MFEM_ABORT("Invalid 2D element type \""
6337 << GetElementType(i) << "\"");
6338 break;
6339 }
6340 fo++;
6341 }
6342 wo++;
6343 }
6344 }
6345 }
6346
6347 if (Dim == 3)
6348 {
6349 DenseMatrix J(3, 3);
6350
6351 for (i = 0; i < NumOfElements; i++)
6352 {
6353 int *vi = elements[i]->GetVertices();
6354 switch (GetElementType(i))
6355 {
6357 if (Nodes == NULL)
6358 {
6359 for (j = 0; j < 4; j++)
6360 {
6361 v[j] = vertices[vi[j]]();
6362 }
6363 for (j = 0; j < 3; j++)
6364 for (k = 0; k < 3; k++)
6365 {
6366 J(j, k) = v[j+1][k] - v[0][k];
6367 }
6368 }
6369 else
6370 {
6371 // only check the Jacobian at the center of the element
6372 GetElementJacobian(i, J);
6373 }
6374 if (J.Det() < 0.0)
6375 {
6376 wo++;
6377 if (fix_it)
6378 {
6379 mfem::Swap(vi[0], vi[1]);
6380 fo++;
6381 }
6382 }
6383 break;
6384
6385 case Element::WEDGE:
6386 // only check the Jacobian at the center of the element
6387 GetElementJacobian(i, J);
6388 if (J.Det() < 0.0)
6389 {
6390 wo++;
6391 if (fix_it)
6392 {
6393 // how?
6394 }
6395 }
6396 break;
6397
6398 case Element::PYRAMID:
6399 // only check the Jacobian at the center of the element
6400 GetElementJacobian(i, J);
6401 if (J.Det() < 0.0)
6402 {
6403 wo++;
6404 if (fix_it)
6405 {
6406 // how?
6407 }
6408 }
6409 break;
6410
6412 // only check the Jacobian at the center of the element
6413 GetElementJacobian(i, J);
6414 if (J.Det() < 0.0)
6415 {
6416 wo++;
6417 if (fix_it)
6418 {
6419 // how?
6420 }
6421 }
6422 break;
6423
6424 default:
6425 MFEM_ABORT("Invalid 3D element type \""
6426 << GetElementType(i) << "\"");
6427 break;
6428 }
6429 }
6430 }
6431#if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
6432 if (wo > 0)
6433 {
6434 mfem::out << "Elements with wrong orientation: " << wo << " / "
6435 << NumOfElements << " (" << fixed_or_not[(wo == fo) ? 0 : 1]
6436 << ")" << endl;
6437 }
6438#else
6439 MFEM_CONTRACT_VAR(fo);
6440#endif
6441 return wo;
6442}
6443
6444int Mesh::GetTriOrientation(const int *base, const int *test)
6445{
6446 // Static method.
6447 // This function computes the index 'j' of the permutation that transforms
6448 // test into base: test[tri_orientation[j][i]]=base[i].
6449 // tri_orientation = Geometry::Constants<Geometry::TRIANGLE>::Orient
6450 int orient;
6451
6452 if (test[0] == base[0])
6453 if (test[1] == base[1])
6454 {
6455 orient = 0; // (0, 1, 2)
6456 }
6457 else
6458 {
6459 orient = 5; // (0, 2, 1)
6460 }
6461 else if (test[0] == base[1])
6462 if (test[1] == base[0])
6463 {
6464 orient = 1; // (1, 0, 2)
6465 }
6466 else
6467 {
6468 orient = 2; // (1, 2, 0)
6469 }
6470 else // test[0] == base[2]
6471 if (test[1] == base[0])
6472 {
6473 orient = 4; // (2, 0, 1)
6474 }
6475 else
6476 {
6477 orient = 3; // (2, 1, 0)
6478 }
6479
6480#ifdef MFEM_DEBUG
6481 const int *aor = tri_t::Orient[orient];
6482 for (int j = 0; j < 3; j++)
6483 if (test[aor[j]] != base[j])
6484 {
6485 mfem::err << "Mesh::GetTriOrientation(...)" << endl;
6486 mfem::err << " base = [";
6487 for (int k = 0; k < 3; k++)
6488 {
6489 mfem::err << " " << base[k];
6490 }
6491 mfem::err << " ]\n test = [";
6492 for (int k = 0; k < 3; k++)
6493 {
6494 mfem::err << " " << test[k];
6495 }
6496 mfem::err << " ]" << endl;
6497 mfem_error();
6498 }
6499#endif
6500
6501 return orient;
6502}
6503
6504int Mesh::ComposeTriOrientations(int ori_a_b, int ori_b_c)
6505{
6506 // Static method.
6507 // Given three, possibly different, configurations of triangular face
6508 // vertices: va, vb, and vc. This function returns the relative orientation
6509 // GetTriOrientation(va, vc) by composing previously computed orientations
6510 // ori_a_b = GetTriOrientation(va, vb) and
6511 // ori_b_c = GetTriOrientation(vb, vc) without accessing the vertices.
6512
6513 const int oo[6][6] =
6514 {
6515 {0, 1, 2, 3, 4, 5},
6516 {1, 0, 5, 4, 3, 2},
6517 {2, 3, 4, 5, 0, 1},
6518 {3, 2, 1, 0, 5, 4},
6519 {4, 5, 0, 1, 2, 3},
6520 {5, 4, 3, 2, 1, 0}
6521 };
6522
6523 int ori_a_c = oo[ori_a_b][ori_b_c];
6524 return ori_a_c;
6525}
6526
6528{
6529 const int inv_ori[6] = {0, 1, 4, 3, 2, 5};
6530 return inv_ori[ori];
6531}
6532
6533int Mesh::GetQuadOrientation(const int *base, const int *test)
6534{
6535 int i;
6536
6537 for (i = 0; i < 4; i++)
6538 if (test[i] == base[0])
6539 {
6540 break;
6541 }
6542
6543#ifdef MFEM_DEBUG
6544 int orient;
6545 if (test[(i+1)%4] == base[1])
6546 {
6547 orient = 2*i;
6548 }
6549 else
6550 {
6551 orient = 2*i+1;
6552 }
6553 const int *aor = quad_t::Orient[orient];
6554 for (int j = 0; j < 4; j++)
6555 if (test[aor[j]] != base[j])
6556 {
6557 mfem::err << "Mesh::GetQuadOrientation(...)" << endl;
6558 mfem::err << " base = [";
6559 for (int k = 0; k < 4; k++)
6560 {
6561 mfem::err << " " << base[k];
6562 }
6563 mfem::err << " ]\n test = [";
6564 for (int k = 0; k < 4; k++)
6565 {
6566 mfem::err << " " << test[k];
6567 }
6568 mfem::err << " ]" << endl;
6569 mfem_error();
6570 }
6571#endif
6572
6573 if (test[(i+1)%4] == base[1])
6574 {
6575 return 2*i;
6576 }
6577
6578 return 2*i+1;
6579}
6580
6581int Mesh::ComposeQuadOrientations(int ori_a_b, int ori_b_c)
6582{
6583 // Static method.
6584 // Given three, possibly different, configurations of quadrilateral face
6585 // vertices: va, vb, and vc. This function returns the relative orientation
6586 // GetQuadOrientation(va, vc) by composing previously computed orientations
6587 // ori_a_b = GetQuadOrientation(va, vb) and
6588 // ori_b_c = GetQuadOrientation(vb, vc) without accessing the vertices.
6589
6590 const int oo[8][8] =
6591 {
6592 {0, 1, 2, 3, 4, 5, 6, 7},
6593 {1, 0, 3, 2, 5, 4, 7, 6},
6594 {2, 7, 4, 1, 6, 3, 0, 5},
6595 {3, 6, 5, 0, 7, 2, 1, 4},
6596 {4, 5, 6, 7, 0, 1, 2, 3},
6597 {5, 4, 7, 6, 1, 0, 3, 2},
6598 {6, 3, 0, 5, 2, 7, 4, 1},
6599 {7, 2, 1, 4, 3, 6, 5, 0}
6600 };
6601
6602 int ori_a_c = oo[ori_a_b][ori_b_c];
6603 return ori_a_c;
6604}
6605
6607{
6608 const int inv_ori[8] = {0, 1, 6, 3, 4, 5, 2, 7};
6609 return inv_ori[ori];
6610}
6611
6612int Mesh::GetTetOrientation(const int *base, const int *test)
6613{
6614 // Static method.
6615 // This function computes the index 'j' of the permutation that transforms
6616 // test into base: test[tet_orientation[j][i]]=base[i].
6617 // tet_orientation = Geometry::Constants<Geometry::TETRAHEDRON>::Orient
6618 int orient;
6619
6620 if (test[0] == base[0])
6621 if (test[1] == base[1])
6622 if (test[2] == base[2])
6623 {
6624 orient = 0; // (0, 1, 2, 3)
6625 }
6626 else
6627 {
6628 orient = 1; // (0, 1, 3, 2)
6629 }
6630 else if (test[2] == base[1])
6631 if (test[3] == base[2])
6632 {
6633 orient = 2; // (0, 2, 3, 1)
6634 }
6635 else
6636 {
6637 orient = 3; // (0, 2, 1, 3)
6638 }
6639 else // test[3] == base[1]
6640 if (test[1] == base[2])
6641 {
6642 orient = 4; // (0, 3, 1, 2)
6643 }
6644 else
6645 {
6646 orient = 5; // (0, 3, 2, 1)
6647 }
6648 else if (test[1] == base[0])
6649 if (test[2] == base[1])
6650 if (test[0] == base[2])
6651 {
6652 orient = 6; // (1, 2, 0, 3)
6653 }
6654 else
6655 {
6656 orient = 7; // (1, 2, 3, 0)
6657 }
6658 else if (test[3] == base[1])
6659 if (test[2] == base[2])
6660 {
6661 orient = 8; // (1, 3, 2, 0)
6662 }
6663 else
6664 {
6665 orient = 9; // (1, 3, 0, 2)
6666 }
6667 else // test[0] == base[1]
6668 if (test[3] == base[2])
6669 {
6670 orient = 10; // (1, 0, 3, 2)
6671 }
6672 else
6673 {
6674 orient = 11; // (1, 0, 2, 3)
6675 }
6676 else if (test[2] == base[0])
6677 if (test[3] == base[1])
6678 if (test[0] == base[2])
6679 {
6680 orient = 12; // (2, 3, 0, 1)
6681 }
6682 else
6683 {
6684 orient = 13; // (2, 3, 1, 0)
6685 }
6686 else if (test[0] == base[1])
6687 if (test[1] == base[2])
6688 {
6689 orient = 14; // (2, 0, 1, 3)
6690 }
6691 else
6692 {
6693 orient = 15; // (2, 0, 3, 1)
6694 }
6695 else // test[1] == base[1]
6696 if (test[3] == base[2])
6697 {
6698 orient = 16; // (2, 1, 3, 0)
6699 }
6700 else
6701 {
6702 orient = 17; // (2, 1, 0, 3)
6703 }
6704 else // (test[3] == base[0])
6705 if (test[0] == base[1])
6706 if (test[2] == base[2])
6707 {
6708 orient = 18; // (3, 0, 2, 1)
6709 }
6710 else
6711 {
6712 orient = 19; // (3, 0, 1, 2)
6713 }
6714 else if (test[1] == base[1])
6715 if (test[0] == base[2])
6716 {
6717 orient = 20; // (3, 1, 0, 2)
6718 }
6719 else
6720 {
6721 orient = 21; // (3, 1, 2, 0)
6722 }
6723 else // test[2] == base[1]
6724 if (test[1] == base[2])
6725 {
6726 orient = 22; // (3, 2, 1, 0)
6727 }
6728 else
6729 {
6730 orient = 23; // (3, 2, 0, 1)
6731 }
6732
6733#ifdef MFEM_DEBUG
6734 const int *aor = tet_t::Orient[orient];
6735 for (int j = 0; j < 4; j++)
6736 if (test[aor[j]] != base[j])
6737 {
6738 mfem_error("Mesh::GetTetOrientation(...)");
6739 }
6740#endif
6741
6742 return orient;
6743}
6744
6746{
6747 int wo = 0; // count wrong orientations
6748
6749 if (Dim == 2)
6750 {
6751 if (el_to_edge == NULL) // edges were not generated
6752 {
6753 el_to_edge = new Table;
6755 GenerateFaces(); // 'Faces' in 2D refers to the edges
6756 }
6757 for (int i = 0; i < NumOfBdrElements; i++)
6758 {
6759 if (faces_info[be_to_face[i]].Elem2No < 0) // boundary face
6760 {
6761 int *bv = boundary[i]->GetVertices();
6762 int *fv = faces[be_to_face[i]]->GetVertices();
6763 if (bv[0] != fv[0])
6764 {
6765 if (fix_it)
6766 {
6767 mfem::Swap<int>(bv[0], bv[1]);
6768 }
6769 wo++;
6770 }
6771 }
6772 }
6773 }
6774
6775 if (Dim == 3)
6776 {
6777 for (int i = 0; i < NumOfBdrElements; i++)
6778 {
6779 const int fi = be_to_face[i];
6780
6781 if (faces_info[fi].Elem2No >= 0) { continue; }
6782
6783 // boundary face
6784 int *bv = boundary[i]->GetVertices();
6785 // Make sure the 'faces' are generated:
6786 MFEM_ASSERT(fi < faces.Size(), "internal error");
6787 const int *fv = faces[fi]->GetVertices();
6788 int orientation; // orientation of the bdr. elem. w.r.t. the
6789 // corresponding face element (that's the base)
6790 const Element::Type bdr_type = GetBdrElementType(i);
6791 switch (bdr_type)
6792 {
6793 case Element::TRIANGLE:
6794 {
6795 orientation = GetTriOrientation(fv, bv);
6796 break;
6797 }
6799 {
6800 orientation = GetQuadOrientation(fv, bv);
6801 break;
6802 }
6803 default:
6804 MFEM_ABORT("Invalid 2D boundary element type \""
6805 << bdr_type << "\"");
6806 orientation = 0; // suppress a warning
6807 break;
6808 }
6809
6810 if (orientation % 2 == 0) { continue; }
6811 wo++;
6812 if (!fix_it) { continue; }
6813
6814 switch (bdr_type)
6815 {
6816 case Element::TRIANGLE:
6817 {
6818 // swap vertices 0 and 1 so that we don't change the marked edge:
6819 // (0,1,2) -> (1,0,2)
6820 mfem::Swap(bv[0], bv[1]);
6821 if (bel_to_edge)
6822 {
6823 int *be = bel_to_edge->GetRow(i);
6824 mfem::Swap(be[1], be[2]);
6825 }
6826 break;
6827 }
6829 {
6830 mfem::Swap(bv[0], bv[2]);
6831 if (bel_to_edge)
6832 {
6833 int *be = bel_to_edge->GetRow(i);
6834 mfem::Swap(be[0], be[1]);
6835 mfem::Swap(be[2], be[3]);
6836 }
6837 break;
6838 }
6839 default: // unreachable
6840 break;
6841 }
6842 }
6843 }
6844 // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
6845#ifdef MFEM_DEBUG
6846 if (wo > 0)
6847 {
6848 mfem::out << "Boundary elements with wrong orientation: " << wo << " / "
6849 << NumOfBdrElements << " (" << fixed_or_not[fix_it ? 0 : 1]
6850 << ")" << endl;
6851 }
6852#endif
6853 return wo;
6854}
6855
6857 const IntegrationPoint &ip)
6858{
6859 IntegrationPoint fip = ip;
6860 if (geom == Geometry::POINT)
6861 {
6862 return fip;
6863 }
6864 else if (geom == Geometry::SEGMENT)
6865 {
6866 MFEM_ASSERT(o >= 0 && o < 2, "Invalid orientation for Geometry::SEGMENT!");
6867 if (o == 0)
6868 {
6869 fip.x = ip.x;
6870 }
6871 else if (o == 1)
6872 {
6873 fip.x = 1.0 - ip.x;
6874 }
6875 }
6876 else if (geom == Geometry::TRIANGLE)
6877 {
6878 MFEM_ASSERT(o >= 0 && o < 6, "Invalid orientation for Geometry::TRIANGLE!");
6879 if (o == 0) // 0, 1, 2
6880 {
6881 fip.x = ip.x;
6882 fip.y = ip.y;
6883 }
6884 else if (o == 5) // 0, 2, 1
6885 {
6886 fip.x = ip.y;
6887 fip.y = ip.x;
6888 }
6889 else if (o == 2) // 1, 2, 0
6890 {
6891 fip.x = 1.0 - ip.x - ip.y;
6892 fip.y = ip.x;
6893 }
6894 else if (o == 1) // 1, 0, 2
6895 {
6896 fip.x = 1.0 - ip.x - ip.y;
6897 fip.y = ip.y;
6898 }
6899 else if (o == 4) // 2, 0, 1
6900 {
6901 fip.x = ip.y;
6902 fip.y = 1.0 - ip.x - ip.y;
6903 }
6904 else if (o == 3) // 2, 1, 0
6905 {
6906 fip.x = ip.x;
6907 fip.y = 1.0 - ip.x - ip.y;
6908 }
6909 }
6910 else if (geom == Geometry::SQUARE)
6911 {
6912 MFEM_ASSERT(o >= 0 && o < 8, "Invalid orientation for Geometry::SQUARE!");
6913 if (o == 0) // 0, 1, 2, 3
6914 {
6915 fip.x = ip.x;
6916 fip.y = ip.y;
6917 }
6918 else if (o == 1) // 0, 3, 2, 1
6919 {
6920 fip.x = ip.y;
6921 fip.y = ip.x;
6922 }
6923 else if (o == 2) // 1, 2, 3, 0
6924 {
6925 fip.x = ip.y;
6926 fip.y = 1.0 - ip.x;
6927 }
6928 else if (o == 3) // 1, 0, 3, 2
6929 {
6930 fip.x = 1.0 - ip.x;
6931 fip.y = ip.y;
6932 }
6933 else if (o == 4) // 2, 3, 0, 1
6934 {
6935 fip.x = 1.0 - ip.x;
6936 fip.y = 1.0 - ip.y;
6937 }
6938 else if (o == 5) // 2, 1, 0, 3
6939 {
6940 fip.x = 1.0 - ip.y;
6941 fip.y = 1.0 - ip.x;
6942 }
6943 else if (o == 6) // 3, 0, 1, 2
6944 {
6945 fip.x = 1.0 - ip.y;
6946 fip.y = ip.x;
6947 }
6948 else if (o == 7) // 3, 2, 1, 0
6949 {
6950 fip.x = ip.x;
6951 fip.y = 1.0 - ip.y;
6952 }
6953 }
6954 else
6955 {
6956 MFEM_ABORT("Unsupported face geometry for TransformBdrElementToFace!");
6957 }
6958 return fip;
6959}
6960
6962{
6963 MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
6964 int num_geoms = 0;
6965 for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
6966 {
6967 if (HasGeometry(Geometry::Type(g))) { num_geoms++; }
6968 }
6969 return num_geoms;
6970}
6971
6973{
6974 MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
6975 el_geoms.SetSize(0);
6976 for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
6977 {
6979 {
6980 el_geoms.Append(Geometry::Type(g));
6981 }
6982 }
6983}
6984
6985void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const
6986{
6987 if (el_to_edge)
6988 {
6989 el_to_edge->GetRow(i, edges);
6990 }
6991 else
6992 {
6993 mfem_error("Mesh::GetElementEdges(...) element to edge table "
6994 "is not generated.");
6995 }
6996
6997 const int *v = elements[i]->GetVertices();
6998 const int ne = elements[i]->GetNEdges();
6999 cor.SetSize(ne);
7000 for (int j = 0; j < ne; j++)
7001 {
7002 const int *e = elements[i]->GetEdgeVertices(j);
7003 cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
7004 }
7005}
7006
7007void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const
7008{
7009 if (Dim == 2)
7010 {
7011 edges.SetSize(1);
7012 cor.SetSize(1);
7013 edges[0] = be_to_face[i];
7014 const int *v = boundary[i]->GetVertices();
7015 cor[0] = (v[0] < v[1]) ? (1) : (-1);
7016 }
7017 else if (Dim == 3)
7018 {
7019 if (bel_to_edge)
7020 {
7021 bel_to_edge->GetRow(i, edges);
7022 }
7023 else
7024 {
7025 mfem_error("Mesh::GetBdrElementEdges(...)");
7026 }
7027
7028 const int *v = boundary[i]->GetVertices();
7029 const int ne = boundary[i]->GetNEdges();
7030 cor.SetSize(ne);
7031 for (int j = 0; j < ne; j++)
7032 {
7033 const int *e = boundary[i]->GetEdgeVertices(j);
7034 cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
7035 }
7036 }
7037}
7038
7039void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const
7040{
7041 if (Dim == 2)
7042 {
7043 edges.SetSize(1);
7044 edges[0] = i;
7045 o.SetSize(1);
7046 const int *v = faces[i]->GetVertices();
7047 o[0] = (v[0] < v[1]) ? (1) : (-1);
7048 }
7049
7050 if (Dim != 3)
7051 {
7052 return;
7053 }
7054
7055 GetFaceEdgeTable(); // generate face_edge Table (if not generated)
7056
7057 face_edge->GetRow(i, edges);
7058
7059 const int *v = faces[i]->GetVertices();
7060 const int ne = faces[i]->GetNEdges();
7061 o.SetSize(ne);
7062 for (int j = 0; j < ne; j++)
7063 {
7064 const int *e = faces[i]->GetEdgeVertices(j);
7065 o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
7066 }
7067}
7068
7069void Mesh::GetEdgeVertices(int i, Array<int> &vert) const
7070{
7071 // the two vertices are sorted: vert[0] < vert[1]
7072 // this is consistent with the global edge orientation
7073 // generate edge_vertex Table (if not generated)
7074 if (!edge_vertex) { GetEdgeVertexTable(); }
7075 edge_vertex->GetRow(i, vert);
7076}
7077
7079{
7080 if (face_edge)
7081 {
7082 return face_edge;
7083 }
7084
7085 if (Dim != 3)
7086 {
7087 return NULL;
7088 }
7089
7090#ifdef MFEM_DEBUG
7091 if (faces.Size() != NumOfFaces)
7092 {
7093 mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!");
7094 }
7095#endif
7096
7097 DSTable v_to_v(NumOfVertices);
7098 GetVertexToVertexTable(v_to_v);
7099
7100 face_edge = new Table;
7102
7103 return (face_edge);
7104}
7105
7107{
7108 if (edge_vertex)
7109 {
7110 return edge_vertex;
7111 }
7112
7113 DSTable v_to_v(NumOfVertices);
7114 GetVertexToVertexTable(v_to_v);
7115
7116 int nedges = v_to_v.NumberOfEntries();
7117 edge_vertex = new Table(nedges, 2);
7118 for (int i = 0; i < NumOfVertices; i++)
7119 {
7120 for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
7121 {
7122 int j = it.Index();
7123 edge_vertex->Push(j, i);
7124 edge_vertex->Push(j, it.Column());
7125 }
7126 }
7128
7129 return edge_vertex;
7130}
7131
7133{
7134 int i, j, nv, *v;
7135
7136 Table *vert_elem = new Table;
7137
7138 vert_elem->MakeI(NumOfVertices);
7139
7140 for (i = 0; i < NumOfElements; i++)
7141 {
7142 nv = elements[i]->GetNVertices();
7143 v = elements[i]->GetVertices();
7144 for (j = 0; j < nv; j++)
7145 {
7146 vert_elem->AddAColumnInRow(v[j]);
7147 }
7148 }
7149
7150 vert_elem->MakeJ();
7151
7152 for (i = 0; i < NumOfElements; i++)
7153 {
7154 nv = elements[i]->GetNVertices();
7155 v = elements[i]->GetVertices();
7156 for (j = 0; j < nv; j++)
7157 {
7158 vert_elem->AddConnection(v[j], i);
7159 }
7160 }
7161
7162 vert_elem->ShiftUpI();
7163
7164 return vert_elem;
7165}
7166
7168{
7169 Table *face_elem = new Table;
7170
7171 face_elem->MakeI(faces_info.Size());
7172
7173 for (int i = 0; i < faces_info.Size(); i++)
7174 {
7175 if (faces_info[i].Elem2No >= 0)
7176 {
7177 face_elem->AddColumnsInRow(i, 2);
7178 }
7179 else
7180 {
7181 face_elem->AddAColumnInRow(i);
7182 }
7183 }
7184
7185 face_elem->MakeJ();
7186
7187 for (int i = 0; i < faces_info.Size(); i++)
7188 {
7189 face_elem->AddConnection(i, faces_info[i].Elem1No);
7190 if (faces_info[i].Elem2No >= 0)
7191 {
7192 face_elem->AddConnection(i, faces_info[i].Elem2No);
7193 }
7194 }
7195
7196 face_elem->ShiftUpI();
7197
7198 return face_elem;
7199}
7200
7201void Mesh::GetElementFaces(int i, Array<int> &el_faces, Array<int> &ori) const
7202{
7203 MFEM_VERIFY(el_to_face != NULL, "el_to_face not generated");
7204
7205 el_to_face->GetRow(i, el_faces);
7206
7207 int n = el_faces.Size();
7208 ori.SetSize(n);
7209
7210 for (int j = 0; j < n; j++)
7211 {
7212 if (faces_info[el_faces[j]].Elem1No == i)
7213 {
7214 ori[j] = faces_info[el_faces[j]].Elem1Inf % 64;
7215 }
7216 else
7217 {
7218 MFEM_ASSERT(faces_info[el_faces[j]].Elem2No == i, "internal error");
7219 ori[j] = faces_info[el_faces[j]].Elem2Inf % 64;
7220 }
7221 }
7222}
7223
7225{
7226 if (face_to_elem == NULL)
7227 {
7229 }
7230
7231 Array<int> elem_faces;
7232 Array<int> ori;
7233 GetElementFaces(elem, elem_faces, ori);
7234
7235 Array<int> nghb;
7236 for (auto f : elem_faces)
7237 {
7238 Array<int> row;
7239 face_to_elem->GetRow(f, row);
7240 for (auto r : row)
7241 {
7242 nghb.Append(r);
7243 }
7244 }
7245
7246 nghb.Sort();
7247 nghb.Unique();
7248
7249 return nghb;
7250}
7251
7252void Mesh::GetBdrElementFace(int i, int *f, int *o) const
7253{
7255
7256 const int *fv = (Dim > 1) ? faces[*f]->GetVertices() : NULL;
7257 const int *bv = boundary[i]->GetVertices();
7258
7259 // find the orientation of the bdr. elem. w.r.t.
7260 // the corresponding face element (that's the base)
7261 switch (GetBdrElementGeometry(i))
7262 {
7263 case Geometry::POINT: *o = 0; break;
7264 case Geometry::SEGMENT: *o = (fv[0] == bv[0]) ? 0 : 1; break;
7265 case Geometry::TRIANGLE: *o = GetTriOrientation(fv, bv); break;
7266 case Geometry::SQUARE: *o = GetQuadOrientation(fv, bv); break;
7267 default: MFEM_ABORT("invalid geometry");
7268 }
7269}
7270
7271void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
7272{
7273 int fid = GetBdrElementFaceIndex(bdr_el);
7274
7275 const FaceInfo &fi = faces_info[fid];
7276 MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
7277
7278 const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
7279 const int *bv = boundary[bdr_el]->GetVertices();
7280 int ori;
7281 switch (GetBdrElementGeometry(bdr_el))
7282 {
7283 case Geometry::POINT: ori = 0; break;
7284 case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
7285 case Geometry::TRIANGLE: ori = GetTriOrientation(fv, bv); break;
7286 case Geometry::SQUARE: ori = GetQuadOrientation(fv, bv); break;
7287 default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
7288 }
7289 el = fi.Elem1No;
7290 info = fi.Elem1Inf + ori;
7291}
7292
7294 int bdr_el, int &el, int &info) const
7295{
7296 int fid = GetBdrElementFaceIndex(bdr_el);
7297
7298 const FaceInfo &fi = faces_info[fid];
7299 MFEM_ASSERT(fi.Elem1Inf % 64 == 0, "internal error"); // orientation == 0
7300
7301 const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
7302 const int *bv = boundary[bdr_el]->GetVertices();
7303 int ori;
7304 switch (GetBdrElementGeometry(bdr_el))
7305 {
7306 case Geometry::POINT: ori = 0; break;
7307 case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
7308 case Geometry::TRIANGLE: ori = GetTriOrientation(bv, fv); break;
7309 case Geometry::SQUARE: ori = GetQuadOrientation(bv, fv); break;
7310 default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
7311 }
7312 el = fi.Elem1No;
7313 info = fi.Elem1Inf + ori;
7314}
7315
7317{
7318 return elements[i]->GetType();
7319}
7320
7322{
7323 return boundary[i]->GetType();
7324}
7325
7326void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const
7327{
7328 int k, j, nv;
7329 const int *v;
7330
7331 v = elements[i]->GetVertices();
7332 nv = elements[i]->GetNVertices();
7333
7334 pointmat.SetSize(spaceDim, nv);
7335 for (k = 0; k < spaceDim; k++)
7336 {
7337 for (j = 0; j < nv; j++)
7338 {
7339 pointmat(k, j) = vertices[v[j]](k);
7340 }
7341 }
7342}
7343
7344void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const
7345{
7346 int k, j, nv;
7347 const int *v;
7348
7349 v = boundary[i]->GetVertices();
7350 nv = boundary[i]->GetNVertices();
7351
7352 pointmat.SetSize(spaceDim, nv);
7353 for (k = 0; k < spaceDim; k++)
7354 for (j = 0; j < nv; j++)
7355 {
7356 pointmat(k, j) = vertices[v[j]](k);
7357 }
7358}
7359
7360real_t Mesh::GetLength(int i, int j) const
7361{
7362 const real_t *vi = vertices[i]();
7363 const real_t *vj = vertices[j]();
7364 real_t length = 0.;
7365
7366 for (int k = 0; k < spaceDim; k++)
7367 {
7368 length += (vi[k]-vj[k])*(vi[k]-vj[k]);
7369 }
7370
7371 return sqrt(length);
7372}
7373
7374// static method
7376 const DSTable &v_to_v, Table &el_to_edge)
7377{
7378 el_to_edge.MakeI(elem_array.Size());
7379 for (int i = 0; i < elem_array.Size(); i++)
7380 {
7381 el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges());
7382 }
7383 el_to_edge.MakeJ();
7384 for (int i = 0; i < elem_array.Size(); i++)
7385 {
7386 const int *v = elem_array[i]->GetVertices();
7387 const int ne = elem_array[i]->GetNEdges();
7388 for (int j = 0; j < ne; j++)
7389 {
7390 const int *e = elem_array[i]->GetEdgeVertices(j);
7391 el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]]));
7392 }
7393 }
7395}
7396
7398{
7399 if (edge_vertex)
7400 {
7401 for (int i = 0; i < edge_vertex->Size(); i++)
7402 {
7403 const int *v = edge_vertex->GetRow(i);
7404 v_to_v.Push(v[0], v[1]);
7405 }
7406 }
7407 else
7408 {
7409 for (int i = 0; i < NumOfElements; i++)
7410 {
7411 const int *v = elements[i]->GetVertices();
7412 const int ne = elements[i]->GetNEdges();
7413 for (int j = 0; j < ne; j++)
7414 {
7415 const int *e = elements[i]->GetEdgeVertices(j);
7416 v_to_v.Push(v[e[0]], v[e[1]]);
7417 }
7418 }
7419 }
7420}
7421
7423{
7424 int i, NumberOfEdges;
7425
7426 DSTable v_to_v(NumOfVertices);
7427 GetVertexToVertexTable(v_to_v);
7428
7429 NumberOfEdges = v_to_v.NumberOfEntries();
7430
7431 // Fill the element to edge table
7432 GetElementArrayEdgeTable(elements, v_to_v, e_to_f);
7433
7434 if (Dim == 2)
7435 {
7436 // Initialize the indices for the boundary elements.
7438 for (i = 0; i < NumOfBdrElements; i++)
7439 {
7440 const int *v = boundary[i]->GetVertices();
7441 be_to_face[i] = v_to_v(v[0], v[1]);
7442 }
7443 }
7444 else if (Dim == 3)
7445 {
7446 if (bel_to_edge == NULL)
7447 {
7448 bel_to_edge = new Table;
7449 }
7451 }
7452 else
7453 {
7454 mfem_error("1D GetElementToEdgeTable is not yet implemented.");
7455 }
7456
7457 // Return the number of edges
7458 return NumberOfEdges;
7459}
7460
7462{
7463 if (el_to_el)
7464 {
7465 return *el_to_el;
7466 }
7467
7468 // Note that, for ParNCMeshes, faces_info will contain also the ghost faces
7469 MFEM_ASSERT(faces_info.Size() >= GetNumFaces(), "faces were not generated!");
7470
7471 Array<Connection> conn;
7472 conn.Reserve(2*faces_info.Size());
7473
7474 for (int i = 0; i < faces_info.Size(); i++)
7475 {
7476 const FaceInfo &fi = faces_info[i];
7477 if (fi.Elem2No >= 0)
7478 {
7479 conn.Append(Connection(fi.Elem1No, fi.Elem2No));
7480 conn.Append(Connection(fi.Elem2No, fi.Elem1No));
7481 }
7482 else if (fi.Elem2Inf >= 0)
7483 {
7484 int nbr_elem_idx = NumOfElements - 1 - fi.Elem2No;
7485 conn.Append(Connection(fi.Elem1No, nbr_elem_idx));
7486 conn.Append(Connection(nbr_elem_idx, fi.Elem1No));
7487 }
7488 }
7489
7490 conn.Sort();
7491 conn.Unique();
7492 el_to_el = new Table(NumOfElements, conn);
7493
7494 return *el_to_el;
7495}
7496
7498{
7499 if (el_to_face == NULL)
7500 {
7501 mfem_error("Mesh::ElementToFaceTable()");
7502 }
7503 return *el_to_face;
7504}
7505
7507{
7508 if (el_to_edge == NULL)
7509 {
7510 mfem_error("Mesh::ElementToEdgeTable()");
7511 }
7512 return *el_to_edge;
7513}
7514
7515void Mesh::AddPointFaceElement(int lf, int gf, int el)
7516{
7517 if (faces[gf] == NULL) // this will be elem1
7518 {
7519 faces[gf] = new Point(&gf);
7520 faces_info[gf].Elem1No = el;
7521 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
7522 faces_info[gf].Elem2No = -1; // in case there's no other side
7523 faces_info[gf].Elem2Inf = -1; // face is not shared
7524 }
7525 else // this will be elem2
7526 {
7527 /* WARNING: Without the following check the mesh faces_info data structure
7528 may contain unreliable data. Normally, the order in which elements are
7529 processed could swap which elements appear as Elem1No and Elem2No. In
7530 branched meshes, where more than two elements can meet at a given node,
7531 the indices stored in Elem1No and Elem2No will be the first and last,
7532 respectively, elements found which touch a given node. This can lead to
7533 inconsistencies in any algorithms which rely on this data structure. To
7534 properly support branched meshes this data structure should be extended
7535 to support multiple elements per face. */
7536 /*
7537 MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
7538 "Interior point found connecting 1D elements "
7539 << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
7540 << " and " << el << ".");
7541 */
7542 faces_info[gf].Elem2No = el;
7543 faces_info[gf].Elem2Inf = 64 * lf + 1;
7544 }
7545}
7546
7547void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
7548{
7549 if (faces[gf] == NULL) // this will be elem1
7550 {
7551 faces[gf] = new Segment(v0, v1);
7552 faces_info[gf].Elem1No = el;
7553 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
7554 faces_info[gf].Elem2No = -1; // in case there's no other side
7555 faces_info[gf].Elem2Inf = -1; // face is not shared
7556 }
7557 else // this will be elem2
7558 {
7559 MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
7560 "Interior edge found between 2D elements "
7561 << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
7562 << " and " << el << ".");
7563 int *v = faces[gf]->GetVertices();
7564 faces_info[gf].Elem2No = el;
7565 if (v[1] == v0 && v[0] == v1)
7566 {
7567 faces_info[gf].Elem2Inf = 64 * lf + 1;
7568 }
7569 else if (v[0] == v0 && v[1] == v1)
7570 {
7571 // Temporarily allow even edge orientations: see the remark in
7572 // AddTriangleFaceElement().
7573 // Also, in a non-orientable surface mesh, the orientation will be even
7574 // for edges that connect elements with opposite orientations.
7575 faces_info[gf].Elem2Inf = 64 * lf;
7576 }
7577 else
7578 {
7579 MFEM_ABORT("internal error");
7580 }
7581 }
7582}
7583
7584void Mesh::AddTriangleFaceElement(int lf, int gf, int el,
7585 int v0, int v1, int v2)
7586{
7587 if (faces[gf] == NULL) // this will be elem1
7588 {
7589 faces[gf] = new Triangle(v0, v1, v2);
7590 faces_info[gf].Elem1No = el;
7591 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
7592 faces_info[gf].Elem2No = -1; // in case there's no other side
7593 faces_info[gf].Elem2Inf = -1; // face is not shared
7594 }
7595 else // this will be elem2
7596 {
7597 MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
7598 "Interior triangular face found connecting elements "
7599 << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
7600 << " and " << el << ".");
7601 int orientation, vv[3] = { v0, v1, v2 };
7602 orientation = GetTriOrientation(faces[gf]->GetVertices(), vv);
7603 // In a valid mesh, we should have (orientation % 2 != 0), however, if
7604 // one of the adjacent elements has wrong orientation, both face
7605 // orientations can be even, until the element orientations are fixed.
7606 // MFEM_ASSERT(orientation % 2 != 0, "");
7607 faces_info[gf].Elem2No = el;
7608 faces_info[gf].Elem2Inf = 64 * lf + orientation;
7609 }
7610}
7611
7612void Mesh::AddQuadFaceElement(int lf, int gf, int el,
7613 int v0, int v1, int v2, int v3)
7614{
7615 if (faces_info[gf].Elem1No < 0) // this will be elem1
7616 {
7617 faces[gf] = new Quadrilateral(v0, v1, v2, v3);
7618 faces_info[gf].Elem1No = el;
7619 faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
7620 faces_info[gf].Elem2No = -1; // in case there's no other side
7621 faces_info[gf].Elem2Inf = -1; // face is not shared
7622 }
7623 else // this will be elem2
7624 {
7625 MFEM_VERIFY(faces_info[gf].Elem2No < 0, "Invalid mesh topology. "
7626 "Interior quadrilateral face found connecting elements "
7627 << faces_info[gf].Elem1No << ", " << faces_info[gf].Elem2No
7628 << " and " << el << ".");
7629 int vv[4] = { v0, v1, v2, v3 };
7630 int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv);
7631 // Temporarily allow even face orientations: see the remark in
7632 // AddTriangleFaceElement().
7633 // MFEM_ASSERT(oo % 2 != 0, "");
7634 faces_info[gf].Elem2No = el;
7635 faces_info[gf].Elem2Inf = 64 * lf + oo;
7636 }
7637}
7638
7640{
7641 int nfaces = GetNumFaces();
7642
7643 for (auto &f : faces)
7644 {
7645 FreeElement(f);
7646 }
7647
7648 // (re)generate the interior faces and the info for them
7649 faces.SetSize(nfaces);
7650 faces_info.SetSize(nfaces);
7651 for (int i = 0; i < nfaces; ++i)
7652 {
7653 faces[i] = NULL;
7654 faces_info[i].Elem1No = -1;
7655 faces_info[i].NCFace = -1;
7656 }
7657
7658 Array<int> v;
7659 for (int i = 0; i < NumOfElements; ++i)
7660 {
7661 elements[i]->GetVertices(v);
7662 if (Dim == 1)
7663 {
7664 AddPointFaceElement(0, v[0], i);
7665 AddPointFaceElement(1, v[1], i);
7666 }
7667 else if (Dim == 2)
7668 {
7669 const int * const ef = el_to_edge->GetRow(i);
7670 const int ne = elements[i]->GetNEdges();
7671 for (int j = 0; j < ne; j++)
7672 {
7673 const int *e = elements[i]->GetEdgeVertices(j);
7674 AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]);
7675 }
7676 }
7677 else
7678 {
7679 const int * const ef = el_to_face->GetRow(i);
7680 switch (GetElementType(i))
7681 {
7683 {
7684 for (int j = 0; j < 4; j++)
7685 {
7686 const int *fv = tet_t::FaceVert[j];
7687 AddTriangleFaceElement(j, ef[j], i,
7688 v[fv[0]], v[fv[1]], v[fv[2]]);
7689 }
7690 break;
7691 }
7692 case Element::WEDGE:
7693 {
7694 for (int j = 0; j < 2; j++)
7695 {
7696 const int *fv = pri_t::FaceVert[j];
7697 AddTriangleFaceElement(j, ef[j], i,
7698 v[fv[0]], v[fv[1]], v[fv[2]]);
7699 }
7700 for (int j = 2; j < 5; j++)
7701 {
7702 const int *fv = pri_t::FaceVert[j];
7703 AddQuadFaceElement(j, ef[j], i,
7704 v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7705 }
7706 break;
7707 }
7708 case Element::PYRAMID:
7709 {
7710 for (int j = 0; j < 1; j++)
7711 {
7712 const int *fv = pyr_t::FaceVert[j];
7713 AddQuadFaceElement(j, ef[j], i,
7714 v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7715 }
7716 for (int j = 1; j < 5; j++)
7717 {
7718 const int *fv = pyr_t::FaceVert[j];
7719 AddTriangleFaceElement(j, ef[j], i,
7720 v[fv[0]], v[fv[1]], v[fv[2]]);
7721 }
7722 break;
7723 }
7725 {
7726 for (int j = 0; j < 6; j++)
7727 {
7728 const int *fv = hex_t::FaceVert[j];
7729 AddQuadFaceElement(j, ef[j], i,
7730 v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7731 }
7732 break;
7733 }
7734 default:
7735 MFEM_ABORT("Unexpected type of Element.");
7736 }
7737 }
7738 }
7739}
7740
7742{
7743 MFEM_VERIFY(ncmesh, "missing NCMesh.");
7744
7745 for (auto &x : faces_info)
7746 {
7747 x.NCFace = -1;
7748 }
7749
7750 const NCMesh::NCList &list =
7751 (Dim == 2) ? ncmesh->GetEdgeList() : ncmesh->GetFaceList();
7752
7753 nc_faces_info.SetSize(0);
7754 nc_faces_info.Reserve(list.masters.Size() + list.slaves.Size());
7755
7756 int nfaces = GetNumFaces();
7757
7758 // add records for master faces
7759 for (const NCMesh::Master &master : list.masters)
7760 {
7761 if (master.index >= nfaces) { continue; }
7762
7763 FaceInfo &master_fi = faces_info[master.index];
7764 master_fi.NCFace = nc_faces_info.Size();
7765 nc_faces_info.Append(NCFaceInfo(false, master.local, NULL));
7766 // NOTE: one of the unused members stores local face no. to be used below
7767 MFEM_ASSERT(master_fi.Elem2No == -1, "internal error");
7768 MFEM_ASSERT(master_fi.Elem2Inf == -1, "internal error");
7769 }
7770
7771 // add records for slave faces
7772 for (const NCMesh::Slave &slave : list.slaves)
7773 {
7774 if (slave.index < 0 || // degenerate slave face
7775 slave.index >= nfaces || // ghost slave
7776 slave.master >= nfaces) // has ghost master
7777 {
7778 continue;
7779 }
7780
7781 FaceInfo &slave_fi = faces_info[slave.index];
7782 FaceInfo &master_fi = faces_info[slave.master];
7783 NCFaceInfo &master_nc = nc_faces_info[master_fi.NCFace];
7784
7785 slave_fi.NCFace = nc_faces_info.Size();
7786 slave_fi.Elem2No = master_fi.Elem1No;
7787 slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
7788 // NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
7789 // matrix. In 2D, the point matrix has the orientation of the parent
7790 // edge, so its columns need to be flipped when applying it, see
7791 // ApplyLocalSlaveTransformation.
7792
7793 nc_faces_info.Append(
7794 NCFaceInfo(true, slave.master,
7795 list.point_matrices[slave.geom][slave.matrix]));
7796 }
7797}
7798
7800{
7801 STable3D *faces_tbl = new STable3D(NumOfVertices);
7802 for (int i = 0; i < NumOfElements; i++)
7803 {
7804 const int *v = elements[i]->GetVertices();
7805 switch (GetElementType(i))
7806 {
7808 {
7809 for (int j = 0; j < 4; j++)
7810 {
7811 const int *fv = tet_t::FaceVert[j];
7812 faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
7813 }
7814 break;
7815 }
7816 case Element::PYRAMID:
7817 {
7818 for (int j = 0; j < 1; j++)
7819 {
7820 const int *fv = pyr_t::FaceVert[j];
7821 faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7822 }
7823 for (int j = 1; j < 5; j++)
7824 {
7825 const int *fv = pyr_t::FaceVert[j];
7826 faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
7827 }
7828 break;
7829 }
7830 case Element::WEDGE:
7831 {
7832 for (int j = 0; j < 2; j++)
7833 {
7834 const int *fv = pri_t::FaceVert[j];
7835 faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
7836 }
7837 for (int j = 2; j < 5; j++)
7838 {
7839 const int *fv = pri_t::FaceVert[j];
7840 faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7841 }
7842 break;
7843 }
7845 {
7846 // find the face by the vertices with the smallest 3 numbers
7847 // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
7848 for (int j = 0; j < 6; j++)
7849 {
7850 const int *fv = hex_t::FaceVert[j];
7851 faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
7852 }
7853 break;
7854 }
7855 default:
7856 MFEM_ABORT("Unexpected type of Element: " << GetElementType(i));
7857 }
7858 }
7859 return faces_tbl;
7860}
7861
7863{
7864 Array<int> v;
7865 STable3D *faces_tbl;
7866
7867 if (el_to_face != NULL)
7868 {
7869 delete el_to_face;
7870 }
7871 el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra
7872 faces_tbl = new STable3D(NumOfVertices);
7873 for (int i = 0; i < NumOfElements; i++)
7874 {
7875 elements[i]->GetVertices(v);
7876 switch (GetElementType(i))
7877 {
7879 {
7880 for (int j = 0; j < 4; j++)
7881 {
7882 const int *fv = tet_t::FaceVert[j];
7884 i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
7885 }
7886 break;
7887 }
7888 case Element::WEDGE:
7889 {
7890 for (int j = 0; j < 2; j++)
7891 {
7892 const int *fv = pri_t::FaceVert[j];
7894 i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
7895 }
7896 for (int j = 2; j < 5; j++)
7897 {
7898 const int *fv = pri_t::FaceVert[j];
7900 i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
7901 }
7902 break;
7903 }
7904 case Element::PYRAMID:
7905 {
7906 for (int j = 0; j < 1; j++)
7907 {
7908 const int *fv = pyr_t::FaceVert[j];
7910 i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
7911 }
7912 for (int j = 1; j < 5; j++)
7913 {
7914 const int *fv = pyr_t::FaceVert[j];
7916 i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
7917 }
7918 break;
7919 }
7921 {
7922 // find the face by the vertices with the smallest 3 numbers
7923 // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
7924 for (int j = 0; j < 6; j++)
7925 {
7926 const int *fv = hex_t::FaceVert[j];
7928 i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
7929 }
7930 break;
7931 }
7932 default:
7933 MFEM_ABORT("Unexpected type of Element.");
7934 }
7935 }
7937 NumOfFaces = faces_tbl->NumberOfElements();
7939
7940 for (int i = 0; i < NumOfBdrElements; i++)
7941 {
7942 boundary[i]->GetVertices(v);
7943 switch (GetBdrElementType(i))
7944 {
7945 case Element::TRIANGLE:
7946 {
7947 be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]);
7948 break;
7949 }
7951 {
7952 be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
7953 break;
7954 }
7955 default:
7956 MFEM_ABORT("Unexpected type of boundary Element.");
7957 }
7958 }
7959
7960 if (ret_ftbl)
7961 {
7962 return faces_tbl;
7963 }
7964 delete faces_tbl;
7965 return NULL;
7966}
7967
7968// shift cyclically 3 integers so that the smallest is first
7969static inline
7970void Rotate3(int &a, int &b, int &c)
7971{
7972 if (a < b)
7973 {
7974 if (a > c)
7975 {
7976 ShiftRight(a, b, c);
7977 }
7978 }
7979 else
7980 {
7981 if (b < c)
7982 {
7983 ShiftRight(c, b, a);
7984 }
7985 else
7986 {
7987 ShiftRight(a, b, c);
7988 }
7989 }
7990}
7991
7993{
7994 if (Dim != 3 || !(meshgen & 1))
7995 {
7996 return;
7997 }
7998
7999 ResetLazyData();
8000
8001 DSTable *old_v_to_v = NULL;
8002 Table *old_elem_vert = NULL;
8003
8004 if (Nodes)
8005 {
8006 PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
8007 }
8008
8009 for (int i = 0; i < NumOfElements; i++)
8010 {
8012 {
8013 int *v = elements[i]->GetVertices();
8014
8015 Rotate3(v[0], v[1], v[2]);
8016 if (v[0] < v[3])
8017 {
8018 Rotate3(v[1], v[2], v[3]);
8019 }
8020 else
8021 {
8022 ShiftRight(v[0], v[1], v[3]);
8023 }
8024 }
8025 }
8026
8027 for (int i = 0; i < NumOfBdrElements; i++)
8028 {
8030 {
8031 int *v = boundary[i]->GetVertices();
8032
8033 Rotate3(v[0], v[1], v[2]);
8034 }
8035 }
8036
8037 if (!Nodes)
8038 {
8040 GenerateFaces();
8041 if (el_to_edge)
8042 {
8044 }
8045 }
8046 else
8047 {
8048 DoNodeReorder(old_v_to_v, old_elem_vert);
8049 delete old_elem_vert;
8050 delete old_v_to_v;
8051 }
8052}
8053
8055{
8056 int *partitioning;
8057 real_t pmin[3] = { infinity(), infinity(), infinity() };
8058 real_t pmax[3] = { -infinity(), -infinity(), -infinity() };
8059 // find a bounding box using the vertices
8060 for (int vi = 0; vi < NumOfVertices; vi++)
8061 {
8062 const real_t *p = vertices[vi]();
8063 for (int i = 0; i < spaceDim; i++)
8064 {
8065 if (p[i] < pmin[i]) { pmin[i] = p[i]; }
8066 if (p[i] > pmax[i]) { pmax[i] = p[i]; }
8067 }
8068 }
8069
8070 partitioning = new int[NumOfElements];
8071
8072 // determine the partitioning using the centers of the elements
8073 real_t ppt[3];
8074 Vector pt(ppt, spaceDim);
8075 for (int el = 0; el < NumOfElements; el++)
8076 {
8077 GetElementTransformation(el)->Transform(
8079 int part = 0;
8080 for (int i = spaceDim-1; i >= 0; i--)
8081 {
8082 int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i])));
8083 if (idx < 0) { idx = 0; }
8084 if (idx >= nxyz[i]) { idx = nxyz[i]-1; }
8085 part = part * nxyz[i] + idx;
8086 }
8087 partitioning[el] = part;
8088 }
8089
8090 return partitioning;
8091}
8092
8093void FindPartitioningComponents(Table &elem_elem,
8094 const Array<int> &partitioning,
8095 Array<int> &component,
8096 Array<int> &num_comp);
8097
8098int *Mesh::GeneratePartitioning(int nparts, int part_method)
8099{
8100#ifdef MFEM_USE_METIS
8101
8102 int print_messages = 1;
8103 // If running in parallel, print messages only from rank 0.
8104#ifdef MFEM_USE_MPI
8105 int init_flag, fin_flag;
8106 MPI_Initialized(&init_flag);
8107 MPI_Finalized(&fin_flag);
8108 if (init_flag && !fin_flag)
8109 {
8110 int rank;
8111 MPI_Comm_rank(GetGlobalMPI_Comm(), &rank);
8112 if (rank != 0) { print_messages = 0; }
8113 }
8114#endif
8115
8116 int i, *partitioning;
8117
8119
8120 partitioning = new int[NumOfElements];
8121
8122 if (nparts == 1)
8123 {
8124 for (i = 0; i < NumOfElements; i++)
8125 {
8126 partitioning[i] = 0;
8127 }
8128 }
8129 else if (NumOfElements <= nparts)
8130 {
8131 for (i = 0; i < NumOfElements; i++)
8132 {
8133 partitioning[i] = i;
8134 }
8135 }
8136 else
8137 {
8138 idx_t *I, *J, n;
8139#ifndef MFEM_USE_METIS_5
8140 idx_t wgtflag = 0;
8141 idx_t numflag = 0;
8142 idx_t options[5];
8143#else
8144 idx_t ncon = 1;
8145 idx_t errflag;
8146 idx_t options[40];
8147#endif
8148 idx_t edgecut;
8149
8150 // In case METIS have been compiled with 64bit indices
8151 bool freedata = false;
8152 idx_t mparts = (idx_t) nparts;
8153 idx_t *mpartitioning;
8154
8155 n = NumOfElements;
8156 if (sizeof(idx_t) == sizeof(int))
8157 {
8158 I = (idx_t*) el_to_el->GetI();
8159 J = (idx_t*) el_to_el->GetJ();
8160 mpartitioning = (idx_t*) partitioning;
8161 }
8162 else
8163 {
8164 int *iI = el_to_el->GetI();
8165 int *iJ = el_to_el->GetJ();
8166 int m = iI[n];
8167 I = new idx_t[n+1];
8168 J = new idx_t[m];
8169 for (int k = 0; k < n+1; k++) { I[k] = iI[k]; }
8170 for (int k = 0; k < m; k++) { J[k] = iJ[k]; }
8171 mpartitioning = new idx_t[n];
8172 freedata = true;
8173 }
8174#ifndef MFEM_USE_METIS_5
8175 options[0] = 0;
8176#else
8177 METIS_SetDefaultOptions(options);
8178 options[METIS_OPTION_CONTIG] = 1; // set METIS_OPTION_CONTIG
8179 // If the mesh is disconnected, disable METIS_OPTION_CONTIG.
8180 {
8181 Array<int> part(partitioning, NumOfElements);
8182 part = 0; // single part for the whole mesh
8183 Array<int> component; // size will be set to num. elem.
8184 Array<int> num_comp; // size will be set to num. parts (1)
8185 FindPartitioningComponents(*el_to_el, part, component, num_comp);
8186 if (num_comp[0] > 1) { options[METIS_OPTION_CONTIG] = 0; }
8187 }
8188#endif
8189
8190 // Sort the neighbor lists
8191 if (part_method >= 0 && part_method <= 2)
8192 {
8193 for (i = 0; i < n; i++)
8194 {
8195 // Sort in increasing order.
8196 // std::sort(J+I[i], J+I[i+1]);
8197
8198 // Sort in decreasing order, as in previous versions of MFEM.
8199 std::sort(J+I[i], J+I[i+1], std::greater<idx_t>());
8200 }
8201 }
8202
8203 // This function should be used to partition a graph into a small
8204 // number of partitions (less than 8).
8205 if (part_method == 0 || part_method == 3)
8206 {
8207#ifndef MFEM_USE_METIS_5
8209 I,
8210 J,
8211 NULL,
8212 NULL,
8213 &wgtflag,
8214 &numflag,
8215 &mparts,
8216 options,
8217 &edgecut,
8218 mpartitioning);
8219#else
8220 errflag = METIS_PartGraphRecursive(&n,
8221 &ncon,
8222 I,
8223 J,
8224 NULL,
8225 NULL,
8226 NULL,
8227 &mparts,
8228 NULL,
8229 NULL,
8230 options,
8231 &edgecut,
8232 mpartitioning);
8233 if (errflag != 1)
8234 {
8235 mfem_error("Mesh::GeneratePartitioning: "
8236 " error in METIS_PartGraphRecursive!");
8237 }
8238#endif
8239 }
8240
8241 // This function should be used to partition a graph into a large
8242 // number of partitions (greater than 8).
8243 if (part_method == 1 || part_method == 4)
8244 {
8245#ifndef MFEM_USE_METIS_5
8247 I,
8248 J,
8249 NULL,
8250 NULL,
8251 &wgtflag,
8252 &numflag,
8253 &mparts,
8254 options,
8255 &edgecut,
8256 mpartitioning);
8257#else
8258 errflag = METIS_PartGraphKway(&n,
8259 &ncon,
8260 I,
8261 J,
8262 NULL,
8263 NULL,
8264 NULL,
8265 &mparts,
8266 NULL,
8267 NULL,
8268 options,
8269 &edgecut,
8270 mpartitioning);
8271 if (errflag != 1)
8272 {
8273 mfem_error("Mesh::GeneratePartitioning: "
8274 " error in METIS_PartGraphKway!");
8275 }
8276#endif
8277 }
8278
8279 // The objective of this partitioning is to minimize the total
8280 // communication volume
8281 if (part_method == 2 || part_method == 5)
8282 {
8283#ifndef MFEM_USE_METIS_5
8285 I,
8286 J,
8287 NULL,
8288 NULL,
8289 &wgtflag,
8290 &numflag,
8291 &mparts,
8292 options,
8293 &edgecut,
8294 mpartitioning);
8295#else
8296 options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
8297 errflag = METIS_PartGraphKway(&n,
8298 &ncon,
8299 I,
8300 J,
8301 NULL,
8302 NULL,
8303 NULL,
8304 &mparts,
8305 NULL,
8306 NULL,
8307 options,
8308 &edgecut,
8309 mpartitioning);
8310 if (errflag != 1)
8311 {
8312 mfem_error("Mesh::GeneratePartitioning: "
8313 " error in METIS_PartGraphKway!");
8314 }
8315#endif
8316 }
8317
8318#ifdef MFEM_DEBUG
8319 if (print_messages)
8320 {
8321 mfem::out << "Mesh::GeneratePartitioning(...): edgecut = "
8322 << edgecut << endl;
8323 }
8324#endif
8325 nparts = (int) mparts;
8326 if (mpartitioning != (idx_t*)partitioning)
8327 {
8328 for (int k = 0; k<NumOfElements; k++)
8329 {
8330 partitioning[k] = mpartitioning[k];
8331 }
8332 }
8333 if (freedata)
8334 {
8335 delete[] I;
8336 delete[] J;
8337 delete[] mpartitioning;
8338 }
8339 }
8340
8341 delete el_to_el;
8342 el_to_el = NULL;
8343
8344 // Check for empty partitionings (a "feature" in METIS)
8345 if (nparts > 1 && NumOfElements > nparts)
8346 {
8347 Array< Pair<int,int> > psize(nparts);
8348 int empty_parts;
8349
8350 // Count how many elements are in each partition, and store the result in
8351 // psize, where psize[i].one is the number of elements, and psize[i].two
8352 // is partition index. Keep track of the number of empty parts.
8353 auto count_partition_elements = [&]()
8354 {
8355 for (i = 0; i < nparts; i++)
8356 {
8357 psize[i].one = 0;
8358 psize[i].two = i;
8359 }
8360
8361 for (i = 0; i < NumOfElements; i++)
8362 {
8363 psize[partitioning[i]].one++;
8364 }
8365
8366 empty_parts = 0;
8367 for (i = 0; i < nparts; i++)
8368 {
8369 if (psize[i].one == 0) { empty_parts++; }
8370 }
8371 };
8372
8373 count_partition_elements();
8374
8375 // This code just split the largest partitionings in two.
8376 // Do we need to replace it with something better?
8377 while (empty_parts)
8378 {
8379 if (print_messages)
8380 {
8381 mfem::err << "Mesh::GeneratePartitioning(...): METIS returned "
8382 << empty_parts << " empty parts!"
8383 << " Applying a simple fix ..." << endl;
8384 }
8385
8386 SortPairs<int,int>(psize, nparts);
8387
8388 for (i = nparts-1; i > nparts-1-empty_parts; i--)
8389 {
8390 psize[i].one /= 2;
8391 }
8392
8393 for (int j = 0; j < NumOfElements; j++)
8394 {
8395 for (i = nparts-1; i > nparts-1-empty_parts; i--)
8396 {
8397 if (psize[i].one == 0 || partitioning[j] != psize[i].two)
8398 {
8399 continue;
8400 }
8401 else
8402 {
8403 partitioning[j] = psize[nparts-1-i].two;
8404 psize[i].one--;
8405 }
8406 }
8407 }
8408
8409 // Check for empty partitionings again
8410 count_partition_elements();
8411 }
8412 }
8413
8414 return partitioning;
8415
8416#else
8417
8418 mfem_error("Mesh::GeneratePartitioning(...): "
8419 "MFEM was compiled without Metis.");
8420
8421 return NULL;
8422
8423#endif
8424}
8425
8426/* required: 0 <= partitioning[i] < num_part */
8428 const Array<int> &partitioning,
8429 Array<int> &component,
8430 Array<int> &num_comp)
8431{
8432 int i, j, k;
8433 int num_elem, *i_elem_elem, *j_elem_elem;
8434
8435 num_elem = elem_elem.Size();
8436 i_elem_elem = elem_elem.GetI();
8437 j_elem_elem = elem_elem.GetJ();
8438
8439 component.SetSize(num_elem);
8440
8441 Array<int> elem_stack(num_elem);
8442 int stack_p, stack_top_p, elem;
8443 int num_part;
8444
8445 num_part = -1;
8446 for (i = 0; i < num_elem; i++)
8447 {
8448 if (partitioning[i] > num_part)
8449 {
8450 num_part = partitioning[i];
8451 }
8452 component[i] = -1;
8453 }
8454 num_part++;
8455
8456 num_comp.SetSize(num_part);
8457 for (i = 0; i < num_part; i++)
8458 {
8459 num_comp[i] = 0;
8460 }
8461
8462 stack_p = 0;
8463 stack_top_p = 0; // points to the first unused element in the stack
8464 for (elem = 0; elem < num_elem; elem++)
8465 {
8466 if (component[elem] >= 0)
8467 {
8468 continue;
8469 }
8470
8471 component[elem] = num_comp[partitioning[elem]]++;
8472
8473 elem_stack[stack_top_p++] = elem;
8474
8475 for ( ; stack_p < stack_top_p; stack_p++)
8476 {
8477 i = elem_stack[stack_p];
8478 for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++)
8479 {
8480 k = j_elem_elem[j];
8481 if (partitioning[k] == partitioning[i])
8482 {
8483 if (component[k] < 0)
8484 {
8485 component[k] = component[i];
8486 elem_stack[stack_top_p++] = k;
8487 }
8488 else if (component[k] != component[i])
8489 {
8490 mfem_error("FindPartitioningComponents");
8491 }
8492 }
8493 }
8494 }
8495 }
8496}
8497
8498void Mesh::CheckPartitioning(int *partitioning_)
8499{
8500 int i, n_empty, n_mcomp;
8501 Array<int> component, num_comp;
8502 const Array<int> partitioning(partitioning_, GetNE());
8503
8505
8506 FindPartitioningComponents(*el_to_el, partitioning, component, num_comp);
8507
8508 n_empty = n_mcomp = 0;
8509 for (i = 0; i < num_comp.Size(); i++)
8510 if (num_comp[i] == 0)
8511 {
8512 n_empty++;
8513 }
8514 else if (num_comp[i] > 1)
8515 {
8516 n_mcomp++;
8517 }
8518
8519 if (n_empty > 0)
8520 {
8521 mfem::out << "Mesh::CheckPartitioning(...) :\n"
8522 << "The following subdomains are empty :\n";
8523 for (i = 0; i < num_comp.Size(); i++)
8524 if (num_comp[i] == 0)
8525 {
8526 mfem::out << ' ' << i;
8527 }
8528 mfem::out << endl;
8529 }
8530 if (n_mcomp > 0)
8531 {
8532 mfem::out << "Mesh::CheckPartitioning(...) :\n"
8533 << "The following subdomains are NOT connected :\n";
8534 for (i = 0; i < num_comp.Size(); i++)
8535 if (num_comp[i] > 1)
8536 {
8537 mfem::out << ' ' << i;
8538 }
8539 mfem::out << endl;
8540 }
8541 if (n_empty == 0 && n_mcomp == 0)
8542 mfem::out << "Mesh::CheckPartitioning(...) : "
8543 "All subdomains are connected." << endl;
8544
8545 if (el_to_el)
8546 {
8547 delete el_to_el;
8548 }
8549 el_to_el = NULL;
8550}
8551
8552// compute the coefficients of the polynomial in t:
8553// c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B)
8554// where A, B are (d x d), d=2,3
8555void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
8556{
8557 const real_t *a = A.Data();
8558 const real_t *b = B.Data();
8559
8560 c.SetSize(A.Width()+1);
8561 switch (A.Width())
8562 {
8563 case 2:
8564 {
8565 // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ |b0 b2|
8566 // |a1 a3| + \ |a1 b3| |b1 a3| / * t + |b1 b3| * t^2
8567 c(0) = a[0]*a[3]-a[1]*a[2];
8568 c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2];
8569 c(2) = b[0]*b[3]-b[1]*b[2];
8570 }
8571 break;
8572
8573 case 3:
8574 {
8575 /* |a0 a3 a6|
8576 * det(A+t*B) = |a1 a4 a7| +
8577 * |a2 a5 a8|
8578
8579 * / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \
8580 * + | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t +
8581 * \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| /
8582
8583 * / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \
8584 * + | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 +
8585 * \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| /
8586
8587 * |b0 b3 b6|
8588 * + |b1 b4 b7| * t^3
8589 * |b2 b5 b8| */
8590 c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) +
8591 a[1] * (a[5] * a[6] - a[3] * a[8]) +
8592 a[2] * (a[3] * a[7] - a[4] * a[6]));
8593
8594 c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) +
8595 b[1] * (a[5] * a[6] - a[3] * a[8]) +
8596 b[2] * (a[3] * a[7] - a[4] * a[6]) +
8597
8598 a[0] * (b[4] * a[8] - b[5] * a[7]) +
8599 a[1] * (b[5] * a[6] - b[3] * a[8]) +
8600 a[2] * (b[3] * a[7] - b[4] * a[6]) +
8601
8602 a[0] * (a[4] * b[8] - a[5] * b[7]) +
8603 a[1] * (a[5] * b[6] - a[3] * b[8]) +
8604 a[2] * (a[3] * b[7] - a[4] * b[6]));
8605
8606 c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) +
8607 a[1] * (b[5] * b[6] - b[3] * b[8]) +
8608 a[2] * (b[3] * b[7] - b[4] * b[6]) +
8609
8610 b[0] * (a[4] * b[8] - a[5] * b[7]) +
8611 b[1] * (a[5] * b[6] - a[3] * b[8]) +
8612 b[2] * (a[3] * b[7] - a[4] * b[6]) +
8613
8614 b[0] * (b[4] * a[8] - b[5] * a[7]) +
8615 b[1] * (b[5] * a[6] - b[3] * a[8]) +
8616 b[2] * (b[3] * a[7] - b[4] * a[6]));
8617
8618 c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) +
8619 b[1] * (b[5] * b[6] - b[3] * b[8]) +
8620 b[2] * (b[3] * b[7] - b[4] * b[6]));
8621 }
8622 break;
8623
8624 default:
8625 mfem_error("DetOfLinComb(...)");
8626 }
8627}
8628
8629// compute the real roots of
8630// z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3;
8631// the roots are returned in x, sorted in increasing order;
8632// it is assumed that x is at least of size d;
8633// return the number of roots counting multiplicity;
8634// return -1 if all z(i) are 0.
8635int FindRoots(const Vector &z, Vector &x)
8636{
8637 int d = z.Size()-1;
8638 if (d > 3 || d < 0)
8639 {
8640 mfem_error("FindRoots(...)");
8641 }
8642
8643 while (z(d) == 0.0)
8644 {
8645 if (d == 0)
8646 {
8647 return (-1);
8648 }
8649 d--;
8650 }
8651 switch (d)
8652 {
8653 case 0:
8654 {
8655 return 0;
8656 }
8657
8658 case 1:
8659 {
8660 x(0) = -z(0)/z(1);
8661 return 1;
8662 }
8663
8664 case 2:
8665 {
8666 real_t a = z(2), b = z(1), c = z(0);
8667 real_t D = b*b-4*a*c;
8668 if (D < 0.0)
8669 {
8670 return 0;
8671 }
8672 if (D == 0.0)
8673 {
8674 x(0) = x(1) = -0.5 * b / a;
8675 return 2; // root with multiplicity 2
8676 }
8677 if (b == 0.0)
8678 {
8679 x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a));
8680 return 2;
8681 }
8682 else
8683 {
8684 real_t t;
8685 if (b > 0.0)
8686 {
8687 t = -0.5 * (b + sqrt(D));
8688 }
8689 else
8690 {
8691 t = -0.5 * (b - sqrt(D));
8692 }
8693 x(0) = t / a;
8694 x(1) = c / t;
8695 if (x(0) > x(1))
8696 {
8697 Swap<real_t>(x(0), x(1));
8698 }
8699 return 2;
8700 }
8701 }
8702
8703 case 3:
8704 {
8705 real_t a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3);
8706
8707 // find the real roots of x^3 + a x^2 + b x + c = 0
8708 real_t Q = (a * a - 3 * b) / 9;
8709 real_t R = (2 * a * a * a - 9 * a * b + 27 * c) / 54;
8710 real_t Q3 = Q * Q * Q;
8711 real_t R2 = R * R;
8712
8713 if (R2 == Q3)
8714 {
8715 if (Q == 0)
8716 {
8717 x(0) = x(1) = x(2) = - a / 3;
8718 }
8719 else
8720 {
8721 real_t sqrtQ = sqrt(Q);
8722
8723 if (R > 0)
8724 {
8725 x(0) = -2 * sqrtQ - a / 3;
8726 x(1) = x(2) = sqrtQ - a / 3;
8727 }
8728 else
8729 {
8730 x(0) = x(1) = - sqrtQ - a / 3;
8731 x(2) = 2 * sqrtQ - a / 3;
8732 }
8733 }
8734 return 3;
8735 }
8736 else if (R2 < Q3)
8737 {
8738 real_t theta = acos(R / sqrt(Q3));
8739 real_t A = -2 * sqrt(Q);
8740 real_t x0, x1, x2;
8741 x0 = A * cos(theta / 3) - a / 3;
8742 x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3;
8743 x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3;
8744
8745 /* Sort x0, x1, x2 */
8746 if (x0 > x1)
8747 {
8748 Swap<real_t>(x0, x1);
8749 }
8750 if (x1 > x2)
8751 {
8752 Swap<real_t>(x1, x2);
8753 if (x0 > x1)
8754 {
8755 Swap<real_t>(x0, x1);
8756 }
8757 }
8758 x(0) = x0;
8759 x(1) = x1;
8760 x(2) = x2;
8761 return 3;
8762 }
8763 else
8764 {
8765 real_t A;
8766 if (R >= 0.0)
8767 {
8768 A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0);
8769 }
8770 else
8771 {
8772 A = pow(sqrt(R2 - Q3) - R, 1.0/3.0);
8773 }
8774 x(0) = A + Q / A - a / 3;
8775 return 1;
8776 }
8777 }
8778 }
8779 return 0;
8780}
8781
8782void FindTMax(Vector &c, Vector &x, real_t &tmax,
8783 const real_t factor, const int Dim)
8784{
8785 const real_t c0 = c(0);
8786 c(0) = c0 * (1.0 - pow(factor, -Dim));
8787 int nr = FindRoots(c, x);
8788 for (int j = 0; j < nr; j++)
8789 {
8790 if (x(j) > tmax)
8791 {
8792 break;
8793 }
8794 if (x(j) >= 0.0)
8795 {
8796 tmax = x(j);
8797 break;
8798 }
8799 }
8800 c(0) = c0 * (1.0 - pow(factor, Dim));
8801 nr = FindRoots(c, x);
8802 for (int j = 0; j < nr; j++)
8803 {
8804 if (x(j) > tmax)
8805 {
8806 break;
8807 }
8808 if (x(j) >= 0.0)
8809 {
8810 tmax = x(j);
8811 break;
8812 }
8813 }
8814}
8815
8816void Mesh::CheckDisplacements(const Vector &displacements, real_t &tmax)
8817{
8818 int nvs = vertices.Size();
8819 DenseMatrix P, V, DS, PDS(spaceDim), VDS(spaceDim);
8820 Vector c(spaceDim+1), x(spaceDim);
8821 const real_t factor = 2.0;
8822
8823 // check for tangling assuming constant speed
8824 if (tmax < 1.0)
8825 {
8826 tmax = 1.0;
8827 }
8828 for (int i = 0; i < NumOfElements; i++)
8829 {
8830 Element *el = elements[i];
8831 int nv = el->GetNVertices();
8832 int *v = el->GetVertices();
8833 P.SetSize(spaceDim, nv);
8834 V.SetSize(spaceDim, nv);
8835 for (int j = 0; j < spaceDim; j++)
8836 for (int k = 0; k < nv; k++)
8837 {
8838 P(j, k) = vertices[v[k]](j);
8839 V(j, k) = displacements(v[k]+j*nvs);
8840 }
8841 DS.SetSize(nv, spaceDim);
8842 const FiniteElement *fe =
8844 // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1
8845 switch (el->GetType())
8846 {
8847 case Element::TRIANGLE:
8849 {
8850 // DS is constant
8852 Mult(P, DS, PDS);
8853 Mult(V, DS, VDS);
8854 DetOfLinComb(PDS, VDS, c);
8855 if (c(0) <= 0.0)
8856 {
8857 tmax = 0.0;
8858 }
8859 else
8860 {
8861 FindTMax(c, x, tmax, factor, Dim);
8862 }
8863 }
8864 break;
8865
8867 {
8868 const IntegrationRule &ir = fe->GetNodes();
8869 for (int j = 0; j < nv; j++)
8870 {
8871 fe->CalcDShape(ir.IntPoint(j), DS);
8872 Mult(P, DS, PDS);
8873 Mult(V, DS, VDS);
8874 DetOfLinComb(PDS, VDS, c);
8875 if (c(0) <= 0.0)
8876 {
8877 tmax = 0.0;
8878 }
8879 else
8880 {
8881 FindTMax(c, x, tmax, factor, Dim);
8882 }
8883 }
8884 }
8885 break;
8886
8887 default:
8888 mfem_error("Mesh::CheckDisplacements(...)");
8889 }
8890 }
8891}
8892
8893void Mesh::MoveVertices(const Vector &displacements)
8894{
8895 for (int i = 0, nv = vertices.Size(); i < nv; i++)
8896 for (int j = 0; j < spaceDim; j++)
8897 {
8898 vertices[i](j) += displacements(j*nv+i);
8899 }
8900}
8901
8902void Mesh::GetVertices(Vector &vert_coord) const
8903{
8904 int nv = vertices.Size();
8905 vert_coord.SetSize(nv*spaceDim);
8906 for (int i = 0; i < nv; i++)
8907 for (int j = 0; j < spaceDim; j++)
8908 {
8909 vert_coord(j*nv+i) = vertices[i](j);
8910 }
8911}
8912
8913void Mesh::SetVertices(const Vector &vert_coord)
8914{
8915 for (int i = 0, nv = vertices.Size(); i < nv; i++)
8916 for (int j = 0; j < spaceDim; j++)
8917 {
8918 vertices[i](j) = vert_coord(j*nv+i);
8919 }
8920}
8921
8922void Mesh::GetNode(int i, real_t *coord) const
8923{
8924 if (Nodes)
8925 {
8927 for (int j = 0; j < spaceDim; j++)
8928 {
8929 coord[j] = AsConst(*Nodes)(fes->DofToVDof(i, j));
8930 }
8931 }
8932 else
8933 {
8934 for (int j = 0; j < spaceDim; j++)
8935 {
8936 coord[j] = vertices[i](j);
8937 }
8938 }
8939}
8940
8941void Mesh::SetNode(int i, const real_t *coord)
8942{
8943 if (Nodes)
8944 {
8946 for (int j = 0; j < spaceDim; j++)
8947 {
8948 (*Nodes)(fes->DofToVDof(i, j)) = coord[j];
8949 }
8950 }
8951 else
8952 {
8953 for (int j = 0; j < spaceDim; j++)
8954 {
8955 vertices[i](j) = coord[j];
8956 }
8957
8958 }
8959}
8960
8961void Mesh::MoveNodes(const Vector &displacements)
8962{
8963 if (Nodes)
8964 {
8965 (*Nodes) += displacements;
8966 }
8967 else
8968 {
8969 MoveVertices(displacements);
8970 }
8971}
8972
8973void Mesh::GetNodes(Vector &node_coord) const
8974{
8975 if (Nodes)
8976 {
8977 node_coord = (*Nodes);
8978 }
8979 else
8980 {
8981 GetVertices(node_coord);
8982 }
8983}
8984
8985void Mesh::SetNodes(const Vector &node_coord)
8986{
8987 if (Nodes)
8988 {
8989 (*Nodes) = node_coord;
8990 }
8991 else
8992 {
8993 SetVertices(node_coord);
8994 }
8995
8996 // Invalidate the old geometric factors
8997 NodesUpdated();
8998}
8999
9000void Mesh::NewNodes(GridFunction &nodes, bool make_owner)
9001{
9002 if (own_nodes) { delete Nodes; }
9003 Nodes = &nodes;
9004 spaceDim = Nodes->FESpace()->GetVDim();
9005 own_nodes = (int)make_owner;
9006
9007 if (NURBSext != nodes.FESpace()->GetNURBSext())
9008 {
9009 delete NURBSext;
9010 NURBSext = nodes.FESpace()->StealNURBSext();
9011 }
9012
9013 if (ncmesh)
9014 {
9016 }
9017
9018 // Invalidate the old geometric factors
9019 NodesUpdated();
9020}
9021
9022void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_)
9023{
9024 // If this is a nonconforming mesh without nodes, ncmesh->coordinates will
9025 // be non-empty; so if the 'nodes' argument is not NULL, we will create an
9026 // inconsistent state where the Mesh has nodes and ncmesh->coordinates is not
9027 // empty. This was creating an issue for Mesh::Print() since both the
9028 // "coordinates" and "nodes" sections were written, leading to crashes during
9029 // loading. This issue is now fixed in Mesh::Printer() by temporarily
9030 // swapping ncmesh->coordinates with an empty array when the Mesh has nodes.
9031
9033 mfem::Swap<int>(own_nodes, own_nodes_);
9034 // TODO:
9035 // if (nodes)
9036 // nodes->FESpace()->MakeNURBSextOwner();
9037 // NURBSext = (Nodes) ? Nodes->FESpace()->StealNURBSext() : NULL;
9038
9039 // Invalidate the old geometric factors
9040 NodesUpdated();
9041}
9042
9043void Mesh::AverageVertices(const int *indexes, int n, int result)
9044{
9045 int j, k;
9046
9047 for (k = 0; k < spaceDim; k++)
9048 {
9049 vertices[result](k) = vertices[indexes[0]](k);
9050 }
9051
9052 for (j = 1; j < n; j++)
9053 for (k = 0; k < spaceDim; k++)
9054 {
9055 vertices[result](k) += vertices[indexes[j]](k);
9056 }
9057
9058 for (k = 0; k < spaceDim; k++)
9059 {
9060 vertices[result](k) *= (1.0 / n);
9061 }
9062}
9063
9065{
9066 if (Nodes)
9067 {
9068 Nodes->FESpace()->Update();
9069 Nodes->Update();
9070
9071 // update vertex coordinates for compatibility (e.g., GetVertex())
9073
9074 // Invalidate the old geometric factors
9075 NodesUpdated();
9076 }
9077}
9078
9079void Mesh::UniformRefinement2D_base(bool update_nodes)
9080{
9081 ResetLazyData();
9082
9083 if (el_to_edge == NULL)
9084 {
9085 el_to_edge = new Table;
9087 }
9088
9089 int quad_counter = 0;
9090 for (int i = 0; i < NumOfElements; i++)
9091 {
9092 if (elements[i]->GetType() == Element::QUADRILATERAL)
9093 {
9094 quad_counter++;
9095 }
9096 }
9097
9098 const int oedge = NumOfVertices;
9099 const int oelem = oedge + NumOfEdges;
9100
9101 Array<Element*> new_elements;
9102 Array<Element*> new_boundary;
9103
9104 vertices.SetSize(oelem + quad_counter);
9105 new_elements.SetSize(4 * NumOfElements);
9106 quad_counter = 0;
9107
9108 for (int i = 0, j = 0; i < NumOfElements; i++)
9109 {
9110 const Element::Type el_type = elements[i]->GetType();
9111 const int attr = elements[i]->GetAttribute();
9112 int *v = elements[i]->GetVertices();
9113 const int *e = el_to_edge->GetRow(i);
9114 int vv[2];
9115
9116 if (el_type == Element::TRIANGLE)
9117 {
9118 for (int ei = 0; ei < 3; ei++)
9119 {
9120 for (int k = 0; k < 2; k++)
9121 {
9122 vv[k] = v[tri_t::Edges[ei][k]];
9123 }
9124 AverageVertices(vv, 2, oedge+e[ei]);
9125 }
9126
9127 new_elements[j++] =
9128 new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
9129 new_elements[j++] =
9130 new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
9131 new_elements[j++] =
9132 new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
9133 new_elements[j++] =
9134 new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
9135 }
9136 else if (el_type == Element::QUADRILATERAL)
9137 {
9138 const int qe = quad_counter;
9139 quad_counter++;
9140 AverageVertices(v, 4, oelem+qe);
9141
9142 for (int ei = 0; ei < 4; ei++)
9143 {
9144 for (int k = 0; k < 2; k++)
9145 {
9146 vv[k] = v[quad_t::Edges[ei][k]];
9147 }
9148 AverageVertices(vv, 2, oedge+e[ei]);
9149 }
9150
9151 new_elements[j++] =
9152 new Quadrilateral(v[0], oedge+e[0], oelem+qe, oedge+e[3], attr);
9153 new_elements[j++] =
9154 new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oelem+qe, attr);
9155 new_elements[j++] =
9156 new Quadrilateral(oelem+qe, oedge+e[1], v[2], oedge+e[2], attr);
9157 new_elements[j++] =
9158 new Quadrilateral(oedge+e[3], oelem+qe, oedge+e[2], v[3], attr);
9159 }
9160 else
9161 {
9162 MFEM_ABORT("unknown element type: " << el_type);
9163 }
9165 }
9166 mfem::Swap(elements, new_elements);
9167
9168 // refine boundary elements
9169 new_boundary.SetSize(2 * NumOfBdrElements);
9170 for (int i = 0, j = 0; i < NumOfBdrElements; i++)
9171 {
9172 const int attr = boundary[i]->GetAttribute();
9173 int *v = boundary[i]->GetVertices();
9174
9175 new_boundary[j++] = new Segment(v[0], oedge+be_to_face[i], attr);
9176 new_boundary[j++] = new Segment(oedge+be_to_face[i], v[1], attr);
9177
9179 }
9180 mfem::Swap(boundary, new_boundary);
9181
9182 static const real_t A = 0.0, B = 0.5, C = 1.0;
9183 static real_t tri_children[2*3*4] =
9184 {
9185 A,A, B,A, A,B,
9186 B,B, A,B, B,A,
9187 B,A, C,A, B,B,
9188 A,B, B,B, A,C
9189 };
9190 static real_t quad_children[2*4*4] =
9191 {
9192 A,A, B,A, B,B, A,B, // lower-left
9193 B,A, C,A, C,B, B,B, // lower-right
9194 B,B, C,B, C,C, B,C, // upper-right
9195 A,B, B,B, B,C, A,C // upper-left
9196 };
9197
9199 .UseExternalData(tri_children, 2, 3, 4);
9201 .UseExternalData(quad_children, 2, 4, 4);
9202 CoarseFineTr.embeddings.SetSize(elements.Size());
9203
9204 for (int i = 0; i < elements.Size(); i++)
9205 {
9207 emb.parent = i / 4;
9208 emb.matrix = i % 4;
9209 }
9210
9211 NumOfVertices = vertices.Size();
9214 NumOfFaces = 0;
9215
9217 GenerateFaces();
9218
9220 sequence++;
9221
9222 if (update_nodes) { UpdateNodes(); }
9223
9224#ifdef MFEM_DEBUG
9225 if (!Nodes || update_nodes)
9226 {
9228 }
9230#endif
9231}
9232
9233static inline real_t sqr(const real_t &x)
9234{
9235 return x*x;
9236}
9237
9239 bool update_nodes)
9240{
9241 ResetLazyData();
9242
9243 if (el_to_edge == NULL)
9244 {
9245 el_to_edge = new Table;
9247 }
9248
9249 if (el_to_face == NULL)
9250 {
9252 }
9253
9254 Array<int> f2qf_loc;
9255 Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
9256 f2qf.SetSize(0);
9257
9258 int NumOfQuadFaces = 0;
9260 {
9262 {
9263 f2qf.SetSize(faces.Size());
9264 for (int i = 0; i < faces.Size(); i++)
9265 {
9266 if (faces[i]->GetType() == Element::QUADRILATERAL)
9267 {
9268 f2qf[i] = NumOfQuadFaces;
9269 NumOfQuadFaces++;
9270 }
9271 }
9272 }
9273 else
9274 {
9275 NumOfQuadFaces = faces.Size();
9276 }
9277 }
9278
9279 int hex_counter = 0;
9281 {
9282 for (int i = 0; i < elements.Size(); i++)
9283 {
9284 if (elements[i]->GetType() == Element::HEXAHEDRON)
9285 {
9286 hex_counter++;
9287 }
9288 }
9289 }
9290
9291 int pyr_counter = 0;
9293 {
9294 for (int i = 0; i < elements.Size(); i++)
9295 {
9296 if (elements[i]->GetType() == Element::PYRAMID)
9297 {
9298 pyr_counter++;
9299 }
9300 }
9301 }
9302
9303 // Map from edge-index to vertex-index, needed for ReorientTetMesh() for
9304 // parallel meshes.
9305 // Note: with the removal of ReorientTetMesh() this may no longer
9306 // be needed. Unfortunately, it's hard to be sure.
9307 Array<int> e2v;
9309 {
9310 e2v.SetSize(NumOfEdges);
9311
9312 DSTable *v_to_v_ptr = v_to_v_p;
9313 if (!v_to_v_p)
9314 {
9315 v_to_v_ptr = new DSTable(NumOfVertices);
9316 GetVertexToVertexTable(*v_to_v_ptr);
9317 }
9318
9319 Array<Pair<int,int> > J_v2v(NumOfEdges); // (second vertex id, edge id)
9320 J_v2v.SetSize(0);
9321 for (int i = 0; i < NumOfVertices; i++)
9322 {
9323 Pair<int,int> *row_start = J_v2v.end();
9324 for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
9325 {
9326 J_v2v.Append(Pair<int,int>(it.Column(), it.Index()));
9327 }
9328 std::sort(row_start, J_v2v.end());
9329 }
9330
9331 for (int i = 0; i < J_v2v.Size(); i++)
9332 {
9333 e2v[J_v2v[i].two] = i;
9334 }
9335
9336 if (!v_to_v_p)
9337 {
9338 delete v_to_v_ptr;
9339 }
9340 else
9341 {
9342 for (int i = 0; i < NumOfVertices; i++)
9343 {
9344 for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
9345 {
9346 it.SetIndex(e2v[it.Index()]);
9347 }
9348 }
9349 }
9350 }
9351
9352 // Offsets for new vertices from edges, faces (quads only), and elements
9353 // (hexes only); each of these entities generates one new vertex.
9354 const int oedge = NumOfVertices;
9355 const int oface = oedge + NumOfEdges;
9356 const int oelem = oface + NumOfQuadFaces;
9357
9358 Array<Element*> new_elements;
9359 Array<Element*> new_boundary;
9360
9361 vertices.SetSize(oelem + hex_counter);
9362 new_elements.SetSize(8 * NumOfElements + 2 * pyr_counter);
9363 CoarseFineTr.embeddings.SetSize(new_elements.Size());
9364
9365 hex_counter = 0;
9366 for (int i = 0, j = 0; i < NumOfElements; i++)
9367 {
9368 const Element::Type el_type = elements[i]->GetType();
9369 const int attr = elements[i]->GetAttribute();
9370 int *v = elements[i]->GetVertices();
9371 const int *e = el_to_edge->GetRow(i);
9372 int vv[4], ev[12];
9373
9374 if (e2v.Size())
9375 {
9376 const int ne = el_to_edge->RowSize(i);
9377 for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
9378 e = ev;
9379 }
9380
9381 switch (el_type)
9382 {
9384 {
9385 for (int ei = 0; ei < 6; ei++)
9386 {
9387 for (int k = 0; k < 2; k++)
9388 {
9389 vv[k] = v[tet_t::Edges[ei][k]];
9390 }
9391 AverageVertices(vv, 2, oedge+e[ei]);
9392 }
9393
9394 // Algorithm for choosing refinement type:
9395 // 0: smallest octahedron diagonal
9396 // 1: best aspect ratio
9397 const int rt_algo = 1;
9398 // Refinement type:
9399 // 0: (v0,v1)-(v2,v3), 1: (v0,v2)-(v1,v3), 2: (v0,v3)-(v1,v2)
9400 // 0: e0-e5, 1: e1-e4, 2: e2-e3
9401 int rt;
9404 const DenseMatrix &J = T->Jacobian();
9405 if (rt_algo == 0)
9406 {
9407 // smallest octahedron diagonal
9408 real_t len_sqr, min_len;
9409
9410 min_len = sqr(J(0,0)-J(0,1)-J(0,2)) +
9411 sqr(J(1,0)-J(1,1)-J(1,2)) +
9412 sqr(J(2,0)-J(2,1)-J(2,2));
9413 rt = 0;
9414
9415 len_sqr = sqr(J(0,1)-J(0,0)-J(0,2)) +
9416 sqr(J(1,1)-J(1,0)-J(1,2)) +
9417 sqr(J(2,1)-J(2,0)-J(2,2));
9418 if (len_sqr < min_len) { min_len = len_sqr; rt = 1; }
9419
9420 len_sqr = sqr(J(0,2)-J(0,0)-J(0,1)) +
9421 sqr(J(1,2)-J(1,0)-J(1,1)) +
9422 sqr(J(2,2)-J(2,0)-J(2,1));
9423 if (len_sqr < min_len) { rt = 2; }
9424 }
9425 else
9426 {
9427 // best aspect ratio
9428 real_t Em_data[18], Js_data[9], Jp_data[9];
9429 DenseMatrix Em(Em_data, 3, 6);
9430 DenseMatrix Js(Js_data, 3, 3), Jp(Jp_data, 3, 3);
9431 real_t ar1, ar2, kappa, kappa_min;
9432
9433 for (int s = 0; s < 3; s++)
9434 {
9435 for (int t = 0; t < 3; t++)
9436 {
9437 Em(t,s) = 0.5*J(t,s);
9438 }
9439 }
9440 for (int t = 0; t < 3; t++)
9441 {
9442 Em(t,3) = 0.5*(J(t,0)+J(t,1));
9443 Em(t,4) = 0.5*(J(t,0)+J(t,2));
9444 Em(t,5) = 0.5*(J(t,1)+J(t,2));
9445 }
9446
9447 // rt = 0; Em: {0,5,1,2}, {0,5,2,4}
9448 for (int t = 0; t < 3; t++)
9449 {
9450 Js(t,0) = Em(t,5)-Em(t,0);
9451 Js(t,1) = Em(t,1)-Em(t,0);
9452 Js(t,2) = Em(t,2)-Em(t,0);
9453 }
9455 ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9456 for (int t = 0; t < 3; t++)
9457 {
9458 Js(t,0) = Em(t,5)-Em(t,0);
9459 Js(t,1) = Em(t,2)-Em(t,0);
9460 Js(t,2) = Em(t,4)-Em(t,0);
9461 }
9463 ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9464 kappa_min = std::max(ar1, ar2);
9465 rt = 0;
9466
9467 // rt = 1; Em: {1,0,4,2}, {1,2,4,5}
9468 for (int t = 0; t < 3; t++)
9469 {
9470 Js(t,0) = Em(t,0)-Em(t,1);
9471 Js(t,1) = Em(t,4)-Em(t,1);
9472 Js(t,2) = Em(t,2)-Em(t,1);
9473 }
9475 ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9476 for (int t = 0; t < 3; t++)
9477 {
9478 Js(t,0) = Em(t,2)-Em(t,1);
9479 Js(t,1) = Em(t,4)-Em(t,1);
9480 Js(t,2) = Em(t,5)-Em(t,1);
9481 }
9483 ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9484 kappa = std::max(ar1, ar2);
9485 if (kappa < kappa_min) { kappa_min = kappa; rt = 1; }
9486
9487 // rt = 2; Em: {2,0,1,3}, {2,1,5,3}
9488 for (int t = 0; t < 3; t++)
9489 {
9490 Js(t,0) = Em(t,0)-Em(t,2);
9491 Js(t,1) = Em(t,1)-Em(t,2);
9492 Js(t,2) = Em(t,3)-Em(t,2);
9493 }
9495 ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9496 for (int t = 0; t < 3; t++)
9497 {
9498 Js(t,0) = Em(t,1)-Em(t,2);
9499 Js(t,1) = Em(t,5)-Em(t,2);
9500 Js(t,2) = Em(t,3)-Em(t,2);
9501 }
9503 ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
9504 kappa = std::max(ar1, ar2);
9505 if (kappa < kappa_min) { rt = 2; }
9506 }
9507
9508 static const int mv_all[3][4][4] =
9509 {
9510 { {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1} }, // rt = 0
9511 { {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0} }, // rt = 1
9512 { {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3} } // rt = 2
9513 };
9514 const int (&mv)[4][4] = mv_all[rt];
9515
9516#ifndef MFEM_USE_MEMALLOC
9517 new_elements[j+0] =
9518 new Tetrahedron(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
9519 new_elements[j+1] =
9520 new Tetrahedron(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
9521 new_elements[j+2] =
9522 new Tetrahedron(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
9523 new_elements[j+3] =
9524 new Tetrahedron(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
9525
9526 for (int k = 0; k < 4; k++)
9527 {
9528 new_elements[j+4+k] =
9529 new Tetrahedron(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
9530 oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
9531 }
9532#else
9533 Tetrahedron *tet;
9534 new_elements[j+0] = tet = TetMemory.Alloc();
9535 tet->Init(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
9536
9537 new_elements[j+1] = tet = TetMemory.Alloc();
9538 tet->Init(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
9539
9540 new_elements[j+2] = tet = TetMemory.Alloc();
9541 tet->Init(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
9542
9543 new_elements[j+3] = tet = TetMemory.Alloc();
9544 tet->Init(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
9545
9546 for (int k = 0; k < 4; k++)
9547 {
9548 new_elements[j+4+k] = tet = TetMemory.Alloc();
9549 tet->Init(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
9550 oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
9551 }
9552#endif
9553 for (int k = 0; k < 4; k++)
9554 {
9555 CoarseFineTr.embeddings[j+k].parent = i;
9556 CoarseFineTr.embeddings[j+k].matrix = k;
9557 }
9558 for (int k = 0; k < 4; k++)
9559 {
9560 CoarseFineTr.embeddings[j+4+k].parent = i;
9561 CoarseFineTr.embeddings[j+4+k].matrix = 4*(rt+1)+k;
9562 }
9563
9564 j += 8;
9565 }
9566 break;
9567
9568 case Element::WEDGE:
9569 {
9570 const int *f = el_to_face->GetRow(i);
9571
9572 for (int fi = 2; fi < 5; fi++)
9573 {
9574 for (int k = 0; k < 4; k++)
9575 {
9576 vv[k] = v[pri_t::FaceVert[fi][k]];
9577 }
9578 AverageVertices(vv, 4, oface + f2qf[f[fi]]);
9579 }
9580
9581 for (int ei = 0; ei < 9; ei++)
9582 {
9583 for (int k = 0; k < 2; k++)
9584 {
9585 vv[k] = v[pri_t::Edges[ei][k]];
9586 }
9587 AverageVertices(vv, 2, oedge+e[ei]);
9588 }
9589
9590 const int qf2 = f2qf[f[2]];
9591 const int qf3 = f2qf[f[3]];
9592 const int qf4 = f2qf[f[4]];
9593
9594 new_elements[j++] =
9595 new Wedge(v[0], oedge+e[0], oedge+e[2],
9596 oedge+e[6], oface+qf2, oface+qf4, attr);
9597
9598 new_elements[j++] =
9599 new Wedge(oedge+e[1], oedge+e[2], oedge+e[0],
9600 oface+qf3, oface+qf4, oface+qf2, attr);
9601
9602 new_elements[j++] =
9603 new Wedge(oedge+e[0], v[1], oedge+e[1],
9604 oface+qf2, oedge+e[7], oface+qf3, attr);
9605
9606 new_elements[j++] =
9607 new Wedge(oedge+e[2], oedge+e[1], v[2],
9608 oface+qf4, oface+qf3, oedge+e[8], attr);
9609
9610 new_elements[j++] =
9611 new Wedge(oedge+e[6], oface+qf2, oface+qf4,
9612 v[3], oedge+e[3], oedge+e[5], attr);
9613
9614 new_elements[j++] =
9615 new Wedge(oface+qf3, oface+qf4, oface+qf2,
9616 oedge+e[4], oedge+e[5], oedge+e[3], attr);
9617
9618 new_elements[j++] =
9619 new Wedge(oface+qf2, oedge+e[7], oface+qf3,
9620 oedge+e[3], v[4], oedge+e[4], attr);
9621
9622 new_elements[j++] =
9623 new Wedge(oface+qf4, oface+qf3, oedge+e[8],
9624 oedge+e[5], oedge+e[4], v[5], attr);
9625 }
9626 break;
9627
9628 case Element::PYRAMID:
9629 {
9630 const int *f = el_to_face->GetRow(i);
9631 // pyr_counter++;
9632
9633 for (int fi = 0; fi < 1; fi++)
9634 {
9635 for (int k = 0; k < 4; k++)
9636 {
9637 vv[k] = v[pyr_t::FaceVert[fi][k]];
9638 }
9639 AverageVertices(vv, 4, oface + f2qf[f[fi]]);
9640 }
9641
9642 for (int ei = 0; ei < 8; ei++)
9643 {
9644 for (int k = 0; k < 2; k++)
9645 {
9646 vv[k] = v[pyr_t::Edges[ei][k]];
9647 }
9648 AverageVertices(vv, 2, oedge+e[ei]);
9649 }
9650
9651 const int qf0 = f2qf[f[0]];
9652
9653 new_elements[j++] =
9654 new Pyramid(v[0], oedge+e[0], oface+qf0,
9655 oedge+e[3], oedge+e[4], attr);
9656
9657 new_elements[j++] =
9658 new Pyramid(oedge+e[0], v[1], oedge+e[1],
9659 oface+qf0, oedge+e[5], attr);
9660
9661 new_elements[j++] =
9662 new Pyramid(oface+qf0, oedge+e[1], v[2],
9663 oedge+e[2], oedge+e[6], attr);
9664
9665 new_elements[j++] =
9666 new Pyramid(oedge+e[3], oface+qf0, oedge+e[2],
9667 v[3], oedge+e[7], attr);
9668
9669 new_elements[j++] =
9670 new Pyramid(oedge+e[4], oedge+e[5], oedge+e[6],
9671 oedge+e[7], v[4], attr);
9672
9673 new_elements[j++] =
9674 new Pyramid(oedge+e[7], oedge+e[6], oedge+e[5],
9675 oedge+e[4], oface+qf0, attr);
9676
9677#ifndef MFEM_USE_MEMALLOC
9678 new_elements[j++] =
9679 new Tetrahedron(oedge+e[0], oedge+e[4], oedge+e[5],
9680 oface+qf0, attr);
9681
9682 new_elements[j++] =
9683 new Tetrahedron(oedge+e[1], oedge+e[5], oedge+e[6],
9684 oface+qf0, attr);
9685
9686 new_elements[j++] =
9687 new Tetrahedron(oedge+e[2], oedge+e[6], oedge+e[7],
9688 oface+qf0, attr);
9689
9690 new_elements[j++] =
9691 new Tetrahedron(oedge+e[3], oedge+e[7], oedge+e[4],
9692 oface+qf0, attr);
9693#else
9694 Tetrahedron *tet;
9695 new_elements[j++] = tet = TetMemory.Alloc();
9696 tet->Init(oedge+e[0], oedge+e[4], oedge+e[5],
9697 oface+qf0, attr);
9698
9699 new_elements[j++] = tet = TetMemory.Alloc();
9700 tet->Init(oedge+e[1], oedge+e[5], oedge+e[6],
9701 oface+qf0, attr);
9702
9703 new_elements[j++] = tet = TetMemory.Alloc();
9704 tet->Init(oedge+e[2], oedge+e[6], oedge+e[7],
9705 oface+qf0, attr);
9706
9707 new_elements[j++] = tet = TetMemory.Alloc();
9708 tet->Init(oedge+e[3], oedge+e[7], oedge+e[4],
9709 oface+qf0, attr);
9710#endif
9711 }
9712 break;
9713
9715 {
9716 const int *f = el_to_face->GetRow(i);
9717 const int he = hex_counter;
9718 hex_counter++;
9719
9720 const int *qf;
9721 int qf_data[6];
9722 if (f2qf.Size() == 0)
9723 {
9724 qf = f;
9725 }
9726 else
9727 {
9728 for (int k = 0; k < 6; k++) { qf_data[k] = f2qf[f[k]]; }
9729 qf = qf_data;
9730 }
9731
9732 AverageVertices(v, 8, oelem+he);
9733
9734 for (int fi = 0; fi < 6; fi++)
9735 {
9736 for (int k = 0; k < 4; k++)
9737 {
9738 vv[k] = v[hex_t::FaceVert[fi][k]];
9739 }
9740 AverageVertices(vv, 4, oface + qf[fi]);
9741 }
9742
9743 for (int ei = 0; ei < 12; ei++)
9744 {
9745 for (int k = 0; k < 2; k++)
9746 {
9747 vv[k] = v[hex_t::Edges[ei][k]];
9748 }
9749 AverageVertices(vv, 2, oedge+e[ei]);
9750 }
9751
9752 new_elements[j++] =
9753 new Hexahedron(v[0], oedge+e[0], oface+qf[0],
9754 oedge+e[3], oedge+e[8], oface+qf[1],
9755 oelem+he, oface+qf[4], attr);
9756 new_elements[j++] =
9757 new Hexahedron(oedge+e[0], v[1], oedge+e[1],
9758 oface+qf[0], oface+qf[1], oedge+e[9],
9759 oface+qf[2], oelem+he, attr);
9760 new_elements[j++] =
9761 new Hexahedron(oface+qf[0], oedge+e[1], v[2],
9762 oedge+e[2], oelem+he, oface+qf[2],
9763 oedge+e[10], oface+qf[3], attr);
9764 new_elements[j++] =
9765 new Hexahedron(oedge+e[3], oface+qf[0], oedge+e[2],
9766 v[3], oface+qf[4], oelem+he,
9767 oface+qf[3], oedge+e[11], attr);
9768 new_elements[j++] =
9769 new Hexahedron(oedge+e[8], oface+qf[1], oelem+he,
9770 oface+qf[4], v[4], oedge+e[4],
9771 oface+qf[5], oedge+e[7], attr);
9772 new_elements[j++] =
9773 new Hexahedron(oface+qf[1], oedge+e[9], oface+qf[2],
9774 oelem+he, oedge+e[4], v[5],
9775 oedge+e[5], oface+qf[5], attr);
9776 new_elements[j++] =
9777 new Hexahedron(oelem+he, oface+qf[2], oedge+e[10],
9778 oface+qf[3], oface+qf[5], oedge+e[5],
9779 v[6], oedge+e[6], attr);
9780 new_elements[j++] =
9781 new Hexahedron(oface+qf[4], oelem+he, oface+qf[3],
9782 oedge+e[11], oedge+e[7], oface+qf[5],
9783 oedge+e[6], v[7], attr);
9784 }
9785 break;
9786
9787 default:
9788 MFEM_ABORT("Unknown 3D element type \"" << el_type << "\"");
9789 break;
9790 }
9792 }
9793 mfem::Swap(elements, new_elements);
9794
9795 // refine boundary elements
9796 new_boundary.SetSize(4 * NumOfBdrElements);
9797 for (int i = 0, j = 0; i < NumOfBdrElements; i++)
9798 {
9799 const Element::Type bdr_el_type = boundary[i]->GetType();
9800 const int attr = boundary[i]->GetAttribute();
9801 int *v = boundary[i]->GetVertices();
9802 const int *e = bel_to_edge->GetRow(i);
9803 int ev[4];
9804
9805 if (e2v.Size())
9806 {
9807 const int ne = bel_to_edge->RowSize(i);
9808 for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
9809 e = ev;
9810 }
9811
9812 if (bdr_el_type == Element::TRIANGLE)
9813 {
9814 new_boundary[j++] =
9815 new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
9816 new_boundary[j++] =
9817 new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
9818 new_boundary[j++] =
9819 new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
9820 new_boundary[j++] =
9821 new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
9822 }
9823 else if (bdr_el_type == Element::QUADRILATERAL)
9824 {
9825 const int qf =
9826 (f2qf.Size() == 0) ? be_to_face[i] : f2qf[be_to_face[i]];
9827
9828 new_boundary[j++] =
9829 new Quadrilateral(v[0], oedge+e[0], oface+qf, oedge+e[3], attr);
9830 new_boundary[j++] =
9831 new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oface+qf, attr);
9832 new_boundary[j++] =
9833 new Quadrilateral(oface+qf, oedge+e[1], v[2], oedge+e[2], attr);
9834 new_boundary[j++] =
9835 new Quadrilateral(oedge+e[3], oface+qf, oedge+e[2], v[3], attr);
9836 }
9837 else
9838 {
9839 MFEM_ABORT("boundary Element is not a triangle or a quad!");
9840 }
9842 }
9843 mfem::Swap(boundary, new_boundary);
9844
9845 static const real_t A = 0.0, B = 0.5, C = 1.0, D = -1.0;
9846 static real_t tet_children[3*4*16] =
9847 {
9848 A,A,A, B,A,A, A,B,A, A,A,B,
9849 B,A,A, C,A,A, B,B,A, B,A,B,
9850 A,B,A, B,B,A, A,C,A, A,B,B,
9851 A,A,B, B,A,B, A,B,B, A,A,C,
9852 // edge coordinates:
9853 // 0 -> B,A,A 1 -> A,B,A 2 -> A,A,B
9854 // 3 -> B,B,A 4 -> B,A,B 5 -> A,B,B
9855 // rt = 0: {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1}
9856 B,A,A, A,B,B, A,B,A, A,A,B,
9857 B,A,A, A,B,B, A,A,B, B,A,B,
9858 B,A,A, A,B,B, B,A,B, B,B,A,
9859 B,A,A, A,B,B, B,B,A, A,B,A,
9860 // rt = 1: {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0}
9861 A,B,A, B,A,A, B,A,B, A,A,B,
9862 A,B,A, A,A,B, B,A,B, A,B,B,
9863 A,B,A, A,B,B, B,A,B, B,B,A,
9864 A,B,A, B,B,A, B,A,B, B,A,A,
9865 // rt = 2: {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3}
9866 A,A,B, B,A,A, A,B,A, B,B,A,
9867 A,A,B, A,B,A, A,B,B, B,B,A,
9868 A,A,B, A,B,B, B,A,B, B,B,A,
9869 A,A,B, B,A,B, B,A,A, B,B,A
9870 };
9871 static real_t pyr_children[3*5*10] =
9872 {
9873 A,A,A, B,A,A, B,B,A, A,B,A, A,A,B,
9874 B,A,A, C,A,A, C,B,A, B,B,A, B,A,B,
9875 B,B,A, C,B,A, C,C,A, B,C,A, B,B,B,
9876 A,B,A, B,B,A, B,C,A, A,C,A, A,B,B,
9877 A,A,B, B,A,B, B,B,B, A,B,B, A,A,C,
9878 A,B,B, B,B,B, B,A,B, A,A,B, B,B,A,
9879 B,A,A, A,A,B, B,A,B, B,B,A, D,D,D,
9880 C,B,A, B,A,B, B,B,B, B,B,A, D,D,D,
9881 B,C,A, B,B,B, A,B,B, B,B,A, D,D,D,
9882 A,B,A, A,B,B, A,A,B, B,B,A, D,D,D
9883 };
9884 static real_t pri_children[3*6*8] =
9885 {
9886 A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
9887 B,B,A, A,B,A, B,A,A, B,B,B, A,B,B, B,A,B,
9888 B,A,A, C,A,A, B,B,A, B,A,B, C,A,B, B,B,B,
9889 A,B,A, B,B,A, A,C,A, A,B,B, B,B,B, A,C,B,
9890 A,A,B, B,A,B, A,B,B, A,A,C, B,A,C, A,B,C,
9891 B,B,B, A,B,B, B,A,B, B,B,C, A,B,C, B,A,C,
9892 B,A,B, C,A,B, B,B,B, B,A,C, C,A,C, B,B,C,
9893 A,B,B, B,B,B, A,C,B, A,B,C, B,B,C, A,C,C
9894 };
9895 static real_t hex_children[3*8*8] =
9896 {
9897 A,A,A, B,A,A, B,B,A, A,B,A, A,A,B, B,A,B, B,B,B, A,B,B,
9898 B,A,A, C,A,A, C,B,A, B,B,A, B,A,B, C,A,B, C,B,B, B,B,B,
9899 B,B,A, C,B,A, C,C,A, B,C,A, B,B,B, C,B,B, C,C,B, B,C,B,
9900 A,B,A, B,B,A, B,C,A, A,C,A, A,B,B, B,B,B, B,C,B, A,C,B,
9901 A,A,B, B,A,B, B,B,B, A,B,B, A,A,C, B,A,C, B,B,C, A,B,C,
9902 B,A,B, C,A,B, C,B,B, B,B,B, B,A,C, C,A,C, C,B,C, B,B,C,
9903 B,B,B, C,B,B, C,C,B, B,C,B, B,B,C, C,B,C, C,C,C, B,C,C,
9904 A,B,B, B,B,B, B,C,B, A,C,B, A,B,C, B,B,C, B,C,C, A,C,C
9905 };
9906
9908 .UseExternalData(tet_children, 3, 4, 16);
9910 .UseExternalData(pyr_children, 3, 5, 10);
9912 .UseExternalData(pri_children, 3, 6, 8);
9914 .UseExternalData(hex_children, 3, 8, 8);
9915
9916 for (int i = 0; i < elements.Size(); i++)
9917 {
9918 // tetrahedron elements are handled above:
9919 if (elements[i]->GetType() == Element::TETRAHEDRON) { continue; }
9920
9922 emb.parent = i / 8;
9923 emb.matrix = i % 8;
9924 }
9925
9926 NumOfVertices = vertices.Size();
9927 NumOfElements = 8 * NumOfElements + 2 * pyr_counter;
9929
9931 GenerateFaces();
9932
9933#ifdef MFEM_DEBUG
9935#endif
9936
9938
9940 sequence++;
9941
9942 if (update_nodes) { UpdateNodes(); }
9943}
9944
9945void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
9946{
9947 int i, j, ind, nedges;
9948 Array<int> v;
9949
9950 ResetLazyData();
9951
9952 if (ncmesh)
9953 {
9954 MFEM_ABORT("Local and nonconforming refinements cannot be mixed.");
9955 }
9956
9958
9959 if (Dim == 1) // --------------------------------------------------------
9960 {
9961 int cne = NumOfElements, cnv = NumOfVertices;
9962 NumOfVertices += marked_el.Size();
9963 NumOfElements += marked_el.Size();
9964 vertices.SetSize(NumOfVertices);
9965 elements.SetSize(NumOfElements);
9967
9968 for (j = 0; j < marked_el.Size(); j++)
9969 {
9970 i = marked_el[j];
9971 Segment *c_seg = (Segment *)elements[i];
9972 int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
9973 int new_v = cnv + j, new_e = cne + j;
9974 AverageVertices(vert, 2, new_v);
9975 elements[new_e] = new Segment(new_v, vert[1], attr);
9976 vert[1] = new_v;
9977
9980 }
9981
9982 static real_t seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
9984 UseExternalData(seg_children, 1, 2, 3);
9985
9986 GenerateFaces();
9987
9988 } // end of 'if (Dim == 1)'
9989 else if (Dim == 2) // ---------------------------------------------------
9990 {
9991 // 1. Get table of vertex to vertex connections.
9992 DSTable v_to_v(NumOfVertices);
9993 GetVertexToVertexTable(v_to_v);
9994
9995 // 2. Get edge to element connections in arrays edge1 and edge2
9996 nedges = v_to_v.NumberOfEntries();
9997 int *edge1 = new int[nedges];
9998 int *edge2 = new int[nedges];
9999 int *middle = new int[nedges];
10000
10001 for (i = 0; i < nedges; i++)
10002 {
10003 edge1[i] = edge2[i] = middle[i] = -1;
10004 }
10005
10006 for (i = 0; i < NumOfElements; i++)
10007 {
10008 elements[i]->GetVertices(v);
10009 for (j = 1; j < v.Size(); j++)
10010 {
10011 ind = v_to_v(v[j-1], v[j]);
10012 (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
10013 }
10014 ind = v_to_v(v[0], v[v.Size()-1]);
10015 (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
10016 }
10017
10018 // 3. Do the red refinement.
10019 for (i = 0; i < marked_el.Size(); i++)
10020 {
10021 RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
10022 }
10023
10024 // 4. Do the green refinement (to get conforming mesh).
10025 int need_refinement;
10026 do
10027 {
10028 need_refinement = 0;
10029 for (i = 0; i < nedges; i++)
10030 {
10031 if (middle[i] != -1 && edge1[i] != -1)
10032 {
10033 need_refinement = 1;
10034 GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
10035 }
10036 }
10037 }
10038 while (need_refinement == 1);
10039
10040 // 5. Update the boundary elements.
10041 int v1[2], v2[2], bisect, temp;
10042 temp = NumOfBdrElements;
10043 for (i = 0; i < temp; i++)
10044 {
10045 boundary[i]->GetVertices(v);
10046 bisect = v_to_v(v[0], v[1]);
10047 if (middle[bisect] != -1) // the element was refined (needs updating)
10048 {
10049 if (boundary[i]->GetType() == Element::SEGMENT)
10050 {
10051 v1[0] = v[0]; v1[1] = middle[bisect];
10052 v2[0] = middle[bisect]; v2[1] = v[1];
10053
10054 boundary[i]->SetVertices(v1);
10056 }
10057 else
10058 mfem_error("Only bisection of segment is implemented"
10059 " for bdr elem.");
10060 }
10061 }
10062 NumOfBdrElements = boundary.Size();
10063
10064 // 6. Free the allocated memory.
10065 delete [] edge1;
10066 delete [] edge2;
10067 delete [] middle;
10068
10069 if (el_to_edge != NULL)
10070 {
10072 GenerateFaces();
10073 }
10074
10075 }
10076 else if (Dim == 3) // ---------------------------------------------------
10077 {
10078 // 1. Hash table of vertex to vertex connections corresponding to refined
10079 // edges.
10080 HashTable<Hashed2> v_to_v;
10081
10082 MFEM_VERIFY(GetNE() == 0 ||
10083 ((Tetrahedron*)elements[0])->GetRefinementFlag() != 0,
10084 "tetrahedral mesh is not marked for refinement:"
10085 " call Finalize(true)");
10086
10087 // 2. Do the red refinement.
10088 int ii;
10089 switch (type)
10090 {
10091 case 1:
10092 for (i = 0; i < marked_el.Size(); i++)
10093 {
10094 Bisection(marked_el[i], v_to_v);
10095 }
10096 break;
10097 case 2:
10098 for (i = 0; i < marked_el.Size(); i++)
10099 {
10100 Bisection(marked_el[i], v_to_v);
10101
10102 Bisection(NumOfElements - 1, v_to_v);
10103 Bisection(marked_el[i], v_to_v);
10104 }
10105 break;
10106 case 3:
10107 for (i = 0; i < marked_el.Size(); i++)
10108 {
10109 Bisection(marked_el[i], v_to_v);
10110
10111 ii = NumOfElements - 1;
10112 Bisection(ii, v_to_v);
10113 Bisection(NumOfElements - 1, v_to_v);
10114 Bisection(ii, v_to_v);
10115
10116 Bisection(marked_el[i], v_to_v);
10117 Bisection(NumOfElements-1, v_to_v);
10118 Bisection(marked_el[i], v_to_v);
10119 }
10120 break;
10121 }
10122
10123 // 3. Do the green refinement (to get conforming mesh).
10124 int need_refinement;
10125 // int need_refinement, onoe, max_gen = 0;
10126 do
10127 {
10128 // int redges[2], type, flag;
10129 need_refinement = 0;
10130 // onoe = NumOfElements;
10131 // for (i = 0; i < onoe; i++)
10132 for (i = 0; i < NumOfElements; i++)
10133 {
10134 // ((Tetrahedron *)elements[i])->
10135 // ParseRefinementFlag(redges, type, flag);
10136 // if (flag > max_gen) max_gen = flag;
10137 if (elements[i]->NeedRefinement(v_to_v))
10138 {
10139 need_refinement = 1;
10140 Bisection(i, v_to_v);
10141 }
10142 }
10143 }
10144 while (need_refinement == 1);
10145
10146 // mfem::out << "Maximum generation: " << max_gen << endl;
10147
10148 // 4. Update the boundary elements.
10149 do
10150 {
10151 need_refinement = 0;
10152 for (i = 0; i < NumOfBdrElements; i++)
10153 if (boundary[i]->NeedRefinement(v_to_v))
10154 {
10155 need_refinement = 1;
10156 BdrBisection(i, v_to_v);
10157 }
10158 }
10159 while (need_refinement == 1);
10160
10161 NumOfVertices = vertices.Size();
10162 NumOfBdrElements = boundary.Size();
10163
10164 // 5. Update element-to-edge and element-to-face relations.
10165 if (el_to_edge != NULL)
10166 {
10168 }
10169 if (el_to_face != NULL)
10170 {
10172 GenerateFaces();
10173 }
10174
10175 } // end 'if (Dim == 3)'
10176
10178 sequence++;
10179
10180 UpdateNodes();
10181
10182#ifdef MFEM_DEBUG
10184#endif
10185}
10186
10188 int nc_limit)
10189{
10190 MFEM_VERIFY(!NURBSext, "Nonconforming refinement of NURBS meshes is "
10191 "not supported. Project the NURBS to Nodes first.");
10192
10193 ResetLazyData();
10194
10195 if (!ncmesh)
10196 {
10197 // start tracking refinement hierarchy
10198 ncmesh = new NCMesh(this);
10199 }
10200
10201 if (!refinements.Size())
10202 {
10204 return;
10205 }
10206
10207 // do the refinements
10209 ncmesh->Refine(refinements);
10210
10211 if (nc_limit > 0)
10212 {
10213 ncmesh->LimitNCLevel(nc_limit);
10214 }
10215
10216 // create a second mesh containing the finest elements from 'ncmesh'
10217 Mesh* mesh2 = new Mesh(*ncmesh);
10218 ncmesh->OnMeshUpdated(mesh2);
10219
10220 // now swap the meshes, the second mesh will become the old coarse mesh
10221 // and this mesh will be the new fine mesh
10222 Swap(*mesh2, false);
10223 delete mesh2;
10224
10226
10228 sequence++;
10229
10230 UpdateNodes();
10231}
10232
10234 const int *fine, int nfine, int op)
10235{
10236 real_t error = (op == 3) ? std::pow(elem_error[fine[0]],
10237 2.0) : elem_error[fine[0]];
10238
10239 for (int i = 1; i < nfine; i++)
10240 {
10241 MFEM_VERIFY(fine[i] < elem_error.Size(), "");
10242
10243 real_t err_fine = elem_error[fine[i]];
10244 switch (op)
10245 {
10246 case 0: error = std::min(error, err_fine); break;
10247 case 1: error += err_fine; break;
10248 case 2: error = std::max(error, err_fine); break;
10249 case 3: error += std::pow(err_fine, 2.0); break;
10250 default: MFEM_ABORT("Invalid operation.");
10251 }
10252 }
10253 return (op == 3) ? std::sqrt(error) : error;
10254}
10255
10257 real_t threshold, int nc_limit, int op)
10258{
10259 MFEM_VERIFY(ncmesh, "Only supported for non-conforming meshes.");
10260 MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. "
10261 "Project the NURBS to Nodes first.");
10262
10263 ResetLazyData();
10264
10265 const Table &dt = ncmesh->GetDerefinementTable();
10266
10267 Array<int> level_ok;
10268 if (nc_limit > 0)
10269 {
10270 ncmesh->CheckDerefinementNCLevel(dt, level_ok, nc_limit);
10271 }
10272
10273 Array<int> derefs;
10274 for (int i = 0; i < dt.Size(); i++)
10275 {
10276 if (nc_limit > 0 && !level_ok[i]) { continue; }
10277
10278 real_t error =
10279 AggregateError(elem_error, dt.GetRow(i), dt.RowSize(i), op);
10280
10281 if (error < threshold) { derefs.Append(i); }
10282 }
10283
10284 if (!derefs.Size()) { return false; }
10285
10286 ncmesh->Derefine(derefs);
10287
10288 Mesh* mesh2 = new Mesh(*ncmesh);
10289 ncmesh->OnMeshUpdated(mesh2);
10290
10291 Swap(*mesh2, false);
10292 delete mesh2;
10293
10295
10297 sequence++;
10298
10299 UpdateNodes();
10300
10301 return true;
10302}
10303
10304bool Mesh::DerefineByError(Array<real_t> &elem_error, real_t threshold,
10305 int nc_limit, int op)
10306{
10307 // NOTE: the error array is not const because it will be expanded in parallel
10308 // by ghost element errors
10309 if (Nonconforming())
10310 {
10311 return NonconformingDerefinement(elem_error, threshold, nc_limit, op);
10312 }
10313 else
10314 {
10315 MFEM_ABORT("Derefinement is currently supported for non-conforming "
10316 "meshes only.");
10317 return false;
10318 }
10319}
10320
10321bool Mesh::DerefineByError(const Vector &elem_error, real_t threshold,
10322 int nc_limit, int op)
10323{
10324 Array<real_t> tmp(elem_error.Size());
10325 for (int i = 0; i < tmp.Size(); i++)
10326 {
10327 tmp[i] = elem_error(i);
10328 }
10329 return DerefineByError(tmp, threshold, nc_limit, op);
10330}
10331
10332
10333void Mesh::InitFromNCMesh(const NCMesh &ncmesh_)
10334{
10335 Dim = ncmesh_.Dimension();
10336 spaceDim = ncmesh_.SpaceDimension();
10337
10338 DeleteTables();
10339
10340 ncmesh_.GetMeshComponents(*this);
10341
10342 NumOfVertices = vertices.Size();
10343 NumOfElements = elements.Size();
10344 NumOfBdrElements = boundary.Size();
10345
10346 SetMeshGen(); // set the mesh type: 'meshgen', ...
10347
10348 NumOfEdges = NumOfFaces = 0;
10350
10351 if (Dim > 1)
10352 {
10353 el_to_edge = new Table;
10355 }
10356 if (Dim > 2)
10357 {
10359 }
10360 GenerateFaces();
10361#ifdef MFEM_DEBUG
10363#endif
10364
10365 // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
10366 // outside after this method.
10367}
10368
10369Mesh::Mesh(const NCMesh &ncmesh_)
10370 : attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
10371{
10372 Init();
10373 InitTables();
10374 InitFromNCMesh(ncmesh_);
10375 SetAttributes();
10376}
10377
10378void Mesh::Swap(Mesh& other, bool non_geometry)
10379{
10380 mfem::Swap(Dim, other.Dim);
10382
10388
10389 mfem::Swap(meshgen, other.meshgen);
10391
10395 mfem::Swap(faces, other.faces);
10400
10409
10412
10415
10416#ifdef MFEM_USE_MEMALLOC
10417 TetMemory.Swap(other.TetMemory);
10418#endif
10419
10420 if (non_geometry)
10421 {
10423 mfem::Swap(ncmesh, other.ncmesh);
10424
10425 mfem::Swap(Nodes, other.Nodes);
10426 if (Nodes) { Nodes->FESpace()->UpdateMeshPointer(this); }
10427 if (other.Nodes) { other.Nodes->FESpace()->UpdateMeshPointer(&other); }
10429
10431
10435 }
10436}
10437
10438void Mesh::GetElementData(const Array<Element*> &elem_array, int geom,
10439 Array<int> &elem_vtx, Array<int> &attr) const
10440{
10441 // protected method
10442 const int nv = Geometry::NumVerts[geom];
10443 int num_elems = 0;
10444 for (int i = 0; i < elem_array.Size(); i++)
10445 {
10446 if (elem_array[i]->GetGeometryType() == geom)
10447 {
10448 num_elems++;
10449 }
10450 }
10451 elem_vtx.SetSize(nv*num_elems);
10452 attr.SetSize(num_elems);
10453 elem_vtx.SetSize(0);
10454 attr.SetSize(0);
10455 for (int i = 0; i < elem_array.Size(); i++)
10456 {
10457 Element *el = elem_array[i];
10458 if (el->GetGeometryType() != geom) { continue; }
10459
10460 Array<int> loc_vtx(el->GetVertices(), nv);
10461 elem_vtx.Append(loc_vtx);
10462 attr.Append(el->GetAttribute());
10463 }
10464}
10465
10466static Array<int>& AllElements(Array<int> &list, int nelem)
10467{
10468 list.SetSize(nelem);
10469 for (int i = 0; i < nelem; i++) { list[i] = i; }
10470 return list;
10471}
10472
10473void Mesh::UniformRefinement(int ref_algo)
10474{
10475 Array<int> list;
10476
10477 if (NURBSext)
10478 {
10480 }
10481 else if (ncmesh)
10482 {
10483 GeneralRefinement(AllElements(list, GetNE()));
10484 }
10485 else if (ref_algo == 1 && meshgen == 1 && Dim == 3)
10486 {
10487 // algorithm "B" for an all-tet mesh
10488 LocalRefinement(AllElements(list, GetNE()));
10489 }
10490 else
10491 {
10492 switch (Dim)
10493 {
10494 case 1: LocalRefinement(AllElements(list, GetNE())); break;
10495 case 2: UniformRefinement2D(); break;
10496 case 3: UniformRefinement3D(); break;
10497 default: MFEM_ABORT("internal error");
10498 }
10499 }
10500}
10501
10503{
10504 if (NURBSext && cf > 1)
10505 {
10507 Array<int> initialCoarsening; // Initial coarsening factors
10508 NURBSext->GetCoarseningFactors(initialCoarsening);
10509
10510 // If refinement formulas are nested, then initial coarsening is skipped.
10511 bool noInitialCoarsening = true;
10512 for (auto f : initialCoarsening)
10513 {
10514 noInitialCoarsening = (noInitialCoarsening && f == 1);
10515 }
10516
10517 if (noInitialCoarsening)
10518 {
10519 NURBSext->Coarsen(cf, tol);
10520 }
10521 else
10522 {
10523 // Perform an initial full coarsening, and then refine. This is
10524 // necessary only for non-nested refinement formulas.
10525 NURBSext->Coarsen(initialCoarsening, tol);
10526
10527 // FiniteElementSpace::Update is not supported
10529 sequence++;
10530
10531 UpdateNURBS();
10532
10533 // Prepare for refinement by factors.
10535
10536 Array<int> rf(initialCoarsening);
10537 bool divisible = true;
10538 for (int i=0; i<rf.Size(); ++i)
10539 {
10540 rf[i] /= cf;
10541 divisible = divisible && cf * rf[i] == initialCoarsening[i];
10542 }
10543
10544 MFEM_VERIFY(divisible, "Invalid coarsening");
10545
10546 // Refine from the fully coarsened mesh to the mesh coarsened by the
10547 // factor cf.
10549 }
10550
10551 last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
10552 sequence++;
10553
10554 UpdateNURBS();
10555 }
10556}
10557
10559 int nonconforming, int nc_limit)
10560{
10561 if (ncmesh)
10562 {
10563 nonconforming = 1;
10564 }
10565 else if (Dim == 1 || (Dim == 3 && (meshgen & 1)))
10566 {
10567 nonconforming = 0;
10568 }
10569 else if (nonconforming < 0)
10570 {
10571 // determine if nonconforming refinement is suitable
10572 if ((meshgen & 2) || (meshgen & 4) || (meshgen & 8))
10573 {
10574 nonconforming = 1; // tensor product elements and wedges
10575 }
10576 else
10577 {
10578 nonconforming = 0; // simplices
10579 }
10580 }
10581
10582 if (nonconforming)
10583 {
10584 // non-conforming refinement (hanging nodes)
10585 NonconformingRefinement(refinements, nc_limit);
10586 }
10587 else
10588 {
10589 Array<int> el_to_refine(refinements.Size());
10590 for (int i = 0; i < refinements.Size(); i++)
10591 {
10592 el_to_refine[i] = refinements[i].index;
10593 }
10594
10595 // infer 'type' of local refinement from first element's 'ref_type'
10596 int type, rt = (refinements.Size() ? refinements[0].ref_type : 7);
10597 if (rt == 1 || rt == 2 || rt == 4)
10598 {
10599 type = 1; // bisection
10600 }
10601 else if (rt == 3 || rt == 5 || rt == 6)
10602 {
10603 type = 2; // quadrisection
10604 }
10605 else
10606 {
10607 type = 3; // octasection
10608 }
10609
10610 // red-green refinement and bisection, no hanging nodes
10611 LocalRefinement(el_to_refine, type);
10612 }
10613}
10614
10615void Mesh::GeneralRefinement(const Array<int> &el_to_refine, int nonconforming,
10616 int nc_limit)
10617{
10618 Array<Refinement> refinements(el_to_refine.Size());
10619 for (int i = 0; i < el_to_refine.Size(); i++)
10620 {
10621 refinements[i] = Refinement(el_to_refine[i]);
10622 }
10623 GeneralRefinement(refinements, nonconforming, nc_limit);
10624}
10625
10626void Mesh::EnsureNCMesh(bool simplices_nonconforming)
10627{
10628 MFEM_VERIFY(!NURBSext, "Cannot convert a NURBS mesh to an NC mesh. "
10629 "Please project the NURBS to Nodes first, with SetCurvature().");
10630
10631#ifdef MFEM_USE_MPI
10632 MFEM_VERIFY(ncmesh != NULL || dynamic_cast<const ParMesh*>(this) == NULL,
10633 "Sorry, converting a conforming ParMesh to an NC mesh is "
10634 "not possible.");
10635#endif
10636
10637 if (!ncmesh)
10638 {
10639 if ((meshgen & 0x2) /* quads/hexes */ ||
10640 (meshgen & 0x4) /* wedges */ ||
10641 (simplices_nonconforming && (meshgen & 0x1)) /* simplices */)
10642 {
10643 ncmesh = new NCMesh(this);
10644 ncmesh->OnMeshUpdated(this);
10646 }
10647 }
10648}
10649
10650void Mesh::RandomRefinement(real_t prob, bool aniso, int nonconforming,
10651 int nc_limit)
10652{
10653 Array<Refinement> refs;
10654 for (int i = 0; i < GetNE(); i++)
10655 {
10656 if ((real_t) rand() / real_t(RAND_MAX) < prob)
10657 {
10658 int type = 7;
10659 if (aniso)
10660 {
10661 type = (Dim == 3) ? (rand() % 7 + 1) : (rand() % 3 + 1);
10662 }
10663 refs.Append(Refinement(i, type));
10664 }
10665 }
10666 GeneralRefinement(refs, nonconforming, nc_limit);
10667}
10668
10669void Mesh::RefineAtVertex(const Vertex& vert, real_t eps, int nonconforming)
10670{
10671 Array<int> v;
10672 Array<Refinement> refs;
10673 for (int i = 0; i < GetNE(); i++)
10674 {
10675 GetElementVertices(i, v);
10676 bool refine = false;
10677 for (int j = 0; j < v.Size(); j++)
10678 {
10679 real_t dist = 0.0;
10680 for (int l = 0; l < spaceDim; l++)
10681 {
10682 real_t d = vert(l) - vertices[v[j]](l);
10683 dist += d*d;
10684 }
10685 if (dist <= eps*eps) { refine = true; break; }
10686 }
10687 if (refine)
10688 {
10689 refs.Append(Refinement(i));
10690 }
10691 }
10692 GeneralRefinement(refs, nonconforming);
10693}
10694
10695bool Mesh::RefineByError(const Array<real_t> &elem_error, real_t threshold,
10696 int nonconforming, int nc_limit)
10697{
10698 MFEM_VERIFY(elem_error.Size() == GetNE(), "");
10699 Array<Refinement> refs;
10700 for (int i = 0; i < GetNE(); i++)
10701 {
10702 if (elem_error[i] > threshold)
10703 {
10704 refs.Append(Refinement(i));
10705 }
10706 }
10707 if (ReduceInt(refs.Size()))
10708 {
10709 GeneralRefinement(refs, nonconforming, nc_limit);
10710 return true;
10711 }
10712 return false;
10713}
10714
10715bool Mesh::RefineByError(const Vector &elem_error, real_t threshold,
10716 int nonconforming, int nc_limit)
10717{
10718 Array<real_t> tmp(const_cast<real_t*>(elem_error.GetData()),
10719 elem_error.Size());
10720 return RefineByError(tmp, threshold, nonconforming, nc_limit);
10721}
10722
10723
10724void Mesh::Bisection(int i, const DSTable &v_to_v,
10725 int *edge1, int *edge2, int *middle)
10726{
10727 int *vert;
10728 int v[2][4], v_new, bisect, t;
10729 Element *el = elements[i];
10730 Vertex V;
10731
10732 t = el->GetType();
10733 if (t == Element::TRIANGLE)
10734 {
10735 Triangle *tri = (Triangle *) el;
10736
10737 vert = tri->GetVertices();
10738
10739 // 1. Get the index for the new vertex in v_new.
10740 bisect = v_to_v(vert[0], vert[1]);
10741 MFEM_ASSERT(bisect >= 0, "");
10742
10743 if (middle[bisect] == -1)
10744 {
10745 v_new = NumOfVertices++;
10746 for (int d = 0; d < spaceDim; d++)
10747 {
10748 V(d) = 0.5 * (vertices[vert[0]](d) + vertices[vert[1]](d));
10749 }
10750 vertices.Append(V);
10751
10752 // Put the element that may need refinement (because of this
10753 // bisection) in edge1, or -1 if no more refinement is needed.
10754 if (edge1[bisect] == i)
10755 {
10756 edge1[bisect] = edge2[bisect];
10757 }
10758
10759 middle[bisect] = v_new;
10760 }
10761 else
10762 {
10763 v_new = middle[bisect];
10764
10765 // This edge will require no more refinement.
10766 edge1[bisect] = -1;
10767 }
10768
10769 // 2. Set the node indices for the new elements in v[0] and v[1] so that
10770 // the edge marked for refinement is between the first two nodes.
10771 v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
10772 v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
10773
10774 tri->SetVertices(v[0]); // changes vert[0..2] !!!
10775
10776 Triangle* tri_new = new Triangle(v[1], tri->GetAttribute());
10777 elements.Append(tri_new);
10778
10779 int tr = tri->GetTransform();
10780 tri_new->ResetTransform(tr);
10781
10782 // record the sequence of refinements
10783 tri->PushTransform(4);
10784 tri_new->PushTransform(5);
10785
10786 int coarse = FindCoarseElement(i);
10787 CoarseFineTr.embeddings[i].parent = coarse;
10789
10790 // 3. edge1 and edge2 may have to be changed for the second triangle.
10791 if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
10792 {
10793 bisect = v_to_v(v[1][0], v[1][1]);
10794 MFEM_ASSERT(bisect >= 0, "");
10795
10796 if (edge1[bisect] == i)
10797 {
10798 edge1[bisect] = NumOfElements;
10799 }
10800 else if (edge2[bisect] == i)
10801 {
10802 edge2[bisect] = NumOfElements;
10803 }
10804 }
10805 NumOfElements++;
10806 }
10807 else
10808 {
10809 MFEM_ABORT("Bisection for now works only for triangles.");
10810 }
10811}
10812
10814{
10815 int *vert;
10816 int v[2][4], v_new, bisect, t;
10817 Element *el = elements[i];
10818 Vertex V;
10819
10820 t = el->GetType();
10821 if (t == Element::TETRAHEDRON)
10822 {
10823 Tetrahedron *tet = (Tetrahedron *) el;
10824
10825 MFEM_VERIFY(tet->GetRefinementFlag() != 0,
10826 "TETRAHEDRON element is not marked for refinement.");
10827
10828 vert = tet->GetVertices();
10829
10830 // 1. Get the index for the new vertex in v_new.
10831 bisect = v_to_v.FindId(vert[0], vert[1]);
10832 if (bisect == -1)
10833 {
10834 v_new = NumOfVertices + v_to_v.GetId(vert[0],vert[1]);
10835 for (int j = 0; j < 3; j++)
10836 {
10837 V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j));
10838 }
10839 vertices.Append(V);
10840 }
10841 else
10842 {
10843 v_new = NumOfVertices + bisect;
10844 }
10845
10846 // 2. Set the node indices for the new elements in v[2][4] so that
10847 // the edge marked for refinement is between the first two nodes.
10848 int type, old_redges[2], flag;
10849 tet->ParseRefinementFlag(old_redges, type, flag);
10850
10851 int new_type, new_redges[2][2];
10852 v[0][3] = v_new;
10853 v[1][3] = v_new;
10854 new_redges[0][0] = 2;
10855 new_redges[0][1] = 1;
10856 new_redges[1][0] = 2;
10857 new_redges[1][1] = 1;
10858 int tr1 = -1, tr2 = -1;
10859 switch (old_redges[0])
10860 {
10861 case 2:
10862 v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3];
10863 if (type == Tetrahedron::TYPE_PF) { new_redges[0][1] = 4; }
10864 tr1 = 0;
10865 break;
10866 case 3:
10867 v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2];
10868 tr1 = 2;
10869 break;
10870 case 5:
10871 v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0];
10872 tr1 = 4;
10873 }
10874 switch (old_redges[1])
10875 {
10876 case 1:
10877 v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3];
10878 if (type == Tetrahedron::TYPE_PF) { new_redges[1][0] = 3; }
10879 tr2 = 1;
10880 break;
10881 case 4:
10882 v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2];
10883 tr2 = 3;
10884 break;
10885 case 5:
10886 v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1];
10887 tr2 = 5;
10888 }
10889
10890 int attr = tet->GetAttribute();
10891 tet->SetVertices(v[0]);
10892
10893#ifdef MFEM_USE_MEMALLOC
10894 Tetrahedron *tet2 = TetMemory.Alloc();
10895 tet2->SetVertices(v[1]);
10896 tet2->SetAttribute(attr);
10897#else
10898 Tetrahedron *tet2 = new Tetrahedron(v[1], attr);
10899#endif
10900 tet2->ResetTransform(tet->GetTransform());
10901 elements.Append(tet2);
10902
10903 // record the sequence of refinements
10904 tet->PushTransform(tr1);
10905 tet2->PushTransform(tr2);
10906
10907 int coarse = FindCoarseElement(i);
10908 CoarseFineTr.embeddings[i].parent = coarse;
10910
10911 // 3. Set the bisection flag
10912 switch (type)
10913 {
10915 new_type = Tetrahedron::TYPE_PF; break;
10917 new_type = Tetrahedron::TYPE_A; break;
10918 default:
10919 new_type = Tetrahedron::TYPE_PU;
10920 }
10921
10922 tet->CreateRefinementFlag(new_redges[0], new_type, flag+1);
10923 tet2->CreateRefinementFlag(new_redges[1], new_type, flag+1);
10924
10925 NumOfElements++;
10926 }
10927 else
10928 {
10929 MFEM_ABORT("Bisection with HashTable for now works only for tetrahedra.");
10930 }
10931}
10932
10933void Mesh::BdrBisection(int i, const HashTable<Hashed2> &v_to_v)
10934{
10935 int *vert;
10936 int v[2][3], v_new, bisect, t;
10937 Element *bdr_el = boundary[i];
10938
10939 t = bdr_el->GetType();
10940 if (t == Element::TRIANGLE)
10941 {
10942 Triangle *tri = (Triangle *) bdr_el;
10943
10944 vert = tri->GetVertices();
10945
10946 // 1. Get the index for the new vertex in v_new.
10947 bisect = v_to_v.FindId(vert[0], vert[1]);
10948 MFEM_ASSERT(bisect >= 0, "");
10949 v_new = NumOfVertices + bisect;
10950 MFEM_ASSERT(v_new != -1, "");
10951
10952 // 2. Set the node indices for the new elements in v[0] and v[1] so that
10953 // the edge marked for refinement is between the first two nodes.
10954 v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
10955 v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
10956
10957 tri->SetVertices(v[0]);
10958
10959 boundary.Append(new Triangle(v[1], tri->GetAttribute()));
10960
10962 }
10963 else
10964 {
10965 MFEM_ABORT("Bisection of boundary elements with HashTable works only for"
10966 " triangles!");
10967 }
10968}
10969
10970void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
10971 int *edge1, int *edge2, int *middle)
10972{
10973 Array<int> v;
10974 int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3];
10975 Vertex V;
10976
10977 if (elements[i]->GetType() == Element::TRIANGLE)
10978 {
10979 Triangle *tri0 = (Triangle*) elements[i];
10980 tri0->GetVertices(v);
10981
10982 // 1. Get the indices for the new vertices in array v_new
10983 bisect[0] = v_to_v(v[0],v[1]);
10984 bisect[1] = v_to_v(v[1],v[2]);
10985 bisect[2] = v_to_v(v[0],v[2]);
10986 MFEM_ASSERT(bisect[0] >= 0 && bisect[1] >= 0 && bisect[2] >= 0, "");
10987
10988 for (j = 0; j < 3; j++) // for the 3 edges fix v_new
10989 {
10990 if (middle[bisect[j]] == -1)
10991 {
10992 v_new[j] = NumOfVertices++;
10993 for (int d = 0; d < spaceDim; d++)
10994 {
10995 V(d) = (vertices[v[j]](d) + vertices[v[(j+1)%3]](d))/2.;
10996 }
10997 vertices.Append(V);
10998
10999 // Put the element that may need refinement (because of this
11000 // bisection) in edge1, or -1 if no more refinement is needed.
11001 if (edge1[bisect[j]] == i)
11002 {
11003 edge1[bisect[j]] = edge2[bisect[j]];
11004 }
11005
11006 middle[bisect[j]] = v_new[j];
11007 }
11008 else
11009 {
11010 v_new[j] = middle[bisect[j]];
11011
11012 // This edge will require no more refinement.
11013 edge1[bisect[j]] = -1;
11014 }
11015 }
11016
11017 // 2. Set the node indices for the new elements in v1, v2, v3 & v4 so that
11018 // the edges marked for refinement be between the first two nodes.
11019 v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2];
11020 v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1];
11021 v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2];
11022 v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0];
11023
11024 Triangle* tri1 = new Triangle(v1, tri0->GetAttribute());
11025 Triangle* tri2 = new Triangle(v2, tri0->GetAttribute());
11026 Triangle* tri3 = new Triangle(v3, tri0->GetAttribute());
11027
11028 elements.Append(tri1);
11029 elements.Append(tri2);
11030 elements.Append(tri3);
11031
11032 tri0->SetVertices(v4);
11033
11034 // record the sequence of refinements
11035 unsigned code = tri0->GetTransform();
11036 tri1->ResetTransform(code);
11037 tri2->ResetTransform(code);
11038 tri3->ResetTransform(code);
11039
11040 tri0->PushTransform(3);
11041 tri1->PushTransform(0);
11042 tri2->PushTransform(1);
11043 tri3->PushTransform(2);
11044
11045 // set parent indices
11046 int coarse = FindCoarseElement(i);
11051
11052 NumOfElements += 3;
11053 }
11054 else
11055 {
11056 MFEM_ABORT("Uniform refinement for now works only for triangles.");
11057 }
11058}
11059
11061{
11062 // initialize CoarseFineTr
11065 for (int i = 0; i < NumOfElements; i++)
11066 {
11067 elements[i]->ResetTransform(0);
11069 }
11070}
11071
11073{
11074 int coarse;
11075 while ((coarse = CoarseFineTr.embeddings[i].parent) != i)
11076 {
11077 i = coarse;
11078 }
11079 return coarse;
11080}
11081
11083{
11084 MFEM_VERIFY(GetLastOperation() == Mesh::REFINE, "");
11085
11086 if (ncmesh)
11087 {
11089 }
11090
11091 Mesh::GeometryList elem_geoms(*this);
11092 for (int i = 0; i < elem_geoms.Size(); i++)
11093 {
11094 const Geometry::Type geom = elem_geoms[i];
11095 if (CoarseFineTr.point_matrices[geom].SizeK()) { continue; }
11096
11097 if (geom == Geometry::TRIANGLE ||
11098 geom == Geometry::TETRAHEDRON)
11099 {
11100 std::map<unsigned, int> mat_no;
11101 mat_no[0] = 1; // identity
11102
11103 // assign matrix indices to element transformations
11104 for (int j = 0; j < elements.Size(); j++)
11105 {
11106 int index = 0;
11107 unsigned code = elements[j]->GetTransform();
11108 if (code)
11109 {
11110 int &matrix = mat_no[code];
11111 if (!matrix) { matrix = mat_no.size(); }
11112 index = matrix-1;
11113 }
11114 CoarseFineTr.embeddings[j].matrix = index;
11115 }
11116
11118 pmats.SetSize(Dim, Dim+1, mat_no.size());
11119
11120 // calculate the point matrices used
11121 std::map<unsigned, int>::iterator it;
11122 for (it = mat_no.begin(); it != mat_no.end(); ++it)
11123 {
11124 if (geom == Geometry::TRIANGLE)
11125 {
11126 Triangle::GetPointMatrix(it->first, pmats(it->second-1));
11127 }
11128 else
11129 {
11130 Tetrahedron::GetPointMatrix(it->first, pmats(it->second-1));
11131 }
11132 }
11133 }
11134 else
11135 {
11136 MFEM_ABORT("Don't know how to construct CoarseFineTransformations for"
11137 " geom = " << geom);
11138 }
11139 }
11140
11141 // NOTE: quads and hexes already have trivial transformations ready
11142 return CoarseFineTr;
11143}
11144
11145void Mesh::PrintXG(std::ostream &os) const
11146{
11147 MFEM_ASSERT(Dim==spaceDim, "2D Manifold meshes not supported");
11148 int i, j;
11149 Array<int> v;
11150
11151 if (Dim == 2)
11152 {
11153 // Print the type of the mesh.
11154 if (Nodes == NULL)
11155 {
11156 os << "areamesh2\n\n";
11157 }
11158 else
11159 {
11160 os << "curved_areamesh2\n\n";
11161 }
11162
11163 // Print the boundary elements.
11164 os << NumOfBdrElements << '\n';
11165 for (i = 0; i < NumOfBdrElements; i++)
11166 {
11167 boundary[i]->GetVertices(v);
11168
11169 os << boundary[i]->GetAttribute();
11170 for (j = 0; j < v.Size(); j++)
11171 {
11172 os << ' ' << v[j] + 1;
11173 }
11174 os << '\n';
11175 }
11176
11177 // Print the elements.
11178 os << NumOfElements << '\n';
11179 for (i = 0; i < NumOfElements; i++)
11180 {
11181 elements[i]->GetVertices(v);
11182
11183 os << elements[i]->GetAttribute() << ' ' << v.Size();
11184 for (j = 0; j < v.Size(); j++)
11185 {
11186 os << ' ' << v[j] + 1;
11187 }
11188 os << '\n';
11189 }
11190
11191 if (Nodes == NULL)
11192 {
11193 // Print the vertices.
11194 os << NumOfVertices << '\n';
11195 for (i = 0; i < NumOfVertices; i++)
11196 {
11197 os << vertices[i](0);
11198 for (j = 1; j < Dim; j++)
11199 {
11200 os << ' ' << vertices[i](j);
11201 }
11202 os << '\n';
11203 }
11204 }
11205 else
11206 {
11207 os << NumOfVertices << '\n';
11208 Nodes->Save(os);
11209 }
11210 }
11211 else // ===== Dim != 2 =====
11212 {
11213 if (Nodes)
11214 {
11215 mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D");
11216 }
11217
11218 if (meshgen == 1)
11219 {
11220 int nv;
11221 const int *ind;
11222
11223 os << "NETGEN_Neutral_Format\n";
11224 // print the vertices
11225 os << NumOfVertices << '\n';
11226 for (i = 0; i < NumOfVertices; i++)
11227 {
11228 for (j = 0; j < Dim; j++)
11229 {
11230 os << ' ' << vertices[i](j);
11231 }
11232 os << '\n';
11233 }
11234
11235 // print the elements
11236 os << NumOfElements << '\n';
11237 for (i = 0; i < NumOfElements; i++)
11238 {
11239 nv = elements[i]->GetNVertices();
11240 ind = elements[i]->GetVertices();
11241 os << elements[i]->GetAttribute();
11242 for (j = 0; j < nv; j++)
11243 {
11244 os << ' ' << ind[j]+1;
11245 }
11246 os << '\n';
11247 }
11248
11249 // print the boundary information.
11250 os << NumOfBdrElements << '\n';
11251 for (i = 0; i < NumOfBdrElements; i++)
11252 {
11253 nv = boundary[i]->GetNVertices();
11254 ind = boundary[i]->GetVertices();
11255 os << boundary[i]->GetAttribute();
11256 for (j = 0; j < nv; j++)
11257 {
11258 os << ' ' << ind[j]+1;
11259 }
11260 os << '\n';
11261 }
11262 }
11263 else if (meshgen == 2) // TrueGrid
11264 {
11265 int nv;
11266 const int *ind;
11267
11268 os << "TrueGrid\n"
11269 << "1 " << NumOfVertices << " " << NumOfElements
11270 << " 0 0 0 0 0 0 0\n"
11271 << "0 0 0 1 0 0 0 0 0 0 0\n"
11272 << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
11273 << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
11274 << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
11275
11276 for (i = 0; i < NumOfVertices; i++)
11277 os << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1)
11278 << ' ' << vertices[i](2) << " 0.0\n";
11279
11280 for (i = 0; i < NumOfElements; i++)
11281 {
11282 nv = elements[i]->GetNVertices();
11283 ind = elements[i]->GetVertices();
11284 os << i+1 << ' ' << elements[i]->GetAttribute();
11285 for (j = 0; j < nv; j++)
11286 {
11287 os << ' ' << ind[j]+1;
11288 }
11289 os << '\n';
11290 }
11291
11292 for (i = 0; i < NumOfBdrElements; i++)
11293 {
11294 nv = boundary[i]->GetNVertices();
11295 ind = boundary[i]->GetVertices();
11296 os << boundary[i]->GetAttribute();
11297 for (j = 0; j < nv; j++)
11298 {
11299 os << ' ' << ind[j]+1;
11300 }
11301 os << " 1.0 1.0 1.0 1.0\n";
11302 }
11303 }
11304 }
11305
11306 os << flush;
11307}
11308
11309void Mesh::Printer(std::ostream &os, std::string section_delimiter,
11310 const std::string &comments) const
11311{
11312 int i, j;
11313
11314 if (NURBSext)
11315 {
11316 // general format
11317 NURBSext->Print(os, comments);
11318 os << '\n';
11319 Nodes->Save(os);
11320
11321 // patch-wise format
11322 // NURBSext->ConvertToPatches(*Nodes);
11323 // NURBSext->Print(os);
11324
11325 return;
11326 }
11327
11328 if (Nonconforming())
11329 {
11330 // Workaround for inconsistent Mesh state where the Mesh has nodes and
11331 // ncmesh->coodrinates is not empty. Such state can be created with the
11332 // method Mesh::SwapNodes(), see the comment at the beginning of its
11333 // implementation.
11334 Array<real_t> coords_save;
11335 if (Nodes) { mfem::Swap(coords_save, ncmesh->coordinates); }
11336
11337 // nonconforming mesh format
11338 ncmesh->Print(os, comments);
11339
11340 if (Nodes)
11341 {
11342 mfem::Swap(coords_save, ncmesh->coordinates);
11343
11344 os << "\n# mesh curvature GridFunction";
11345 os << "\nnodes\n";
11346 Nodes->Save(os);
11347 }
11348
11349 os << "\nmfem_mesh_end" << endl;
11350 return;
11351 }
11352
11353 // serial/parallel conforming mesh format
11354 const bool set_names = attribute_sets.SetsExist() ||
11356 os << (!set_names && section_delimiter.empty()
11357 ? "MFEM mesh v1.0\n" :
11358 (!set_names ? "MFEM mesh v1.2\n" : "MFEM mesh v1.3\n"));
11359
11360 if (set_names && section_delimiter.empty())
11361 {
11362 section_delimiter = "mfem_mesh_end";
11363 }
11364
11365 // optional
11366 if (!comments.empty()) { os << '\n' << comments << '\n'; }
11367
11368 os <<
11369 "\n#\n# MFEM Geometry Types (see fem/geom.hpp):\n#\n"
11370 "# POINT = 0\n"
11371 "# SEGMENT = 1\n"
11372 "# TRIANGLE = 2\n"
11373 "# SQUARE = 3\n"
11374 "# TETRAHEDRON = 4\n"
11375 "# CUBE = 5\n"
11376 "# PRISM = 6\n"
11377 "# PYRAMID = 7\n"
11378 "#\n";
11379
11380 os << "\ndimension\n" << Dim;
11381
11382 os << "\n\nelements\n" << NumOfElements << '\n';
11383 for (i = 0; i < NumOfElements; i++)
11384 {
11385 PrintElement(elements[i], os);
11386 }
11387
11388 if (set_names)
11389 {
11390 os << "\nattribute_sets\n";
11392 }
11393
11394 os << "\nboundary\n" << NumOfBdrElements << '\n';
11395 for (i = 0; i < NumOfBdrElements; i++)
11396 {
11397 PrintElement(boundary[i], os);
11398 }
11399
11400 if (set_names)
11401 {
11402 os << "\nbdr_attribute_sets\n";
11404 }
11405
11406 os << "\nvertices\n" << NumOfVertices << '\n';
11407 if (Nodes == NULL)
11408 {
11409 os << spaceDim << '\n';
11410 for (i = 0; i < NumOfVertices; i++)
11411 {
11412 os << vertices[i](0);
11413 for (j = 1; j < spaceDim; j++)
11414 {
11415 os << ' ' << vertices[i](j);
11416 }
11417 os << '\n';
11418 }
11419 os.flush();
11420 }
11421 else
11422 {
11423 os << "\nnodes\n";
11424 Nodes->Save(os);
11425 }
11426
11427 if (!section_delimiter.empty())
11428 {
11429 os << '\n'
11430 << section_delimiter << endl; // only with formats v1.2 and above
11431 }
11432}
11433
11434void Mesh::PrintTopo(std::ostream &os, const Array<int> &e_to_k,
11435 const int version, const std::string &comments) const
11436{
11437 MFEM_VERIFY(version == 10 || version == 11, "Invalid NURBS mesh version");
11438
11439 int i;
11440 Array<int> vert;
11441
11442 os << "MFEM NURBS mesh v" << int(version / 10) << "." << version % 10 << "\n";
11443
11444 // optional
11445 if (!comments.empty()) { os << '\n' << comments << '\n'; }
11446
11447 os <<
11448 "\n#\n# MFEM Geometry Types (see fem/geom.hpp):\n#\n"
11449 "# SEGMENT = 1\n"
11450 "# SQUARE = 3\n"
11451 "# CUBE = 5\n"
11452 "#\n";
11453
11454 os << "\ndimension\n" << Dim
11455 << "\n\nelements\n" << NumOfElements << '\n';
11456 for (i = 0; i < NumOfElements; i++)
11457 {
11458 PrintElement(elements[i], os);
11459 }
11460
11461 os << "\nboundary\n" << NumOfBdrElements << '\n';
11462 for (i = 0; i < NumOfBdrElements; i++)
11463 {
11464 PrintElement(boundary[i], os);
11465 }
11466
11467 os << "\nedges\n" << NumOfEdges << '\n';
11468 for (i = 0; i < NumOfEdges; i++)
11469 {
11470 edge_vertex->GetRow(i, vert);
11471 int ki = e_to_k[i];
11472 if (ki < 0)
11473 {
11474 ki = -1 - ki;
11475 }
11476 os << ki << ' ' << vert[0] << ' ' << vert[1] << '\n';
11477 }
11478 os << "\nvertices\n" << NumOfVertices << '\n';
11479}
11480
11481void Mesh::Save(const std::string &fname, int precision) const
11482{
11483 ofstream ofs(fname);
11484 ofs.precision(precision);
11485 Print(ofs);
11486}
11487
11488#ifdef MFEM_USE_ADIOS2
11490{
11491 os.Print(*this);
11492}
11493#endif
11494
11495void Mesh::PrintVTK(std::ostream &os)
11496{
11497 os <<
11498 "# vtk DataFile Version 3.0\n"
11499 "Generated by MFEM\n"
11500 "ASCII\n"
11501 "DATASET UNSTRUCTURED_GRID\n";
11502
11503 if (Nodes == NULL)
11504 {
11505 os << "POINTS " << NumOfVertices << " double\n";
11506 for (int i = 0; i < NumOfVertices; i++)
11507 {
11508 os << vertices[i](0);
11509 int j;
11510 for (j = 1; j < spaceDim; j++)
11511 {
11512 os << ' ' << vertices[i](j);
11513 }
11514 for ( ; j < 3; j++)
11515 {
11516 os << ' ' << 0.0;
11517 }
11518 os << '\n';
11519 }
11520 }
11521 else
11522 {
11523 Array<int> vdofs(3);
11524 os << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n";
11525 for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++)
11526 {
11527 vdofs.SetSize(1);
11528 vdofs[0] = i;
11529 Nodes->FESpace()->DofsToVDofs(vdofs);
11530 os << (*Nodes)(vdofs[0]);
11531 int j;
11532 for (j = 1; j < spaceDim; j++)
11533 {
11534 os << ' ' << (*Nodes)(vdofs[j]);
11535 }
11536 for ( ; j < 3; j++)
11537 {
11538 os << ' ' << 0.0;
11539 }
11540 os << '\n';
11541 }
11542 }
11543
11544 int order = -1;
11545 if (Nodes == NULL)
11546 {
11547 int size = 0;
11548 for (int i = 0; i < NumOfElements; i++)
11549 {
11550 size += elements[i]->GetNVertices() + 1;
11551 }
11552 os << "CELLS " << NumOfElements << ' ' << size << '\n';
11553 for (int i = 0; i < NumOfElements; i++)
11554 {
11555 const int *v = elements[i]->GetVertices();
11556 const int nv = elements[i]->GetNVertices();
11557 os << nv;
11558 Geometry::Type geom = elements[i]->GetGeometryType();
11559 const int *perm = VTKGeometry::VertexPermutation[geom];
11560 for (int j = 0; j < nv; j++)
11561 {
11562 os << ' ' << v[perm ? perm[j] : j];
11563 }
11564 os << '\n';
11565 }
11566 order = 1;
11567 }
11568 else
11569 {
11570 Array<int> dofs;
11571 int size = 0;
11572 for (int i = 0; i < NumOfElements; i++)
11573 {
11574 Nodes->FESpace()->GetElementDofs(i, dofs);
11575 MFEM_ASSERT(Dim != 0 || dofs.Size() == 1,
11576 "Point meshes should have a single dof per element");
11577 size += dofs.Size() + 1;
11578 }
11579 os << "CELLS " << NumOfElements << ' ' << size << '\n';
11580 const char *fec_name = Nodes->FESpace()->FEColl()->Name();
11581
11582 if (!strcmp(fec_name, "Linear") ||
11583 !strcmp(fec_name, "H1_0D_P1") ||
11584 !strcmp(fec_name, "H1_1D_P1") ||
11585 !strcmp(fec_name, "H1_2D_P1") ||
11586 !strcmp(fec_name, "H1_3D_P1"))
11587 {
11588 order = 1;
11589 }
11590 else if (!strcmp(fec_name, "Quadratic") ||
11591 !strcmp(fec_name, "H1_1D_P2") ||
11592 !strcmp(fec_name, "H1_2D_P2") ||
11593 !strcmp(fec_name, "H1_3D_P2"))
11594 {
11595 order = 2;
11596 }
11597 if (order == -1)
11598 {
11599 mfem::err << "Mesh::PrintVTK : can not save '"
11600 << fec_name << "' elements!" << endl;
11601 mfem_error();
11602 }
11603 for (int i = 0; i < NumOfElements; i++)
11604 {
11605 Nodes->FESpace()->GetElementDofs(i, dofs);
11606 os << dofs.Size();
11607 if (order == 1)
11608 {
11609 for (int j = 0; j < dofs.Size(); j++)
11610 {
11611 os << ' ' << dofs[j];
11612 }
11613 }
11614 else if (order == 2)
11615 {
11616 const int *vtk_mfem;
11617 switch (elements[i]->GetGeometryType())
11618 {
11619 case Geometry::SEGMENT:
11620 case Geometry::TRIANGLE:
11621 case Geometry::SQUARE:
11622 vtk_mfem = vtk_quadratic_hex; break; // identity map
11624 vtk_mfem = vtk_quadratic_tet; break;
11625 case Geometry::PRISM:
11626 vtk_mfem = vtk_quadratic_wedge; break;
11627 case Geometry::CUBE:
11628 default:
11629 vtk_mfem = vtk_quadratic_hex; break;
11630 }
11631 for (int j = 0; j < dofs.Size(); j++)
11632 {
11633 os << ' ' << dofs[vtk_mfem[j]];
11634 }
11635 }
11636 os << '\n';
11637 }
11638 }
11639
11640 os << "CELL_TYPES " << NumOfElements << '\n';
11641 for (int i = 0; i < NumOfElements; i++)
11642 {
11643 int vtk_cell_type = 5;
11645 if (order == 1) { vtk_cell_type = VTKGeometry::Map[geom]; }
11646 else if (order == 2) { vtk_cell_type = VTKGeometry::QuadraticMap[geom]; }
11647 os << vtk_cell_type << '\n';
11648 }
11649
11650 // write attributes
11651 os << "CELL_DATA " << NumOfElements << '\n'
11652 << "SCALARS material int\n"
11653 << "LOOKUP_TABLE default\n";
11654 for (int i = 0; i < NumOfElements; i++)
11655 {
11656 os << elements[i]->GetAttribute() << '\n';
11657 }
11658 os.flush();
11659}
11660
11661void Mesh::PrintVTU(std::string fname,
11662 VTKFormat format,
11663 bool high_order_output,
11664 int compression_level,
11665 bool bdr)
11666{
11667 int ref = (high_order_output && Nodes)
11668 ? Nodes->FESpace()->GetMaxElementOrder() : 1;
11669
11670 fname = fname + ".vtu";
11671 std::fstream os(fname.c_str(),std::ios::out);
11672 os << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"";
11673 if (compression_level != 0)
11674 {
11675 os << " compressor=\"vtkZLibDataCompressor\"";
11676 }
11677 os << " byte_order=\"" << VTKByteOrder() << "\">\n";
11678 os << "<UnstructuredGrid>\n";
11679 PrintVTU(os, ref, format, high_order_output, compression_level, bdr);
11680 os << "</Piece>\n"; // need to close the piece open in the PrintVTU method
11681 os << "</UnstructuredGrid>\n";
11682 os << "</VTKFile>" << std::endl;
11683
11684 os.close();
11685}
11686
11687void Mesh::PrintBdrVTU(std::string fname,
11688 VTKFormat format,
11689 bool high_order_output,
11690 int compression_level)
11691{
11692 PrintVTU(fname, format, high_order_output, compression_level, true);
11693}
11694
11695void Mesh::PrintVTU(std::ostream &os, int ref, VTKFormat format,
11696 bool high_order_output, int compression_level,
11697 bool bdr_elements)
11698{
11699 RefinedGeometry *RefG;
11700 DenseMatrix pmat;
11701
11702 const char *fmt_str = (format == VTKFormat::ASCII) ? "ascii" : "binary";
11703 const char *type_str = (format != VTKFormat::BINARY32) ? "Float64" : "Float32";
11704 std::vector<char> buf;
11705
11706 auto get_geom = [&](int i)
11707 {
11708 if (bdr_elements) { return GetBdrElementGeometry(i); }
11709 else { return GetElementBaseGeometry(i); }
11710 };
11711
11712 int ne = bdr_elements ? GetNBE() : GetNE();
11713 // count the number of points and cells
11714 int np = 0, nc_ref = 0;
11715 for (int i = 0; i < ne; i++)
11716 {
11717 Geometry::Type geom = get_geom(i);
11718 int nv = Geometries.GetVertices(geom)->GetNPoints();
11719 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11720 np += RefG->RefPts.GetNPoints();
11721 nc_ref += RefG->RefGeoms.Size() / nv;
11722 }
11723
11724 os << "<Piece NumberOfPoints=\"" << np << "\" NumberOfCells=\""
11725 << (high_order_output ? ne : nc_ref) << "\">\n";
11726
11727 // print out the points
11728 os << "<Points>\n";
11729 os << "<DataArray type=\"" << type_str
11730 << "\" NumberOfComponents=\"3\" format=\"" << fmt_str << "\">\n";
11731 for (int i = 0; i < ne; i++)
11732 {
11733 RefG = GlobGeometryRefiner.Refine(get_geom(i), ref, 1);
11734
11735 if (bdr_elements)
11736 {
11738 }
11739 else
11740 {
11741 GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
11742 }
11743
11744 for (int j = 0; j < pmat.Width(); j++)
11745 {
11746 WriteBinaryOrASCII(os, buf, pmat(0,j), " ", format);
11747 if (pmat.Height() > 1)
11748 {
11749 WriteBinaryOrASCII(os, buf, pmat(1,j), " ", format);
11750 }
11751 else
11752 {
11753 WriteBinaryOrASCII(os, buf, 0.0, " ", format);
11754 }
11755 if (pmat.Height() > 2)
11756 {
11757 WriteBinaryOrASCII(os, buf, pmat(2,j), "", format);
11758 }
11759 else
11760 {
11761 WriteBinaryOrASCII(os, buf, 0.0, "", format);
11762 }
11763 if (format == VTKFormat::ASCII) { os << '\n'; }
11764 }
11765 }
11766 if (format != VTKFormat::ASCII)
11767 {
11768 WriteBase64WithSizeAndClear(os, buf, compression_level);
11769 }
11770 os << "</DataArray>" << std::endl;
11771 os << "</Points>" << std::endl;
11772
11773 os << "<Cells>" << std::endl;
11774 os << "<DataArray type=\"Int32\" Name=\"connectivity\" format=\""
11775 << fmt_str << "\">" << std::endl;
11776 // connectivity
11777 std::vector<int> offset;
11778
11779 np = 0;
11780 if (high_order_output)
11781 {
11782 Array<int> local_connectivity;
11783 for (int iel = 0; iel < ne; iel++)
11784 {
11785 Geometry::Type geom = get_geom(iel);
11786 CreateVTKElementConnectivity(local_connectivity, geom, ref);
11787 int nnodes = local_connectivity.Size();
11788 for (int i=0; i<nnodes; ++i)
11789 {
11790 WriteBinaryOrASCII(os, buf, np+local_connectivity[i], " ",
11791 format);
11792 }
11793 if (format == VTKFormat::ASCII) { os << '\n'; }
11794 np += nnodes;
11795 offset.push_back(np);
11796 }
11797 }
11798 else
11799 {
11800 int coff = 0;
11801 for (int i = 0; i < ne; i++)
11802 {
11803 Geometry::Type geom = get_geom(i);
11804 int nv = Geometries.GetVertices(geom)->GetNPoints();
11805 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11806 Array<int> &RG = RefG->RefGeoms;
11807 for (int j = 0; j < RG.Size(); )
11808 {
11809 coff = coff+nv;
11810 offset.push_back(coff);
11811 const int *p = VTKGeometry::VertexPermutation[geom];
11812 for (int k = 0; k < nv; k++, j++)
11813 {
11814 WriteBinaryOrASCII(os, buf, np + RG[p ? p[j] : j], " ",
11815 format);
11816 }
11817 if (format == VTKFormat::ASCII) { os << '\n'; }
11818 }
11819 np += RefG->RefPts.GetNPoints();
11820 }
11821 }
11822 if (format != VTKFormat::ASCII)
11823 {
11824 WriteBase64WithSizeAndClear(os, buf, compression_level);
11825 }
11826 os << "</DataArray>" << std::endl;
11827
11828 os << "<DataArray type=\"Int32\" Name=\"offsets\" format=\""
11829 << fmt_str << "\">" << std::endl;
11830 // offsets
11831 for (size_t ii=0; ii<offset.size(); ii++)
11832 {
11833 WriteBinaryOrASCII(os, buf, offset[ii], "\n", format);
11834 }
11835 if (format != VTKFormat::ASCII)
11836 {
11837 WriteBase64WithSizeAndClear(os, buf, compression_level);
11838 }
11839 os << "</DataArray>" << std::endl;
11840 os << "<DataArray type=\"UInt8\" Name=\"types\" format=\""
11841 << fmt_str << "\">" << std::endl;
11842 // cell types
11843 const int *vtk_geom_map =
11844 high_order_output ? VTKGeometry::HighOrderMap : VTKGeometry::Map;
11845 for (int i = 0; i < ne; i++)
11846 {
11847 Geometry::Type geom = get_geom(i);
11848 uint8_t vtk_cell_type = 5;
11849
11850 vtk_cell_type = vtk_geom_map[geom];
11851
11852 if (high_order_output)
11853 {
11854 WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
11855 }
11856 else
11857 {
11858 int nv = Geometries.GetVertices(geom)->GetNPoints();
11859 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11860 Array<int> &RG = RefG->RefGeoms;
11861 for (int j = 0; j < RG.Size(); j += nv)
11862 {
11863 WriteBinaryOrASCII(os, buf, vtk_cell_type, "\n", format);
11864 }
11865 }
11866 }
11867 if (format != VTKFormat::ASCII)
11868 {
11869 WriteBase64WithSizeAndClear(os, buf, compression_level);
11870 }
11871 os << "</DataArray>" << std::endl;
11872 os << "</Cells>" << std::endl;
11873
11874 os << "<CellData Scalars=\"attribute\">" << std::endl;
11875 os << "<DataArray type=\"Int32\" Name=\"attribute\" format=\""
11876 << fmt_str << "\">" << std::endl;
11877 for (int i = 0; i < ne; i++)
11878 {
11879 int attr = bdr_elements ? GetBdrAttribute(i) : GetAttribute(i);
11880 if (high_order_output)
11881 {
11882 WriteBinaryOrASCII(os, buf, attr, "\n", format);
11883 }
11884 else
11885 {
11886 Geometry::Type geom = get_geom(i);
11887 int nv = Geometries.GetVertices(geom)->GetNPoints();
11888 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11889 for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
11890 {
11891 WriteBinaryOrASCII(os, buf, attr, "\n", format);
11892 }
11893 }
11894 }
11895 if (format != VTKFormat::ASCII)
11896 {
11897 WriteBase64WithSizeAndClear(os, buf, compression_level);
11898 }
11899 os << "</DataArray>" << std::endl;
11900 os << "</CellData>" << std::endl;
11901}
11902
11903
11904void Mesh::PrintVTK(std::ostream &os, int ref, int field_data)
11905{
11906 int np, nc, size;
11907 RefinedGeometry *RefG;
11908 DenseMatrix pmat;
11909
11910 os <<
11911 "# vtk DataFile Version 3.0\n"
11912 "Generated by MFEM\n"
11913 "ASCII\n"
11914 "DATASET UNSTRUCTURED_GRID\n";
11915
11916 // additional dataset information
11917 if (field_data)
11918 {
11919 os << "FIELD FieldData 1\n"
11920 << "MaterialIds " << 1 << " " << attributes.Size() << " int\n";
11921 for (int i = 0; i < attributes.Size(); i++)
11922 {
11923 os << ' ' << attributes[i];
11924 }
11925 os << '\n';
11926 }
11927
11928 // count the points, cells, size
11929 np = nc = size = 0;
11930 for (int i = 0; i < GetNE(); i++)
11931 {
11933 int nv = Geometries.GetVertices(geom)->GetNPoints();
11934 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11935 np += RefG->RefPts.GetNPoints();
11936 nc += RefG->RefGeoms.Size() / nv;
11937 size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
11938 }
11939 os << "POINTS " << np << " double\n";
11940 // write the points
11941 for (int i = 0; i < GetNE(); i++)
11942 {
11944 GetElementBaseGeometry(i), ref, 1);
11945
11946 GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
11947
11948 for (int j = 0; j < pmat.Width(); j++)
11949 {
11950 os << pmat(0, j) << ' ';
11951 if (pmat.Height() > 1)
11952 {
11953 os << pmat(1, j) << ' ';
11954 if (pmat.Height() > 2)
11955 {
11956 os << pmat(2, j);
11957 }
11958 else
11959 {
11960 os << 0.0;
11961 }
11962 }
11963 else
11964 {
11965 os << 0.0 << ' ' << 0.0;
11966 }
11967 os << '\n';
11968 }
11969 }
11970
11971 // write the cells
11972 os << "CELLS " << nc << ' ' << size << '\n';
11973 np = 0;
11974 for (int i = 0; i < GetNE(); i++)
11975 {
11977 int nv = Geometries.GetVertices(geom)->GetNPoints();
11978 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11979 Array<int> &RG = RefG->RefGeoms;
11980
11981 for (int j = 0; j < RG.Size(); )
11982 {
11983 os << nv;
11984 for (int k = 0; k < nv; k++, j++)
11985 {
11986 os << ' ' << np + RG[j];
11987 }
11988 os << '\n';
11989 }
11990 np += RefG->RefPts.GetNPoints();
11991 }
11992 os << "CELL_TYPES " << nc << '\n';
11993 for (int i = 0; i < GetNE(); i++)
11994 {
11996 int nv = Geometries.GetVertices(geom)->GetNPoints();
11997 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
11998 Array<int> &RG = RefG->RefGeoms;
11999 int vtk_cell_type = VTKGeometry::Map[geom];
12000
12001 for (int j = 0; j < RG.Size(); j += nv)
12002 {
12003 os << vtk_cell_type << '\n';
12004 }
12005 }
12006 // write attributes (materials)
12007 os << "CELL_DATA " << nc << '\n'
12008 << "SCALARS material int\n"
12009 << "LOOKUP_TABLE default\n";
12010 for (int i = 0; i < GetNE(); i++)
12011 {
12013 int nv = Geometries.GetVertices(geom)->GetNPoints();
12014 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12015 int attr = GetAttribute(i);
12016 for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
12017 {
12018 os << attr << '\n';
12019 }
12020 }
12021
12022 if (Dim > 1)
12023 {
12024 Array<int> coloring;
12025 srand((unsigned)time(0));
12026 real_t a = rand_real();
12027 int el0 = (int)floor(a * GetNE());
12028 GetElementColoring(coloring, el0);
12029 os << "SCALARS element_coloring int\n"
12030 << "LOOKUP_TABLE default\n";
12031 for (int i = 0; i < GetNE(); i++)
12032 {
12034 int nv = Geometries.GetVertices(geom)->GetNPoints();
12035 RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
12036 for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
12037 {
12038 os << coloring[i] + 1 << '\n';
12039 }
12040 }
12041 }
12042
12043 // prepare to write data
12044 os << "POINT_DATA " << np << '\n' << flush;
12045}
12046
12048{
12049 int delete_el_to_el = (el_to_el) ? (0) : (1);
12050 const Table &el_el = ElementToElementTable();
12051 int num_el = GetNE(), stack_p, stack_top_p, max_num_col;
12052 Array<int> el_stack(num_el);
12053
12054 const int *i_el_el = el_el.GetI();
12055 const int *j_el_el = el_el.GetJ();
12056
12057 colors.SetSize(num_el);
12058 colors = -2;
12059 max_num_col = 1;
12060 stack_p = stack_top_p = 0;
12061 for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el)
12062 {
12063 if (colors[el] != -2)
12064 {
12065 continue;
12066 }
12067
12068 colors[el] = -1;
12069 el_stack[stack_top_p++] = el;
12070
12071 for ( ; stack_p < stack_top_p; stack_p++)
12072 {
12073 int i = el_stack[stack_p];
12074 int num_nb = i_el_el[i+1] - i_el_el[i];
12075 if (max_num_col < num_nb + 1)
12076 {
12077 max_num_col = num_nb + 1;
12078 }
12079 for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
12080 {
12081 int k = j_el_el[j];
12082 if (colors[k] == -2)
12083 {
12084 colors[k] = -1;
12085 el_stack[stack_top_p++] = k;
12086 }
12087 }
12088 }
12089 }
12090
12091 Array<int> col_marker(max_num_col);
12092
12093 for (stack_p = 0; stack_p < stack_top_p; stack_p++)
12094 {
12095 int i = el_stack[stack_p], col;
12096 col_marker = 0;
12097 for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
12098 {
12099 col = colors[j_el_el[j]];
12100 if (col != -1)
12101 {
12102 col_marker[col] = 1;
12103 }
12104 }
12105
12106 for (col = 0; col < max_num_col; col++)
12107 if (col_marker[col] == 0)
12108 {
12109 break;
12110 }
12111
12112 colors[i] = col;
12113 }
12114
12115 if (delete_el_to_el)
12116 {
12117 delete el_to_el;
12118 el_to_el = NULL;
12119 }
12120}
12121
12122void Mesh::PrintWithPartitioning(int *partitioning, std::ostream &os,
12123 int elem_attr) const
12124{
12125 if (Dim != 3 && Dim != 2) { return; }
12126
12127 int i, j, k, l, nv, nbe, *v;
12128
12129 os << "MFEM mesh v1.0\n";
12130
12131 // optional
12132 os <<
12133 "\n#\n# MFEM Geometry Types (see fem/geom.hpp):\n#\n"
12134 "# POINT = 0\n"
12135 "# SEGMENT = 1\n"
12136 "# TRIANGLE = 2\n"
12137 "# SQUARE = 3\n"
12138 "# TETRAHEDRON = 4\n"
12139 "# CUBE = 5\n"
12140 "# PRISM = 6\n"
12141 "#\n";
12142
12143 os << "\ndimension\n" << Dim
12144 << "\n\nelements\n" << NumOfElements << '\n';
12145 for (i = 0; i < NumOfElements; i++)
12146 {
12147 os << int((elem_attr) ? partitioning[i]+1 : elements[i]->GetAttribute())
12148 << ' ' << elements[i]->GetGeometryType();
12149 nv = elements[i]->GetNVertices();
12150 v = elements[i]->GetVertices();
12151 for (j = 0; j < nv; j++)
12152 {
12153 os << ' ' << v[j];
12154 }
12155 os << '\n';
12156 }
12157 nbe = 0;
12158 for (i = 0; i < faces_info.Size(); i++)
12159 {
12160 if ((l = faces_info[i].Elem2No) >= 0)
12161 {
12162 k = partitioning[faces_info[i].Elem1No];
12163 l = partitioning[l];
12164 if (k != l)
12165 {
12166 nbe++;
12167 if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
12168 {
12169 nbe++;
12170 }
12171 }
12172 }
12173 else
12174 {
12175 nbe++;
12176 }
12177 }
12178 os << "\nboundary\n" << nbe << '\n';
12179 for (i = 0; i < faces_info.Size(); i++)
12180 {
12181 if ((l = faces_info[i].Elem2No) >= 0)
12182 {
12183 k = partitioning[faces_info[i].Elem1No];
12184 l = partitioning[l];
12185 if (k != l)
12186 {
12187 nv = faces[i]->GetNVertices();
12188 v = faces[i]->GetVertices();
12189 os << k+1 << ' ' << faces[i]->GetGeometryType();
12190 for (j = 0; j < nv; j++)
12191 {
12192 os << ' ' << v[j];
12193 }
12194 os << '\n';
12195 if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
12196 {
12197 os << l+1 << ' ' << faces[i]->GetGeometryType();
12198 for (j = nv-1; j >= 0; j--)
12199 {
12200 os << ' ' << v[j];
12201 }
12202 os << '\n';
12203 }
12204 }
12205 }
12206 else
12207 {
12208 k = partitioning[faces_info[i].Elem1No];
12209 nv = faces[i]->GetNVertices();
12210 v = faces[i]->GetVertices();
12211 os << k+1 << ' ' << faces[i]->GetGeometryType();
12212 for (j = 0; j < nv; j++)
12213 {
12214 os << ' ' << v[j];
12215 }
12216 os << '\n';
12217 }
12218 }
12219 os << "\nvertices\n" << NumOfVertices << '\n';
12220 if (Nodes == NULL)
12221 {
12222 os << spaceDim << '\n';
12223 for (i = 0; i < NumOfVertices; i++)
12224 {
12225 os << vertices[i](0);
12226 for (j = 1; j < spaceDim; j++)
12227 {
12228 os << ' ' << vertices[i](j);
12229 }
12230 os << '\n';
12231 }
12232 os.flush();
12233 }
12234 else
12235 {
12236 os << "\nnodes\n";
12237 Nodes->Save(os);
12238 }
12239}
12240
12242 std::ostream &os,
12243 int interior_faces)
12244{
12245 MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported\n");
12246 if (Dim != 3 && Dim != 2) { return; }
12247
12248 int *vcount = new int[NumOfVertices];
12249 for (int i = 0; i < NumOfVertices; i++)
12250 {
12251 vcount[i] = 0;
12252 }
12253 for (int i = 0; i < NumOfElements; i++)
12254 {
12255 int nv = elements[i]->GetNVertices();
12256 const int *ind = elements[i]->GetVertices();
12257 for (int j = 0; j < nv; j++)
12258 {
12259 vcount[ind[j]]++;
12260 }
12261 }
12262
12263 int *voff = new int[NumOfVertices+1];
12264 voff[0] = 0;
12265 for (int i = 1; i <= NumOfVertices; i++)
12266 {
12267 voff[i] = vcount[i-1] + voff[i-1];
12268 }
12269
12270 int **vown = new int*[NumOfVertices];
12271 for (int i = 0; i < NumOfVertices; i++)
12272 {
12273 vown[i] = new int[vcount[i]];
12274 }
12275
12276 // 2D
12277 if (Dim == 2)
12278 {
12279 Table edge_el;
12280 Transpose(ElementToEdgeTable(), edge_el);
12281
12282 // Fake printing of the elements.
12283 for (int i = 0; i < NumOfElements; i++)
12284 {
12285 int nv = elements[i]->GetNVertices();
12286 const int *ind = elements[i]->GetVertices();
12287 for (int j = 0; j < nv; j++)
12288 {
12289 vcount[ind[j]]--;
12290 vown[ind[j]][vcount[ind[j]]] = i;
12291 }
12292 }
12293
12294 for (int i = 0; i < NumOfVertices; i++)
12295 {
12296 vcount[i] = voff[i+1] - voff[i];
12297 }
12298
12299 int nbe = 0;
12300 for (int i = 0; i < edge_el.Size(); i++)
12301 {
12302 const int *el = edge_el.GetRow(i);
12303 if (edge_el.RowSize(i) > 1)
12304 {
12305 int k = partitioning[el[0]];
12306 int l = partitioning[el[1]];
12307 if (interior_faces || k != l)
12308 {
12309 nbe += 2;
12310 }
12311 }
12312 else
12313 {
12314 nbe++;
12315 }
12316 }
12317
12318 // Print the type of the mesh and the boundary elements.
12319 os << "areamesh2\n\n" << nbe << '\n';
12320
12321 for (int i = 0; i < edge_el.Size(); i++)
12322 {
12323 const int *el = edge_el.GetRow(i);
12324 if (edge_el.RowSize(i) > 1)
12325 {
12326 int k = partitioning[el[0]];
12327 int l = partitioning[el[1]];
12328 if (interior_faces || k != l)
12329 {
12330 Array<int> ev;
12331 GetEdgeVertices(i,ev);
12332 os << k+1; // attribute
12333 for (int j = 0; j < 2; j++)
12334 for (int s = 0; s < vcount[ev[j]]; s++)
12335 if (vown[ev[j]][s] == el[0])
12336 {
12337 os << ' ' << voff[ev[j]]+s+1;
12338 }
12339 os << '\n';
12340 os << l+1; // attribute
12341 for (int j = 1; j >= 0; j--)
12342 for (int s = 0; s < vcount[ev[j]]; s++)
12343 if (vown[ev[j]][s] == el[1])
12344 {
12345 os << ' ' << voff[ev[j]]+s+1;
12346 }
12347 os << '\n';
12348 }
12349 }
12350 else
12351 {
12352 int k = partitioning[el[0]];
12353 Array<int> ev;
12354 GetEdgeVertices(i,ev);
12355 os << k+1; // attribute
12356 for (int j = 0; j < 2; j++)
12357 for (int s = 0; s < vcount[ev[j]]; s++)
12358 if (vown[ev[j]][s] == el[0])
12359 {
12360 os << ' ' << voff[ev[j]]+s+1;
12361 }
12362 os << '\n';
12363 }
12364 }
12365
12366 // Print the elements.
12367 os << NumOfElements << '\n';
12368 for (int i = 0; i < NumOfElements; i++)
12369 {
12370 int nv = elements[i]->GetNVertices();
12371 const int *ind = elements[i]->GetVertices();
12372 os << partitioning[i]+1 << ' '; // use subdomain number as attribute
12373 os << nv << ' ';
12374 for (int j = 0; j < nv; j++)
12375 {
12376 os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
12377 vown[ind[j]][vcount[ind[j]]] = i;
12378 }
12379 os << '\n';
12380 }
12381
12382 for (int i = 0; i < NumOfVertices; i++)
12383 {
12384 vcount[i] = voff[i+1] - voff[i];
12385 }
12386
12387 // Print the vertices.
12388 os << voff[NumOfVertices] << '\n';
12389 for (int i = 0; i < NumOfVertices; i++)
12390 for (int k = 0; k < vcount[i]; k++)
12391 {
12392 for (int j = 0; j < Dim; j++)
12393 {
12394 os << vertices[i](j) << ' ';
12395 }
12396 os << '\n';
12397 }
12398 }
12399 // Dim is 3
12400 else if (meshgen == 1)
12401 {
12402 os << "NETGEN_Neutral_Format\n";
12403 // print the vertices
12404 os << voff[NumOfVertices] << '\n';
12405 for (int i = 0; i < NumOfVertices; i++)
12406 for (int k = 0; k < vcount[i]; k++)
12407 {
12408 for (int j = 0; j < Dim; j++)
12409 {
12410 os << ' ' << vertices[i](j);
12411 }
12412 os << '\n';
12413 }
12414
12415 // print the elements
12416 os << NumOfElements << '\n';
12417 for (int i = 0; i < NumOfElements; i++)
12418 {
12419 int nv = elements[i]->GetNVertices();
12420 const int *ind = elements[i]->GetVertices();
12421 os << partitioning[i]+1; // use subdomain number as attribute
12422 for (int j = 0; j < nv; j++)
12423 {
12424 os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
12425 vown[ind[j]][vcount[ind[j]]] = i;
12426 }
12427 os << '\n';
12428 }
12429
12430 for (int i = 0; i < NumOfVertices; i++)
12431 {
12432 vcount[i] = voff[i+1] - voff[i];
12433 }
12434
12435 // print the boundary information.
12436 int nbe = 0;
12437 for (int i = 0; i < NumOfFaces; i++)
12438 {
12439 int l = faces_info[i].Elem2No;
12440 if (l >= 0)
12441 {
12442 int k = partitioning[faces_info[i].Elem1No];
12443 l = partitioning[l];
12444 if (interior_faces || k != l)
12445 {
12446 nbe += 2;
12447 }
12448 }
12449 else
12450 {
12451 nbe++;
12452 }
12453 }
12454
12455 os << nbe << '\n';
12456 for (int i = 0; i < NumOfFaces; i++)
12457 {
12458 int l = faces_info[i].Elem2No;
12459 if (l >= 0)
12460 {
12461 int k = partitioning[faces_info[i].Elem1No];
12462 l = partitioning[l];
12463 if (interior_faces || k != l)
12464 {
12465 int nv = faces[i]->GetNVertices();
12466 const int *ind = faces[i]->GetVertices();
12467 os << k+1; // attribute
12468 for (int j = 0; j < nv; j++)
12469 for (int s = 0; s < vcount[ind[j]]; s++)
12470 if (vown[ind[j]][s] == faces_info[i].Elem1No)
12471 {
12472 os << ' ' << voff[ind[j]]+s+1;
12473 }
12474 os << '\n';
12475 os << l+1; // attribute
12476 for (int j = nv-1; j >= 0; j--)
12477 for (int s = 0; s < vcount[ind[j]]; s++)
12478 if (vown[ind[j]][s] == faces_info[i].Elem2No)
12479 {
12480 os << ' ' << voff[ind[j]]+s+1;
12481 }
12482 os << '\n';
12483 }
12484 }
12485 else
12486 {
12487 int k = partitioning[faces_info[i].Elem1No];
12488 int nv = faces[i]->GetNVertices();
12489 const int *ind = faces[i]->GetVertices();
12490 os << k+1; // attribute
12491 for (int j = 0; j < nv; j++)
12492 for (int s = 0; s < vcount[ind[j]]; s++)
12493 if (vown[ind[j]][s] == faces_info[i].Elem1No)
12494 {
12495 os << ' ' << voff[ind[j]]+s+1;
12496 }
12497 os << '\n';
12498 }
12499 }
12500 }
12501 // Dim is 3
12502 else if (meshgen == 2) // TrueGrid
12503 {
12504 // count the number of the boundary elements.
12505 int nbe = 0;
12506 for (int i = 0; i < NumOfFaces; i++)
12507 {
12508 int l = faces_info[i].Elem2No;
12509 if (l >= 0)
12510 {
12511 int k = partitioning[faces_info[i].Elem1No];
12512 l = partitioning[l];
12513 if (interior_faces || k != l)
12514 {
12515 nbe += 2;
12516 }
12517 }
12518 else
12519 {
12520 nbe++;
12521 }
12522 }
12523
12524 os << "TrueGrid\n"
12525 << "1 " << voff[NumOfVertices] << " " << NumOfElements
12526 << " 0 0 0 0 0 0 0\n"
12527 << "0 0 0 1 0 0 0 0 0 0 0\n"
12528 << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
12529 << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
12530 << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
12531
12532 for (int i = 0; i < NumOfVertices; i++)
12533 for (int k = 0; k < vcount[i]; k++)
12534 os << voff[i]+k << " 0.0 " << vertices[i](0) << ' '
12535 << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n";
12536
12537 for (int i = 0; i < NumOfElements; i++)
12538 {
12539 int nv = elements[i]->GetNVertices();
12540 const int *ind = elements[i]->GetVertices();
12541 os << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute
12542 for (int j = 0; j < nv; j++)
12543 {
12544 os << ' ' << voff[ind[j]]+vcount[ind[j]]--;
12545 vown[ind[j]][vcount[ind[j]]] = i;
12546 }
12547 os << '\n';
12548 }
12549
12550 for (int i = 0; i < NumOfVertices; i++)
12551 {
12552 vcount[i] = voff[i+1] - voff[i];
12553 }
12554
12555 // boundary elements
12556 for (int i = 0; i < NumOfFaces; i++)
12557 {
12558 int l = faces_info[i].Elem2No;
12559 if (l >= 0)
12560 {
12561 int k = partitioning[faces_info[i].Elem1No];
12562 l = partitioning[l];
12563 if (interior_faces || k != l)
12564 {
12565 int nv = faces[i]->GetNVertices();
12566 const int *ind = faces[i]->GetVertices();
12567 os << k+1; // attribute
12568 for (int j = 0; j < nv; j++)
12569 for (int s = 0; s < vcount[ind[j]]; s++)
12570 if (vown[ind[j]][s] == faces_info[i].Elem1No)
12571 {
12572 os << ' ' << voff[ind[j]]+s+1;
12573 }
12574 os << " 1.0 1.0 1.0 1.0\n";
12575 os << l+1; // attribute
12576 for (int j = nv-1; j >= 0; j--)
12577 for (int s = 0; s < vcount[ind[j]]; s++)
12578 if (vown[ind[j]][s] == faces_info[i].Elem2No)
12579 {
12580 os << ' ' << voff[ind[j]]+s+1;
12581 }
12582 os << " 1.0 1.0 1.0 1.0\n";
12583 }
12584 }
12585 else
12586 {
12587 int k = partitioning[faces_info[i].Elem1No];
12588 int nv = faces[i]->GetNVertices();
12589 const int *ind = faces[i]->GetVertices();
12590 os << k+1; // attribute
12591 for (int j = 0; j < nv; j++)
12592 for (int s = 0; s < vcount[ind[j]]; s++)
12593 if (vown[ind[j]][s] == faces_info[i].Elem1No)
12594 {
12595 os << ' ' << voff[ind[j]]+s+1;
12596 }
12597 os << " 1.0 1.0 1.0 1.0\n";
12598 }
12599 }
12600 }
12601
12602 os << flush;
12603
12604 for (int i = 0; i < NumOfVertices; i++)
12605 {
12606 delete [] vown[i];
12607 }
12608
12609 delete [] vcount;
12610 delete [] voff;
12611 delete [] vown;
12612}
12613
12614void Mesh::PrintSurfaces(const Table & Aface_face, std::ostream &os) const
12615{
12616 int i, j;
12617
12618 if (NURBSext)
12619 {
12620 mfem_error("Mesh::PrintSurfaces"
12621 " NURBS mesh is not supported!");
12622 return;
12623 }
12624
12625 os << "MFEM mesh v1.0\n";
12626
12627 // optional
12628 os <<
12629 "\n#\n# MFEM Geometry Types (see fem/geom.hpp):\n#\n"
12630 "# POINT = 0\n"
12631 "# SEGMENT = 1\n"
12632 "# TRIANGLE = 2\n"
12633 "# SQUARE = 3\n"
12634 "# TETRAHEDRON = 4\n"
12635 "# CUBE = 5\n"
12636 "# PRISM = 6\n"
12637 "#\n";
12638
12639 os << "\ndimension\n" << Dim
12640 << "\n\nelements\n" << NumOfElements << '\n';
12641 for (i = 0; i < NumOfElements; i++)
12642 {
12643 PrintElement(elements[i], os);
12644 }
12645
12646 os << "\nboundary\n" << Aface_face.Size_of_connections() << '\n';
12647 const int * const i_AF_f = Aface_face.GetI();
12648 const int * const j_AF_f = Aface_face.GetJ();
12649
12650 for (int iAF=0; iAF < Aface_face.Size(); ++iAF)
12651 for (const int * iface = j_AF_f + i_AF_f[iAF];
12652 iface < j_AF_f + i_AF_f[iAF+1];
12653 ++iface)
12654 {
12655 os << iAF+1 << ' ';
12656 PrintElementWithoutAttr(faces[*iface],os);
12657 }
12658
12659 os << "\nvertices\n" << NumOfVertices << '\n';
12660 if (Nodes == NULL)
12661 {
12662 os << spaceDim << '\n';
12663 for (i = 0; i < NumOfVertices; i++)
12664 {
12665 os << vertices[i](0);
12666 for (j = 1; j < spaceDim; j++)
12667 {
12668 os << ' ' << vertices[i](j);
12669 }
12670 os << '\n';
12671 }
12672 os.flush();
12673 }
12674 else
12675 {
12676 os << "\nnodes\n";
12677 Nodes->Save(os);
12678 }
12679}
12680
12682{
12683 int i,j,k;
12684 Array<int> vert;
12685 DenseMatrix pointmat;
12686 int na = attributes.Size();
12687 real_t *cg = new real_t[na*spaceDim];
12688 int *nbea = new int[na];
12689
12690 int *vn = new int[NumOfVertices];
12691 for (i = 0; i < NumOfVertices; i++)
12692 {
12693 vn[i] = 0;
12694 }
12695 for (i = 0; i < na; i++)
12696 {
12697 for (j = 0; j < spaceDim; j++)
12698 {
12699 cg[i*spaceDim+j] = 0.0;
12700 }
12701 nbea[i] = 0;
12702 }
12703
12704 for (i = 0; i < NumOfElements; i++)
12705 {
12706 GetElementVertices(i, vert);
12707 for (k = 0; k < vert.Size(); k++)
12708 {
12709 vn[vert[k]] = 1;
12710 }
12711 }
12712
12713 for (i = 0; i < NumOfElements; i++)
12714 {
12715 int bea = GetAttribute(i)-1;
12716 GetPointMatrix(i, pointmat);
12717 GetElementVertices(i, vert);
12718
12719 for (k = 0; k < vert.Size(); k++)
12720 if (vn[vert[k]] == 1)
12721 {
12722 nbea[bea]++;
12723 for (j = 0; j < spaceDim; j++)
12724 {
12725 cg[bea*spaceDim+j] += pointmat(j,k);
12726 }
12727 vn[vert[k]] = 2;
12728 }
12729 }
12730
12731 for (i = 0; i < NumOfElements; i++)
12732 {
12733 int bea = GetAttribute(i)-1;
12734 GetElementVertices (i, vert);
12735
12736 for (k = 0; k < vert.Size(); k++)
12737 if (vn[vert[k]])
12738 {
12739 for (j = 0; j < spaceDim; j++)
12740 vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
12741 (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
12742 vn[vert[k]] = 0;
12743 }
12744 }
12745
12746 delete [] cg;
12747 delete [] nbea;
12748 delete [] vn;
12749}
12750
12752{
12753 int i,j,k;
12754 Array<int> vert;
12755 DenseMatrix pointmat;
12756 int na = NumOfElements;
12757 real_t *cg = new real_t[na*spaceDim];
12758 int *nbea = new int[na];
12759
12760 int *vn = new int[NumOfVertices];
12761 for (i = 0; i < NumOfVertices; i++)
12762 {
12763 vn[i] = 0;
12764 }
12765 for (i = 0; i < na; i++)
12766 {
12767 for (j = 0; j < spaceDim; j++)
12768 {
12769 cg[i*spaceDim+j] = 0.0;
12770 }
12771 nbea[i] = 0;
12772 }
12773
12774 for (i = 0; i < NumOfElements; i++)
12775 {
12776 GetElementVertices(i, vert);
12777 for (k = 0; k < vert.Size(); k++)
12778 {
12779 vn[vert[k]] = 1;
12780 }
12781 }
12782
12783 for (i = 0; i < NumOfElements; i++)
12784 {
12785 int bea = i;
12786 GetPointMatrix(i, pointmat);
12787 GetElementVertices(i, vert);
12788
12789 for (k = 0; k < vert.Size(); k++)
12790 if (vn[vert[k]] == 1)
12791 {
12792 nbea[bea]++;
12793 for (j = 0; j < spaceDim; j++)
12794 {
12795 cg[bea*spaceDim+j] += pointmat(j,k);
12796 }
12797 vn[vert[k]] = 2;
12798 }
12799 }
12800
12801 for (i = 0; i < NumOfElements; i++)
12802 {
12803 int bea = i;
12804 GetElementVertices(i, vert);
12805
12806 for (k = 0; k < vert.Size(); k++)
12807 if (vn[vert[k]])
12808 {
12809 for (j = 0; j < spaceDim; j++)
12810 vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
12811 (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
12812 vn[vert[k]] = 0;
12813 }
12814 }
12815
12816 delete [] cg;
12817 delete [] nbea;
12818 delete [] vn;
12819}
12820
12821void Mesh::Transform(void (*f)(const Vector&, Vector&))
12822{
12823 // TODO: support for different new spaceDim.
12824 if (Nodes == NULL)
12825 {
12826 Vector vold(spaceDim), vnew(NULL, spaceDim);
12827 for (int i = 0; i < vertices.Size(); i++)
12828 {
12829 for (int j = 0; j < spaceDim; j++)
12830 {
12831 vold(j) = vertices[i](j);
12832 }
12833 vnew.SetData(vertices[i]());
12834 (*f)(vold, vnew);
12835 }
12836 }
12837 else
12838 {
12839 GridFunction xnew(Nodes->FESpace());
12841 xnew.ProjectCoefficient(f_pert);
12842 *Nodes = xnew;
12843 }
12844 NodesUpdated();
12845}
12846
12848{
12849 MFEM_VERIFY(spaceDim == deformation.GetVDim(),
12850 "incompatible vector dimensions");
12851 if (Nodes == NULL)
12852 {
12855 GridFunction xnew(&fes);
12856 xnew.ProjectCoefficient(deformation);
12857 for (int i = 0; i < NumOfVertices; i++)
12858 for (int d = 0; d < spaceDim; d++)
12859 {
12860 vertices[i](d) = xnew(d + spaceDim*i);
12861 }
12862 }
12863 else
12864 {
12865 GridFunction xnew(Nodes->FESpace());
12866 xnew.ProjectCoefficient(deformation);
12867 *Nodes = xnew;
12868 }
12869 NodesUpdated();
12870}
12871
12873{
12874 if (NURBSext || ncmesh) { return; }
12875
12876 Array<int> v2v(GetNV());
12877 v2v = -1;
12878 for (int i = 0; i < GetNE(); i++)
12879 {
12880 Element *el = GetElement(i);
12881 int nv = el->GetNVertices();
12882 int *v = el->GetVertices();
12883 for (int j = 0; j < nv; j++)
12884 {
12885 v2v[v[j]] = 0;
12886 }
12887 }
12888 for (int i = 0; i < GetNBE(); i++)
12889 {
12890 Element *el = GetBdrElement(i);
12891 int *v = el->GetVertices();
12892 int nv = el->GetNVertices();
12893 for (int j = 0; j < nv; j++)
12894 {
12895 v2v[v[j]] = 0;
12896 }
12897 }
12898 int num_vert = 0;
12899 for (int i = 0; i < v2v.Size(); i++)
12900 {
12901 if (v2v[i] == 0)
12902 {
12903 vertices[num_vert] = vertices[i];
12904 v2v[i] = num_vert++;
12905 }
12906 }
12907
12908 if (num_vert == v2v.Size()) { return; }
12909
12910 Vector nodes_by_element;
12911 Array<int> vdofs;
12912 if (Nodes)
12913 {
12914 int s = 0;
12915 for (int i = 0; i < GetNE(); i++)
12916 {
12917 Nodes->FESpace()->GetElementVDofs(i, vdofs);
12918 s += vdofs.Size();
12919 }
12920 nodes_by_element.SetSize(s);
12921 s = 0;
12922 for (int i = 0; i < GetNE(); i++)
12923 {
12924 Nodes->FESpace()->GetElementVDofs(i, vdofs);
12925 Nodes->GetSubVector(vdofs, &nodes_by_element(s));
12926 s += vdofs.Size();
12927 }
12928 }
12929 vertices.SetSize(num_vert);
12930 NumOfVertices = num_vert;
12931 for (int i = 0; i < GetNE(); i++)
12932 {
12933 Element *el = GetElement(i);
12934 int *v = el->GetVertices();
12935 int nv = el->GetNVertices();
12936 for (int j = 0; j < nv; j++)
12937 {
12938 v[j] = v2v[v[j]];
12939 }
12940 }
12941 for (int i = 0; i < GetNBE(); i++)
12942 {
12943 Element *el = GetBdrElement(i);
12944 int *v = el->GetVertices();
12945 int nv = el->GetNVertices();
12946 for (int j = 0; j < nv; j++)
12947 {
12948 v[j] = v2v[v[j]];
12949 }
12950 }
12951 DeleteTables();
12952 if (Dim > 1)
12953 {
12954 // generate el_to_edge, be_to_face (2D), bel_to_edge (3D)
12955 el_to_edge = new Table;
12957 }
12958 if (Dim > 2)
12959 {
12960 // generate el_to_face, be_to_face
12962 }
12963 // Update faces and faces_info
12964 GenerateFaces();
12965 if (Nodes)
12966 {
12967 Nodes->FESpace()->Update();
12968 Nodes->Update();
12969 int s = 0;
12970 for (int i = 0; i < GetNE(); i++)
12971 {
12972 Nodes->FESpace()->GetElementVDofs(i, vdofs);
12973 Nodes->SetSubVector(vdofs, &nodes_by_element(s));
12974 s += vdofs.Size();
12975 }
12976 }
12977}
12978
12980{
12981 if (NURBSext || ncmesh) { return; }
12982
12983 int num_bdr_elem = 0;
12984 int new_bel_to_edge_nnz = 0;
12985 for (int i = 0; i < GetNBE(); i++)
12986 {
12988 {
12990 }
12991 else
12992 {
12993 num_bdr_elem++;
12994 if (Dim == 3)
12995 {
12996 new_bel_to_edge_nnz += bel_to_edge->RowSize(i);
12997 }
12998 }
12999 }
13000
13001 if (num_bdr_elem == GetNBE()) { return; }
13002
13003 Array<Element *> new_boundary(num_bdr_elem);
13004 Array<int> new_be_to_face;
13005 Table *new_bel_to_edge = NULL;
13006 new_boundary.SetSize(0);
13007 new_be_to_face.Reserve(num_bdr_elem);
13008 if (Dim == 3)
13009 {
13010 new_bel_to_edge = new Table;
13011 new_bel_to_edge->SetDims(num_bdr_elem, new_bel_to_edge_nnz);
13012 }
13013 for (int i = 0; i < GetNBE(); i++)
13014 {
13016 {
13017 new_boundary.Append(boundary[i]);
13018 int row = new_be_to_face.Size();
13019 new_be_to_face.Append(be_to_face[i]);
13020 if (Dim == 3)
13021 {
13022 int *e = bel_to_edge->GetRow(i);
13023 int ne = bel_to_edge->RowSize(i);
13024 int *new_e = new_bel_to_edge->GetRow(row);
13025 for (int j = 0; j < ne; j++)
13026 {
13027 new_e[j] = e[j];
13028 }
13029 new_bel_to_edge->GetI()[row+1] = new_bel_to_edge->GetI()[row] + ne;
13030 }
13031 }
13032 }
13033
13034 NumOfBdrElements = new_boundary.Size();
13035 mfem::Swap(boundary, new_boundary);
13036
13037 mfem::Swap(be_to_face, new_be_to_face);
13038
13039 if (Dim == 3)
13040 {
13041 delete bel_to_edge;
13042 bel_to_edge = new_bel_to_edge;
13043 }
13044
13045 Array<int> attribs(num_bdr_elem);
13046 for (int i = 0; i < attribs.Size(); i++)
13047 {
13048 attribs[i] = GetBdrAttribute(i);
13049 }
13050 attribs.Sort();
13051 attribs.Unique();
13053 attribs.Copy(bdr_attributes);
13054}
13055
13057{
13058#ifdef MFEM_USE_MEMALLOC
13059 if (E)
13060 {
13061 if (E->GetType() == Element::TETRAHEDRON)
13062 {
13063 TetMemory.Free((Tetrahedron*) E);
13064 }
13065 else
13066 {
13067 delete E;
13068 }
13069 }
13070#else
13071 delete E;
13072#endif
13073}
13074
13075std::ostream &operator<<(std::ostream &os, const Mesh &mesh)
13076{
13077 mesh.Print(os);
13078 return os;
13079}
13080
13081int Mesh::FindPoints(DenseMatrix &point_mat, Array<int>& elem_ids,
13082 Array<IntegrationPoint>& ips, bool warn,
13084{
13085 const int npts = point_mat.Width();
13086 if (!npts) { return 0; }
13087 MFEM_VERIFY(point_mat.Height() == spaceDim,"Invalid points matrix");
13088 elem_ids.SetSize(npts);
13089 ips.SetSize(npts);
13090 elem_ids = -1;
13091 if (!GetNE()) { return 0; }
13092
13093 real_t *data = point_mat.GetData();
13094 InverseElementTransformation *inv_tr = inv_trans;
13095 inv_tr = inv_tr ? inv_tr : new InverseElementTransformation;
13096
13097 // For each point in 'point_mat', find the element whose center is closest.
13098 Vector min_dist(npts);
13099 Array<int> e_idx(npts);
13100 min_dist = std::numeric_limits<real_t>::max();
13101 e_idx = -1;
13102
13103 Vector pt(spaceDim);
13104 for (int i = 0; i < GetNE(); i++)
13105 {
13106 GetElementTransformation(i)->Transform(
13108 for (int k = 0; k < npts; k++)
13109 {
13110 real_t dist = pt.DistanceTo(data+k*spaceDim);
13111 if (dist < min_dist(k))
13112 {
13113 min_dist(k) = dist;
13114 e_idx[k] = i;
13115 }
13116 }
13117 }
13118
13119 // Checks if the points lie in the closest element
13120 int pts_found = 0;
13121 pt.NewDataAndSize(NULL, spaceDim);
13122 for (int k = 0; k < npts; k++)
13123 {
13124 pt.SetData(data+k*spaceDim);
13125 inv_tr->SetTransformation(*GetElementTransformation(e_idx[k]));
13126 int res = inv_tr->Transform(pt, ips[k]);
13128 {
13129 elem_ids[k] = e_idx[k];
13130 pts_found++;
13131 }
13132 }
13133 if (pts_found != npts)
13134 {
13135 Array<int> elvertices;
13136 Table *vtoel = GetVertexToElementTable();
13137 for (int k = 0; k < npts; k++)
13138 {
13139 if (elem_ids[k] != -1) { continue; }
13140 // Try all vertex-neighbors of element e_idx[k]
13141 pt.SetData(data+k*spaceDim);
13142 GetElementVertices(e_idx[k], elvertices);
13143 for (int v = 0; v < elvertices.Size(); v++)
13144 {
13145 int vv = elvertices[v];
13146 int ne = vtoel->RowSize(vv);
13147 const int* els = vtoel->GetRow(vv);
13148 for (int e = 0; e < ne; e++)
13149 {
13150 if (els[e] == e_idx[k]) { continue; }
13152 int res = inv_tr->Transform(pt, ips[k]);
13154 {
13155 elem_ids[k] = els[e];
13156 pts_found++;
13157 goto next_point;
13158 }
13159 }
13160 }
13161 // Try neighbors for non-conforming meshes
13162 if (ncmesh)
13163 {
13164 Array<int> neigh;
13165 int le = ncmesh->leaf_elements[e_idx[k]];
13166 ncmesh->FindNeighbors(le,neigh);
13167 for (int e = 0; e < neigh.Size(); e++)
13168 {
13169 int nn = neigh[e];
13170 if (ncmesh->IsGhost(ncmesh->elements[nn])) { continue; }
13171 int el = ncmesh->elements[nn].index;
13173 int res = inv_tr->Transform(pt, ips[k]);
13175 {
13176 elem_ids[k] = el;
13177 pts_found++;
13178 goto next_point;
13179 }
13180 }
13181 }
13182 next_point: ;
13183 }
13184 delete vtoel;
13185 }
13186 if (inv_trans == NULL) { delete inv_tr; }
13187
13188 if (warn && pts_found != npts)
13189 {
13190 MFEM_WARNING((npts-pts_found) << " points were not found");
13191 }
13192 return pts_found;
13193}
13194
13196 real_t &volume,
13197 Vector &aspr,
13198 Vector &skew,
13199 Vector &ori) const
13200{
13201 J.HostRead();
13202 aspr.HostWrite();
13203 skew.HostWrite();
13204 ori.HostWrite();
13205 MFEM_VERIFY(Dim == 2 || Dim == 3, "Only 2D/3D meshes supported right now.");
13206 MFEM_VERIFY(Dim == spaceDim, "Surface meshes not currently supported.");
13207 if (Dim == 2)
13208 {
13209 aspr.SetSize(1);
13210 skew.SetSize(1);
13211 ori.SetSize(1);
13212 Vector col1, col2;
13213 J.GetColumn(0, col1);
13214 J.GetColumn(1, col2);
13215
13216 // Area/Volume
13217 volume = J.Det();
13218
13219 // Aspect-ratio
13220 aspr(0) = col2.Norml2()/col1.Norml2();
13221
13222 // Skewness
13223 skew(0) = std::atan2(J.Det(), col1 * col2);
13224
13225 // Orientation
13226 ori(0) = std::atan2(J(1,0), J(0,0));
13227 }
13228 else if (Dim == 3)
13229 {
13230 aspr.SetSize(4);
13231 skew.SetSize(3);
13232 ori.SetSize(4);
13233 Vector col1, col2, col3;
13234 J.GetColumn(0, col1);
13235 J.GetColumn(1, col2);
13236 J.GetColumn(2, col3);
13237 real_t len1 = col1.Norml2(),
13238 len2 = col2.Norml2(),
13239 len3 = col3.Norml2();
13240
13241 Vector col1unit = col1,
13242 col2unit = col2,
13243 col3unit = col3;
13244 col1unit *= 1.0/len1;
13245 col2unit *= 1.0/len2;
13246 col3unit *= 1.0/len3;
13247
13248 // Area/Volume
13249 volume = J.Det();
13250
13251 // Aspect-ratio - non-dimensional
13252 aspr(0) = len1/std::sqrt(len2*len3),
13253 aspr(1) = len2/std::sqrt(len1*len3);
13254
13255 // Aspect-ratio - dimensional - needed for TMOP
13256 aspr(2) = std::sqrt(len1/(len2*len3)),
13257 aspr(3) = std::sqrt(len2/(len1*len3));
13258
13259 // Skewness
13260 Vector crosscol12, crosscol13;
13261 col1.cross3D(col2, crosscol12);
13262 col1.cross3D(col3, crosscol13);
13263 skew(0) = std::acos(col1unit*col2unit);
13264 skew(1) = std::acos(col1unit*col3unit);
13265 skew(2) = std::atan(len1*volume/(crosscol12*crosscol13));
13266
13267 // Orientation
13268 // First we define the rotation matrix
13269 DenseMatrix rot(Dim);
13270 // First column
13271 for (int d=0; d<Dim; d++) { rot(d, 0) = col1unit(d); }
13272 // Second column
13273 Vector rot2 = col2unit;
13274 Vector rot1 = col1unit;
13275 rot1 *= col1unit*col2unit;
13276 rot2 -= rot1;
13277 col1unit.cross3D(col2unit, rot1);
13278 rot2 /= rot1.Norml2();
13279 for (int d=0; d < Dim; d++) { rot(d, 1) = rot2(d); }
13280 // Third column
13281 rot1 /= rot1.Norml2();
13282 for (int d=0; d < Dim; d++) { rot(d, 2) = rot1(d); }
13283 real_t delta = sqrt(pow(rot(2,1)-rot(1,2), 2.0) +
13284 pow(rot(0,2)-rot(2,0), 2.0) +
13285 pow(rot(1,0)-rot(0,1), 2.0));
13286 ori = 0.0;
13287 if (delta == 0.0) // Matrix is symmetric. Check if it is Identity.
13288 {
13289 DenseMatrix Iden(Dim);
13290 for (int d = 0; d < Dim; d++) { Iden(d, d) = 1.0; };
13291 Iden -= rot;
13292 if (Iden.FNorm2() != 0)
13293 {
13294 // TODO: Handling of these cases.
13295 rot.Print();
13296 MFEM_ABORT("Invalid rotation matrix. Contact TMOP Developers.");
13297 }
13298 }
13299 else
13300 {
13301 ori(0) = (1./delta)*(rot(2,1)-rot(1,2));
13302 ori(1) = (1./delta)*(rot(0,2)-rot(2,0));
13303 ori(2) = (1./delta)*(rot(1,0)-rot(0,1));
13304 ori(3) = std::acos(0.5*(rot.Trace()-1.0));
13305 }
13306 }
13307}
13308
13309
13311 int dim_, const Array<int> (&entity_to_vertex_)[Geometry::NumGeom])
13312 : dim(dim_),
13313 entity_to_vertex(entity_to_vertex_)
13314{
13315 int geom_offset = 0;
13316 for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
13317 {
13318 geom_offsets[g] = geom_offset;
13319 geom_offset += entity_to_vertex[g].Size()/Geometry::NumVerts[g];
13320 }
13321 geom_offsets[Geometry::DimStart[dim+1]] = geom_offset;
13322 num_entities = geom_offset;
13323}
13324
13326{
13327 // Find the 'geom' that corresponds to 'bytype_entity_id'
13328 int geom = Geometry::DimStart[dim];
13329 while (geom_offsets[geom+1] <= bytype_entity_id) { geom++; }
13330 MFEM_ASSERT(geom < Geometry::NumGeom, "internal error");
13331 MFEM_ASSERT(Geometry::Dimension[geom] == dim, "internal error");
13332 const int nv = Geometry::NumVerts[geom];
13333 const int geom_elem_id = bytype_entity_id - geom_offsets[geom];
13334 const int *v = &entity_to_vertex[geom][nv*geom_elem_id];
13335 return { geom, nv, v };
13336}
13337
13338void MeshPart::Print(std::ostream &os) const
13339{
13340 os << "MFEM mesh v1.2\n";
13341
13342 // optional
13343 os <<
13344 "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
13345 "# POINT = 0\n"
13346 "# SEGMENT = 1\n"
13347 "# TRIANGLE = 2\n"
13348 "# SQUARE = 3\n"
13349 "# TETRAHEDRON = 4\n"
13350 "# CUBE = 5\n"
13351 "# PRISM = 6\n"
13352 "# PYRAMID = 7\n"
13353 "#\n";
13354
13355 const int dim = dimension;
13356 os << "\ndimension\n" << dim;
13357
13358 os << "\n\nelements\n" << num_elements << '\n';
13359 {
13360 const bool have_element_map = (element_map.Size() == num_elements);
13361 MFEM_ASSERT(have_element_map || element_map.Size() == 0,
13362 "invalid MeshPart state");
13363 EntityHelper elem_helper(dim, entity_to_vertex);
13364 MFEM_ASSERT(elem_helper.num_entities == num_elements,
13365 "invalid MeshPart state");
13366 for (int nat_elem_id = 0; nat_elem_id < num_elements; nat_elem_id++)
13367 {
13368 const int bytype_elem_id = have_element_map ?
13369 element_map[nat_elem_id] : nat_elem_id;
13370 const Entity ent = elem_helper.FindEntity(bytype_elem_id);
13371 // Print the element
13372 os << attributes[nat_elem_id] << ' ' << ent.geom;
13373 for (int i = 0; i < ent.num_verts; i++)
13374 {
13375 os << ' ' << ent.verts[i];
13376 }
13377 os << '\n';
13378 }
13379 }
13380
13381 os << "\nboundary\n" << num_bdr_elements << '\n';
13382 {
13383 const bool have_boundary_map = (boundary_map.Size() == num_bdr_elements);
13384 MFEM_ASSERT(have_boundary_map || boundary_map.Size() == 0,
13385 "invalid MeshPart state");
13386 EntityHelper bdr_helper(dim-1, entity_to_vertex);
13387 MFEM_ASSERT(bdr_helper.num_entities == num_bdr_elements,
13388 "invalid MeshPart state");
13389 for (int nat_bdr_id = 0; nat_bdr_id < num_bdr_elements; nat_bdr_id++)
13390 {
13391 const int bytype_bdr_id = have_boundary_map ?
13392 boundary_map[nat_bdr_id] : nat_bdr_id;
13393 const Entity ent = bdr_helper.FindEntity(bytype_bdr_id);
13394 // Print the boundary element
13395 os << bdr_attributes[nat_bdr_id] << ' ' << ent.geom;
13396 for (int i = 0; i < ent.num_verts; i++)
13397 {
13398 os << ' ' << ent.verts[i];
13399 }
13400 os << '\n';
13401 }
13402 }
13403
13404 os << "\nvertices\n" << num_vertices << '\n';
13405 if (!nodes)
13406 {
13407 const int sdim = space_dimension;
13408 os << sdim << '\n';
13409 for (int i = 0; i < num_vertices; i++)
13410 {
13411 os << vertex_coordinates[i*sdim];
13412 for (int d = 1; d < sdim; d++)
13413 {
13414 os << ' ' << vertex_coordinates[i*sdim+d];
13415 }
13416 os << '\n';
13417 }
13418 }
13419 else
13420 {
13421 os << "\nnodes\n";
13422 nodes->Save(os);
13423 }
13424
13425 os << "\nmfem_serial_mesh_end\n";
13426
13427 // Start: GroupTopology::Save
13428 const int num_groups = my_groups.Size();
13429 os << "\ncommunication_groups\n";
13430 os << "number_of_groups " << num_groups << "\n\n";
13431
13432 os << "# number of entities in each group, followed by ranks in group\n";
13433 for (int group_id = 0; group_id < num_groups; ++group_id)
13434 {
13435 const int group_size = my_groups.RowSize(group_id);
13436 const int *group_ptr = my_groups.GetRow(group_id);
13437 os << group_size;
13438 for (int group_member_index = 0; group_member_index < group_size;
13439 ++group_member_index)
13440 {
13441 os << ' ' << group_ptr[group_member_index];
13442 }
13443 os << '\n';
13444 }
13445 // End: GroupTopology::Save
13446
13451
13452 MFEM_VERIFY(g2v.RowSize(0) == 0, "internal erroor");
13453 os << "\ntotal_shared_vertices " << g2v.Size_of_connections() << '\n';
13454 if (dimension >= 2)
13455 {
13456 MFEM_VERIFY(g2ev.RowSize(0) == 0, "internal erroor");
13457 os << "total_shared_edges " << g2ev.Size_of_connections()/2 << '\n';
13458 }
13459 if (dimension >= 3)
13460 {
13461 MFEM_VERIFY(g2tv.RowSize(0) == 0, "internal erroor");
13462 MFEM_VERIFY(g2qv.RowSize(0) == 0, "internal erroor");
13463 const int total_shared_faces =
13464 g2tv.Size_of_connections()/3 + g2qv.Size_of_connections()/4;
13465 os << "total_shared_faces " << total_shared_faces << '\n';
13466 }
13467 os << "\n# group 0 has no shared entities\n";
13468 for (int gr = 1; gr < num_groups; gr++)
13469 {
13470 {
13471 const int nv = g2v.RowSize(gr);
13472 const int *sv = g2v.GetRow(gr);
13473 os << "\n# group " << gr << "\nshared_vertices " << nv << '\n';
13474 for (int i = 0; i < nv; i++)
13475 {
13476 os << sv[i] << '\n';
13477 }
13478 }
13479 if (dimension >= 2)
13480 {
13481 const int ne = g2ev.RowSize(gr)/2;
13482 const int *se = g2ev.GetRow(gr);
13483 os << "\nshared_edges " << ne << '\n';
13484 for (int i = 0; i < ne; i++)
13485 {
13486 const int *v = se + 2*i;
13487 os << v[0] << ' ' << v[1] << '\n';
13488 }
13489 }
13490 if (dimension >= 3)
13491 {
13492 const int nt = g2tv.RowSize(gr)/3;
13493 const int *st = g2tv.GetRow(gr);
13494 const int nq = g2qv.RowSize(gr)/4;
13495 const int *sq = g2qv.GetRow(gr);
13496 os << "\nshared_faces " << nt+nq << '\n';
13497 for (int i = 0; i < nt; i++)
13498 {
13499 os << Geometry::TRIANGLE;
13500 const int *v = st + 3*i;
13501 for (int j = 0; j < 3; j++) { os << ' ' << v[j]; }
13502 os << '\n';
13503 }
13504 for (int i = 0; i < nq; i++)
13505 {
13506 os << Geometry::SQUARE;
13507 const int *v = sq + 4*i;
13508 for (int j = 0; j < 4; j++) { os << ' ' << v[j]; }
13509 os << '\n';
13510 }
13511 }
13512 }
13513
13514 // Write out section end tag for mesh.
13515 os << "\nmfem_mesh_end" << endl;
13516}
13517
13519{
13520 if (mesh) { return *mesh; }
13521
13522 mesh.reset(new Mesh(dimension,
13527
13528 // Add elements
13529 {
13530 const bool have_element_map = (element_map.Size() == num_elements);
13531 MFEM_ASSERT(have_element_map || element_map.Size() == 0,
13532 "invalid MeshPart state");
13534 MFEM_ASSERT(elem_helper.num_entities == num_elements,
13535 "invalid MeshPart state");
13536 const bool have_tet_refine_flags = (tet_refine_flags.Size() > 0);
13537 for (int nat_elem_id = 0; nat_elem_id < num_elements; nat_elem_id++)
13538 {
13539 const int bytype_elem_id = have_element_map ?
13540 element_map[nat_elem_id] : nat_elem_id;
13541 const Entity ent = elem_helper.FindEntity(bytype_elem_id);
13542 Element *el = mesh->NewElement(ent.geom);
13543 el->SetVertices(ent.verts);
13544 el->SetAttribute(attributes[nat_elem_id]);
13545 if (ent.geom == Geometry::TETRAHEDRON && have_tet_refine_flags)
13546 {
13547 constexpr int geom_tet = Geometry::TETRAHEDRON;
13548 const int tet_id = (ent.verts - entity_to_vertex[geom_tet])/4;
13549 const int ref_flag = tet_refine_flags[tet_id];
13550 static_cast<Tetrahedron*>(el)->SetRefinementFlag(ref_flag);
13551 }
13552 mesh->AddElement(el);
13553 }
13554 }
13555
13556 // Add boundary elements
13557 {
13558 const bool have_boundary_map = (boundary_map.Size() == num_bdr_elements);
13559 MFEM_ASSERT(have_boundary_map || boundary_map.Size() == 0,
13560 "invalid MeshPart state");
13562 MFEM_ASSERT(bdr_helper.num_entities == num_bdr_elements,
13563 "invalid MeshPart state");
13564 for (int nat_bdr_id = 0; nat_bdr_id < num_bdr_elements; nat_bdr_id++)
13565 {
13566 const int bytype_bdr_id = have_boundary_map ?
13567 boundary_map[nat_bdr_id] : nat_bdr_id;
13568 const Entity ent = bdr_helper.FindEntity(bytype_bdr_id);
13569 Element *bdr = mesh->NewElement(ent.geom);
13570 bdr->SetVertices(ent.verts);
13571 bdr->SetAttribute(bdr_attributes[nat_bdr_id]);
13572 mesh->AddBdrElement(bdr);
13573 }
13574 }
13575
13576 // Add vertices
13578 {
13579 MFEM_ASSERT(!nodes, "invalid MeshPart state");
13580 for (int vert_id = 0; vert_id < num_vertices; vert_id++)
13581 {
13582 mesh->AddVertex(vertex_coordinates + space_dimension*vert_id);
13583 }
13584 }
13585 else
13586 {
13587 MFEM_ASSERT(vertex_coordinates.Size() == 0, "invalid MeshPart state");
13588 for (int vert_id = 0; vert_id < num_vertices; vert_id++)
13589 {
13590 mesh->AddVertex(0., 0., 0.);
13591 }
13592 // 'mesh.Nodes' cannot be set here -- they can be set later, if needed
13593 }
13594
13595 mesh->FinalizeTopology(/* generate_bdr: */ false);
13596
13597 return *mesh;
13598}
13599
13600
13602 int num_parts_,
13603 int *partitioning_,
13604 int part_method)
13605 : mesh(mesh_)
13606{
13607 if (partitioning_)
13608 {
13609 partitioning.MakeRef(partitioning_, mesh.GetNE(), false);
13610 }
13611 else
13612 {
13613 partitioning_ = mesh.GeneratePartitioning(num_parts_, part_method);
13614 // Mesh::GeneratePartitioning always uses new[] to allocate the,
13615 // partitioning, so we need to tell the memory manager to free it with
13616 // delete[] (even if a different host memory type has been selected).
13617 const MemoryType mt = MemoryType::HOST;
13618 partitioning.MakeRef(partitioning_, mesh.GetNE(), mt, true);
13619 }
13620
13622 // Note: the element ids in each row of 'part_to_element' are sorted.
13623
13624 const int dim = mesh.Dimension();
13625 if (dim >= 2)
13626 {
13628 }
13629
13630 Array<int> boundary_to_part(mesh.GetNBE());
13631 // Same logic as in ParMesh::BuildLocalBoundary
13632 if (dim >= 3)
13633 {
13634 for (int i = 0; i < boundary_to_part.Size(); i++)
13635 {
13636 int face, o, el1, el2;
13637 mesh.GetBdrElementFace(i, &face, &o);
13638 mesh.GetFaceElements(face, &el1, &el2);
13639 boundary_to_part[i] =
13640 partitioning[(o % 2 == 0 || el2 < 0) ? el1 : el2];
13641 }
13642 }
13643 else if (dim == 2)
13644 {
13645 for (int i = 0; i < boundary_to_part.Size(); i++)
13646 {
13647 int edge = mesh.GetBdrElementFaceIndex(i);
13648 int el1 = edge_to_element.GetRow(edge)[0];
13649 boundary_to_part[i] = partitioning[el1];
13650 }
13651 }
13652 else if (dim == 1)
13653 {
13654 for (int i = 0; i < boundary_to_part.Size(); i++)
13655 {
13656 int vert = mesh.GetBdrElementFaceIndex(i);
13657 int el1, el2;
13658 mesh.GetFaceElements(vert, &el1, &el2);
13659 boundary_to_part[i] = partitioning[el1];
13660 }
13661 }
13662 Transpose(boundary_to_part, part_to_boundary, num_parts_);
13663 // Note: the boundary element ids in each row of 'part_to_boundary' are
13664 // sorted.
13665 boundary_to_part.DeleteAll();
13666
13667 Table *vert_element = mesh.GetVertexToElementTable(); // we must delete this
13668 vertex_to_element.Swap(*vert_element);
13669 delete vert_element;
13670}
13671
13672void MeshPartitioner::ExtractPart(int part_id, MeshPart &mesh_part) const
13673{
13674 const int num_parts = part_to_element.Size();
13675
13676 MFEM_VERIFY(0 <= part_id && part_id < num_parts,
13677 "invalid part_id = " << part_id
13678 << ", num_parts = " << num_parts);
13679
13680 const int dim = mesh.Dimension();
13681 const int sdim = mesh.SpaceDimension();
13682 const int num_elems = part_to_element.RowSize(part_id);
13683 const int *elem_list = part_to_element.GetRow(part_id); // sorted
13684 const int num_bdr_elems = part_to_boundary.RowSize(part_id);
13685 const int *bdr_elem_list = part_to_boundary.GetRow(part_id); // sorted
13686
13687 // Initialize 'mesh_part'
13688 mesh_part.dimension = dim;
13689 mesh_part.space_dimension = sdim;
13690 mesh_part.num_vertices = 0;
13691 mesh_part.num_elements = num_elems;
13692 mesh_part.num_bdr_elements = num_bdr_elems;
13693 for (int g = 0; g < Geometry::NumGeom; g++)
13694 {
13695 mesh_part.entity_to_vertex[g].SetSize(0); // can reuse Array allocation
13696 }
13697 mesh_part.tet_refine_flags.SetSize(0);
13698 mesh_part.element_map.SetSize(0); // 0 or 'num_elements', if needed
13699 mesh_part.boundary_map.SetSize(0); // 0 or 'num_bdr_elements', if needed
13700 mesh_part.attributes.SetSize(num_elems);
13701 mesh_part.bdr_attributes.SetSize(num_bdr_elems);
13702 mesh_part.vertex_coordinates.SetSize(0);
13703
13704 mesh_part.num_parts = num_parts;
13705 mesh_part.my_part_id = part_id;
13706 mesh_part.my_groups.Clear();
13707 for (int g = 0; g < Geometry::NumGeom; g++)
13708 {
13709 mesh_part.group_shared_entity_to_vertex[g].Clear();
13710 }
13711 mesh_part.nodes.reset(nullptr);
13712 mesh_part.nodal_fes.reset(nullptr);
13713 mesh_part.mesh.reset(nullptr);
13714
13715 // Initialize:
13716 // - 'mesh_part.entity_to_vertex' for the elements (boundary elements are
13717 // set later); vertex ids are global at this point - they will be mapped to
13718 // local ids later
13719 // - 'mesh_part.attributes'
13720 // - 'mesh_part.tet_refine_flags' if needed
13721 int geom_marker = 0, num_geom = 0;
13722 for (int i = 0; i < num_elems; i++)
13723 {
13724 const Element *elem = mesh.GetElement(elem_list[i]);
13725 const int geom = elem->GetGeometryType();
13726 const int nv = Geometry::NumVerts[geom];
13727 const int *v = elem->GetVertices();
13728 MFEM_VERIFY(numeric_limits<int>::max() - nv >=
13729 mesh_part.entity_to_vertex[geom].Size(),
13730 "overflow in 'entity_to_vertex[geom]', geom: "
13731 << Geometry::Name[geom]);
13732 mesh_part.entity_to_vertex[geom].Append(v, nv);
13733 mesh_part.attributes[i] = elem->GetAttribute();
13734 if (geom == Geometry::TETRAHEDRON)
13735 {
13736 // Create 'mesh_part.tet_refine_flags' but only if we find at least one
13737 // non-zero flag in a tetrahedron.
13738 const Tetrahedron *tet = static_cast<const Tetrahedron*>(elem);
13739 const int ref_flag = tet->GetRefinementFlag();
13740 if (mesh_part.tet_refine_flags.Size() == 0)
13741 {
13742 if (ref_flag)
13743 {
13744 // This is the first time we encounter non-zero 'ref_flag'
13745 const int num_tets = mesh_part.entity_to_vertex[geom].Size()/nv;
13746 mesh_part.tet_refine_flags.SetSize(num_tets, 0);
13747 mesh_part.tet_refine_flags.Last() = ref_flag;
13748 }
13749 }
13750 else
13751 {
13752 mesh_part.tet_refine_flags.Append(ref_flag);
13753 }
13754 }
13755 if ((geom_marker & (1 << geom)) == 0)
13756 {
13757 geom_marker |= (1 << geom);
13758 num_geom++;
13759 }
13760 }
13761 MFEM_ASSERT(mesh_part.tet_refine_flags.Size() == 0 ||
13762 mesh_part.tet_refine_flags.Size() ==
13764 "internal error");
13765 // Initialize 'mesh_part.element_map' if needed
13766 if (num_geom > 1)
13767 {
13768 int offsets[Geometry::NumGeom];
13769 int offset = 0;
13770 for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
13771 {
13772 offsets[g] = offset;
13773 offset += mesh_part.entity_to_vertex[g].Size()/Geometry::NumVerts[g];
13774 }
13775 mesh_part.element_map.SetSize(num_elems);
13776 for (int i = 0; i < num_elems; i++)
13777 {
13778 const int geom = mesh.GetElementGeometry(elem_list[i]);
13779 mesh_part.element_map[i] = offsets[geom]++;
13780 }
13781 }
13782
13783 // Initialize:
13784 // - 'mesh_part.entity_to_vertex' for the boundary elements; vertex ids are
13785 // global at this point - they will be mapped to local ids later
13786 // - 'mesh_part.bdr_attributes'
13787 geom_marker = 0; num_geom = 0;
13788 for (int i = 0; i < num_bdr_elems; i++)
13789 {
13790 const Element *bdr_elem = mesh.GetBdrElement(bdr_elem_list[i]);
13791 const int geom = bdr_elem->GetGeometryType();
13792 const int nv = Geometry::NumVerts[geom];
13793 const int *v = bdr_elem->GetVertices();
13794 MFEM_VERIFY(numeric_limits<int>::max() - nv >=
13795 mesh_part.entity_to_vertex[geom].Size(),
13796 "overflow in 'entity_to_vertex[geom]', geom: "
13797 << Geometry::Name[geom]);
13798 mesh_part.entity_to_vertex[geom].Append(v, nv);
13799 mesh_part.bdr_attributes[i] = bdr_elem->GetAttribute();
13800 if ((geom_marker & (1 << geom)) == 0)
13801 {
13802 geom_marker |= (1 << geom);
13803 num_geom++;
13804 }
13805 }
13806 // Initialize 'mesh_part.boundary_map' if needed
13807 if (num_geom > 1)
13808 {
13809 int offsets[Geometry::NumGeom];
13810 int offset = 0;
13811 for (int g = Geometry::DimStart[dim-1]; g < Geometry::DimStart[dim]; g++)
13812 {
13813 offsets[g] = offset;
13814 offset += mesh_part.entity_to_vertex[g].Size()/Geometry::NumVerts[g];
13815 }
13816 mesh_part.boundary_map.SetSize(num_bdr_elems);
13817 for (int i = 0; i < num_bdr_elems; i++)
13818 {
13819 const int geom = mesh.GetBdrElementGeometry(bdr_elem_list[i]);
13820 mesh_part.boundary_map[i] = offsets[geom]++;
13821 }
13822 }
13823
13824 // Create the vertex id map, 'vertex_loc_to_glob', which maps local ids to
13825 // global ones; the map is sorted, preserving the global ordering.
13826 Array<int> vertex_loc_to_glob;
13827 {
13828 std::unordered_set<int> vertex_set;
13829 for (int i = 0; i < num_elems; i++)
13830 {
13831 const Element *elem = mesh.GetElement(elem_list[i]);
13832 const int geom = elem->GetGeometryType();
13833 const int nv = Geometry::NumVerts[geom];
13834 const int *v = elem->GetVertices();
13835 vertex_set.insert(v, v + nv);
13836 }
13837 vertex_loc_to_glob.SetSize(vertex_set.size());
13838 std::copy(vertex_set.begin(), vertex_set.end(), // src
13839 vertex_loc_to_glob.begin()); // dest
13840 }
13841 vertex_loc_to_glob.Sort();
13842
13843 // Initialize 'mesh_part.num_vertices'
13844 mesh_part.num_vertices = vertex_loc_to_glob.Size();
13845
13846 // Update the vertex ids in the arrays 'mesh_part.entity_to_vertex' from
13847 // global to local.
13848 for (int g = 0; g < Geometry::NumGeom; g++)
13849 {
13850 Array<int> &vert_array = mesh_part.entity_to_vertex[g];
13851 for (int i = 0; i < vert_array.Size(); i++)
13852 {
13853 const int glob_id = vert_array[i];
13854 const int loc_id = vertex_loc_to_glob.FindSorted(glob_id);
13855 MFEM_ASSERT(loc_id >= 0, "internal error: global vertex id not found");
13856 vert_array[i] = loc_id;
13857 }
13858 }
13859
13860 // Initialize one of 'mesh_part.vertex_coordinates' or 'mesh_part.nodes'
13861 if (!mesh.GetNodes())
13862 {
13863 MFEM_VERIFY(numeric_limits<int>::max()/sdim >= vertex_loc_to_glob.Size(),
13864 "overflow in 'vertex_coordinates', num_vertices = "
13865 << vertex_loc_to_glob.Size() << ", sdim = " << sdim);
13866 mesh_part.vertex_coordinates.SetSize(sdim*vertex_loc_to_glob.Size());
13867 for (int i = 0; i < vertex_loc_to_glob.Size(); i++)
13868 {
13869 const real_t *coord = mesh.GetVertex(vertex_loc_to_glob[i]);
13870 for (int d = 0; d < sdim; d++)
13871 {
13872 mesh_part.vertex_coordinates[i*sdim+d] = coord[d];
13873 }
13874 }
13875 }
13876 else
13877 {
13878 const GridFunction &glob_nodes = *mesh.GetNodes();
13879 mesh_part.nodal_fes = ExtractFESpace(mesh_part, *glob_nodes.FESpace());
13880 // Initialized 'mesh_part.mesh'.
13881 // Note: the nodes of 'mesh_part.mesh' are not set.
13882
13883 mesh_part.nodes = ExtractGridFunction(mesh_part, glob_nodes,
13884 *mesh_part.nodal_fes);
13885
13886 // Attach the 'mesh_part.nodes' to the 'mesh_part.mesh'.
13887 mesh_part.mesh->NewNodes(*mesh_part.nodes, /* make_owner: */ false);
13888 // Note: the vertices of 'mesh_part.mesh' are not set.
13889 }
13890
13891 // Begin constructing the "neighbor" groups, i.e. the groups that contain
13892 // 'part_id'.
13893 ListOfIntegerSets groups;
13894 {
13895 // the first group is the local one
13896 IntegerSet group;
13897 group.Recreate(1, &part_id);
13898 groups.Insert(group);
13899 }
13900
13901 // 'shared_faces' : shared face id -> (global_face_id, group_id)
13902 // Note: 'shared_faces' will be sorted by 'global_face_id'.
13903 Array<Pair<int,int>> shared_faces;
13904
13905 // Add "neighbor" groups defined by faces
13906 // Construct 'shared_faces'.
13907 if (dim >= 3)
13908 {
13909 std::unordered_set<int> face_set;
13910 // Construct 'face_set'
13911 const Table &elem_to_face = mesh.ElementToFaceTable();
13912 for (int loc_elem_id = 0; loc_elem_id < num_elems; loc_elem_id++)
13913 {
13914 const int glob_elem_id = elem_list[loc_elem_id];
13915 const int nfaces = elem_to_face.RowSize(glob_elem_id);
13916 const int *faces = elem_to_face.GetRow(glob_elem_id);
13917 face_set.insert(faces, faces + nfaces);
13918 }
13919 // Construct 'shared_faces'; add "neighbor" groups defined by faces.
13920 IntegerSet group;
13921 for (int glob_face_id : face_set)
13922 {
13923 int el[2];
13924 mesh.GetFaceElements(glob_face_id, &el[0], &el[1]);
13925 if (el[1] < 0) { continue; }
13926 el[0] = partitioning[el[0]];
13927 el[1] = partitioning[el[1]];
13928 MFEM_ASSERT(el[0] == part_id || el[1] == part_id, "internal error");
13929 if (el[0] != part_id || el[1] != part_id)
13930 {
13931 group.Recreate(2, el);
13932 const int group_id = groups.Insert(group);
13933 shared_faces.Append(Pair<int,int>(glob_face_id, group_id));
13934 }
13935 }
13936 shared_faces.Sort(); // sort the shared faces by 'glob_face_id'
13937 }
13938
13939 // 'shared_edges' : shared edge id -> (global_edge_id, group_id)
13940 // Note: 'shared_edges' will be sorted by 'global_edge_id'.
13941 Array<Pair<int,int>> shared_edges;
13942
13943 // Add "neighbor" groups defined by edges.
13944 // Construct 'shared_edges'.
13945 if (dim >= 2)
13946 {
13947 std::unordered_set<int> edge_set;
13948 // Construct 'edge_set'
13949 const Table &elem_to_edge = mesh.ElementToEdgeTable();
13950 for (int loc_elem_id = 0; loc_elem_id < num_elems; loc_elem_id++)
13951 {
13952 const int glob_elem_id = elem_list[loc_elem_id];
13953 const int nedges = elem_to_edge.RowSize(glob_elem_id);
13954 const int *edges = elem_to_edge.GetRow(glob_elem_id);
13955 edge_set.insert(edges, edges + nedges);
13956 }
13957 // Construct 'shared_edges'; add "neighbor" groups defined by edges.
13958 IntegerSet group;
13959 for (int glob_edge_id : edge_set)
13960 {
13961 const int nelem = edge_to_element.RowSize(glob_edge_id);
13962 const int *elem = edge_to_element.GetRow(glob_edge_id);
13963 Array<int> &gr = group; // reference to the 'group' internal Array
13964 gr.SetSize(nelem);
13965 for (int j = 0; j < nelem; j++)
13966 {
13967 gr[j] = partitioning[elem[j]];
13968 }
13969 gr.Sort();
13970 gr.Unique();
13971 MFEM_ASSERT(gr.FindSorted(part_id) >= 0, "internal error");
13972 if (group.Size() > 1)
13973 {
13974 const int group_id = groups.Insert(group);
13975 shared_edges.Append(Pair<int,int>(glob_edge_id, group_id));
13976 }
13977 }
13978 shared_edges.Sort(); // sort the shared edges by 'glob_edge_id'
13979 }
13980
13981 // 'shared_verts' : shared vertex id -> (global_vertex_id, group_id)
13982 // Note: 'shared_verts' will be sorted by 'global_vertex_id'.
13983 Array<Pair<int,int>> shared_verts;
13984
13985 // Add "neighbor" groups defined by vertices.
13986 // Construct 'shared_verts'.
13987 {
13988 IntegerSet group;
13989 for (int i = 0; i < vertex_loc_to_glob.Size(); i++)
13990 {
13991 // 'vertex_to_element' maps global vertex ids to global element ids
13992 const int glob_vertex_id = vertex_loc_to_glob[i];
13993 const int nelem = vertex_to_element.RowSize(glob_vertex_id);
13994 const int *elem = vertex_to_element.GetRow(glob_vertex_id);
13995 Array<int> &gr = group; // reference to the 'group' internal Array
13996 gr.SetSize(nelem);
13997 for (int j = 0; j < nelem; j++)
13998 {
13999 gr[j] = partitioning[elem[j]];
14000 }
14001 gr.Sort();
14002 gr.Unique();
14003 MFEM_ASSERT(gr.FindSorted(part_id) >= 0, "internal error");
14004 if (group.Size() > 1)
14005 {
14006 const int group_id = groups.Insert(group);
14007 shared_verts.Append(Pair<int,int>(glob_vertex_id, group_id));
14008 }
14009 }
14010 }
14011
14012 // Done constructing the "neighbor" groups in 'groups'.
14013 const int num_groups = groups.Size();
14014
14015 // Define 'mesh_part.my_groups'
14016 groups.AsTable(mesh_part.my_groups);
14017
14018 // Construct 'mesh_part.group_shared_entity_to_vertex[Geometry::POINT]'
14019 Table &group__shared_vertex_to_vertex =
14021 group__shared_vertex_to_vertex.MakeI(num_groups);
14022 for (int sv = 0; sv < shared_verts.Size(); sv++)
14023 {
14024 const int group_id = shared_verts[sv].two;
14025 group__shared_vertex_to_vertex.AddAColumnInRow(group_id);
14026 }
14027 group__shared_vertex_to_vertex.MakeJ();
14028 for (int sv = 0; sv < shared_verts.Size(); sv++)
14029 {
14030 const int glob_vertex_id = shared_verts[sv].one;
14031 const int group_id = shared_verts[sv].two;
14032 const int loc_vertex_id = vertex_loc_to_glob.FindSorted(glob_vertex_id);
14033 MFEM_ASSERT(loc_vertex_id >= 0, "internal error");
14034 group__shared_vertex_to_vertex.AddConnection(group_id, loc_vertex_id);
14035 }
14036 group__shared_vertex_to_vertex.ShiftUpI();
14037
14038 // Construct 'mesh_part.group_shared_entity_to_vertex[Geometry::SEGMENT]'
14039 if (dim >= 2)
14040 {
14041 Table &group__shared_edge_to_vertex =
14043 group__shared_edge_to_vertex.MakeI(num_groups);
14044 for (int se = 0; se < shared_edges.Size(); se++)
14045 {
14046 const int group_id = shared_edges[se].two;
14047 group__shared_edge_to_vertex.AddColumnsInRow(group_id, 2);
14048 }
14049 group__shared_edge_to_vertex.MakeJ();
14050 const Table &edge_to_vertex = *mesh.GetEdgeVertexTable();
14051 for (int se = 0; se < shared_edges.Size(); se++)
14052 {
14053 const int glob_edge_id = shared_edges[se].one;
14054 const int group_id = shared_edges[se].two;
14055 const int *v = edge_to_vertex.GetRow(glob_edge_id);
14056 for (int i = 0; i < 2; i++)
14057 {
14058 const int loc_vertex_id = vertex_loc_to_glob.FindSorted(v[i]);
14059 MFEM_ASSERT(loc_vertex_id >= 0, "internal error");
14060 group__shared_edge_to_vertex.AddConnection(group_id, loc_vertex_id);
14061 }
14062 }
14063 group__shared_edge_to_vertex.ShiftUpI();
14064 }
14065
14066 // Construct 'mesh_part.group_shared_entity_to_vertex[Geometry::TRIANGLE]'
14067 // and 'mesh_part.group_shared_entity_to_vertex[Geometry::SQUARE]'.
14068 if (dim >= 3)
14069 {
14070 Table &group__shared_tria_to_vertex =
14072 Table &group__shared_quad_to_vertex =
14074 Array<int> vertex_ids;
14075 group__shared_tria_to_vertex.MakeI(num_groups);
14076 group__shared_quad_to_vertex.MakeI(num_groups);
14077 for (int sf = 0; sf < shared_faces.Size(); sf++)
14078 {
14079 const int glob_face_id = shared_faces[sf].one;
14080 const int group_id = shared_faces[sf].two;
14081 const int geom = mesh.GetFaceGeometry(glob_face_id);
14082 mesh_part.group_shared_entity_to_vertex[geom].
14083 AddColumnsInRow(group_id, Geometry::NumVerts[geom]);
14084 }
14085 group__shared_tria_to_vertex.MakeJ();
14086 group__shared_quad_to_vertex.MakeJ();
14087 for (int sf = 0; sf < shared_faces.Size(); sf++)
14088 {
14089 const int glob_face_id = shared_faces[sf].one;
14090 const int group_id = shared_faces[sf].two;
14091 const int geom = mesh.GetFaceGeometry(glob_face_id);
14092 mesh.GetFaceVertices(glob_face_id, vertex_ids);
14093 // Rotate shared triangles that have an adjacent tetrahedron with a
14094 // nonzero refinement flag.
14095 // See also ParMesh::BuildSharedFaceElems.
14096 if (geom == Geometry::TRIANGLE)
14097 {
14098 int glob_el_id[2];
14099 mesh.GetFaceElements(glob_face_id, &glob_el_id[0], &glob_el_id[1]);
14100 int side = 0;
14101 const Element *el = mesh.GetElement(glob_el_id[0]);
14102 const Tetrahedron *tet = nullptr;
14104 {
14105 tet = static_cast<const Tetrahedron*>(el);
14106 }
14107 else
14108 {
14109 side = 1;
14110 el = mesh.GetElement(glob_el_id[1]);
14112 {
14113 tet = static_cast<const Tetrahedron*>(el);
14114 }
14115 }
14116 if (tet && tet->GetRefinementFlag())
14117 {
14118 // mark the shared face for refinement by reorienting
14119 // it according to the refinement flag in the tetrahedron
14120 // to which this shared face belongs to.
14121 int info[2];
14122 mesh.GetFaceInfos(glob_face_id, &info[0], &info[1]);
14123 tet->GetMarkedFace(info[side]/64, &vertex_ids[0]);
14124 }
14125 }
14126 for (int i = 0; i < vertex_ids.Size(); i++)
14127 {
14128 const int glob_id = vertex_ids[i];
14129 const int loc_id = vertex_loc_to_glob.FindSorted(glob_id);
14130 MFEM_ASSERT(loc_id >= 0, "internal error");
14131 vertex_ids[i] = loc_id;
14132 }
14133 mesh_part.group_shared_entity_to_vertex[geom].
14134 AddConnections(group_id, vertex_ids, vertex_ids.Size());
14135 }
14136 group__shared_tria_to_vertex.ShiftUpI();
14137 group__shared_quad_to_vertex.ShiftUpI();
14138 }
14139}
14140
14141std::unique_ptr<FiniteElementSpace>
14143 const FiniteElementSpace &global_fespace) const
14144{
14145 mesh_part.GetMesh(); // initialize 'mesh_part.mesh'
14146 // Note: the nodes of 'mesh_part.mesh' are not set by GetMesh() unless they
14147 // were already constructed, e.g. by ExtractPart().
14148
14149 return std::unique_ptr<FiniteElementSpace>(
14150 new FiniteElementSpace(mesh_part.mesh.get(),
14151 global_fespace.FEColl(),
14152 global_fespace.GetVDim(),
14153 global_fespace.GetOrdering()));
14154}
14155
14156std::unique_ptr<GridFunction>
14158 const GridFunction &global_gf,
14159 FiniteElementSpace &local_fespace) const
14160{
14161 std::unique_ptr<GridFunction> local_gf(new GridFunction(&local_fespace));
14162
14163 // Transfer data from 'global_gf' to 'local_gf'.
14164 Array<int> gvdofs, lvdofs;
14165 Vector loc_vals;
14166 const int part_id = mesh_part.my_part_id;
14167 const int num_elems = part_to_element.RowSize(part_id);
14168 const int *elem_list = part_to_element.GetRow(part_id); // sorted
14169 for (int loc_elem_id = 0; loc_elem_id < num_elems; loc_elem_id++)
14170 {
14171 const int glob_elem_id = elem_list[loc_elem_id];
14172 auto glob_dt = global_gf.FESpace()->GetElementVDofs(glob_elem_id, gvdofs);
14173 global_gf.GetSubVector(gvdofs, loc_vals);
14174 if (glob_dt) { glob_dt->InvTransformPrimal(loc_vals); }
14175 auto local_dt = local_fespace.GetElementVDofs(loc_elem_id, lvdofs);
14176 if (local_dt) { local_dt->TransformPrimal(loc_vals); }
14177 local_gf->SetSubVector(lvdofs, loc_vals);
14178 }
14179 return local_gf;
14180}
14181
14182
14184 int flags, MemoryType d_mt)
14185{
14186 this->mesh = mesh;
14187 IntRule = &ir;
14188 computed_factors = flags;
14189
14190 MFEM_ASSERT(mesh->GetNumGeometries(mesh->Dimension()) <= 1,
14191 "mixed meshes are not supported!");
14192 MFEM_ASSERT(mesh->GetNodes(), "meshes without nodes are not supported!");
14193
14194 Compute(*mesh->GetNodes(), d_mt);
14195}
14196
14198 const IntegrationRule &ir,
14199 int flags, MemoryType d_mt)
14200{
14201 this->mesh = nodes.FESpace()->GetMesh();
14202 IntRule = &ir;
14203 computed_factors = flags;
14204
14205 Compute(nodes, d_mt);
14206}
14207
14208void GeometricFactors::Compute(const GridFunction &nodes,
14209 MemoryType d_mt)
14210{
14211
14212 const FiniteElementSpace *fespace = nodes.FESpace();
14213 const FiniteElement *fe = fespace->GetFE(0);
14214 const int dim = fe->GetDim();
14215 const int vdim = fespace->GetVDim();
14216 const int NE = fespace->GetNE();
14217 const int ND = fe->GetDof();
14218 const int NQ = IntRule->GetNPoints();
14219
14220 unsigned eval_flags = 0;
14221 MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
14222 Device::GetDeviceMemoryType();
14224 {
14225 X.SetSize(vdim*NQ*NE, my_d_mt); // NQ x SDIM x NE
14226 eval_flags |= QuadratureInterpolator::VALUES;
14227 }
14229 {
14230 J.SetSize(dim*vdim*NQ*NE, my_d_mt); // NQ x SDIM x DIM x NE
14232 }
14234 {
14235 detJ.SetSize(NQ*NE, my_d_mt); // NQ x NE
14237 }
14238
14239 const QuadratureInterpolator *qi = fespace->GetQuadratureInterpolator(*IntRule);
14240 // All X, J, and detJ use this layout:
14242
14243 const bool use_tensor_products = UsesTensorBasis(*fespace);
14244
14245 qi->DisableTensorProducts(!use_tensor_products);
14246 const ElementDofOrdering e_ordering = use_tensor_products ?
14249 const Operator *elem_restr = fespace->GetElementRestriction(e_ordering);
14250
14251 if (elem_restr) // Always true as of 2021-04-27
14252 {
14253 Vector Enodes(vdim*ND*NE, my_d_mt);
14254 elem_restr->Mult(nodes, Enodes);
14255 qi->Mult(Enodes, eval_flags, X, J, detJ);
14256 }
14257 else
14258 {
14259 qi->Mult(nodes, eval_flags, X, J, detJ);
14260 }
14261}
14262
14264 const IntegrationRule &ir,
14265 int flags, FaceType type,
14266 MemoryType d_mt)
14267 : type(type)
14268{
14269 this->mesh = mesh;
14270 IntRule = &ir;
14271 computed_factors = flags;
14272
14273 const GridFunction *nodes = mesh->GetNodes();
14274 const FiniteElementSpace *fespace = nodes->FESpace();
14275 const int vdim = fespace->GetVDim();
14276 const int NF = fespace->GetNFbyType(type);
14277 const int NQ = ir.GetNPoints();
14278
14279 const FaceRestriction *face_restr = fespace->GetFaceRestriction(
14281 type,
14283
14284
14285 MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
14287
14288 Vector Fnodes(face_restr->Height(), my_d_mt);
14289 face_restr->Mult(*nodes, Fnodes);
14290
14291 unsigned eval_flags = 0;
14292
14294 {
14295 X.SetSize(vdim*NQ*NF, my_d_mt);
14297 }
14299 {
14300 J.SetSize(vdim*vdim*NQ*NF, my_d_mt);
14302 }
14304 {
14305 detJ.SetSize(NQ*NF, my_d_mt);
14307 }
14309 {
14310 normal.SetSize(vdim*NQ*NF, my_d_mt);
14312 }
14313
14314 const FaceQuadratureInterpolator *qi =
14315 fespace->GetFaceQuadratureInterpolator(ir, type);
14316 // All face data vectors assume layout byNODES.
14318 const bool use_tensor_products = UsesTensorBasis(*fespace);
14319 qi->DisableTensorProducts(!use_tensor_products);
14320
14321 qi->Mult(Fnodes, eval_flags, X, J, detJ, normal);
14322}
14323
14325 const real_t s_)
14326 : VectorCoefficient(dim), n(n_), s(s_), tip(p, dim-1)
14327{
14328}
14329
14331 const IntegrationPoint &ip)
14332{
14333 V.SetSize(vdim);
14334 T.Transform(ip, tip);
14335 V(0) = p[0];
14336 if (vdim == 2)
14337 {
14338 V(1) = s * ((ip.y + layer) / n);
14339 }
14340 else
14341 {
14342 V(1) = p[1];
14343 V(2) = s * ((ip.z + layer) / n);
14344 }
14345}
14346
14347
14348Mesh *Extrude1D(Mesh *mesh, const int ny, const real_t sy, const bool closed)
14349{
14350 if (mesh->Dimension() != 1)
14351 {
14352 mfem::err << "Extrude1D : Not a 1D mesh!" << endl;
14353 mfem_error();
14354 }
14355
14356 int nvy = (closed) ? (ny) : (ny + 1);
14357 int nvt = mesh->GetNV() * nvy;
14358
14359 Mesh *mesh2d;
14360
14361 if (closed)
14362 {
14363 mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny, mesh->GetNBE()*ny);
14364 }
14365 else
14366 mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny,
14367 mesh->GetNBE()*ny+2*mesh->GetNE());
14368
14369 // vertices
14370 real_t vc[2];
14371 for (int i = 0; i < mesh->GetNV(); i++)
14372 {
14373 vc[0] = mesh->GetVertex(i)[0];
14374 for (int j = 0; j < nvy; j++)
14375 {
14376 vc[1] = sy * (real_t(j) / ny);
14377 mesh2d->AddVertex(vc);
14378 }
14379 }
14380 // elements
14381 Array<int> vert;
14382 for (int i = 0; i < mesh->GetNE(); i++)
14383 {
14384 const Element *elem = mesh->GetElement(i);
14385 elem->GetVertices(vert);
14386 const int attr = elem->GetAttribute();
14387 for (int j = 0; j < ny; j++)
14388 {
14389 int qv[4];
14390 qv[0] = vert[0] * nvy + j;
14391 qv[1] = vert[1] * nvy + j;
14392 qv[2] = vert[1] * nvy + (j + 1) % nvy;
14393 qv[3] = vert[0] * nvy + (j + 1) % nvy;
14394
14395 mesh2d->AddQuad(qv, attr);
14396 }
14397 }
14398 // 2D boundary from the 1D boundary
14399 for (int i = 0; i < mesh->GetNBE(); i++)
14400 {
14401 const Element *elem = mesh->GetBdrElement(i);
14402 elem->GetVertices(vert);
14403 const int attr = elem->GetAttribute();
14404 for (int j = 0; j < ny; j++)
14405 {
14406 int sv[2];
14407 sv[0] = vert[0] * nvy + j;
14408 sv[1] = vert[0] * nvy + (j + 1) % nvy;
14409
14410 if (attr%2)
14411 {
14412 Swap<int>(sv[0], sv[1]);
14413 }
14414
14415 mesh2d->AddBdrSegment(sv, attr);
14416 }
14417 }
14418
14419 if (!closed)
14420 {
14421 // 2D boundary from the 1D elements (bottom + top)
14422 int nba = (mesh->bdr_attributes.Size() > 0 ?
14423 mesh->bdr_attributes.Max() : 0);
14424 for (int i = 0; i < mesh->GetNE(); i++)
14425 {
14426 const Element *elem = mesh->GetElement(i);
14427 elem->GetVertices(vert);
14428 const int attr = nba + elem->GetAttribute();
14429 int sv[2];
14430 sv[0] = vert[0] * nvy;
14431 sv[1] = vert[1] * nvy;
14432
14433 mesh2d->AddBdrSegment(sv, attr);
14434
14435 sv[0] = vert[1] * nvy + ny;
14436 sv[1] = vert[0] * nvy + ny;
14437
14438 mesh2d->AddBdrSegment(sv, attr);
14439 }
14440 }
14441
14442 mesh2d->FinalizeQuadMesh(1, 0, false);
14443
14444 GridFunction *nodes = mesh->GetNodes();
14445 if (nodes)
14446 {
14447 // duplicate the fec of the 1D mesh so that it can be deleted safely
14448 // along with its nodes, fes and fec
14449 FiniteElementCollection *fec2d = NULL;
14450 FiniteElementSpace *fes2d;
14451 const char *name = nodes->FESpace()->FEColl()->Name();
14452 string cname = name;
14453 if (cname == "Linear")
14454 {
14455 fec2d = new LinearFECollection;
14456 }
14457 else if (cname == "Quadratic")
14458 {
14459 fec2d = new QuadraticFECollection;
14460 }
14461 else if (cname == "Cubic")
14462 {
14463 fec2d = new CubicFECollection;
14464 }
14465 else if (!strncmp(name, "H1_", 3))
14466 {
14467 fec2d = new H1_FECollection(atoi(name + 7), 2);
14468 }
14469 else if (!strncmp(name, "L2_T", 4))
14470 {
14471 fec2d = new L2_FECollection(atoi(name + 10), 2, atoi(name + 4));
14472 }
14473 else if (!strncmp(name, "L2_", 3))
14474 {
14475 fec2d = new L2_FECollection(atoi(name + 7), 2);
14476 }
14477 else
14478 {
14479 delete mesh2d;
14480 mfem::err << "Extrude1D : The mesh uses unknown FE collection : "
14481 << cname << endl;
14482 mfem_error();
14483 }
14484 fes2d = new FiniteElementSpace(mesh2d, fec2d, 2);
14485 mesh2d->SetNodalFESpace(fes2d);
14486 GridFunction *nodes2d = mesh2d->GetNodes();
14487 nodes2d->MakeOwner(fec2d);
14488
14489 NodeExtrudeCoefficient ecoeff(2, ny, sy);
14490 Vector lnodes;
14491 Array<int> vdofs2d;
14492 for (int i = 0; i < mesh->GetNE(); i++)
14493 {
14495 for (int j = ny-1; j >= 0; j--)
14496 {
14497 fes2d->GetElementVDofs(i*ny+j, vdofs2d);
14498 lnodes.SetSize(vdofs2d.Size());
14499 ecoeff.SetLayer(j);
14500 fes2d->GetFE(i*ny+j)->Project(ecoeff, T, lnodes);
14501 nodes2d->SetSubVector(vdofs2d, lnodes);
14502 }
14503 }
14504 }
14505 return mesh2d;
14506}
14507
14508Mesh *Extrude2D(Mesh *mesh, const int nz, const real_t sz)
14509{
14510 if (mesh->Dimension() != 2)
14511 {
14512 mfem::err << "Extrude2D : Not a 2D mesh!" << endl;
14513 mfem_error();
14514 }
14515
14516 int nvz = nz + 1;
14517 int nvt = mesh->GetNV() * nvz;
14518
14519 Mesh *mesh3d = new Mesh(3, nvt, mesh->GetNE()*nz,
14520 mesh->GetNBE()*nz+2*mesh->GetNE());
14521
14522 bool wdgMesh = false;
14523 bool hexMesh = false;
14524
14525 // vertices
14526 real_t vc[3];
14527 for (int i = 0; i < mesh->GetNV(); i++)
14528 {
14529 vc[0] = mesh->GetVertex(i)[0];
14530 vc[1] = mesh->GetVertex(i)[1];
14531 for (int j = 0; j < nvz; j++)
14532 {
14533 vc[2] = sz * (real_t(j) / nz);
14534 mesh3d->AddVertex(vc);
14535 }
14536 }
14537 // elements
14538 Array<int> vert;
14539 for (int i = 0; i < mesh->GetNE(); i++)
14540 {
14541 const Element *elem = mesh->GetElement(i);
14542 elem->GetVertices(vert);
14543 const int attr = elem->GetAttribute();
14544 Geometry::Type geom = elem->GetGeometryType();
14545 switch (geom)
14546 {
14547 case Geometry::TRIANGLE:
14548 wdgMesh = true;
14549 for (int j = 0; j < nz; j++)
14550 {
14551 int pv[6];
14552 pv[0] = vert[0] * nvz + j;
14553 pv[1] = vert[1] * nvz + j;
14554 pv[2] = vert[2] * nvz + j;
14555 pv[3] = vert[0] * nvz + (j + 1) % nvz;
14556 pv[4] = vert[1] * nvz + (j + 1) % nvz;
14557 pv[5] = vert[2] * nvz + (j + 1) % nvz;
14558
14559 mesh3d->AddWedge(pv, attr);
14560 }
14561 break;
14562 case Geometry::SQUARE:
14563 hexMesh = true;
14564 for (int j = 0; j < nz; j++)
14565 {
14566 int hv[8];
14567 hv[0] = vert[0] * nvz + j;
14568 hv[1] = vert[1] * nvz + j;
14569 hv[2] = vert[2] * nvz + j;
14570 hv[3] = vert[3] * nvz + j;
14571 hv[4] = vert[0] * nvz + (j + 1) % nvz;
14572 hv[5] = vert[1] * nvz + (j + 1) % nvz;
14573 hv[6] = vert[2] * nvz + (j + 1) % nvz;
14574 hv[7] = vert[3] * nvz + (j + 1) % nvz;
14575
14576 mesh3d->AddHex(hv, attr);
14577 }
14578 break;
14579 default:
14580 mfem::err << "Extrude2D : Invalid 2D element type \'"
14581 << geom << "\'" << endl;
14582 mfem_error();
14583 break;
14584 }
14585 }
14586 // 3D boundary from the 2D boundary
14587 for (int i = 0; i < mesh->GetNBE(); i++)
14588 {
14589 const Element *elem = mesh->GetBdrElement(i);
14590 elem->GetVertices(vert);
14591 const int attr = elem->GetAttribute();
14592 for (int j = 0; j < nz; j++)
14593 {
14594 int qv[4];
14595 qv[0] = vert[0] * nvz + j;
14596 qv[1] = vert[1] * nvz + j;
14597 qv[2] = vert[1] * nvz + (j + 1) % nvz;
14598 qv[3] = vert[0] * nvz + (j + 1) % nvz;
14599
14600 mesh3d->AddBdrQuad(qv, attr);
14601 }
14602 }
14603
14604 // 3D boundary from the 2D elements (bottom + top)
14605 int nba = (mesh->bdr_attributes.Size() > 0 ?
14606 mesh->bdr_attributes.Max() : 0);
14607 for (int i = 0; i < mesh->GetNE(); i++)
14608 {
14609 const Element *elem = mesh->GetElement(i);
14610 elem->GetVertices(vert);
14611 const int attr = nba + elem->GetAttribute();
14612 Geometry::Type geom = elem->GetGeometryType();
14613 switch (geom)
14614 {
14615 case Geometry::TRIANGLE:
14616 {
14617 int tv[3];
14618 tv[0] = vert[0] * nvz;
14619 tv[1] = vert[2] * nvz;
14620 tv[2] = vert[1] * nvz;
14621
14622 mesh3d->AddBdrTriangle(tv, attr);
14623
14624 tv[0] = vert[0] * nvz + nz;
14625 tv[1] = vert[1] * nvz + nz;
14626 tv[2] = vert[2] * nvz + nz;
14627
14628 mesh3d->AddBdrTriangle(tv, attr);
14629 }
14630 break;
14631 case Geometry::SQUARE:
14632 {
14633 int qv[4];
14634 qv[0] = vert[0] * nvz;
14635 qv[1] = vert[3] * nvz;
14636 qv[2] = vert[2] * nvz;
14637 qv[3] = vert[1] * nvz;
14638
14639 mesh3d->AddBdrQuad(qv, attr);
14640
14641 qv[0] = vert[0] * nvz + nz;
14642 qv[1] = vert[1] * nvz + nz;
14643 qv[2] = vert[2] * nvz + nz;
14644 qv[3] = vert[3] * nvz + nz;
14645
14646 mesh3d->AddBdrQuad(qv, attr);
14647 }
14648 break;
14649 default:
14650 mfem::err << "Extrude2D : Invalid 2D element type \'"
14651 << geom << "\'" << endl;
14652 mfem_error();
14653 break;
14654 }
14655 }
14656
14657 if ( hexMesh && wdgMesh )
14658 {
14659 mesh3d->FinalizeMesh(0, false);
14660 }
14661 else if ( hexMesh )
14662 {
14663 mesh3d->FinalizeHexMesh(1, 0, false);
14664 }
14665 else if ( wdgMesh )
14666 {
14667 mesh3d->FinalizeWedgeMesh(1, 0, false);
14668 }
14669
14670 GridFunction *nodes = mesh->GetNodes();
14671 if (nodes)
14672 {
14673 // duplicate the fec of the 2D mesh so that it can be deleted safely
14674 // along with its nodes, fes and fec
14675 FiniteElementCollection *fec3d = NULL;
14676 FiniteElementSpace *fes3d;
14677 const char *name = nodes->FESpace()->FEColl()->Name();
14678 string cname = name;
14679 if (cname == "Linear")
14680 {
14681 fec3d = new LinearFECollection;
14682 }
14683 else if (cname == "Quadratic")
14684 {
14685 fec3d = new QuadraticFECollection;
14686 }
14687 else if (cname == "Cubic")
14688 {
14689 fec3d = new CubicFECollection;
14690 }
14691 else if (!strncmp(name, "H1_", 3))
14692 {
14693 fec3d = new H1_FECollection(atoi(name + 7), 3);
14694 }
14695 else if (!strncmp(name, "L2_T", 4))
14696 {
14697 fec3d = new L2_FECollection(atoi(name + 10), 3, atoi(name + 4));
14698 }
14699 else if (!strncmp(name, "L2_", 3))
14700 {
14701 fec3d = new L2_FECollection(atoi(name + 7), 3);
14702 }
14703 else
14704 {
14705 delete mesh3d;
14706 mfem::err << "Extrude3D : The mesh uses unknown FE collection : "
14707 << cname << endl;
14708 mfem_error();
14709 }
14710 fes3d = new FiniteElementSpace(mesh3d, fec3d, 3);
14711 mesh3d->SetNodalFESpace(fes3d);
14712 GridFunction *nodes3d = mesh3d->GetNodes();
14713 nodes3d->MakeOwner(fec3d);
14714
14715 NodeExtrudeCoefficient ecoeff(3, nz, sz);
14716 Vector lnodes;
14717 Array<int> vdofs3d;
14718 for (int i = 0; i < mesh->GetNE(); i++)
14719 {
14721 for (int j = nz-1; j >= 0; j--)
14722 {
14723 fes3d->GetElementVDofs(i*nz+j, vdofs3d);
14724 lnodes.SetSize(vdofs3d.Size());
14725 ecoeff.SetLayer(j);
14726 fes3d->GetFE(i*nz+j)->Project(ecoeff, T, lnodes);
14727 nodes3d->SetSubVector(vdofs3d, lnodes);
14728 }
14729 }
14730 }
14731 return mesh3d;
14732}
14733
14734#ifdef MFEM_DEBUG
14735void Mesh::DebugDump(std::ostream &os) const
14736{
14737 // dump vertices and edges (NCMesh "nodes")
14738 os << NumOfVertices + NumOfEdges << "\n";
14739 for (int i = 0; i < NumOfVertices; i++)
14740 {
14741 const real_t *v = GetVertex(i);
14742 os << i << " " << v[0] << " " << v[1] << " " << v[2]
14743 << " 0 0 " << i << " -1 0\n";
14744 }
14745
14746 Array<int> ev;
14747 for (int i = 0; i < NumOfEdges; i++)
14748 {
14749 GetEdgeVertices(i, ev);
14750 real_t mid[3] = {0, 0, 0};
14751 for (int j = 0; j < 2; j++)
14752 {
14753 for (int k = 0; k < spaceDim; k++)
14754 {
14755 mid[k] += GetVertex(ev[j])[k];
14756 }
14757 }
14758 os << NumOfVertices+i << " "
14759 << mid[0]/2 << " " << mid[1]/2 << " " << mid[2]/2 << " "
14760 << ev[0] << " " << ev[1] << " -1 " << i << " 0\n";
14761 }
14762
14763 // dump elements
14764 os << NumOfElements << "\n";
14765 for (int i = 0; i < NumOfElements; i++)
14766 {
14767 const Element* e = elements[i];
14768 os << e->GetNVertices() << " ";
14769 for (int j = 0; j < e->GetNVertices(); j++)
14770 {
14771 os << e->GetVertices()[j] << " ";
14772 }
14773 os << e->GetAttribute() << " 0 " << i << "\n";
14774 }
14775
14776 // dump faces
14777 os << "0\n";
14778}
14779#endif
14780
14781}
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:838
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
Definition array.hpp:261
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition array.hpp:162
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:697
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:144
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:882
void DeleteAll()
Delete the whole array.
Definition array.hpp:864
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:769
T * GetData()
Returns the data.
Definition array.hpp:118
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition array.hpp:874
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T.
Definition array.hpp:269
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition array.hpp:305
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition array.hpp:302
T & Last()
Return the last element in the array.
Definition array.hpp:802
bool SetsExist() const
Return true if any named sets are currently defined.
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:61
Piecewise-(bi)cubic continuous finite elements.
Definition fe_coll.hpp:819
int NumberOfEntries() const
Definition table.hpp:271
int NumberOfRows() const
Definition table.hpp:270
int Push(int a, int b)
Definition table.hpp:272
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:262
const real_t * HostRead() const
Shortcut for mfem::Read(GetMemory(), TotalSize(), false).
Definition densemat.hpp:470
real_t * Data() const
Returns the matrix data array.
Definition densemat.hpp:111
real_t * GetData() const
Returns the matrix data array.
Definition densemat.hpp:115
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:105
real_t Weight() const
Definition densemat.cpp:592
virtual void Print(std::ostream &out=mfem::out, int width_=4) const
Prints matrix to stream out.
real_t Trace() const
Trace of a square matrix.
Definition densemat.cpp:511
real_t CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
void GetColumn(int c, Vector &col) const
real_t FNorm2() const
Compute the square of the Frobenius norm of the matrix.
Definition densemat.hpp:269
real_t Det() const
Definition densemat.cpp:535
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:84
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition eltrans.hpp:162
real_t Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint....
Definition eltrans.hpp:131
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:119
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition eltrans.hpp:93
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:89
Abstract data type element.
Definition element.hpp:29
Geometry::Type GetGeometryType() const
Definition element.hpp:52
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:58
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:55
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:484
ElementTransformation * Elem2
Definition eltrans.hpp:525
ElementTransformation * Elem1
Definition eltrans.hpp:525
@ HAVE_ELEM2
Element on side 2 is configured.
Definition eltrans.hpp:517
@ HAVE_LOC1
Point transformation for side 1 is configured.
Definition eltrans.hpp:518
@ HAVE_ELEM1
Element on side 1 is configured.
Definition eltrans.hpp:516
@ HAVE_FACE
Face transformation is configured.
Definition eltrans.hpp:520
@ HAVE_LOC2
Point transformation for side 2 is configured.
Definition eltrans.hpp:519
IntegrationPointTransformation Loc1
Definition eltrans.hpp:527
void SetGeometryType(Geometry::Type g)
Method to set the geometry type of the face.
Definition eltrans.hpp:539
void SetConfigurationMask(int m)
Set the mask indicating which portions of the object have been setup.
Definition eltrans.hpp:510
IntegrationPointTransformation Loc2
Definition eltrans.hpp:527
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:643
Structure for storing face geometric factors: coordinates, Jacobians, determinants of the Jacobians,...
Definition mesh.hpp:2844
Vector normal
Normals at all quadrature points.
Definition mesh.hpp:2890
Vector J
Jacobians of the element transformations at all quadrature points.
Definition mesh.hpp:2877
const IntegrationRule * IntRule
Definition mesh.hpp:2847
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition mesh.hpp:2868
FaceGeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, FaceType type, MemoryType d_mt=MemoryType::DEFAULT)
Definition mesh.cpp:14263
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition mesh.hpp:2883
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:126
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:220
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Compute the full set of vdofs corresponding to each entry in dofs.
Definition fespace.cpp:213
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:3149
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary fac...
Definition fespace.cpp:3204
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:2846
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:322
void GetVertexDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the specified vertices.
Definition fespace.cpp:3094
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:710
virtual void UpdateMeshPointer(Mesh *new_mesh)
Definition fespace.cpp:3544
const NURBSExtension * GetNURBSext() const
Definition fespace.hpp:561
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition fespace.cpp:1404
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:287
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:3168
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:725
NURBSExtension * StealNURBSext()
Definition fespace.cpp:2290
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:740
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition fespace.cpp:1336
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:3267
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:316
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition fespace.cpp:3439
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:3276
void SetRelaxedHpConformity(bool relaxed=true)
Definition fespace.hpp:1327
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition fespace.hpp:734
int GetElementOrder(int i) const
Returns the order of the i'th finite element.
Definition fespace.cpp:176
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Definition fespace.cpp:3237
void SetElementOrder(int i, int p)
Sets the order of the i'th finite element.
Definition fespace.cpp:149
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition fespace.hpp:757
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:727
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:559
int GetMaxElementOrder() const
Return the maximum polynomial order.
Definition fespace.hpp:577
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:2950
int GetVDim() const
Returns vector dimension.
Definition fespace.hpp:706
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:1433
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition fespace.hpp:1313
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:3125
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:3104
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:303
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:249
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:1369
Abstract class for all finite elements.
Definition fe_base.hpp:239
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:316
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition fe_base.hpp:395
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:326
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:329
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition mesh.hpp:2790
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition mesh.hpp:2820
const Mesh * mesh
Definition mesh.hpp:2796
const IntegrationRule * IntRule
Definition mesh.hpp:2797
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition mesh.hpp:2835
Vector J
Jacobians of the element transformations at all quadrature points.
Definition mesh.hpp:2829
GeometricFactors(const Mesh *mesh, const IntegrationRule &ir, int flags, MemoryType d_mt=MemoryType::DEFAULT)
Definition mesh.cpp:14183
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
Definition geom.cpp:1136
static const int NumGeom
Definition geom.hpp:42
static const int Dimension[NumGeom]
Definition geom.hpp:47
const IntegrationPoint & GetCenter(int GeomType) const
Return the center of the given Geometry::Type, GeomType.
Definition geom.hpp:71
static const char * Name[NumGeom]
Definition geom.hpp:45
static const int NumVerts[NumGeom]
Definition geom.hpp:49
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:48
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:164
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 and fes.
Definition gridfunc.hpp:122
FiniteElementSpace * FESpace()
Definition gridfunc.hpp:696
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
int VectorDim() const
Definition gridfunc.cpp:323
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:395
void GetVectorValues(int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const
Definition gridfunc.cpp:714
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:260
const int * GetDofMap(Geometry::Type GeomType) const
Get the Cartesian to local H1 dof map.
Definition fe_coll.cpp:2017
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:611
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:702
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:68
int Size()
Return the size of the set.
Definition sets.hpp:39
IsoparametricTransformation Transf
Definition eltrans.hpp:467
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition eltrans.cpp:543
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:187
virtual int Transform(const Vector &pt, IntegrationPoint &ip)
Given a point, pt, in physical space, find its reference coordinates, ip.
Definition eltrans.cpp:336
@ Inside
The point is inside the element.
Definition eltrans.hpp:225
void SetTransformation(ElementTransformation &Trans)
Set a new forward ElementTransformation, Trans.
Definition eltrans.hpp:293
A standard isoparametric element transformation.
Definition eltrans.hpp:363
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition eltrans.hpp:402
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition eltrans.hpp:382
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition eltrans.hpp:405
virtual void Transform(const IntegrationPoint &, Vector &)
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Definition eltrans.cpp:488
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:330
Piecewise-(bi/tri)linear continuous finite elements.
Definition fe_coll.hpp:739
List of integer sets.
Definition sets.hpp:63
int Size()
Return the number of integer sets in the list.
Definition sets.hpp:70
int Insert(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:91
void AsTable(Table &t)
Write the list of sets into table 't'.
Definition sets.cpp:116
Class containing a minimal description of a part (a subset of the elements) of a Mesh and its connect...
Definition mesh.hpp:2479
Array< real_t > vertex_coordinates
Definition mesh.hpp:2579
int dimension
Reference space dimension of the elements.
Definition mesh.hpp:2496
int num_vertices
Number of vertices.
Definition mesh.hpp:2502
Table group_shared_entity_to_vertex[Geometry::NumGeom]
Definition mesh.hpp:2642
Array< int > entity_to_vertex[Geometry::NumGeom]
Definition mesh.hpp:2531
std::unique_ptr< Mesh > mesh
Definition mesh.hpp:2586
Array< int > boundary_map
Optional re-ordering for the boundary elements, similar to 'element_map'.
Definition mesh.hpp:2555
std::unique_ptr< FiniteElementSpace > nodal_fes
Definition mesh.hpp:2592
int num_parts
Total number of MeshParts.
Definition mesh.hpp:2606
Array< int > tet_refine_flags
Store the refinement flags for tetraheral elements. If all tets have zero refinement flags then this ...
Definition mesh.hpp:2535
int space_dimension
Dimension of the physical space into which the MeshPart is embedded.
Definition mesh.hpp:2499
int num_bdr_elements
Number of boundary elements with reference space dimension equal to 'dimension'-1.
Definition mesh.hpp:2509
int num_elements
Number of elements with reference space dimension equal to 'dimension'.
Definition mesh.hpp:2505
Mesh & GetMesh()
Construct a serial Mesh object from the MeshPart.
Definition mesh.cpp:13518
int my_part_id
Index of the part described by this MeshPart: 0 <= 'my_part_id' < 'num_parts'.
Definition mesh.hpp:2610
Array< int > element_map
Definition mesh.hpp:2552
Array< int > attributes
Definition mesh.hpp:2561
Table my_groups
Definition mesh.hpp:2623
std::unique_ptr< GridFunction > nodes
Definition mesh.hpp:2600
void Print(std::ostream &os) const
Write the MeshPart to a stream using the parallel format "MFEM mesh v1.2".
Definition mesh.cpp:13338
Array< int > bdr_attributes
Definition mesh.hpp:2568
Array< int > partitioning
Definition mesh.hpp:2710
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:14142
MeshPartitioner(Mesh &mesh_, int num_parts_, int *partitioning_=NULL, int part_method=1)
Construct a MeshPartitioner.
Definition mesh.cpp:13601
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:14157
void ExtractPart(int part_id, MeshPart &mesh_part) const
Construct a MeshPart corresponding to the given part_id.
Definition mesh.cpp:13672
List of mesh geometries stored as Array<Geometry::Type>.
Definition mesh.hpp:1419
Mesh data type.
Definition mesh.hpp:56
int CheckElementOrientation(bool fix_it=true)
Check (and optionally attempt to fix) the orientation of the elements.
Definition mesh.cpp:6294
Array< Vertex > vertices
Definition mesh.hpp:97
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
Definition mesh.cpp:7039
void GetEdgeOrdering(const DSTable &v_to_v, Array< int > &order)
Definition mesh.cpp:2642
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:914
void NURBSCoarsening(int cf=2, real_t tol=1.0e-12)
Definition mesh.cpp:10502
void SetVerticesFromNodes(const GridFunction *nodes)
Helper to set vertex coordinates given a high-order curvature function.
Definition mesh.cpp:6236
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:3016
int GetElementToEdgeTable(Table &)
Definition mesh.cpp:7422
int meshgen
Definition mesh.hpp:80
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:6972
void SetVertices(const Vector &vert_coord)
Definition mesh.cpp:8913
Element * NewElement(int geom)
Definition mesh.cpp:4401
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition mesh.hpp:2236
IsoparametricTransformation Transformation2
Definition mesh.hpp:241
int GetNEdges() const
Return the number of edges.
Definition mesh.hpp:1232
void MarkForRefinement()
Definition mesh.cpp:2610
void GetBdrElementFace(int i, int *f, int *o) const
Definition mesh.cpp:7252
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem)
Begin construction of a mesh.
Definition mesh.cpp:1635
static void PrintElement(const Element *el, std::ostream &os)
Definition mesh.cpp:4467
Array< FaceInfo > faces_info
Definition mesh.hpp:224
int EulerNumber() const
Equals 1 + num_holes - num_loops.
Definition mesh.hpp:1166
CoarseFineTransformations CoarseFineTr
Definition mesh.hpp:247
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:1715
int AddBdrElement(Element *elem)
Definition mesh.cpp:2028
void GetElementColoring(Array< int > &colors, int el0=0)
Definition mesh.cpp:12047
virtual FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition mesh.cpp:980
void FinalizeMesh(int refine=0, bool fix_orientation=true)
Finalize the construction of any type of Mesh.
Definition mesh.cpp:3128
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:282
static void PrintElementWithoutAttr(const Element *el, std::ostream &os)
Definition mesh.cpp:4443
MemAlloc< Tetrahedron, 1024 > TetMemory
Definition mesh.hpp:262
void RedRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition mesh.hpp:371
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:290
void ReadTrueGridMesh(std::istream &input)
static const int vtk_quadratic_tet[10]
Definition mesh.hpp:255
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
Definition mesh.cpp:1439
friend class ParNCMesh
Definition mesh.hpp:61
IsoparametricTransformation EdgeTransformation
Definition mesh.hpp:243
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:2063
int * CartesianPartitioning(int nxyz[])
Definition mesh.cpp:8054
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:7224
static int GetQuadOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition mesh.cpp:6533
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition mesh.cpp:7316
void GetLocalSegToQuadTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:692
virtual long long ReduceInt(int value) const
Utility function: sum integers from all processors (Allreduce).
Definition mesh.hpp:2439
int NumOfBdrElements
Definition mesh.hpp:71
void BdrBisection(int i, const HashTable< Hashed2 > &)
Bisect a boundary triangle: boundary element with index i is bisected.
Definition mesh.cpp:10933
Element::Type GetBdrElementType(int i) const
Returns the type of boundary element i.
Definition mesh.cpp:7321
const Table & ElementToEdgeTable() const
Definition mesh.cpp:7506
bool Conforming() const
Definition mesh.hpp:2228
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:6250
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:1442
Geometry::Type GetFaceGeometry(int i) const
Return the Geometry::Type associated with face i.
Definition mesh.cpp:1452
void GeneralRefinement(const Array< Refinement > &refinements, int nonconforming=-1, int nc_limit=0)
Definition mesh.cpp:10558
Geometry::Type GetElementGeometry(int i) const
Definition mesh.hpp:1371
Geometry::Type GetBdrElementGeometry(int i) const
Definition mesh.hpp:1376
int AddTri(const int *vi, int attr=1)
Adds a triangle to the mesh given by 3 vertices vi.
Definition mesh.hpp:894
static Mesh MakeCartesian1D(int n, real_t sx=1.0)
Creates 1D mesh, divided into n equal intervals.
Definition mesh.cpp:4235
int GetAttribute(int i) const
Return the attribute of element i.
Definition mesh.hpp:1333
void NodesUpdated()
This function should be called after the mesh node coordinates have been updated externally,...
Definition mesh.hpp:2075
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:6159
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition mesh.hpp:1438
void UniformRefinement3D_base(Array< int > *f2qf=NULL, DSTable *v_to_v_p=NULL, bool update_nodes=true)
Definition mesh.cpp:9238
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:1743
long nodes_sequence
Counter for geometric factor invalidation.
Definition mesh.hpp:90
virtual void Load(std::istream &input, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition mesh.hpp:718
IsoparametricTransformation FaceTransformation
Definition mesh.hpp:243
Array< NCFaceInfo > nc_faces_info
Definition mesh.hpp:225
friend class NCMesh
Definition mesh.hpp:57
void MakeRefined_(Mesh &orig_mesh, const Array< int > &ref_factors, int ref_type)
Internal function used in Mesh::MakeRefined.
Definition mesh.cpp:4900
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:1778
Array< int > GetFaceToBdrElMap() const
Definition mesh.cpp:1477
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:4272
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:2987
void FinalizeTetMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a tetrahedral Mesh.
Definition mesh.cpp:3022
real_t GetLength(int i, int j) const
Return the length of the segment from node i to node j.
Definition mesh.cpp:7360
const FiniteElementSpace * GetNodalFESpace() const
Definition mesh.cpp:6206
void AddBdrQuadAsTriangles(const int *vi, int attr=1)
Definition mesh.cpp:2077
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:1792
void Loader(std::istream &input, int generate_edges=0, std::string parse_tag="")
Definition mesh.cpp:4526
const Table & ElementToElementTable()
Definition mesh.cpp:7461
void ScaleElements(real_t sf)
Definition mesh.cpp:12751
void GenerateNCFaceInfo()
Definition mesh.cpp:7741
void ReadLineMesh(std::istream &input)
void ApplyLocalSlaveTransformation(FaceElementTransformations &FT, const FaceInfo &fi, bool is_ghost) const
Definition mesh.cpp:1130
Array< Element * > faces
Definition mesh.hpp:99
int Dim
Definition mesh.hpp:68
real_t AggregateError(const Array< real_t > &elem_error, const int *fine, int nfine, int op)
Derefinement helper.
Definition mesh.cpp:10233
void CheckPartitioning(int *partitioning_)
Definition mesh.cpp:8498
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
Definition mesh.cpp:2756
void GetLocalPtToSegTransformation(IsoparametricTransformation &, int i) const
Used in GetFaceElementTransformations (...)
Definition mesh.cpp:657
bool Nonconforming() const
Definition mesh.hpp:2229
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition mesh.hpp:1339
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:5796
static int ComposeQuadOrientations(int ori_a_b, int ori_b_c)
Definition mesh.cpp:6581
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:1729
void GenerateFaces()
Definition mesh.cpp:7639
static const int vtk_quadratic_wedge[18]
Definition mesh.hpp:257
int EulerNumber2D() const
Equals 1 - num_holes.
Definition mesh.hpp:1169
AttributeSets bdr_attribute_sets
Named sets of boundary element attributes.
Definition mesh.hpp:288
void Destroy()
Definition mesh.cpp:1565
int GetBdrElementFaceIndex(int be_idx) const
Return the local face (codimension-1) index for the given boundary element index.
Definition mesh.hpp:1518
void GetVertices(Vector &vert_coord) const
Definition mesh.cpp:8902
void InitFromNCMesh(const NCMesh &ncmesh)
Initialize vertices/elements/boundary/tables from a nonconforming mesh.
Definition mesh.cpp:10333
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:6266
void Make1D(int n, real_t sx=1.0)
Definition mesh.cpp:4038
friend class Tetrahedron
Definition mesh.hpp:261
void DeleteTables()
Definition mesh.hpp:308
void RefineNURBSFromFile(std::string ref_file)
Definition mesh.cpp:5627
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1283
int AddBdrPoint(int v, int attr=1)
Definition mesh.cpp:2092
void FinalizeWedgeMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a wedge Mesh.
Definition mesh.cpp:3063
static int GetTriOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition mesh.cpp:6444
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:11434
static Mesh MakeSimplicial(const Mesh &orig_mesh)
Definition mesh.cpp:5128
void SetPatchBdrAttribute(int i, int attr)
Set the attribute of patch boundary element i, for a NURBS mesh.
Definition mesh.cpp:3004
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition mesh.hpp:1235
int AddVertexAtMeanCenter(const int *vi, const int nverts, int dim=3)
Definition mesh.cpp:1698
static int GetTetOrientation(const int *base, const int *test)
Returns the orientation of "test" relative to "base".
Definition mesh.cpp:6612
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:2239
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:1990
bool FaceIsTrueInterior(int FaceNo) const
Definition mesh.hpp:540
long GetSequence() const
Definition mesh.hpp:2242
const CoarseFineTransformations & GetRefinementTransforms() const
Definition mesh.cpp:11082
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:3671
void GetLocalQuadToWdgTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:809
ElementTransformation * GetFaceTransformation(int FaceNo)
Returns a pointer to the transformation defining the given face element.
Definition mesh.cpp:583
void SetAttribute(int i, int attr)
Set the attribute of element i.
Definition mesh.hpp:1336
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition mesh.cpp:3135
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Definition mesh.hpp:2288
void DestroyTables()
Definition mesh.cpp:1520
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:4281
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:876
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:12122
void Clear()
Clear the contents of the Mesh.
Definition mesh.hpp:730
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
Definition mesh.cpp:2690
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:1658
virtual void LocalRefinement(const Array< int > &marked_el, int type=3)
This function is not public anymore. Use GeneralRefinement instead.
Definition mesh.cpp:9945
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1226
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:3316
virtual void Save(const std::string &fname, int precision=16) const
Definition mesh.cpp:11481
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:1757
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:7344
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1160
Table * el_to_face
Definition mesh.hpp:228
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:10650
const Element * GetBdrElement(int i) const
Return pointer to the i'th boundary element object.
Definition mesh.hpp:1298
void CheckDisplacements(const Vector &displacements, real_t &tmax)
Definition mesh.cpp:8816
friend class NURBSExtension
Definition mesh.hpp:58
void AddTriangleFaceElement(int lf, int gf, int el, int v0, int v1, int v2)
Definition mesh.cpp:7584
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:1960
void GetNode(int i, real_t *coord) const
Definition mesh.cpp:8922
void ReorderElements(const Array< int > &ordering, bool reorder_vertices=true)
Definition mesh.cpp:2458
void GreenRefinement(int i, const DSTable &v_to_v, int *edge1, int *edge2, int *middle)
Definition mesh.hpp:377
void UpdateNodes()
Update the nodes of a curved mesh after the topological part of a Mesh::Operation,...
Definition mesh.cpp:9064
void PrintElementsWithPartitioning(int *partitioning, std::ostream &os, int interior_faces=0)
Definition mesh.cpp:12241
Mesh & operator=(Mesh &&mesh)
Move assignment operator.
Definition mesh.cpp:4219
long sequence
Definition mesh.hpp:87
static int InvertQuadOrientation(int ori)
Definition mesh.cpp:6606
Array< FaceGeometricFactors * > face_geom_factors
Definition mesh.hpp:293
void GetLocalTriToPyrTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:762
Table * bel_to_edge
Definition mesh.hpp:232
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:4290
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:4425
int AddBdrSegment(int v1, int v2, int attr=1)
Definition mesh.cpp:2035
bool DerefineByError(Array< real_t > &elem_error, real_t threshold, int nc_limit=0, int op=1)
Definition mesh.cpp:10304
void FinalizeHexMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a hexahedral Mesh.
Definition mesh.cpp:3098
int AddElement(Element *elem)
Definition mesh.cpp:2021
static int DecodeFaceInfoLocalIndex(int info)
Given a "face info int", return the local face index.
Definition mesh.hpp:1986
Table * el_to_edge
Definition mesh.hpp:227
FaceInformation GetFaceInformation(int f) const
Definition mesh.cpp:1169
int GetNumFacesWithGhost() const
Return the number of faces (3D), edges (2D) or vertices (1D) including ghost faces.
Definition mesh.cpp:6261
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:10669
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:7007
static int InvertTriOrientation(int ori)
Definition mesh.cpp:6527
STable3D * GetElementToFaceTable(int ret_ftbl=0)
Definition mesh.cpp:7862
void FinalizeQuadMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a quadrilateral Mesh.
Definition mesh.cpp:2177
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:3745
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:10256
void AddVertexParents(int i, int p1, int p2)
Mark vertex i as nonconforming, with parent vertices p1 and p2.
Definition mesh.cpp:1682
MFEM_DEPRECATED void GetBdrElementAdjacentElement2(int bdr_el, int &el, int &info) const
Deprecated.
Definition mesh.cpp:7293
int GetPatchAttribute(int i) const
Return the attribute of patch i, for a NURBS mesh.
Definition mesh.cpp:2998
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
Definition mesh.cpp:1433
void Printer(std::ostream &os=mfem::out, std::string section_delimiter="", const std::string &comments="") const
Definition mesh.cpp:11309
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition mesh.hpp:1392
ElementTransformation * GetBdrElementTransformation(int i)
Returns a pointer to the transformation defining the i-th boundary element.
Definition mesh.cpp:506
IsoparametricTransformation Transformation
Definition mesh.hpp:241
void Init()
Definition mesh.cpp:1488
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:3598
void GetLocalTriToWdgTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:736
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:7201
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1163
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:856
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:4253
Table * edge_vertex
Definition mesh.hpp:239
void LoadPatchTopo(std::istream &input, Array< int > &edge_to_knot)
Read NURBS patch/macro-element mesh.
Definition mesh.cpp:5858
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:6200
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:8941
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:8973
int NumOfVertices
Definition mesh.hpp:71
AttributeSets attribute_sets
Named sets of element attributes.
Definition mesh.hpp:285
virtual void UniformRefinement3D()
Refine a mixed 3D mesh uniformly.
Definition mesh.hpp:426
static int ComposeTriOrientations(int ori_a_b, int ori_b_c)
Definition mesh.cpp:6504
Array< int > be_to_face
Definition mesh.hpp:230
void PrintBdrVTU(std::string fname, VTKFormat format=VTKFormat::ASCII, bool high_order_output=false, int compression_level=0)
Definition mesh.cpp:11687
void AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
Definition mesh.cpp:7547
FaceElementTransformations * GetBdrFaceTransformations(int BdrElemNo)
Builds the transformation defining the given boundary face.
Definition mesh.cpp:1099
int AddBdrTriangle(int v1, int v2, int v3, int attr=1)
Definition mesh.cpp:2049
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:13195
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1223
static int DecodeFaceInfoOrientation(int info)
Given a "face info int", return the face orientation.
Definition mesh.hpp:1983
void GetHilbertElementOrdering(Array< int > &ordering)
Definition mesh.cpp:2406
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition mesh.cpp:7069
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:1900
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:11695
virtual void UniformRefinement2D()
Refine a mixed 2D mesh uniformly.
Definition mesh.hpp:416
GridFunction * Nodes
Definition mesh.hpp:252
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:5457
Element::Type GetFaceElementType(int Face) const
Definition mesh.cpp:1472
int CheckBdrElementOrientation(bool fix_it=true)
Check the orientation of the boundary elements.
Definition mesh.cpp:6745
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:7271
Table * el_to_el
Definition mesh.hpp:229
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:9043
Table * face_edge
Definition mesh.hpp:238
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:4225
int NumOfElements
Definition mesh.hpp:71
static const int vtk_quadratic_hex[27]
Definition mesh.hpp:258
void Swap(Mesh &other, bool non_geometry)
Definition mesh.cpp:10378
Array< Triple< int, int, int > > tmp_vertex_parents
Definition mesh.hpp:266
virtual void GenerateBoundaryElements()
Definition mesh.cpp:2099
static void GetElementArrayEdgeTable(const Array< Element * > &elem_array, const DSTable &v_to_v, Table &el_to_edge)
Definition mesh.cpp:7375
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:5491
void Bisection(int i, const DSTable &, int *, int *, int *)
Bisect a triangle: element with index i is bisected.
Definition mesh.cpp:10724
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
Definition mesh.hpp:1456
void ResetLazyData()
Definition mesh.cpp:1593
void UniformRefinement2D_base(bool update_nodes=true)
Definition mesh.cpp:9079
IsoparametricTransformation BdrTransformation
Definition mesh.hpp:242
void GetLocalSegToTriTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:672
void DestroyPointers()
Definition mesh.cpp:1539
void InitTables()
Definition mesh.cpp:1507
void DegreeElevate(int rel_degree, int degree=16)
Definition mesh.cpp:5779
Table * face_to_elem
Definition mesh.hpp:237
int NumOfFaces
Definition mesh.hpp:72
int spaceDim
Definition mesh.hpp:69
int FindCoarseElement(int i)
Definition mesh.cpp:11072
void FinalizeTriMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a triangular Mesh.
Definition mesh.cpp:2148
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:1859
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:1806
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:6856
void SetEmpty()
Definition mesh.cpp:1514
virtual void SetNodalFESpace(FiniteElementSpace *nfes)
Definition mesh.cpp:6153
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1229
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
Definition mesh.cpp:3241
void AddQuadFaceElement(int lf, int gf, int el, int v0, int v1, int v2, int v3)
Definition mesh.cpp:7612
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:5708
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:13081
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:589
int own_nodes
Definition mesh.hpp:253
void GetElementData(const Array< Element * > &elem_array, int geom, Array< int > &elem_vtx, Array< int > &attr) const
Definition mesh.cpp:10438
void PrintSurfaces(const Table &Aface_face, std::ostream &os) const
Print set of disjoint surfaces:
Definition mesh.cpp:12614
bool IsSlaveFace(const FaceInfo &fi) const
Definition mesh.cpp:1125
void FreeElement(Element *E)
Definition mesh.cpp:13056
Array< Element * > boundary
Definition mesh.hpp:98
virtual void MarkTetMeshForRefinement(const DSTable &v_to_v)
Definition mesh.cpp:2667
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition mesh.cpp:7326
FaceElementTransformations * GetInteriorFaceTransformations(int FaceNo)
See GetFaceElementTransformations().
Definition mesh.cpp:1079
void GetLocalTriToTetTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:712
virtual void PrintXG(std::ostream &os=mfem::out) const
Print the mesh to the given stream using Netgen/Truegrid format.
Definition mesh.cpp:11145
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition mesh.hpp:291
void NewNodes(GridFunction &nodes, bool make_owner=false)
Replace the internal node GridFunction with the given GridFunction.
Definition mesh.cpp:9000
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:5730
int mesh_geoms
Definition mesh.hpp:82
void DebugDump(std::ostream &os) const
Output an NCMesh-compatible debug dump.
Definition mesh.cpp:14735
GridFunction * GetNodes()
Return a pointer to the internal node GridFunction (may be NULL).
Definition mesh.hpp:2093
bool RefineByError(const Array< real_t > &elem_error, real_t threshold, int nonconforming=-1, int nc_limit=0)
Definition mesh.cpp:10695
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:4263
STable3D * GetFacesTable()
Definition mesh.cpp:7799
Table * GetFaceEdgeTable() const
Definition mesh.cpp:7078
void EnsureNCMesh(bool simplices_nonconforming=false)
Definition mesh.cpp:10626
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:1194
virtual MFEM_DEPRECATED void ReorientTetMesh()
Definition mesh.cpp:7992
void PrintVTK(std::ostream &os)
Definition mesh.cpp:11495
void MoveNodes(const Vector &displacements)
Definition mesh.cpp:8961
Array< GeometricFactors * > geom_factors
Optional geometric factors.
Definition mesh.hpp:292
void SetMeshGen()
Determine the mesh generator bitmask meshgen, see MeshGenerator().
Definition mesh.cpp:4473
int nbBoundaryFaces
Definition mesh.hpp:77
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:4243
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:6985
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:3860
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:1822
FaceElementTransformations FaceElemTr
Definition mesh.hpp:244
void SetNodes(const Vector &node_coord)
Updates the vertex/node locations. Invokes NodesUpdated().
Definition mesh.cpp:8985
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition mesh.cpp:6961
void FinalizeCheck()
Definition mesh.cpp:2134
void GetLocalQuadToPyrTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:833
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:1841
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:6211
Element * ReadElement(std::istream &input)
Definition mesh.cpp:4455
virtual bool HasBoundaryElements() const
Checks if the mesh has boundary elements.
Definition mesh.hpp:1190
void ScaleSubdomains(real_t sf)
Definition mesh.cpp:12681
void GetVertexToVertexTable(DSTable &) const
Definition mesh.cpp:7397
void GetLocalQuadToHexTransformation(IsoparametricTransformation &loc, int i) const
Definition mesh.cpp:787
int NumOfEdges
Definition mesh.hpp:72
void Transform(void(*f)(const Vector &, Vector &))
Definition mesh.cpp:12821
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:10970
Geometry::Type GetElementBaseGeometry(int i) const
Definition mesh.hpp:1385
Operation last_operation
Definition mesh.hpp:302
void SwapNodes(GridFunction *&nodes, int &own_nodes_)
Swap the internal node GridFunction pointer and ownership flag members with the given ones.
Definition mesh.cpp:9022
void SetBdrAttribute(int i, int attr)
Set the attribute of boundary element i.
Definition mesh.hpp:1342
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:4334
int nbInteriorFaces
Definition mesh.hpp:77
Table * GetVertexToElementTable()
Definition mesh.cpp:7132
void InitRefinementTransforms()
Definition mesh.cpp:11060
Table * GetEdgeVertexTable() const
Definition mesh.cpp:7106
int * GeneratePartitioning(int nparts, int part_method=1)
Definition mesh.cpp:8098
Table * GetFaceToElementTable() const
Definition mesh.cpp:7167
void MarkTriMeshForRefinement()
Definition mesh.cpp:2627
void ReadNetgen2DMesh(std::istream &input, int &curved)
Array< Element * > elements
Definition mesh.hpp:92
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition mesh.hpp:280
void AddPointFaceElement(int lf, int gf, int el)
Used in GenerateFaces()
Definition mesh.cpp:7515
void RemoveInternalBoundaries()
Definition mesh.cpp:12979
virtual void NonconformingRefinement(const Array< Refinement > &refinements, int nc_limit=0)
This function is not public anymore. Use GeneralRefinement instead.
Definition mesh.cpp:10187
void MakeSimplicial_(const Mesh &orig_mesh, int *vglobal)
Definition mesh.cpp:5135
void MoveVertices(const Vector &displacements)
Definition mesh.cpp:8893
virtual void SetAttributes()
Determine the sets of unique attribute values in domain and boundary elements.
Definition mesh.cpp:1604
const real_t * GetVertex(int i) const
Return pointer to vertex i's coordinates.
Definition mesh.hpp:1265
void DeleteGeometricFactors()
Destroy all GeometricFactors stored by the Mesh.
Definition mesh.cpp:898
const Table & ElementToFaceTable() const
Definition mesh.cpp:7497
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:1878
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition mesh.cpp:12872
void KnotInsert(Array< KnotVector * > &kv)
For NURBS meshes, insert the new knots in kv, for each direction.
Definition mesh.cpp:5664
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
Definition ncmesh.hpp:123
void OnMeshUpdated(Mesh *mesh)
Definition ncmesh.cpp:2590
void FindNeighbors(int elem, Array< int > &neighbors, const Array< int > *search_set=NULL)
Definition ncmesh.cpp:3841
void MakeTopologyOnly()
Definition ncmesh.hpp:478
void GetMeshComponents(Mesh &mesh) const
Fill Mesh::{vertices,elements,boundary} for the current finest level.
Definition ncmesh.cpp:2463
const CoarseFineTransformations & GetRefinementTransforms() const
Definition ncmesh.cpp:4674
int Dimension() const
Return the dimension of the NCMesh.
Definition ncmesh.hpp:145
BlockArray< Element > elements
Definition ncmesh.hpp:575
static void GridSfcOrdering3D(int width, int height, int depth, Array< int > &coords)
Definition ncmesh.cpp:5077
Array< int > leaf_elements
finest elements, in Mesh ordering (+ ghosts)
Definition ncmesh.hpp:604
virtual void LimitNCLevel(int max_nc_level)
Definition ncmesh.cpp:5549
const NCList & GetFaceList()
Return the current list of conforming and nonconforming faces.
Definition ncmesh.hpp:298
virtual void Derefine(const Array< int > &derefs)
Definition ncmesh.cpp:2009
Array< real_t > coordinates
Definition ncmesh.hpp:585
bool IsGhost(const Element &el) const
Return true if the Element el is a ghost element.
Definition ncmesh.hpp:668
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Definition ncmesh.hpp:305
void Print(std::ostream &out, const std::string &comments="") const
Definition ncmesh.cpp:5746
int spaceDim
dimensions of the elements and the vertex coordinates
Definition ncmesh.hpp:482
void MarkCoarseLevel()
Definition ncmesh.cpp:4626
virtual void CheckDerefinementNCLevel(const Table &deref_table, Array< int > &level_ok, int max_nc_level)
Definition ncmesh.cpp:1980
const Table & GetDerefinementTable()
Definition ncmesh.cpp:1965
int SpaceDimension() const
Return the space dimension of the NCMesh.
Definition ncmesh.hpp:147
virtual void Refine(const Array< Refinement > &refinements)
Definition ncmesh.cpp:1648
static void GridSfcOrdering2D(int width, int height, Array< int > &coords)
Definition ncmesh.cpp:5062
int GetNBE() const
Definition nurbs.hpp:498
void GetCoarseningFactors(Array< int > &f) const
Definition nurbs.cpp:4277
void SetPatchAttribute(int i, int attr)
Definition nurbs.hpp:536
const Array< int > & GetPatchElements(int patch)
Definition nurbs.cpp:4704
void UniformRefinement(int rf=2)
Refine with optional refinement factor rf. Uniform means refinement is done everywhere by the same fa...
Definition nurbs.cpp:4248
void Print(std::ostream &os, const std::string &comments="") const
Definition nurbs.cpp:2354
void SetPatchBdrAttribute(int i, int attr)
Definition nurbs.hpp:544
void SetCoordsFromPatches(Vector &Nodes)
Definition nurbs.cpp:4100
void Coarsen(int cf=2, real_t tol=1.0e-12)
Definition nurbs.cpp:4270
int GetPatchAttribute(int i) const
Definition nurbs.hpp:540
void GetElementTopo(Array< Element * > &elements) const
Definition nurbs.cpp:3382
const Array< int > & GetPatchBdrElements(int patch)
Definition nurbs.cpp:4711
int GetNKV() const
Definition nurbs.hpp:491
void GetVertexLocalToGlobal(Array< int > &lvert_vert)
Definition nurbs.cpp:4025
void GetBdrElementTopo(Array< Element * > &boundary) const
Definition nurbs.cpp:3511
void KnotRemove(Array< Vector * > &kv, real_t tol=1.0e-12)
Definition nurbs.cpp:4416
void GetElementLocalToGlobal(Array< int > &lelem_elem)
Definition nurbs.cpp:4035
void KnotInsert(Array< KnotVector * > &kv)
Definition nurbs.cpp:4304
int GetNV() const
Definition nurbs.hpp:494
void ConvertToPatches(const Vector &Nodes)
Definition nurbs.cpp:4089
int Dimension() const
Definition nurbs.hpp:481
void SetKnotsFromPatches()
Definition nurbs.cpp:4108
int GetNE() const
Definition nurbs.hpp:496
int GetPatchBdrAttribute(int i) const
Definition nurbs.hpp:548
void DegreeElevate(int rel_degree, int degree=16)
Definition nurbs.cpp:4224
Class for standard nodal finite elements.
Definition fe_base.hpp:715
Class used to extrude the nodes of a mesh.
Definition mesh.hpp:2896
void SetLayer(const int l)
Definition mesh.hpp:2903
virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip)
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
Definition mesh.cpp:14330
NodeExtrudeCoefficient(const int dim, const int n_, const real_t s_)
Definition mesh.cpp:14324
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
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:767
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:317
Array< int > RefGeoms
Definition geom.hpp:318
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:114
void AddConnections(int r, const int *c, int nc)
Definition table.cpp:104
void Swap(Table &other)
Definition table.cpp:395
int RowSize(int i) const
Definition table.hpp:108
void ShiftUpI()
Definition table.cpp:115
void Clear()
Definition table.cpp:381
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
Definition table.cpp:124
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition table.cpp:187
int Push(int i, int j)
Definition table.cpp:219
void AddConnection(int r, int c)
Definition table.hpp:80
void Finalize()
Definition table.cpp:243
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition table.cpp:81
int Size() const
Returns the number of TYPE I elements.
Definition table.hpp:92
int Size_of_connections() const
Definition table.hpp:98
void AddColumnsInRow(int r, int ncol)
Definition table.hpp:78
void MakeJ()
Definition table.cpp:91
int * GetI()
Definition table.hpp:113
void AddAColumnInRow(int r)
Definition table.hpp:77
void SetDims(int rows, int nnz)
Definition table.cpp:140
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:80
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:478
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:604
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:832
int Size() const
Returns the size of the vector.
Definition vector.hpp:218
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:538
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:486
void NewDataAndSize(real_t *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition vector.hpp:181
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:227
void SetData(real_t *d)
Definition vector.hpp:168
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:578
void cross3D(const Vector &vin, Vector &vout) const
Definition vector.cpp:541
real_t DistanceTo(const real_t *p) const
Compute the Euclidean distance to another vector.
Definition vector.hpp:690
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:235
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:648
real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:45
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:476
GeometryRefiner GlobGeometryRefiner
Definition geom.cpp:1891
int FindRoots(const Vector &z, Vector &x)
Definition mesh.cpp:8635
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:59
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:316
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:414
void ShiftRight(int &a, int &b, int &c)
Definition mesh.hpp:2919
MFEM_EXPORT class Linear3DFiniteElement TetrahedronFE
Definition fe.cpp:36
void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
Definition mesh.cpp:8555
Mesh * Extrude1D(Mesh *mesh, const int ny, const real_t sy, const bool closed)
Extrude a 1D mesh.
Definition mesh.cpp:14348
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:14508
VTKFormat
Data array format for VTK and VTU files.
Definition vtk.hpp:99
@ 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:1345
void FindTMax(Vector &c, Vector &x, real_t &tmax, const real_t factor, const int Dim)
Definition mesh.cpp:8782
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:147
@ byNODES
NQPT x VDIM x NE (values) / NQPT x VDIM x DIM x NE (grads)
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:360
float real_t
Definition config.hpp:43
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:8427
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:75
@ LEXICOGRAPHIC
Lexicographic ordering for tensor-product FiniteElements.
@ 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:62
void XYZ_VectorFunction(const Vector &p, Vector &v)
Definition mesh.cpp:6116
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:47
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:486
real_t p(const Vector &x, real_t t)
T sq(T x)
RefCoord t[3]
RefCoord s[3]
Defines the coarse-fine transformations of all fine elements.
Definition ncmesh.hpp:72
Array< Embedding > embeddings
Fine element positions in their parents.
Definition ncmesh.hpp:74
DenseTensor point_matrices[Geometry::NumGeom]
Definition ncmesh.hpp:78
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:51
int parent
Coarse Element index in the coarse mesh.
Definition ncmesh.hpp:53
unsigned matrix
Definition ncmesh.hpp:59
static const int FaceVert[NumFaces][MaxFaceVert]
Definition geom.hpp:255
static const int Edges[NumEdges][2]
Definition geom.hpp:251
static const int FaceVert[NumFaces][MaxFaceVert]
Definition geom.hpp:277
static const int Edges[NumEdges][2]
Definition geom.hpp:273
static const int Edges[NumEdges][2]
Definition geom.hpp:295
static const int FaceVert[NumFaces][MaxFaceVert]
Definition geom.hpp:299
static const int Orient[NumOrient][NumVert]
Definition geom.hpp:158
static const int Orient[NumOrient][NumVert]
Definition geom.hpp:212
static const int Edges[NumEdges][2]
Definition geom.hpp:201
static const int Edges[NumEdges][2]
Definition geom.hpp:225
static const int FaceVert[NumFaces][MaxFaceVert]
Definition geom.hpp:229
static const int Orient[NumOrient][NumVert]
Definition geom.hpp:238
static const int Edges[NumEdges][2]
Definition geom.hpp:171
static const int Orient[NumOrient][NumVert]
Definition geom.hpp:187
EntityHelper(int dim_, const Array< int >(&entity_to_vertex_)[Geometry::NumGeom])
Definition mesh.cpp:13310
Entity FindEntity(int bytype_entity_id)
Definition mesh.cpp:13325
entity_to_vertex_type & entity_to_vertex
Definition mesh.hpp:2487
int geom_offsets[Geometry::NumGeom+1]
Definition mesh.hpp:2485
const int * verts
Definition mesh.hpp:2481
This structure stores the low level information necessary to interpret the configuration of elements ...
Definition mesh.hpp:161
This structure is used as a human readable output format that deciphers the information contained in ...
Definition mesh.hpp:1894
ElementLocation location
Definition mesh.hpp:1899
bool IsNonconformingCoarse() const
Return true if the face is a nonconforming coarse face.
Definition mesh.hpp:1972
bool IsOfFaceType(FaceType type) const
Return true if the face is of the same type as type.
Definition mesh.hpp:1941
struct mfem::Mesh::FaceInformation::@13 element[2]
ElementConformity conformity
Definition mesh.hpp:1900
const DenseMatrix * point_matrix
Definition mesh.hpp:1908
Lists all edges/faces in the nonconforming mesh.
Definition ncmesh.hpp:230
Nonconforming edge/face within a bigger edge/face.
Definition ncmesh.hpp:216
static const int HighOrderMap[Geometry::NUM_GEOMETRIES]
Map from MFEM's Geometry::Type to arbitrary-order Lagrange VTK geometries.
Definition vtk.hpp:82
static const int QuadraticMap[Geometry::NUM_GEOMETRIES]
Map from MFEM's Geometry::Type to legacy quadratic VTK geometries/.
Definition vtk.hpp:80
static const int * VertexPermutation[Geometry::NUM_GEOMETRIES]
Permutation from MFEM's vertex ordering to VTK's vertex ordering.
Definition vtk.hpp:75
static const int Map[Geometry::NUM_GEOMETRIES]
Map from MFEM's Geometry::Type to linear VTK geometries.
Definition vtk.hpp:78