MFEM  v4.2.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
mesh.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 // Implementation of data type mesh
13 
14 #include "mesh_headers.hpp"
15 #include "../fem/fem.hpp"
16 #include "../general/sort_pairs.hpp"
17 #include "../general/binaryio.hpp"
18 #include "../general/text.hpp"
19 #include "../general/device.hpp"
20 #include "../general/tic_toc.hpp"
21 #include "../general/gecko.hpp"
22 #include "../fem/quadinterpolator.hpp"
23 
24 #include <iostream>
25 #include <sstream>
26 #include <fstream>
27 #include <limits>
28 #include <cmath>
29 #include <cstring>
30 #include <ctime>
31 #include <functional>
32 
33 // Include the METIS header, if using version 5. If using METIS 4, the needed
34 // declarations are inlined below, i.e. no header is needed.
35 #if defined(MFEM_USE_METIS) && defined(MFEM_USE_METIS_5)
36 #include "metis.h"
37 #endif
38 
39 // METIS 4 prototypes
40 #if defined(MFEM_USE_METIS) && !defined(MFEM_USE_METIS_5)
41 typedef int idx_t;
42 typedef int idxtype;
43 extern "C" {
45  int*, int*, int*, int*, int*, idxtype*);
47  int*, int*, int*, int*, int*, idxtype*);
49  int*, int*, int*, int*, int*, idxtype*);
50 }
51 #endif
52 
53 using namespace std;
54 
55 namespace mfem
56 {
57 
58 void Mesh::GetElementJacobian(int i, DenseMatrix &J)
59 {
60  Geometry::Type geom = GetElementBaseGeometry(i);
61  ElementTransformation *eltransf = GetElementTransformation(i);
62  eltransf->SetIntPoint(&Geometries.GetCenter(geom));
63  Geometries.JacToPerfJac(geom, eltransf->Jacobian(), J);
64 }
65 
66 void Mesh::GetElementCenter(int i, Vector &center)
67 {
68  center.SetSize(spaceDim);
69  int geom = GetElementBaseGeometry(i);
70  ElementTransformation *eltransf = GetElementTransformation(i);
71  eltransf->Transform(Geometries.GetCenter(geom), center);
72 }
73 
74 double Mesh::GetElementSize(int i, int type)
75 {
76  DenseMatrix J(Dim);
77  GetElementJacobian(i, J);
78  if (type == 0)
79  {
80  return pow(fabs(J.Det()), 1./Dim);
81  }
82  else if (type == 1)
83  {
84  return J.CalcSingularvalue(Dim-1); // h_min
85  }
86  else
87  {
88  return J.CalcSingularvalue(0); // h_max
89  }
90 }
91 
92 double Mesh::GetElementSize(int i, const Vector &dir)
93 {
94  DenseMatrix J(Dim);
95  Vector d_hat(Dim);
96  GetElementJacobian(i, J);
97  J.MultTranspose(dir, d_hat);
98  return sqrt((d_hat * d_hat) / (dir * dir));
99 }
100 
101 double Mesh::GetElementVolume(int i)
102 {
103  ElementTransformation *et = GetElementTransformation(i);
104  const IntegrationRule &ir = IntRules.Get(GetElementBaseGeometry(i),
105  et->OrderJ());
106  double volume = 0.0;
107  for (int j = 0; j < ir.GetNPoints(); j++)
108  {
109  const IntegrationPoint &ip = ir.IntPoint(j);
110  et->SetIntPoint(&ip);
111  volume += ip.weight * et->Weight();
112  }
113 
114  return volume;
115 }
116 
117 // Similar to VisualizationSceneSolution3d::FindNewBox in GLVis
118 void Mesh::GetBoundingBox(Vector &min, Vector &max, int ref)
119 {
120  min.SetSize(spaceDim);
121  max.SetSize(spaceDim);
122 
123  for (int d = 0; d < spaceDim; d++)
124  {
125  min(d) = infinity();
126  max(d) = -infinity();
127  }
128 
129  if (Nodes == NULL)
130  {
131  double *coord;
132  for (int i = 0; i < NumOfVertices; i++)
133  {
134  coord = GetVertex(i);
135  for (int d = 0; d < spaceDim; d++)
136  {
137  if (coord[d] < min(d)) { min(d) = coord[d]; }
138  if (coord[d] > max(d)) { max(d) = coord[d]; }
139  }
140  }
141  }
142  else
143  {
144  const bool use_boundary = false; // make this a parameter?
145  int ne = use_boundary ? GetNBE() : GetNE();
146  int fn, fo;
147  DenseMatrix pointmat;
148  RefinedGeometry *RefG;
149  IntegrationRule eir;
152 
153  for (int i = 0; i < ne; i++)
154  {
155  if (use_boundary)
156  {
157  GetBdrElementFace(i, &fn, &fo);
158  RefG = GlobGeometryRefiner.Refine(GetFaceBaseGeometry(fn), ref);
159  Tr = GetFaceElementTransformations(fn, 5);
160  eir.SetSize(RefG->RefPts.GetNPoints());
161  Tr->Loc1.Transform(RefG->RefPts, eir);
162  Tr->Elem1->Transform(eir, pointmat);
163  }
164  else
165  {
166  T = GetElementTransformation(i);
167  RefG = GlobGeometryRefiner.Refine(GetElementBaseGeometry(i), ref);
168  T->Transform(RefG->RefPts, pointmat);
169  }
170  for (int j = 0; j < pointmat.Width(); j++)
171  {
172  for (int d = 0; d < pointmat.Height(); d++)
173  {
174  if (pointmat(d,j) < min(d)) { min(d) = pointmat(d,j); }
175  if (pointmat(d,j) > max(d)) { max(d) = pointmat(d,j); }
176  }
177  }
178  }
179  }
180 }
181 
182 void Mesh::GetCharacteristics(double &h_min, double &h_max,
183  double &kappa_min, double &kappa_max,
184  Vector *Vh, Vector *Vk)
185 {
186  int i, dim, sdim;
187  DenseMatrix J;
188  double h, kappa;
189 
190  dim = Dimension();
191  sdim = SpaceDimension();
192 
193  if (Vh) { Vh->SetSize(NumOfElements); }
194  if (Vk) { Vk->SetSize(NumOfElements); }
195 
196  h_min = kappa_min = infinity();
197  h_max = kappa_max = -h_min;
198  if (dim == 0) { if (Vh) { *Vh = 1.0; } if (Vk) {*Vk = 1.0; } return; }
199  J.SetSize(sdim, dim);
200  for (i = 0; i < NumOfElements; i++)
201  {
202  GetElementJacobian(i, J);
203  h = pow(fabs(J.Weight()), 1.0/double(dim));
204  kappa = (dim == sdim) ?
205  J.CalcSingularvalue(0) / J.CalcSingularvalue(dim-1) : -1.0;
206  if (Vh) { (*Vh)(i) = h; }
207  if (Vk) { (*Vk)(i) = kappa; }
208 
209  if (h < h_min) { h_min = h; }
210  if (h > h_max) { h_max = h; }
211  if (kappa < kappa_min) { kappa_min = kappa; }
212  if (kappa > kappa_max) { kappa_max = kappa; }
213  }
214 }
215 
216 // static method
217 void Mesh::PrintElementsByGeometry(int dim,
218  const Array<int> &num_elems_by_geom,
219  std::ostream &out)
220 {
221  for (int g = Geometry::DimStart[dim], first = 1;
222  g < Geometry::DimStart[dim+1]; g++)
223  {
224  if (!num_elems_by_geom[g]) { continue; }
225  if (!first) { out << " + "; }
226  else { first = 0; }
227  out << num_elems_by_geom[g] << ' ' << Geometry::Name[g] << "(s)";
228  }
229 }
230 
231 void Mesh::PrintCharacteristics(Vector *Vh, Vector *Vk, std::ostream &out)
232 {
233  double h_min, h_max, kappa_min, kappa_max;
234 
235  out << "Mesh Characteristics:";
236 
237  this->GetCharacteristics(h_min, h_max, kappa_min, kappa_max, Vh, Vk);
238 
239  Array<int> num_elems_by_geom(Geometry::NumGeom);
240  num_elems_by_geom = 0;
241  for (int i = 0; i < GetNE(); i++)
242  {
243  num_elems_by_geom[GetElementBaseGeometry(i)]++;
244  }
245 
246  out << '\n'
247  << "Dimension : " << Dimension() << '\n'
248  << "Space dimension : " << SpaceDimension();
249  if (Dim == 0)
250  {
251  out << '\n'
252  << "Number of vertices : " << GetNV() << '\n'
253  << "Number of elements : " << GetNE() << '\n'
254  << "Number of bdr elem : " << GetNBE() << '\n';
255  }
256  else if (Dim == 1)
257  {
258  out << '\n'
259  << "Number of vertices : " << GetNV() << '\n'
260  << "Number of elements : " << GetNE() << '\n'
261  << "Number of bdr elem : " << GetNBE() << '\n'
262  << "h_min : " << h_min << '\n'
263  << "h_max : " << h_max << '\n';
264  }
265  else if (Dim == 2)
266  {
267  out << '\n'
268  << "Number of vertices : " << GetNV() << '\n'
269  << "Number of edges : " << GetNEdges() << '\n'
270  << "Number of elements : " << GetNE() << " -- ";
271  PrintElementsByGeometry(2, num_elems_by_geom, out);
272  out << '\n'
273  << "Number of bdr elem : " << GetNBE() << '\n'
274  << "Euler Number : " << EulerNumber2D() << '\n'
275  << "h_min : " << h_min << '\n'
276  << "h_max : " << h_max << '\n'
277  << "kappa_min : " << kappa_min << '\n'
278  << "kappa_max : " << kappa_max << '\n';
279  }
280  else
281  {
282  Array<int> num_bdr_elems_by_geom(Geometry::NumGeom);
283  num_bdr_elems_by_geom = 0;
284  for (int i = 0; i < GetNBE(); i++)
285  {
286  num_bdr_elems_by_geom[GetBdrElementBaseGeometry(i)]++;
287  }
288  Array<int> num_faces_by_geom(Geometry::NumGeom);
289  num_faces_by_geom = 0;
290  for (int i = 0; i < GetNFaces(); i++)
291  {
292  num_faces_by_geom[GetFaceBaseGeometry(i)]++;
293  }
294 
295  out << '\n'
296  << "Number of vertices : " << GetNV() << '\n'
297  << "Number of edges : " << GetNEdges() << '\n'
298  << "Number of faces : " << GetNFaces() << " -- ";
299  PrintElementsByGeometry(Dim-1, num_faces_by_geom, out);
300  out << '\n'
301  << "Number of elements : " << GetNE() << " -- ";
302  PrintElementsByGeometry(Dim, num_elems_by_geom, out);
303  out << '\n'
304  << "Number of bdr elem : " << GetNBE() << " -- ";
305  PrintElementsByGeometry(Dim-1, num_bdr_elems_by_geom, out);
306  out << '\n'
307  << "Euler Number : " << EulerNumber() << '\n'
308  << "h_min : " << h_min << '\n'
309  << "h_max : " << h_max << '\n'
310  << "kappa_min : " << kappa_min << '\n'
311  << "kappa_max : " << kappa_max << '\n';
312  }
313  out << '\n' << std::flush;
314 }
315 
316 FiniteElement *Mesh::GetTransformationFEforElementType(Element::Type ElemType)
317 {
318  switch (ElemType)
319  {
320  case Element::POINT : return &PointFE;
321  case Element::SEGMENT : return &SegmentFE;
322  case Element::TRIANGLE : return &TriangleFE;
323  case Element::QUADRILATERAL : return &QuadrilateralFE;
324  case Element::TETRAHEDRON : return &TetrahedronFE;
325  case Element::HEXAHEDRON : return &HexahedronFE;
326  case Element::WEDGE : return &WedgeFE;
327  default:
328  MFEM_ABORT("Unknown element type \"" << ElemType << "\"");
329  break;
330  }
331  MFEM_ABORT("Unknown element type");
332  return NULL;
333 }
334 
335 
336 void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr)
337 {
338  ElTr->Attribute = GetAttribute(i);
339  ElTr->ElementNo = i;
340  ElTr->ElementType = ElementTransformation::ELEMENT;
341  ElTr->Reset();
342  if (Nodes == NULL)
343  {
344  GetPointMatrix(i, ElTr->GetPointMat());
345  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
346  }
347  else
348  {
349  DenseMatrix &pm = ElTr->GetPointMat();
350  Array<int> vdofs;
351  Nodes->FESpace()->GetElementVDofs(i, vdofs);
352  Nodes->HostRead();
353  const GridFunction &nodes = *Nodes;
354  int n = vdofs.Size()/spaceDim;
355  pm.SetSize(spaceDim, n);
356  for (int k = 0; k < spaceDim; k++)
357  {
358  for (int j = 0; j < n; j++)
359  {
360  pm(k,j) = nodes(vdofs[n*k+j]);
361  }
362  }
363  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
364  }
365 }
366 
367 void Mesh::GetElementTransformation(int i, const Vector &nodes,
369 {
370  ElTr->Attribute = GetAttribute(i);
371  ElTr->ElementNo = i;
372  ElTr->ElementType = ElementTransformation::ELEMENT;
373  DenseMatrix &pm = ElTr->GetPointMat();
374  ElTr->Reset();
375  nodes.HostRead();
376  if (Nodes == NULL)
377  {
378  MFEM_ASSERT(nodes.Size() == spaceDim*GetNV(), "");
379  int nv = elements[i]->GetNVertices();
380  const int *v = elements[i]->GetVertices();
381  int n = vertices.Size();
382  pm.SetSize(spaceDim, nv);
383  for (int k = 0; k < spaceDim; k++)
384  {
385  for (int j = 0; j < nv; j++)
386  {
387  pm(k, j) = nodes(k*n+v[j]);
388  }
389  }
390  ElTr->SetFE(GetTransformationFEforElementType(GetElementType(i)));
391  }
392  else
393  {
394  MFEM_ASSERT(nodes.Size() == Nodes->Size(), "");
395  Array<int> vdofs;
396  Nodes->FESpace()->GetElementVDofs(i, vdofs);
397  int n = vdofs.Size()/spaceDim;
398  pm.SetSize(spaceDim, n);
399  for (int k = 0; k < spaceDim; k++)
400  {
401  for (int j = 0; j < n; j++)
402  {
403  pm(k,j) = nodes(vdofs[n*k+j]);
404  }
405  }
406  ElTr->SetFE(Nodes->FESpace()->GetFE(i));
407  }
408 }
409 
410 ElementTransformation *Mesh::GetElementTransformation(int i)
411 {
412  GetElementTransformation(i, &Transformation);
413 
414  return &Transformation;
415 }
416 
417 ElementTransformation *Mesh::GetBdrElementTransformation(int i)
418 {
419  GetBdrElementTransformation(i, &BdrTransformation);
420  return &BdrTransformation;
421 }
422 
423 void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr)
424 {
425  ElTr->Attribute = GetBdrAttribute(i);
426  ElTr->ElementNo = i; // boundary element number
427  ElTr->ElementType = ElementTransformation::BDR_ELEMENT;
428  DenseMatrix &pm = ElTr->GetPointMat();
429  ElTr->Reset();
430  if (Nodes == NULL)
431  {
432  GetBdrPointMatrix(i, pm);
433  ElTr->SetFE(GetTransformationFEforElementType(GetBdrElementType(i)));
434  }
435  else
436  {
437  const FiniteElement *bdr_el = Nodes->FESpace()->GetBE(i);
438  Nodes->HostRead();
439  const GridFunction &nodes = *Nodes;
440  if (bdr_el)
441  {
442  Array<int> vdofs;
443  Nodes->FESpace()->GetBdrElementVDofs(i, vdofs);
444  int n = vdofs.Size()/spaceDim;
445  pm.SetSize(spaceDim, n);
446  for (int k = 0; k < spaceDim; k++)
447  {
448  for (int j = 0; j < n; j++)
449  {
450  pm(k,j) = nodes(vdofs[n*k+j]);
451  }
452  }
453  ElTr->SetFE(bdr_el);
454  }
455  else // L2 Nodes (e.g., periodic mesh)
456  {
457  int elem_id, face_info;
458  GetBdrElementAdjacentElement(i, elem_id, face_info);
459 
460  GetLocalFaceTransformation(GetBdrElementType(i),
461  GetElementType(elem_id),
462  FaceElemTr.Loc1.Transf, face_info);
463  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
464 
465  const FiniteElement *face_el =
466  Nodes->FESpace()->GetTraceElement(elem_id,
467  GetBdrElementBaseGeometry(i));
468 
469  IntegrationRule eir(face_el->GetDof());
470  FaceElemTr.Loc1.Transf.ElementNo = elem_id;
471  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
472  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
473  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
474 
475  ElTr->SetFE(face_el);
476  }
477  }
478 }
479 
480 void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr)
481 {
482  FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute();
483  FTr->ElementNo = FaceNo;
484  FTr->ElementType = ElementTransformation::FACE;
485  DenseMatrix &pm = FTr->GetPointMat();
486  FTr->Reset();
487  if (Nodes == NULL)
488  {
489  const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
490  const int nv = (Dim == 1) ? 1 : faces[FaceNo]->GetNVertices();
491  pm.SetSize(spaceDim, nv);
492  for (int i = 0; i < spaceDim; i++)
493  {
494  for (int j = 0; j < nv; j++)
495  {
496  pm(i, j) = vertices[v[j]](i);
497  }
498  }
499  FTr->SetFE(GetTransformationFEforElementType(GetFaceElementType(FaceNo)));
500  }
501  else // curved mesh
502  {
503  const FiniteElement *face_el = Nodes->FESpace()->GetFaceElement(FaceNo);
504  Nodes->HostRead();
505  const GridFunction &nodes = *Nodes;
506  if (face_el)
507  {
508  Array<int> vdofs;
509  Nodes->FESpace()->GetFaceVDofs(FaceNo, vdofs);
510  int n = vdofs.Size()/spaceDim;
511  pm.SetSize(spaceDim, n);
512  for (int i = 0; i < spaceDim; i++)
513  {
514  for (int j = 0; j < n; j++)
515  {
516  pm(i, j) = nodes(vdofs[n*i+j]);
517  }
518  }
519  FTr->SetFE(face_el);
520  }
521  else // L2 Nodes (e.g., periodic mesh), go through the volume of Elem1
522  {
523  FaceInfo &face_info = faces_info[FaceNo];
524 
525  Geometry::Type face_geom = GetFaceGeometryType(FaceNo);
526  Element::Type face_type = GetFaceElementType(FaceNo);
527 
528  GetLocalFaceTransformation(face_type,
529  GetElementType(face_info.Elem1No),
530  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
531  // NOTE: FaceElemTr.Loc1 is overwritten here -- used as a temporary
532 
533  face_el = Nodes->FESpace()->GetTraceElement(face_info.Elem1No,
534  face_geom);
535 
536  IntegrationRule eir(face_el->GetDof());
537  FaceElemTr.Loc1.Transf.ElementNo = face_info.Elem1No;
538  FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
539  FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
540  Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
541 
542  FTr->SetFE(face_el);
543  }
544  }
545 }
546 
547 ElementTransformation *Mesh::GetFaceTransformation(int FaceNo)
548 {
549  GetFaceTransformation(FaceNo, &FaceTransformation);
550  return &FaceTransformation;
551 }
552 
553 void Mesh::GetEdgeTransformation(int EdgeNo, IsoparametricTransformation *EdTr)
554 {
555  if (Dim == 2)
556  {
557  GetFaceTransformation(EdgeNo, EdTr);
558  return;
559  }
560  if (Dim == 1)
561  {
562  mfem_error("Mesh::GetEdgeTransformation not defined in 1D \n");
563  }
564 
565  EdTr->Attribute = 1;
566  EdTr->ElementNo = EdgeNo;
567  EdTr->ElementType = ElementTransformation::EDGE;
568  DenseMatrix &pm = EdTr->GetPointMat();
569  EdTr->Reset();
570  if (Nodes == NULL)
571  {
572  Array<int> v;
573  GetEdgeVertices(EdgeNo, v);
574  const int nv = 2;
575  pm.SetSize(spaceDim, nv);
576  for (int i = 0; i < spaceDim; i++)
577  {
578  for (int j = 0; j < nv; j++)
579  {
580  pm(i, j) = vertices[v[j]](i);
581  }
582  }
583  EdTr->SetFE(GetTransformationFEforElementType(Element::SEGMENT));
584  }
585  else
586  {
587  const FiniteElement *edge_el = Nodes->FESpace()->GetEdgeElement(EdgeNo);
588  if (edge_el)
589  {
590  Array<int> vdofs;
591  Nodes->FESpace()->GetEdgeVDofs(EdgeNo, vdofs);
592  int n = vdofs.Size()/spaceDim;
593  pm.SetSize(spaceDim, n);
594  for (int i = 0; i < spaceDim; i++)
595  {
596  for (int j = 0; j < n; j++)
597  {
598  pm(i, j) = (*Nodes)(vdofs[n*i+j]);
599  }
600  }
601  EdTr->SetFE(edge_el);
602  }
603  else
604  {
605  MFEM_ABORT("Not implemented.");
606  }
607  }
608 }
609 
610 ElementTransformation *Mesh::GetEdgeTransformation(int EdgeNo)
611 {
612  GetEdgeTransformation(EdgeNo, &EdgeTransformation);
613  return &EdgeTransformation;
614 }
615 
616 
617 void Mesh::GetLocalPtToSegTransformation(
618  IsoparametricTransformation &Transf, int i)
619 {
620  const IntegrationRule *SegVert;
621  DenseMatrix &locpm = Transf.GetPointMat();
622  Transf.Reset();
623 
624  Transf.SetFE(&PointFE);
625  SegVert = Geometries.GetVertices(Geometry::SEGMENT);
626  locpm.SetSize(1, 1);
627  locpm(0, 0) = SegVert->IntPoint(i/64).x;
628  // (i/64) is the local face no. in the segment
629  // (i%64) is the orientation of the point (not used)
630 }
631 
632 void Mesh::GetLocalSegToTriTransformation(
633  IsoparametricTransformation &Transf, int i)
634 {
635  const int *tv, *so;
636  const IntegrationRule *TriVert;
637  DenseMatrix &locpm = Transf.GetPointMat();
638  Transf.Reset();
639 
640  Transf.SetFE(&SegmentFE);
641  tv = tri_t::Edges[i/64]; // (i/64) is the local face no. in the triangle
642  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
643  TriVert = Geometries.GetVertices(Geometry::TRIANGLE);
644  locpm.SetSize(2, 2);
645  for (int j = 0; j < 2; j++)
646  {
647  locpm(0, so[j]) = TriVert->IntPoint(tv[j]).x;
648  locpm(1, so[j]) = TriVert->IntPoint(tv[j]).y;
649  }
650 }
651 
652 void Mesh::GetLocalSegToQuadTransformation(
653  IsoparametricTransformation &Transf, int i)
654 {
655  const int *qv, *so;
656  const IntegrationRule *QuadVert;
657  DenseMatrix &locpm = Transf.GetPointMat();
658  Transf.Reset();
659 
660  Transf.SetFE(&SegmentFE);
661  qv = quad_t::Edges[i/64]; // (i/64) is the local face no. in the quad
662  so = seg_t::Orient[i%64]; // (i%64) is the orientation of the segment
663  QuadVert = Geometries.GetVertices(Geometry::SQUARE);
664  locpm.SetSize(2, 2);
665  for (int j = 0; j < 2; j++)
666  {
667  locpm(0, so[j]) = QuadVert->IntPoint(qv[j]).x;
668  locpm(1, so[j]) = QuadVert->IntPoint(qv[j]).y;
669  }
670 }
671 
672 void Mesh::GetLocalTriToTetTransformation(
673  IsoparametricTransformation &Transf, int i)
674 {
675  DenseMatrix &locpm = Transf.GetPointMat();
676  Transf.Reset();
677 
678  Transf.SetFE(&TriangleFE);
679  // (i/64) is the local face no. in the tet
680  const int *tv = tet_t::FaceVert[i/64];
681  // (i%64) is the orientation of the tetrahedron face
682  // w.r.t. the face element
683  const int *to = tri_t::Orient[i%64];
684  const IntegrationRule *TetVert =
685  Geometries.GetVertices(Geometry::TETRAHEDRON);
686  locpm.SetSize(3, 3);
687  for (int j = 0; j < 3; j++)
688  {
689  const IntegrationPoint &vert = TetVert->IntPoint(tv[to[j]]);
690  locpm(0, j) = vert.x;
691  locpm(1, j) = vert.y;
692  locpm(2, j) = vert.z;
693  }
694 }
695 
696 void Mesh::GetLocalTriToWdgTransformation(
697  IsoparametricTransformation &Transf, int i)
698 {
699  DenseMatrix &locpm = Transf.GetPointMat();
700  Transf.Reset();
701 
702  Transf.SetFE(&TriangleFE);
703  // (i/64) is the local face no. in the pri
704  MFEM_VERIFY(i < 128, "Local face index " << i/64
705  << " is not a triangular face of a wedge.");
706  const int *pv = pri_t::FaceVert[i/64];
707  // (i%64) is the orientation of the wedge face
708  // w.r.t. the face element
709  const int *to = tri_t::Orient[i%64];
710  const IntegrationRule *PriVert =
711  Geometries.GetVertices(Geometry::PRISM);
712  locpm.SetSize(3, 3);
713  for (int j = 0; j < 3; j++)
714  {
715  const IntegrationPoint &vert = PriVert->IntPoint(pv[to[j]]);
716  locpm(0, j) = vert.x;
717  locpm(1, j) = vert.y;
718  locpm(2, j) = vert.z;
719  }
720 }
721 
722 void Mesh::GetLocalQuadToHexTransformation(
723  IsoparametricTransformation &Transf, int i)
724 {
725  DenseMatrix &locpm = Transf.GetPointMat();
726  Transf.Reset();
727 
728  Transf.SetFE(&QuadrilateralFE);
729  // (i/64) is the local face no. in the hex
730  const int *hv = hex_t::FaceVert[i/64];
731  // (i%64) is the orientation of the quad
732  const int *qo = quad_t::Orient[i%64];
733  const IntegrationRule *HexVert = Geometries.GetVertices(Geometry::CUBE);
734  locpm.SetSize(3, 4);
735  for (int j = 0; j < 4; j++)
736  {
737  const IntegrationPoint &vert = HexVert->IntPoint(hv[qo[j]]);
738  locpm(0, j) = vert.x;
739  locpm(1, j) = vert.y;
740  locpm(2, j) = vert.z;
741  }
742 }
743 
744 void Mesh::GetLocalQuadToWdgTransformation(
745  IsoparametricTransformation &Transf, int i)
746 {
747  DenseMatrix &locpm = Transf.GetPointMat();
748  Transf.Reset();
749 
750  Transf.SetFE(&QuadrilateralFE);
751  // (i/64) is the local face no. in the pri
752  MFEM_VERIFY(i >= 128, "Local face index " << i/64
753  << " is not a quadrilateral face of a wedge.");
754  const int *pv = pri_t::FaceVert[i/64];
755  // (i%64) is the orientation of the quad
756  const int *qo = quad_t::Orient[i%64];
757  const IntegrationRule *PriVert = Geometries.GetVertices(Geometry::PRISM);
758  locpm.SetSize(3, 4);
759  for (int j = 0; j < 4; j++)
760  {
761  const IntegrationPoint &vert = PriVert->IntPoint(pv[qo[j]]);
762  locpm(0, j) = vert.x;
763  locpm(1, j) = vert.y;
764  locpm(2, j) = vert.z;
765  }
766 }
767 
768 const GeometricFactors* Mesh::GetGeometricFactors(const IntegrationRule& ir,
769  const int flags)
770 {
771  for (int i = 0; i < geom_factors.Size(); i++)
772  {
773  GeometricFactors *gf = geom_factors[i];
774  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags)
775  {
776  return gf;
777  }
778  }
779 
780  this->EnsureNodes();
781 
782  GeometricFactors *gf = new GeometricFactors(this, ir, flags);
783  geom_factors.Append(gf);
784  return gf;
785 }
786 
787 const FaceGeometricFactors* Mesh::GetFaceGeometricFactors(
788  const IntegrationRule& ir,
789  const int flags, FaceType type)
790 {
791  for (int i = 0; i < face_geom_factors.Size(); i++)
792  {
793  FaceGeometricFactors *gf = face_geom_factors[i];
794  if (gf->IntRule == &ir && (gf->computed_factors & flags) == flags &&
795  gf->type==type)
796  {
797  return gf;
798  }
799  }
800 
801  this->EnsureNodes();
802 
803  FaceGeometricFactors *gf = new FaceGeometricFactors(this, ir, flags, type);
804  face_geom_factors.Append(gf);
805  return gf;
806 }
807 
808 void Mesh::DeleteGeometricFactors()
809 {
810  for (int i = 0; i < geom_factors.Size(); i++)
811  {
812  delete geom_factors[i];
813  }
814  geom_factors.SetSize(0);
815  for (int i = 0; i < face_geom_factors.Size(); i++)
816  {
817  delete face_geom_factors[i];
818  }
819  face_geom_factors.SetSize(0);
820 }
821 
822 void Mesh::GetLocalFaceTransformation(
823  int face_type, int elem_type, IsoparametricTransformation &Transf, int info)
824 {
825  switch (face_type)
826  {
827  case Element::POINT:
828  GetLocalPtToSegTransformation(Transf, info);
829  break;
830 
831  case Element::SEGMENT:
832  if (elem_type == Element::TRIANGLE)
833  {
834  GetLocalSegToTriTransformation(Transf, info);
835  }
836  else
837  {
838  MFEM_ASSERT(elem_type == Element::QUADRILATERAL, "");
839  GetLocalSegToQuadTransformation(Transf, info);
840  }
841  break;
842 
843  case Element::TRIANGLE:
844  if (elem_type == Element::TETRAHEDRON)
845  {
846  GetLocalTriToTetTransformation(Transf, info);
847  }
848  else
849  {
850  MFEM_ASSERT(elem_type == Element::WEDGE, "");
851  GetLocalTriToWdgTransformation(Transf, info);
852  }
853  break;
854 
855  case Element::QUADRILATERAL:
856  if (elem_type == Element::HEXAHEDRON)
857  {
858  GetLocalQuadToHexTransformation(Transf, info);
859  }
860  else
861  {
862  MFEM_ASSERT(elem_type == Element::WEDGE, "");
863  GetLocalQuadToWdgTransformation(Transf, info);
864  }
865  break;
866  }
867 }
868 
869 FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo,
870  int mask)
871 {
872  FaceInfo &face_info = faces_info[FaceNo];
873 
874  int cmask = 0;
875  FaceElemTr.SetConfigurationMask(cmask);
876  FaceElemTr.Elem1 = NULL;
877  FaceElemTr.Elem2 = NULL;
878 
879  // setup the transformation for the first element
880  FaceElemTr.Elem1No = face_info.Elem1No;
881  if (mask & FaceElementTransformations::HAVE_ELEM1)
882  {
883  GetElementTransformation(FaceElemTr.Elem1No, &Transformation);
884  FaceElemTr.Elem1 = &Transformation;
885  cmask |= 1;
886  }
887 
888  // setup the transformation for the second element
889  // return NULL in the Elem2 field if there's no second element, i.e.
890  // the face is on the "boundary"
891  FaceElemTr.Elem2No = face_info.Elem2No;
892  if ((mask & FaceElementTransformations::HAVE_ELEM2) &&
893  FaceElemTr.Elem2No >= 0)
894  {
895 #ifdef MFEM_DEBUG
896  if (NURBSext && (mask & FaceElementTransformations::HAVE_ELEM1))
897  { MFEM_ABORT("NURBS mesh not supported!"); }
898 #endif
899  GetElementTransformation(FaceElemTr.Elem2No, &Transformation2);
900  FaceElemTr.Elem2 = &Transformation2;
901  cmask |= 2;
902  }
903 
904  // setup the face transformation
905  if (mask & FaceElementTransformations::HAVE_FACE)
906  {
907  GetFaceTransformation(FaceNo, &FaceElemTr);
908  cmask |= 16;
909  }
910  else
911  {
912  FaceElemTr.SetGeometryType(GetFaceGeometryType(FaceNo));
913  }
914 
915  // setup Loc1 & Loc2
916  int face_type = GetFaceElementType(FaceNo);
917  if (mask & FaceElementTransformations::HAVE_LOC1)
918  {
919  int elem_type = GetElementType(face_info.Elem1No);
920  GetLocalFaceTransformation(face_type, elem_type,
921  FaceElemTr.Loc1.Transf, face_info.Elem1Inf);
922  cmask |= 4;
923  }
924  if ((mask & FaceElementTransformations::HAVE_LOC2) &&
925  FaceElemTr.Elem2No >= 0)
926  {
927  int elem_type = GetElementType(face_info.Elem2No);
928  GetLocalFaceTransformation(face_type, elem_type,
929  FaceElemTr.Loc2.Transf, face_info.Elem2Inf);
930 
931  // NC meshes: prepend slave edge/face transformation to Loc2
932  if (Nonconforming() && IsSlaveFace(face_info))
933  {
934  ApplyLocalSlaveTransformation(FaceElemTr, face_info, false);
935  }
936  cmask |= 8;
937  }
938 
939  FaceElemTr.SetConfigurationMask(cmask);
940 
941  // This check can be useful for internal debugging, however it will fail on
942  // periodic boundary faces, so we keep it disabled in general.
943 #if 0
944 #ifdef MFEM_DEBUG
945  double dist = FaceElemTr.CheckConsistency();
946  if (dist >= 1e-12)
947  {
948  mfem::out << "\nInternal error: face id = " << FaceNo
949  << ", dist = " << dist << '\n';
950  FaceElemTr.CheckConsistency(1); // print coordinates
951  MFEM_ABORT("internal error");
952  }
953 #endif
954 #endif
955 
956  return &FaceElemTr;
957 }
958 
959 bool Mesh::IsSlaveFace(const FaceInfo &fi) const
960 {
961  return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
962 }
963 
964 void Mesh::ApplyLocalSlaveTransformation(FaceElementTransformations &FT,
965  const FaceInfo &fi, bool is_ghost)
966 {
967 #ifdef MFEM_THREAD_SAFE
968  DenseMatrix composition;
969 #else
970  static DenseMatrix composition;
971 #endif
972  MFEM_ASSERT(fi.NCFace >= 0, "");
973  MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error");
974  if (!is_ghost)
975  {
976  // side 1 -> child side, side 2 -> parent side
978  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
979  // In 2D, we need to flip the point matrix since it is aligned with the
980  // parent side.
981  if (Dim == 2)
982  {
983  // swap points (columns) 0 and 1
984  std::swap(composition(0,0), composition(0,1));
985  std::swap(composition(1,0), composition(1,1));
986  }
987  LT.SetPointMat(composition);
988  }
989  else // is_ghost == true
990  {
991  // side 1 -> parent side, side 2 -> child side
993  LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
994  // In 2D, there is no need to flip the point matrix since it is already
995  // aligned with the parent side, see also ParNCMesh::GetFaceNeighbors.
996  // In 3D the point matrix was flipped during construction in
997  // ParNCMesh::GetFaceNeighbors and due to that it is already aligned with
998  // the parent side.
999  LT.SetPointMat(composition);
1000  }
1001 }
1002 
1003 FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
1004 {
1006  int fn;
1007  if (Dim == 3)
1008  {
1009  fn = be_to_face[BdrElemNo];
1010  }
1011  else if (Dim == 2)
1012  {
1013  fn = be_to_edge[BdrElemNo];
1014  }
1015  else
1016  {
1017  fn = boundary[BdrElemNo]->GetVertices()[0];
1018  }
1019  // Check if the face is interior, shared, or non-conforming.
1020  if (FaceIsTrueInterior(fn) || faces_info[fn].NCFace >= 0)
1021  {
1022  return NULL;
1023  }
1024  tr = GetFaceElementTransformations(fn, 21);
1025  tr->Attribute = boundary[BdrElemNo]->GetAttribute();
1026  tr->ElementNo = BdrElemNo;
1027  tr->ElementType = ElementTransformation::BDR_FACE;
1028  return tr;
1029 }
1030 
1031 void Mesh::GetFaceElements(int Face, int *Elem1, int *Elem2) const
1032 {
1033  *Elem1 = faces_info[Face].Elem1No;
1034  *Elem2 = faces_info[Face].Elem2No;
1035 }
1036 
1037 void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const
1038 {
1039  *Inf1 = faces_info[Face].Elem1Inf;
1040  *Inf2 = faces_info[Face].Elem2Inf;
1041 }
1042 
1043 Geometry::Type Mesh::GetFaceGeometryType(int Face) const
1044 {
1045  switch (Dim)
1046  {
1047  case 1: return Geometry::POINT;
1048  case 2: return Geometry::SEGMENT;
1049  case 3:
1050  if (Face < NumOfFaces) // local (non-ghost) face
1051  {
1052  return faces[Face]->GetGeometryType();
1053  }
1054  // ghost face
1055  const int nc_face_id = faces_info[Face].NCFace;
1056  MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported");
1057  return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType();
1058  }
1059  return Geometry::INVALID;
1060 }
1061 
1062 Element::Type Mesh::GetFaceElementType(int Face) const
1063 {
1064  return (Dim == 1) ? Element::POINT : faces[Face]->GetType();
1065 }
1066 
1067 void Mesh::Init()
1068 {
1069  // in order of declaration:
1070  Dim = spaceDim = 0;
1071  NumOfVertices = -1;
1072  NumOfElements = NumOfBdrElements = 0;
1073  NumOfEdges = NumOfFaces = 0;
1074  nbInteriorFaces = -1;
1075  nbBoundaryFaces = -1;
1076  meshgen = mesh_geoms = 0;
1077  sequence = 0;
1078  Nodes = NULL;
1079  own_nodes = 1;
1080  NURBSext = NULL;
1081  ncmesh = NULL;
1082  last_operation = Mesh::NONE;
1083 }
1084 
1085 void Mesh::InitTables()
1086 {
1087  el_to_edge =
1088  el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
1089 }
1090 
1091 void Mesh::SetEmpty()
1092 {
1093  Init();
1094  InitTables();
1095 }
1096 
1097 void Mesh::DestroyTables()
1098 {
1099  delete el_to_edge;
1100  delete el_to_face;
1101  delete el_to_el;
1102  DeleteGeometricFactors();
1103 
1104  if (Dim == 3)
1105  {
1106  delete bel_to_edge;
1107  }
1108 
1109  delete face_edge;
1110  delete edge_vertex;
1111 }
1112 
1113 void Mesh::DestroyPointers()
1114 {
1115  if (own_nodes) { delete Nodes; }
1116 
1117  delete ncmesh;
1118 
1119  delete NURBSext;
1120 
1121  for (int i = 0; i < NumOfElements; i++)
1122  {
1123  FreeElement(elements[i]);
1124  }
1125 
1126  for (int i = 0; i < NumOfBdrElements; i++)
1127  {
1128  FreeElement(boundary[i]);
1129  }
1130 
1131  for (int i = 0; i < faces.Size(); i++)
1132  {
1133  FreeElement(faces[i]);
1134  }
1135 
1136  DestroyTables();
1137 }
1138 
1139 void Mesh::Destroy()
1140 {
1141  DestroyPointers();
1142 
1143  elements.DeleteAll();
1144  vertices.DeleteAll();
1145  boundary.DeleteAll();
1146  faces.DeleteAll();
1147  faces_info.DeleteAll();
1148  nc_faces_info.DeleteAll();
1149  be_to_edge.DeleteAll();
1150  be_to_face.DeleteAll();
1151 
1152  // TODO:
1153  // IsoparametricTransformations
1154  // Transformation, Transformation2, BdrTransformation, FaceTransformation,
1155  // EdgeTransformation;
1156  // FaceElementTransformations FaceElemTr;
1157 
1158  CoarseFineTr.Clear();
1159 
1160 #ifdef MFEM_USE_MEMALLOC
1161  TetMemory.Clear();
1162 #endif
1163 
1164  attributes.DeleteAll();
1165  bdr_attributes.DeleteAll();
1166 }
1167 
1168 void Mesh::ResetLazyData()
1169 {
1170  delete el_to_el; el_to_el = NULL;
1171  delete face_edge; face_edge = NULL;
1172  delete edge_vertex; edge_vertex = NULL;
1173  DeleteGeometricFactors();
1174  nbInteriorFaces = -1;
1175  nbBoundaryFaces = -1;
1176 }
1177 
1178 void Mesh::SetAttributes()
1179 {
1180  Array<int> attribs;
1181 
1182  attribs.SetSize(GetNBE());
1183  for (int i = 0; i < attribs.Size(); i++)
1184  {
1185  attribs[i] = GetBdrAttribute(i);
1186  }
1187  attribs.Sort();
1188  attribs.Unique();
1189  attribs.Copy(bdr_attributes);
1190  if (bdr_attributes.Size() > 0 && bdr_attributes[0] <= 0)
1191  {
1192  MFEM_WARNING("Non-positive attributes on the boundary!");
1193  }
1194 
1195  attribs.SetSize(GetNE());
1196  for (int i = 0; i < attribs.Size(); i++)
1197  {
1198  attribs[i] = GetAttribute(i);
1199  }
1200  attribs.Sort();
1201  attribs.Unique();
1202  attribs.Copy(attributes);
1203  if (attributes.Size() > 0 && attributes[0] <= 0)
1204  {
1205  MFEM_WARNING("Non-positive attributes in the domain!");
1206  }
1207 }
1208 
1209 void Mesh::InitMesh(int _Dim, int _spaceDim, int NVert, int NElem, int NBdrElem)
1210 {
1211  SetEmpty();
1212 
1213  Dim = _Dim;
1214  spaceDim = _spaceDim;
1215 
1216  NumOfVertices = 0;
1217  vertices.SetSize(NVert); // just allocate space for vertices
1218 
1219  NumOfElements = 0;
1220  elements.SetSize(NElem); // just allocate space for Element *
1221 
1222  NumOfBdrElements = 0;
1223  boundary.SetSize(NBdrElem); // just allocate space for Element *
1224 }
1225 
1226 template<typename T>
1227 static void CheckEnlarge(Array<T> &array, int size)
1228 {
1229  if (size >= array.Size()) { array.SetSize(size + 1); }
1230 }
1231 
1232 int Mesh::AddVertex(double x, double y, double z)
1233 {
1234  CheckEnlarge(vertices, NumOfVertices);
1235  double *v = vertices[NumOfVertices]();
1236  v[0] = x;
1237  v[1] = y;
1238  v[2] = z;
1239  return NumOfVertices++;
1240 }
1241 
1242 int Mesh::AddVertex(const double *coords)
1243 {
1244  CheckEnlarge(vertices, NumOfVertices);
1245  vertices[NumOfVertices].SetCoords(spaceDim, coords);
1246  return NumOfVertices++;
1247 }
1248 
1249 void Mesh::AddVertexParents(int i, int p1, int p2)
1250 {
1251  tmp_vertex_parents.Append(Triple<int, int, int>(i, p1, p2));
1252 
1253  // if vertex coordinates are defined, make sure the hanging vertex has the
1254  // correct position
1255  if (i < vertices.Size())
1256  {
1257  double *vi = vertices[i](), *vp1 = vertices[p1](), *vp2 = vertices[p2]();
1258  for (int j = 0; j < 3; j++)
1259  {
1260  vi[j] = (vp1[j] + vp2[j]) * 0.5;
1261  }
1262  }
1263 }
1264 
1265 int Mesh::AddSegment(int v1, int v2, int attr)
1266 {
1267  CheckEnlarge(elements, NumOfElements);
1268  elements[NumOfElements] = new Segment(v1, v2, attr);
1269  return NumOfElements++;
1270 }
1271 
1272 int Mesh::AddSegment(const int *vi, int attr)
1273 {
1274  CheckEnlarge(elements, NumOfElements);
1275  elements[NumOfElements] = new Segment(vi, attr);
1276  return NumOfElements++;
1277 }
1278 
1279 int Mesh::AddTriangle(int v1, int v2, int v3, int attr)
1280 {
1281  CheckEnlarge(elements, NumOfElements);
1282  elements[NumOfElements] = new Triangle(v1, v2, v3, attr);
1283  return NumOfElements++;
1284 }
1285 
1286 int Mesh::AddTriangle(const int *vi, int attr)
1287 {
1288  CheckEnlarge(elements, NumOfElements);
1289  elements[NumOfElements] = new Triangle(vi, attr);
1290  return NumOfElements++;
1291 }
1292 
1293 int Mesh::AddQuad(int v1, int v2, int v3, int v4, int attr)
1294 {
1295  CheckEnlarge(elements, NumOfElements);
1296  elements[NumOfElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1297  return NumOfElements++;
1298 }
1299 
1300 int Mesh::AddQuad(const int *vi, int attr)
1301 {
1302  CheckEnlarge(elements, NumOfElements);
1303  elements[NumOfElements] = new Quadrilateral(vi, attr);
1304  return NumOfElements++;
1305 }
1306 
1307 int Mesh::AddTet(int v1, int v2, int v3, int v4, int attr)
1308 {
1309  int vi[4] = {v1, v2, v3, v4};
1310  return AddTet(vi, attr);
1311 }
1312 
1313 int Mesh::AddTet(const int *vi, int attr)
1314 {
1315  CheckEnlarge(elements, NumOfElements);
1316 #ifdef MFEM_USE_MEMALLOC
1317  Tetrahedron *tet;
1318  tet = TetMemory.Alloc();
1319  tet->SetVertices(vi);
1320  tet->SetAttribute(attr);
1321  elements[NumOfElements] = tet;
1322 #else
1323  elements[NumOfElements] = new Tetrahedron(vi, attr);
1324 #endif
1325  return NumOfElements++;
1326 }
1327 
1328 int Mesh::AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr)
1329 {
1330  CheckEnlarge(elements, NumOfElements);
1331  elements[NumOfElements] = new Wedge(v1, v2, v3, v4, v5, v6, attr);
1332  return NumOfElements++;
1333 }
1334 
1335 int Mesh::AddWedge(const int *vi, int attr)
1336 {
1337  CheckEnlarge(elements, NumOfElements);
1338  elements[NumOfElements] = new Wedge(vi, attr);
1339  return NumOfElements++;
1340 }
1341 
1342 int Mesh::AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8,
1343  int attr)
1344 {
1345  CheckEnlarge(elements, NumOfElements);
1346  elements[NumOfElements] =
1347  new Hexahedron(v1, v2, v3, v4, v5, v6, v7, v8, attr);
1348  return NumOfElements++;
1349 }
1350 
1351 int Mesh::AddHex(const int *vi, int attr)
1352 {
1353  CheckEnlarge(elements, NumOfElements);
1354  elements[NumOfElements] = new Hexahedron(vi, attr);
1355  return NumOfElements++;
1356 }
1357 
1358 void Mesh::AddHexAsTets(const int *vi, int attr)
1359 {
1360  static const int hex_to_tet[6][4] =
1361  {
1362  { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
1363  { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
1364  };
1365  int ti[4];
1366 
1367  for (int i = 0; i < 6; i++)
1368  {
1369  for (int j = 0; j < 4; j++)
1370  {
1371  ti[j] = vi[hex_to_tet[i][j]];
1372  }
1373  AddTet(ti, attr);
1374  }
1375 }
1376 
1377 void Mesh::AddHexAsWedges(const int *vi, int attr)
1378 {
1379  static const int hex_to_wdg[2][6] =
1380  {
1381  { 0, 1, 2, 4, 5, 6 }, { 0, 2, 3, 4, 6, 7 }
1382  };
1383  int ti[6];
1384 
1385  for (int i = 0; i < 2; i++)
1386  {
1387  for (int j = 0; j < 6; j++)
1388  {
1389  ti[j] = vi[hex_to_wdg[i][j]];
1390  }
1391  AddWedge(ti, attr);
1392  }
1393 }
1394 
1395 int Mesh::AddElement(Element *elem)
1396 {
1397  CheckEnlarge(elements, NumOfElements);
1398  elements[NumOfElements] = elem;
1399  return NumOfElements++;
1400 }
1401 
1402 int Mesh::AddBdrElement(Element *elem)
1403 {
1404  CheckEnlarge(boundary, NumOfBdrElements);
1405  boundary[NumOfBdrElements] = elem;
1406  return NumOfBdrElements++;
1407 }
1408 
1409 int Mesh::AddBdrSegment(int v1, int v2, int attr)
1410 {
1411  CheckEnlarge(boundary, NumOfBdrElements);
1412  boundary[NumOfBdrElements] = new Segment(v1, v2, attr);
1413  return NumOfBdrElements++;
1414 }
1415 
1416 int Mesh::AddBdrSegment(const int *vi, int attr)
1417 {
1418  CheckEnlarge(boundary, NumOfBdrElements);
1419  boundary[NumOfBdrElements] = new Segment(vi, attr);
1420  return NumOfBdrElements++;
1421 }
1422 
1423 int Mesh::AddBdrTriangle(int v1, int v2, int v3, int attr)
1424 {
1425  CheckEnlarge(boundary, NumOfBdrElements);
1426  boundary[NumOfBdrElements] = new Triangle(v1, v2, v3, attr);
1427  return NumOfBdrElements++;
1428 }
1429 
1430 int Mesh::AddBdrTriangle(const int *vi, int attr)
1431 {
1432  CheckEnlarge(boundary, NumOfBdrElements);
1433  boundary[NumOfBdrElements] = new Triangle(vi, attr);
1434  return NumOfBdrElements++;
1435 }
1436 
1437 int Mesh::AddBdrQuad(int v1, int v2, int v3, int v4, int attr)
1438 {
1439  CheckEnlarge(boundary, NumOfBdrElements);
1440  boundary[NumOfBdrElements] = new Quadrilateral(v1, v2, v3, v4, attr);
1441  return NumOfBdrElements++;
1442 }
1443 
1444 int Mesh::AddBdrQuad(const int *vi, int attr)
1445 {
1446  CheckEnlarge(boundary, NumOfBdrElements);
1447  boundary[NumOfBdrElements] = new Quadrilateral(vi, attr);
1448  return NumOfBdrElements++;
1449 }
1450 
1451 void Mesh::AddBdrQuadAsTriangles(const int *vi, int attr)
1452 {
1453  static const int quad_to_tri[2][3] = { { 0, 1, 2 }, { 0, 2, 3 } };
1454  int ti[3];
1455 
1456  for (int i = 0; i < 2; i++)
1457  {
1458  for (int j = 0; j < 3; j++)
1459  {
1460  ti[j] = vi[quad_to_tri[i][j]];
1461  }
1462  AddBdrTriangle(ti, attr);
1463  }
1464 }
1465 
1466 void Mesh::GenerateBoundaryElements()
1467 {
1468  int i, j;
1469  Array<int> &be2face = (Dim == 2) ? be_to_edge : be_to_face;
1470 
1471  // GenerateFaces();
1472 
1473  for (i = 0; i < boundary.Size(); i++)
1474  {
1475  FreeElement(boundary[i]);
1476  }
1477 
1478  if (Dim == 3)
1479  {
1480  delete bel_to_edge;
1481  bel_to_edge = NULL;
1482  }
1483 
1484  // count the 'NumOfBdrElements'
1485  NumOfBdrElements = 0;
1486  for (i = 0; i < faces_info.Size(); i++)
1487  {
1488  if (faces_info[i].Elem2No < 0) { NumOfBdrElements++; }
1489  }
1490 
1491  boundary.SetSize(NumOfBdrElements);
1492  be2face.SetSize(NumOfBdrElements);
1493  for (j = i = 0; i < faces_info.Size(); i++)
1494  {
1495  if (faces_info[i].Elem2No < 0)
1496  {
1497  boundary[j] = faces[i]->Duplicate(this);
1498  be2face[j++] = i;
1499  }
1500  }
1501  // In 3D, 'bel_to_edge' is destroyed but it's not updated.
1502 }
1503 
1504 void Mesh::FinalizeCheck()
1505 {
1506  MFEM_VERIFY(vertices.Size() == NumOfVertices ||
1507  vertices.Size() == 0,
1508  "incorrect number of vertices: preallocated: " << vertices.Size()
1509  << ", actually added: " << NumOfVertices);
1510  MFEM_VERIFY(elements.Size() == NumOfElements,
1511  "incorrect number of elements: preallocated: " << elements.Size()
1512  << ", actually added: " << NumOfElements);
1513  MFEM_VERIFY(boundary.Size() == NumOfBdrElements,
1514  "incorrect number of boundary elements: preallocated: "
1515  << boundary.Size() << ", actually added: " << NumOfBdrElements);
1516 }
1517 
1518 void Mesh::FinalizeTriMesh(int generate_edges, int refine, bool fix_orientation)
1519 {
1520  FinalizeCheck();
1521  CheckElementOrientation(fix_orientation);
1522 
1523  if (refine)
1524  {
1525  MarkTriMeshForRefinement();
1526  }
1527 
1528  if (generate_edges)
1529  {
1530  el_to_edge = new Table;
1531  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1532  GenerateFaces();
1533  CheckBdrElementOrientation();
1534  }
1535  else
1536  {
1537  NumOfEdges = 0;
1538  }
1539 
1540  NumOfFaces = 0;
1541 
1542  SetAttributes();
1543 
1544  SetMeshGen();
1545 }
1546 
1547 void Mesh::FinalizeQuadMesh(int generate_edges, int refine,
1548  bool fix_orientation)
1549 {
1550  FinalizeCheck();
1551  if (fix_orientation)
1552  {
1553  CheckElementOrientation(fix_orientation);
1554  }
1555 
1556  if (generate_edges)
1557  {
1558  el_to_edge = new Table;
1559  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1560  GenerateFaces();
1561  CheckBdrElementOrientation();
1562  }
1563  else
1564  {
1565  NumOfEdges = 0;
1566  }
1567 
1568  NumOfFaces = 0;
1569 
1570  SetAttributes();
1571 
1572  SetMeshGen();
1573 }
1574 
1575 
1576 class GeckoProgress : public Gecko::Progress
1577 {
1578  double limit;
1579  mutable StopWatch sw;
1580 public:
1581  GeckoProgress(double limit) : limit(limit) { sw.Start(); }
1582  virtual bool quit() const { return limit > 0 && sw.UserTime() > limit; }
1583 };
1584 
1585 class GeckoVerboseProgress : public GeckoProgress
1586 {
1587  using Float = Gecko::Float;
1588  using Graph = Gecko::Graph;
1589  using uint = Gecko::uint;
1590 public:
1591  GeckoVerboseProgress(double limit) : GeckoProgress(limit) {}
1592 
1593  virtual void beginorder(const Graph* graph, Float cost) const
1594  { mfem::out << "Begin Gecko ordering, cost = " << cost << std::endl; }
1595  virtual void endorder(const Graph* graph, Float cost) const
1596  { mfem::out << "End ordering, cost = " << cost << std::endl; }
1597 
1598  virtual void beginiter(const Graph* graph,
1599  uint iter, uint maxiter, uint window) const
1600  {
1601  mfem::out << "Iteration " << iter << "/" << maxiter << ", window "
1602  << window << std::flush;
1603  }
1604  virtual void enditer(const Graph* graph, Float mincost, Float cost) const
1605  { mfem::out << ", cost = " << cost << endl; }
1606 };
1607 
1608 
1609 double Mesh::GetGeckoElementOrdering(Array<int> &ordering,
1610  int iterations, int window,
1611  int period, int seed, bool verbose,
1612  double time_limit)
1613 {
1614  Gecko::Graph graph;
1615  Gecko::FunctionalGeometric functional; // edge product cost
1616 
1617  GeckoProgress progress(time_limit);
1618  GeckoVerboseProgress vprogress(time_limit);
1619 
1620  // insert elements as nodes in the graph
1621  for (int elemid = 0; elemid < GetNE(); ++elemid)
1622  {
1623  graph.insert_node();
1624  }
1625 
1626  // insert graph edges for element neighbors
1627  // NOTE: indices in Gecko are 1 based hence the +1 on insertion
1628  const Table &my_el_to_el = ElementToElementTable();
1629  for (int elemid = 0; elemid < GetNE(); ++elemid)
1630  {
1631  const int *neighid = my_el_to_el.GetRow(elemid);
1632  for (int i = 0; i < my_el_to_el.RowSize(elemid); ++i)
1633  {
1634  graph.insert_arc(elemid + 1, neighid[i] + 1);
1635  }
1636  }
1637 
1638  // get the ordering from Gecko and copy it into the Array<int>
1639  graph.order(&functional, iterations, window, period, seed,
1640  verbose ? &vprogress : &progress);
1641 
1642  ordering.SetSize(GetNE());
1643  Gecko::Node::Index NE = GetNE();
1644  for (Gecko::Node::Index gnodeid = 1; gnodeid <= NE; ++gnodeid)
1645  {
1646  ordering[gnodeid - 1] = graph.rank(gnodeid);
1647  }
1648 
1649  return graph.cost();
1650 }
1651 
1652 
1653 struct HilbertCmp
1654 {
1655  int coord;
1656  bool dir;
1657  const Array<double> &points;
1658  double mid;
1659 
1660  HilbertCmp(int coord, bool dir, const Array<double> &points, double mid)
1661  : coord(coord), dir(dir), points(points), mid(mid) {}
1662 
1663  bool operator()(int i) const
1664  {
1665  return (points[3*i + coord] < mid) != dir;
1666  }
1667 };
1668 
1669 static void HilbertSort2D(int coord1, // major coordinate to sort points by
1670  bool dir1, // sort coord1 ascending/descending?
1671  bool dir2, // sort coord2 ascending/descending?
1672  const Array<double> &points, int *beg, int *end,
1673  double xmin, double ymin, double xmax, double ymax)
1674 {
1675  if (end - beg <= 1) { return; }
1676 
1677  double xmid = (xmin + xmax)*0.5;
1678  double ymid = (ymin + ymax)*0.5;
1679 
1680  int coord2 = (coord1 + 1) % 2; // the 'other' coordinate
1681 
1682  // sort (partition) points into four quadrants
1683  int *p0 = beg, *p4 = end;
1684  int *p2 = std::partition(p0, p4, HilbertCmp(coord1, dir1, points, xmid));
1685  int *p1 = std::partition(p0, p2, HilbertCmp(coord2, dir2, points, ymid));
1686  int *p3 = std::partition(p2, p4, HilbertCmp(coord2, !dir2, points, ymid));
1687 
1688  if (p1 != p4)
1689  {
1690  HilbertSort2D(coord2, dir2, dir1, points, p0, p1,
1691  ymin, xmin, ymid, xmid);
1692  }
1693  if (p1 != p0 || p2 != p4)
1694  {
1695  HilbertSort2D(coord1, dir1, dir2, points, p1, p2,
1696  xmin, ymid, xmid, ymax);
1697  }
1698  if (p2 != p0 || p3 != p4)
1699  {
1700  HilbertSort2D(coord1, dir1, dir2, points, p2, p3,
1701  xmid, ymid, xmax, ymax);
1702  }
1703  if (p3 != p0)
1704  {
1705  HilbertSort2D(coord2, !dir2, !dir1, points, p3, p4,
1706  ymid, xmax, ymin, xmid);
1707  }
1708 }
1709 
1710 static void HilbertSort3D(int coord1, bool dir1, bool dir2, bool dir3,
1711  const Array<double> &points, int *beg, int *end,
1712  double xmin, double ymin, double zmin,
1713  double xmax, double ymax, double zmax)
1714 {
1715  if (end - beg <= 1) { return; }
1716 
1717  double xmid = (xmin + xmax)*0.5;
1718  double ymid = (ymin + ymax)*0.5;
1719  double zmid = (zmin + zmax)*0.5;
1720 
1721  int coord2 = (coord1 + 1) % 3;
1722  int coord3 = (coord1 + 2) % 3;
1723 
1724  // sort (partition) points into eight octants
1725  int *p0 = beg, *p8 = end;
1726  int *p4 = std::partition(p0, p8, HilbertCmp(coord1, dir1, points, xmid));
1727  int *p2 = std::partition(p0, p4, HilbertCmp(coord2, dir2, points, ymid));
1728  int *p6 = std::partition(p4, p8, HilbertCmp(coord2, !dir2, points, ymid));
1729  int *p1 = std::partition(p0, p2, HilbertCmp(coord3, dir3, points, zmid));
1730  int *p3 = std::partition(p2, p4, HilbertCmp(coord3, !dir3, points, zmid));
1731  int *p5 = std::partition(p4, p6, HilbertCmp(coord3, dir3, points, zmid));
1732  int *p7 = std::partition(p6, p8, HilbertCmp(coord3, !dir3, points, zmid));
1733 
1734  if (p1 != p8)
1735  {
1736  HilbertSort3D(coord3, dir3, dir1, dir2, points, p0, p1,
1737  zmin, xmin, ymin, zmid, xmid, ymid);
1738  }
1739  if (p1 != p0 || p2 != p8)
1740  {
1741  HilbertSort3D(coord2, dir2, dir3, dir1, points, p1, p2,
1742  ymin, zmid, xmin, ymid, zmax, xmid);
1743  }
1744  if (p2 != p0 || p3 != p8)
1745  {
1746  HilbertSort3D(coord2, dir2, dir3, dir1, points, p2, p3,
1747  ymid, zmid, xmin, ymax, zmax, xmid);
1748  }
1749  if (p3 != p0 || p4 != p8)
1750  {
1751  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p3, p4,
1752  xmin, ymax, zmid, xmid, ymid, zmin);
1753  }
1754  if (p4 != p0 || p5 != p8)
1755  {
1756  HilbertSort3D(coord1, dir1, !dir2, !dir3, points, p4, p5,
1757  xmid, ymax, zmid, xmax, ymid, zmin);
1758  }
1759  if (p5 != p0 || p6 != p8)
1760  {
1761  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p5, p6,
1762  ymax, zmid, xmax, ymid, zmax, xmid);
1763  }
1764  if (p6 != p0 || p7 != p8)
1765  {
1766  HilbertSort3D(coord2, !dir2, dir3, !dir1, points, p6, p7,
1767  ymid, zmid, xmax, ymin, zmax, xmid);
1768  }
1769  if (p7 != p0)
1770  {
1771  HilbertSort3D(coord3, !dir3, !dir1, dir2, points, p7, p8,
1772  zmid, xmax, ymin, zmin, xmid, ymid);
1773  }
1774 }
1775 
1776 void Mesh::GetHilbertElementOrdering(Array<int> &ordering)
1777 {
1778  MFEM_VERIFY(spaceDim <= 3, "");
1779 
1780  Vector min, max, center;
1781  GetBoundingBox(min, max);
1782 
1783  Array<int> indices(GetNE());
1784  Array<double> points(3*GetNE());
1785 
1786  if (spaceDim < 3) { points = 0.0; }
1787 
1788  // calculate element centers
1789  for (int i = 0; i < GetNE(); i++)
1790  {
1791  GetElementCenter(i, center);
1792  for (int j = 0; j < spaceDim; j++)
1793  {
1794  points[3*i + j] = center(j);
1795  }
1796  indices[i] = i;
1797  }
1798 
1799  if (spaceDim == 1)
1800  {
1801  indices.Sort([&](int a, int b)
1802  { return points[3*a] < points[3*b]; });
1803  }
1804  else if (spaceDim == 2)
1805  {
1806  // recursively partition the points in 2D
1807  HilbertSort2D(0, false, false,
1808  points, indices.begin(), indices.end(),
1809  min(0), min(1), max(0), max(1));
1810  }
1811  else
1812  {
1813  // recursively partition the points in 3D
1814  HilbertSort3D(0, false, false, false,
1815  points, indices.begin(), indices.end(),
1816  min(0), min(1), min(2), max(0), max(1), max(2));
1817  }
1818 
1819  // return ordering in the format required by ReorderElements
1820  ordering.SetSize(GetNE());
1821  for (int i = 0; i < GetNE(); i++)
1822  {
1823  ordering[indices[i]] = i;
1824  }
1825 }
1826 
1827 
1828 void Mesh::ReorderElements(const Array<int> &ordering, bool reorder_vertices)
1829 {
1830  if (NURBSext)
1831  {
1832  MFEM_WARNING("element reordering of NURBS meshes is not supported.");
1833  return;
1834  }
1835  if (ncmesh)
1836  {
1837  MFEM_WARNING("element reordering of non-conforming meshes is not"
1838  " supported.");
1839  return;
1840  }
1841  MFEM_VERIFY(ordering.Size() == GetNE(), "invalid reordering array.")
1842 
1843  // Data members that need to be updated:
1844 
1845  // - elements - reorder of the pointers and the vertex ids if reordering
1846  // the vertices
1847  // - vertices - if reordering the vertices
1848  // - boundary - update the vertex ids, if reordering the vertices
1849  // - faces - regenerate
1850  // - faces_info - regenerate
1851 
1852  // Deleted by DeleteTables():
1853  // - el_to_edge - rebuild in 2D and 3D only
1854  // - el_to_face - rebuild in 3D only
1855  // - bel_to_edge - rebuild in 3D only
1856  // - el_to_el - no need to rebuild
1857  // - face_edge - no need to rebuild
1858  // - edge_vertex - no need to rebuild
1859  // - geom_factors - no need to rebuild
1860 
1861  // - be_to_edge - 2D only
1862  // - be_to_face - 3D only
1863 
1864  // - Nodes
1865 
1866  // Save the locations of the Nodes so we can rebuild them later
1867  Array<Vector*> old_elem_node_vals;
1868  FiniteElementSpace *nodes_fes = NULL;
1869  if (Nodes)
1870  {
1871  old_elem_node_vals.SetSize(GetNE());
1872  nodes_fes = Nodes->FESpace();
1873  Array<int> old_dofs;
1874  Vector vals;
1875  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
1876  {
1877  nodes_fes->GetElementVDofs(old_elid, old_dofs);
1878  Nodes->GetSubVector(old_dofs, vals);
1879  old_elem_node_vals[old_elid] = new Vector(vals);
1880  }
1881  }
1882 
1883  // Get the newly ordered elements
1884  Array<Element *> new_elements(GetNE());
1885  for (int old_elid = 0; old_elid < ordering.Size(); ++old_elid)
1886  {
1887  int new_elid = ordering[old_elid];
1888  new_elements[new_elid] = elements[old_elid];
1889  }
1890  mfem::Swap(elements, new_elements);
1891  new_elements.DeleteAll();
1892 
1893  if (reorder_vertices)
1894  {
1895  // Get the new vertex ordering permutation vectors and fill the new
1896  // vertices
1897  Array<int> vertex_ordering(GetNV());
1898  vertex_ordering = -1;
1899  Array<Vertex> new_vertices(GetNV());
1900  int new_vertex_ind = 0;
1901  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
1902  {
1903  int *elem_vert = elements[new_elid]->GetVertices();
1904  int nv = elements[new_elid]->GetNVertices();
1905  for (int vi = 0; vi < nv; ++vi)
1906  {
1907  int old_vertex_ind = elem_vert[vi];
1908  if (vertex_ordering[old_vertex_ind] == -1)
1909  {
1910  vertex_ordering[old_vertex_ind] = new_vertex_ind;
1911  new_vertices[new_vertex_ind] = vertices[old_vertex_ind];
1912  new_vertex_ind++;
1913  }
1914  }
1915  }
1916  mfem::Swap(vertices, new_vertices);
1917  new_vertices.DeleteAll();
1918 
1919  // Replace the vertex ids in the elements with the reordered vertex
1920  // numbers
1921  for (int new_elid = 0; new_elid < GetNE(); ++new_elid)
1922  {
1923  int *elem_vert = elements[new_elid]->GetVertices();
1924  int nv = elements[new_elid]->GetNVertices();
1925  for (int vi = 0; vi < nv; ++vi)
1926  {
1927  elem_vert[vi] = vertex_ordering[elem_vert[vi]];
1928  }
1929  }
1930 
1931  // Replace the vertex ids in the boundary with reordered vertex numbers
1932  for (int belid = 0; belid < GetNBE(); ++belid)
1933  {
1934  int *be_vert = boundary[belid]->GetVertices();
1935  int nv = boundary[belid]->GetNVertices();
1936  for (int vi = 0; vi < nv; ++vi)
1937  {
1938  be_vert[vi] = vertex_ordering[be_vert[vi]];
1939  }
1940  }
1941  }
1942 
1943  // Destroy tables that need to be rebuild
1944  DeleteTables();
1945 
1946  if (Dim > 1)
1947  {
1948  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
1949  el_to_edge = new Table;
1950  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
1951  }
1952  if (Dim > 2)
1953  {
1954  // generate el_to_face, be_to_face
1955  GetElementToFaceTable();
1956  }
1957  // Update faces and faces_info
1958  GenerateFaces();
1959 
1960  // Build the nodes from the saved locations if they were around before
1961  if (Nodes)
1962  {
1963  // To force FE space update, we need to increase 'sequence':
1964  sequence++;
1965  last_operation = Mesh::NONE;
1966  nodes_fes->Update(false); // want_transform = false
1967  Nodes->Update(); // just needed to update Nodes->sequence
1968  Array<int> new_dofs;
1969  for (int old_elid = 0; old_elid < GetNE(); ++old_elid)
1970  {
1971  int new_elid = ordering[old_elid];
1972  nodes_fes->GetElementVDofs(new_elid, new_dofs);
1973  Nodes->SetSubVector(new_dofs, *(old_elem_node_vals[old_elid]));
1974  delete old_elem_node_vals[old_elid];
1975  }
1976  }
1977 }
1978 
1979 
1980 void Mesh::MarkForRefinement()
1981 {
1982  if (meshgen & 1)
1983  {
1984  if (Dim == 2)
1985  {
1986  MarkTriMeshForRefinement();
1987  }
1988  else if (Dim == 3)
1989  {
1990  DSTable v_to_v(NumOfVertices);
1991  GetVertexToVertexTable(v_to_v);
1992  MarkTetMeshForRefinement(v_to_v);
1993  }
1994  }
1995 }
1996 
1997 void Mesh::MarkTriMeshForRefinement()
1998 {
1999  // Mark the longest triangle edge by rotating the indeces so that
2000  // vertex 0 - vertex 1 is the longest edge in the triangle.
2001  DenseMatrix pmat;
2002  for (int i = 0; i < NumOfElements; i++)
2003  {
2004  if (elements[i]->GetType() == Element::TRIANGLE)
2005  {
2006  GetPointMatrix(i, pmat);
2007  static_cast<Triangle*>(elements[i])->MarkEdge(pmat);
2008  }
2009  }
2010 }
2011 
2012 void Mesh::GetEdgeOrdering(DSTable &v_to_v, Array<int> &order)
2013 {
2014  NumOfEdges = v_to_v.NumberOfEntries();
2015  order.SetSize(NumOfEdges);
2016  Array<Pair<double, int> > length_idx(NumOfEdges);
2017 
2018  for (int i = 0; i < NumOfVertices; i++)
2019  {
2020  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
2021  {
2022  int j = it.Index();
2023  length_idx[j].one = GetLength(i, it.Column());
2024  length_idx[j].two = j;
2025  }
2026  }
2027 
2028  // Sort by increasing edge-length.
2029  length_idx.Sort();
2030 
2031  for (int i = 0; i < NumOfEdges; i++)
2032  {
2033  order[length_idx[i].two] = i;
2034  }
2035 }
2036 
2037 void Mesh::MarkTetMeshForRefinement(DSTable &v_to_v)
2038 {
2039  // Mark the longest tetrahedral edge by rotating the indices so that
2040  // vertex 0 - vertex 1 is the longest edge in the element.
2041  Array<int> order;
2042  GetEdgeOrdering(v_to_v, order);
2043 
2044  for (int i = 0; i < NumOfElements; i++)
2045  {
2046  if (elements[i]->GetType() == Element::TETRAHEDRON)
2047  {
2048  elements[i]->MarkEdge(v_to_v, order);
2049  }
2050  }
2051  for (int i = 0; i < NumOfBdrElements; i++)
2052  {
2053  if (boundary[i]->GetType() == Element::TRIANGLE)
2054  {
2055  boundary[i]->MarkEdge(v_to_v, order);
2056  }
2057  }
2058 }
2059 
2060 void Mesh::PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert)
2061 {
2062  if (*old_v_to_v && *old_elem_vert)
2063  {
2064  return;
2065  }
2066 
2067  FiniteElementSpace *fes = Nodes->FESpace();
2068 
2069  if (*old_v_to_v == NULL)
2070  {
2071  bool need_v_to_v = false;
2072  Array<int> dofs;
2073  for (int i = 0; i < GetNEdges(); i++)
2074  {
2075  // Since edge indices may change, we need to permute edge interior dofs
2076  // any time an edge index changes and there is at least one dof on that
2077  // edge.
2078  fes->GetEdgeInteriorDofs(i, dofs);
2079  if (dofs.Size() > 0)
2080  {
2081  need_v_to_v = true;
2082  break;
2083  }
2084  }
2085  if (need_v_to_v)
2086  {
2087  *old_v_to_v = new DSTable(NumOfVertices);
2088  GetVertexToVertexTable(*(*old_v_to_v));
2089  }
2090  }
2091  if (*old_elem_vert == NULL)
2092  {
2093  bool need_elem_vert = false;
2094  Array<int> dofs;
2095  for (int i = 0; i < GetNE(); i++)
2096  {
2097  // Since element indices do not change, we need to permute element
2098  // interior dofs only when there are at least 2 interior dofs in an
2099  // element (assuming the nodal dofs are non-directional).
2100  fes->GetElementInteriorDofs(i, dofs);
2101  if (dofs.Size() > 1)
2102  {
2103  need_elem_vert = true;
2104  break;
2105  }
2106  }
2107  if (need_elem_vert)
2108  {
2109  *old_elem_vert = new Table;
2110  (*old_elem_vert)->MakeI(GetNE());
2111  for (int i = 0; i < GetNE(); i++)
2112  {
2113  (*old_elem_vert)->AddColumnsInRow(i, elements[i]->GetNVertices());
2114  }
2115  (*old_elem_vert)->MakeJ();
2116  for (int i = 0; i < GetNE(); i++)
2117  {
2118  (*old_elem_vert)->AddConnections(i, elements[i]->GetVertices(),
2119  elements[i]->GetNVertices());
2120  }
2121  (*old_elem_vert)->ShiftUpI();
2122  }
2123  }
2124 }
2125 
2126 void Mesh::DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert)
2127 {
2128  FiniteElementSpace *fes = Nodes->FESpace();
2129  const FiniteElementCollection *fec = fes->FEColl();
2130  Array<int> old_dofs, new_dofs;
2131 
2132  // assuming that all edges have the same number of dofs
2133  if (NumOfEdges) { fes->GetEdgeInteriorDofs(0, old_dofs); }
2134  const int num_edge_dofs = old_dofs.Size();
2135 
2136  // Save the original nodes
2137  const Vector onodes = *Nodes;
2138 
2139  // vertex dofs do not need to be moved
2140  fes->GetVertexDofs(0, old_dofs);
2141  int offset = NumOfVertices * old_dofs.Size();
2142 
2143  // edge dofs:
2144  // edge enumeration may be different but edge orientation is the same
2145  if (num_edge_dofs > 0)
2146  {
2147  DSTable new_v_to_v(NumOfVertices);
2148  GetVertexToVertexTable(new_v_to_v);
2149 
2150  for (int i = 0; i < NumOfVertices; i++)
2151  {
2152  for (DSTable::RowIterator it(new_v_to_v, i); !it; ++it)
2153  {
2154  const int old_i = (*old_v_to_v)(i, it.Column());
2155  const int new_i = it.Index();
2156  if (new_i == old_i) { continue; }
2157 
2158  old_dofs.SetSize(num_edge_dofs);
2159  new_dofs.SetSize(num_edge_dofs);
2160  for (int j = 0; j < num_edge_dofs; j++)
2161  {
2162  old_dofs[j] = offset + old_i * num_edge_dofs + j;
2163  new_dofs[j] = offset + new_i * num_edge_dofs + j;
2164  }
2165  fes->DofsToVDofs(old_dofs);
2166  fes->DofsToVDofs(new_dofs);
2167  for (int j = 0; j < old_dofs.Size(); j++)
2168  {
2169  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2170  }
2171  }
2172  }
2173  offset += NumOfEdges * num_edge_dofs;
2174  }
2175 
2176  // face dofs:
2177  // both enumeration and orientation of the faces may be different
2178  if (fes->GetNFDofs() > 0)
2179  {
2180  // generate the old face-vertex table using the unmodified 'faces'
2181  Table old_face_vertex;
2182  old_face_vertex.MakeI(NumOfFaces);
2183  for (int i = 0; i < NumOfFaces; i++)
2184  {
2185  old_face_vertex.AddColumnsInRow(i, faces[i]->GetNVertices());
2186  }
2187  old_face_vertex.MakeJ();
2188  for (int i = 0; i < NumOfFaces; i++)
2189  old_face_vertex.AddConnections(i, faces[i]->GetVertices(),
2190  faces[i]->GetNVertices());
2191  old_face_vertex.ShiftUpI();
2192 
2193  // update 'el_to_face', 'be_to_face', 'faces', and 'faces_info'
2194  STable3D *faces_tbl = GetElementToFaceTable(1);
2195  GenerateFaces();
2196 
2197  // compute the new face dof offsets
2198  Array<int> new_fdofs(NumOfFaces+1);
2199  new_fdofs[0] = 0;
2200  for (int i = 0; i < NumOfFaces; i++) // i = old face index
2201  {
2202  const int *old_v = old_face_vertex.GetRow(i);
2203  int new_i; // new face index
2204  switch (old_face_vertex.RowSize(i))
2205  {
2206  case 3:
2207  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2208  break;
2209  case 4:
2210  default:
2211  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2212  break;
2213  }
2214  fes->GetFaceInteriorDofs(i, old_dofs);
2215  new_fdofs[new_i+1] = old_dofs.Size();
2216  }
2217  new_fdofs.PartialSum();
2218 
2219  // loop over the old face numbers
2220  for (int i = 0; i < NumOfFaces; i++)
2221  {
2222  const int *old_v = old_face_vertex.GetRow(i), *new_v;
2223  const int *dof_ord;
2224  int new_i, new_or;
2225  switch (old_face_vertex.RowSize(i))
2226  {
2227  case 3:
2228  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2]);
2229  new_v = faces[new_i]->GetVertices();
2230  new_or = GetTriOrientation(old_v, new_v);
2231  dof_ord = fec->DofOrderForOrientation(Geometry::TRIANGLE, new_or);
2232  break;
2233  case 4:
2234  default:
2235  new_i = (*faces_tbl)(old_v[0], old_v[1], old_v[2], old_v[3]);
2236  new_v = faces[new_i]->GetVertices();
2237  new_or = GetQuadOrientation(old_v, new_v);
2238  dof_ord = fec->DofOrderForOrientation(Geometry::SQUARE, new_or);
2239  break;
2240  }
2241 
2242  fes->GetFaceInteriorDofs(i, old_dofs);
2243  new_dofs.SetSize(old_dofs.Size());
2244  for (int j = 0; j < old_dofs.Size(); j++)
2245  {
2246  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2247  const int old_j = dof_ord[j];
2248  new_dofs[old_j] = offset + new_fdofs[new_i] + j;
2249  }
2250  fes->DofsToVDofs(old_dofs);
2251  fes->DofsToVDofs(new_dofs);
2252  for (int j = 0; j < old_dofs.Size(); j++)
2253  {
2254  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2255  }
2256  }
2257 
2258  offset += fes->GetNFDofs();
2259  delete faces_tbl;
2260  }
2261 
2262  // element dofs:
2263  // element orientation may be different
2264  if (old_elem_vert) // have elements with 2 or more dofs
2265  {
2266  // matters when the 'fec' is
2267  // (this code is executed only for triangles/tets)
2268  // - Pk on triangles, k >= 4
2269  // - Qk on quads, k >= 3
2270  // - Pk on tets, k >= 5
2271  // - Qk on hexes, k >= 3
2272  // - DG spaces
2273  // - ...
2274 
2275  // loop over all elements
2276  for (int i = 0; i < GetNE(); i++)
2277  {
2278  const int *old_v = old_elem_vert->GetRow(i);
2279  const int *new_v = elements[i]->GetVertices();
2280  const int *dof_ord;
2281  int new_or;
2282  const Geometry::Type geom = elements[i]->GetGeometryType();
2283  switch (geom)
2284  {
2285  case Geometry::SEGMENT:
2286  new_or = (old_v[0] == new_v[0]) ? +1 : -1;
2287  break;
2288  case Geometry::TRIANGLE:
2289  new_or = GetTriOrientation(old_v, new_v);
2290  break;
2291  case Geometry::SQUARE:
2292  new_or = GetQuadOrientation(old_v, new_v);
2293  break;
2294  case Geometry::TETRAHEDRON:
2295  new_or = GetTetOrientation(old_v, new_v);
2296  break;
2297  default:
2298  new_or = 0;
2299  MFEM_ABORT(Geometry::Name[geom] << " elements (" << fec->Name()
2300  << " FE collection) are not supported yet!");
2301  break;
2302  }
2303  dof_ord = fec->DofOrderForOrientation(geom, new_or);
2304  MFEM_VERIFY(dof_ord != NULL,
2305  "FE collection '" << fec->Name()
2306  << "' does not define reordering for "
2307  << Geometry::Name[geom] << " elements!");
2308  fes->GetElementInteriorDofs(i, old_dofs);
2309  new_dofs.SetSize(old_dofs.Size());
2310  for (int j = 0; j < new_dofs.Size(); j++)
2311  {
2312  // we assume the dofs are non-directional, i.e. dof_ord[j] is >= 0
2313  const int old_j = dof_ord[j];
2314  new_dofs[old_j] = offset + j;
2315  }
2316  offset += new_dofs.Size();
2317  fes->DofsToVDofs(old_dofs);
2318  fes->DofsToVDofs(new_dofs);
2319  for (int j = 0; j < old_dofs.Size(); j++)
2320  {
2321  (*Nodes)(new_dofs[j]) = onodes(old_dofs[j]);
2322  }
2323  }
2324  }
2325 
2326  // Update Tables, faces, etc
2327  if (Dim > 2)
2328  {
2329  if (fes->GetNFDofs() == 0)
2330  {
2331  // needed for FE spaces that have face dofs, even if
2332  // the 'Nodes' do not have face dofs.
2333  GetElementToFaceTable();
2334  GenerateFaces();
2335  }
2336  CheckBdrElementOrientation();
2337  }
2338  if (el_to_edge)
2339  {
2340  // update 'el_to_edge', 'be_to_edge' (2D), 'bel_to_edge' (3D)
2341  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2342  if (Dim == 2)
2343  {
2344  // update 'faces' and 'faces_info'
2345  GenerateFaces();
2346  CheckBdrElementOrientation();
2347  }
2348  }
2349  // To force FE space update, we need to increase 'sequence':
2350  sequence++;
2351  last_operation = Mesh::NONE;
2352  fes->Update(false); // want_transform = false
2353  Nodes->Update(); // just needed to update Nodes->sequence
2354 }
2355 
2356 void Mesh::FinalizeTetMesh(int generate_edges, int refine, bool fix_orientation)
2357 {
2358  FinalizeCheck();
2359  CheckElementOrientation(fix_orientation);
2360 
2361  if (NumOfBdrElements == 0)
2362  {
2363  GetElementToFaceTable();
2364  GenerateFaces();
2365  GenerateBoundaryElements();
2366  }
2367 
2368  if (refine)
2369  {
2370  DSTable v_to_v(NumOfVertices);
2371  GetVertexToVertexTable(v_to_v);
2372  MarkTetMeshForRefinement(v_to_v);
2373  }
2374 
2375  GetElementToFaceTable();
2376  GenerateFaces();
2377 
2378  CheckBdrElementOrientation();
2379 
2380  if (generate_edges == 1)
2381  {
2382  el_to_edge = new Table;
2383  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2384  }
2385  else
2386  {
2387  el_to_edge = NULL; // Not really necessary -- InitTables was called
2388  bel_to_edge = NULL;
2389  NumOfEdges = 0;
2390  }
2391 
2392  SetAttributes();
2393 
2394  SetMeshGen();
2395 }
2396 
2397 void Mesh::FinalizeWedgeMesh(int generate_edges, int refine,
2398  bool fix_orientation)
2399 {
2400  FinalizeCheck();
2401  CheckElementOrientation(fix_orientation);
2402 
2403  if (NumOfBdrElements == 0)
2404  {
2405  GetElementToFaceTable();
2406  GenerateFaces();
2407  GenerateBoundaryElements();
2408  }
2409 
2410  GetElementToFaceTable();
2411  GenerateFaces();
2412 
2413  CheckBdrElementOrientation();
2414 
2415  if (generate_edges == 1)
2416  {
2417  el_to_edge = new Table;
2418  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2419  }
2420  else
2421  {
2422  el_to_edge = NULL; // Not really necessary -- InitTables was called
2423  bel_to_edge = NULL;
2424  NumOfEdges = 0;
2425  }
2426 
2427  SetAttributes();
2428 
2429  SetMeshGen();
2430 }
2431 
2432 void Mesh::FinalizeHexMesh(int generate_edges, int refine, bool fix_orientation)
2433 {
2434  FinalizeCheck();
2435  CheckElementOrientation(fix_orientation);
2436 
2437  GetElementToFaceTable();
2438  GenerateFaces();
2439 
2440  if (NumOfBdrElements == 0)
2441  {
2442  GenerateBoundaryElements();
2443  }
2444 
2445  CheckBdrElementOrientation();
2446 
2447  if (generate_edges)
2448  {
2449  el_to_edge = new Table;
2450  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2451  }
2452  else
2453  {
2454  NumOfEdges = 0;
2455  }
2456 
2457  SetAttributes();
2458 
2459  SetMeshGen();
2460 }
2461 
2462 void Mesh::FinalizeMesh(int refine, bool fix_orientation)
2463 {
2464  FinalizeTopology();
2465 
2466  Finalize(refine, fix_orientation);
2467 }
2468 
2469 void Mesh::FinalizeTopology(bool generate_bdr)
2470 {
2471  // Requirements: the following should be defined:
2472  // 1) Dim
2473  // 2) NumOfElements, elements
2474  // 3) NumOfBdrElements, boundary
2475  // 4) NumOfVertices
2476  // Optional:
2477  // 2) ncmesh may be defined
2478  // 3) el_to_edge may be allocated (it will be re-computed)
2479 
2480  FinalizeCheck();
2481  bool generate_edges = true;
2482 
2483  if (spaceDim == 0) { spaceDim = Dim; }
2484  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
2485 
2486  // set the mesh type: 'meshgen', ...
2487  SetMeshGen();
2488 
2489  // generate the faces
2490  if (Dim > 2)
2491  {
2492  GetElementToFaceTable();
2493  GenerateFaces();
2494  if (NumOfBdrElements == 0 && generate_bdr)
2495  {
2496  GenerateBoundaryElements();
2497  GetElementToFaceTable(); // update be_to_face
2498  }
2499  }
2500  else
2501  {
2502  NumOfFaces = 0;
2503  }
2504 
2505  // generate edges if requested
2506  if (Dim > 1 && generate_edges)
2507  {
2508  // el_to_edge may already be allocated (P2 VTK meshes)
2509  if (!el_to_edge) { el_to_edge = new Table; }
2510  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
2511  if (Dim == 2)
2512  {
2513  GenerateFaces(); // 'Faces' in 2D refers to the edges
2514  if (NumOfBdrElements == 0 && generate_bdr)
2515  {
2516  GenerateBoundaryElements();
2517  }
2518  }
2519  }
2520  else
2521  {
2522  NumOfEdges = 0;
2523  }
2524 
2525  if (Dim == 1)
2526  {
2527  GenerateFaces();
2528  }
2529 
2530  if (ncmesh)
2531  {
2532  // tell NCMesh the numbering of edges/faces
2533  ncmesh->OnMeshUpdated(this);
2534 
2535  // update faces_info with NC relations
2536  GenerateNCFaceInfo();
2537  }
2538 
2539  // generate the arrays 'attributes' and 'bdr_attributes'
2540  SetAttributes();
2541 
2542  // if the user defined any hanging nodes (see AddVertexParent),
2543  // initialize the NC mesh now
2544  if (tmp_vertex_parents.Size())
2545  {
2546  MFEM_VERIFY(ncmesh == NULL, "");
2547  EnsureNCMesh(true);
2548  tmp_vertex_parents.DeleteAll();
2549  }
2550 }
2551 
2552 void Mesh::Finalize(bool refine, bool fix_orientation)
2553 {
2554  if (NURBSext || ncmesh)
2555  {
2556  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
2557  MFEM_ASSERT(CheckBdrElementOrientation() == 0, "");
2558  return;
2559  }
2560 
2561  // Requirements:
2562  // 1) FinalizeTopology() or equivalent was called
2563  // 2) if (Nodes == NULL), vertices must be defined
2564  // 3) if (Nodes != NULL), Nodes must be defined
2565 
2566  const bool check_orientation = true; // for regular elements, not boundary
2567  const bool curved = (Nodes != NULL);
2568  const bool may_change_topology =
2569  ( refine && (Dim > 1 && (meshgen & 1)) ) ||
2570  ( check_orientation && fix_orientation &&
2571  (Dim == 2 || (Dim == 3 && (meshgen & 1))) );
2572 
2573  DSTable *old_v_to_v = NULL;
2574  Table *old_elem_vert = NULL;
2575 
2576  if (curved && may_change_topology)
2577  {
2578  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
2579  }
2580 
2581  if (check_orientation)
2582  {
2583  // check and optionally fix element orientation
2584  CheckElementOrientation(fix_orientation);
2585  }
2586  if (refine)
2587  {
2588  MarkForRefinement(); // may change topology!
2589  }
2590 
2591  if (may_change_topology)
2592  {
2593  if (curved)
2594  {
2595  DoNodeReorder(old_v_to_v, old_elem_vert); // updates the mesh topology
2596  delete old_elem_vert;
2597  delete old_v_to_v;
2598  }
2599  else
2600  {
2601  FinalizeTopology(); // Re-computes some data unnecessarily.
2602  }
2603 
2604  // TODO: maybe introduce Mesh::NODE_REORDER operation and FESpace::
2605  // NodeReorderMatrix and do Nodes->Update() instead of DoNodeReorder?
2606  }
2607 
2608  // check and fix boundary element orientation
2609  CheckBdrElementOrientation();
2610 
2611 #ifdef MFEM_DEBUG
2612  // For non-orientable surfaces/manifolds, the check below will fail, so we
2613  // only perform it when Dim == spaceDim.
2614  if (Dim >= 2 && Dim == spaceDim)
2615  {
2616  const int num_faces = GetNumFaces();
2617  for (int i = 0; i < num_faces; i++)
2618  {
2619  MFEM_VERIFY(faces_info[i].Elem2No < 0 ||
2620  faces_info[i].Elem2Inf%2 != 0, "invalid mesh topology");
2621  }
2622  }
2623 #endif
2624 }
2625 
2626 void Mesh::Make3D(int nx, int ny, int nz, Element::Type type,
2627  double sx, double sy, double sz, bool sfc_ordering)
2628 {
2629  int x, y, z;
2630 
2631  int NVert, NElem, NBdrElem;
2632 
2633  NVert = (nx+1) * (ny+1) * (nz+1);
2634  NElem = nx * ny * nz;
2635  NBdrElem = 2*(nx*ny+nx*nz+ny*nz);
2636  if (type == Element::TETRAHEDRON)
2637  {
2638  NElem *= 6;
2639  NBdrElem *= 2;
2640  }
2641  else if (type == Element::WEDGE)
2642  {
2643  NElem *= 2;
2644  NBdrElem += 2*nx*ny;
2645  }
2646 
2647  InitMesh(3, 3, NVert, NElem, NBdrElem);
2648 
2649  double coord[3];
2650  int ind[8];
2651 
2652  // Sets vertices and the corresponding coordinates
2653  for (z = 0; z <= nz; z++)
2654  {
2655  coord[2] = ((double) z / nz) * sz;
2656  for (y = 0; y <= ny; y++)
2657  {
2658  coord[1] = ((double) y / ny) * sy;
2659  for (x = 0; x <= nx; x++)
2660  {
2661  coord[0] = ((double) x / nx) * sx;
2662  AddVertex(coord);
2663  }
2664  }
2665  }
2666 
2667 #define VTX(XC, YC, ZC) ((XC)+((YC)+(ZC)*(ny+1))*(nx+1))
2668 
2669  // Sets elements and the corresponding indices of vertices
2670  if (sfc_ordering && type == Element::HEXAHEDRON)
2671  {
2672  Array<int> sfc;
2673  NCMesh::GridSfcOrdering3D(nx, ny, nz, sfc);
2674  MFEM_VERIFY(sfc.Size() == 3*nx*ny*nz, "");
2675 
2676  for (int k = 0; k < nx*ny*nz; k++)
2677  {
2678  x = sfc[3*k + 0];
2679  y = sfc[3*k + 1];
2680  z = sfc[3*k + 2];
2681 
2682  ind[0] = VTX(x , y , z );
2683  ind[1] = VTX(x+1, y , z );
2684  ind[2] = VTX(x+1, y+1, z );
2685  ind[3] = VTX(x , y+1, z );
2686  ind[4] = VTX(x , y , z+1);
2687  ind[5] = VTX(x+1, y , z+1);
2688  ind[6] = VTX(x+1, y+1, z+1);
2689  ind[7] = VTX(x , y+1, z+1);
2690 
2691  AddHex(ind, 1);
2692  }
2693  }
2694  else
2695  {
2696  for (z = 0; z < nz; z++)
2697  {
2698  for (y = 0; y < ny; y++)
2699  {
2700  for (x = 0; x < nx; x++)
2701  {
2702  ind[0] = VTX(x , y , z );
2703  ind[1] = VTX(x+1, y , z );
2704  ind[2] = VTX(x+1, y+1, z );
2705  ind[3] = VTX(x , y+1, z );
2706  ind[4] = VTX(x , y , z+1);
2707  ind[5] = VTX(x+1, y , z+1);
2708  ind[6] = VTX(x+1, y+1, z+1);
2709  ind[7] = VTX( x, y+1, z+1);
2710  if (type == Element::TETRAHEDRON)
2711  {
2712  AddHexAsTets(ind, 1);
2713  }
2714  else if (type == Element::WEDGE)
2715  {
2716  AddHexAsWedges(ind, 1);
2717  }
2718  else
2719  {
2720  AddHex(ind, 1);
2721  }
2722  }
2723  }
2724  }
2725  }
2726 
2727  // Sets boundary elements and the corresponding indices of vertices
2728  // bottom, bdr. attribute 1
2729  for (y = 0; y < ny; y++)
2730  {
2731  for (x = 0; x < nx; x++)
2732  {
2733  ind[0] = VTX(x , y , 0);
2734  ind[1] = VTX(x , y+1, 0);
2735  ind[2] = VTX(x+1, y+1, 0);
2736  ind[3] = VTX(x+1, y , 0);
2737  if (type == Element::TETRAHEDRON)
2738  {
2739  AddBdrQuadAsTriangles(ind, 1);
2740  }
2741  else if (type == Element::WEDGE)
2742  {
2743  AddBdrQuadAsTriangles(ind, 1);
2744  }
2745  else
2746  {
2747  AddBdrQuad(ind, 1);
2748  }
2749  }
2750  }
2751  // top, bdr. attribute 6
2752  for (y = 0; y < ny; y++)
2753  {
2754  for (x = 0; x < nx; x++)
2755  {
2756  ind[0] = VTX(x , y , nz);
2757  ind[1] = VTX(x+1, y , nz);
2758  ind[2] = VTX(x+1, y+1, nz);
2759  ind[3] = VTX(x , y+1, nz);
2760  if (type == Element::TETRAHEDRON)
2761  {
2762  AddBdrQuadAsTriangles(ind, 6);
2763  }
2764  else if (type == Element::WEDGE)
2765  {
2766  AddBdrQuadAsTriangles(ind, 1);
2767  }
2768  else
2769  {
2770  AddBdrQuad(ind, 6);
2771  }
2772  }
2773  }
2774  // left, bdr. attribute 5
2775  for (z = 0; z < nz; z++)
2776  {
2777  for (y = 0; y < ny; y++)
2778  {
2779  ind[0] = VTX(0 , y , z );
2780  ind[1] = VTX(0 , y , z+1);
2781  ind[2] = VTX(0 , y+1, z+1);
2782  ind[3] = VTX(0 , y+1, z );
2783  if (type == Element::TETRAHEDRON)
2784  {
2785  AddBdrQuadAsTriangles(ind, 5);
2786  }
2787  else
2788  {
2789  AddBdrQuad(ind, 5);
2790  }
2791  }
2792  }
2793  // right, bdr. attribute 3
2794  for (z = 0; z < nz; z++)
2795  {
2796  for (y = 0; y < ny; y++)
2797  {
2798  ind[0] = VTX(nx, y , z );
2799  ind[1] = VTX(nx, y+1, z );
2800  ind[2] = VTX(nx, y+1, z+1);
2801  ind[3] = VTX(nx, y , z+1);
2802  if (type == Element::TETRAHEDRON)
2803  {
2804  AddBdrQuadAsTriangles(ind, 3);
2805  }
2806  else
2807  {
2808  AddBdrQuad(ind, 3);
2809  }
2810  }
2811  }
2812  // front, bdr. attribute 2
2813  for (x = 0; x < nx; x++)
2814  {
2815  for (z = 0; z < nz; z++)
2816  {
2817  ind[0] = VTX(x , 0, z );
2818  ind[1] = VTX(x+1, 0, z );
2819  ind[2] = VTX(x+1, 0, z+1);
2820  ind[3] = VTX(x , 0, z+1);
2821  if (type == Element::TETRAHEDRON)
2822  {
2823  AddBdrQuadAsTriangles(ind, 2);
2824  }
2825  else
2826  {
2827  AddBdrQuad(ind, 2);
2828  }
2829  }
2830  }
2831  // back, bdr. attribute 4
2832  for (x = 0; x < nx; x++)
2833  {
2834  for (z = 0; z < nz; z++)
2835  {
2836  ind[0] = VTX(x , ny, z );
2837  ind[1] = VTX(x , ny, z+1);
2838  ind[2] = VTX(x+1, ny, z+1);
2839  ind[3] = VTX(x+1, ny, z );
2840  if (type == Element::TETRAHEDRON)
2841  {
2842  AddBdrQuadAsTriangles(ind, 4);
2843  }
2844  else
2845  {
2846  AddBdrQuad(ind, 4);
2847  }
2848  }
2849  }
2850 
2851 #undef VTX
2852 
2853 #if 0
2854  ofstream test_stream("debug.mesh");
2855  Print(test_stream);
2856  test_stream.close();
2857 #endif
2858 
2859  FinalizeTopology();
2860 
2861  // Finalize(...) can be called after this method, if needed
2862 }
2863 
2864 void Mesh::Make2D(int nx, int ny, Element::Type type,
2865  double sx, double sy,
2866  bool generate_edges, bool sfc_ordering)
2867 {
2868  int i, j, k;
2869 
2870  SetEmpty();
2871 
2872  Dim = spaceDim = 2;
2873 
2874  // Creates quadrilateral mesh
2875  if (type == Element::QUADRILATERAL)
2876  {
2877  NumOfVertices = (nx+1) * (ny+1);
2878  NumOfElements = nx * ny;
2879  NumOfBdrElements = 2 * nx + 2 * ny;
2880 
2881  vertices.SetSize(NumOfVertices);
2882  elements.SetSize(NumOfElements);
2883  boundary.SetSize(NumOfBdrElements);
2884 
2885  double cx, cy;
2886  int ind[4];
2887 
2888  // Sets vertices and the corresponding coordinates
2889  k = 0;
2890  for (j = 0; j < ny+1; j++)
2891  {
2892  cy = ((double) j / ny) * sy;
2893  for (i = 0; i < nx+1; i++)
2894  {
2895  cx = ((double) i / nx) * sx;
2896  vertices[k](0) = cx;
2897  vertices[k](1) = cy;
2898  k++;
2899  }
2900  }
2901 
2902  // Sets elements and the corresponding indices of vertices
2903  if (sfc_ordering)
2904  {
2905  Array<int> sfc;
2906  NCMesh::GridSfcOrdering2D(nx, ny, sfc);
2907  MFEM_VERIFY(sfc.Size() == 2*nx*ny, "");
2908 
2909  for (k = 0; k < nx*ny; k++)
2910  {
2911  i = sfc[2*k + 0];
2912  j = sfc[2*k + 1];
2913  ind[0] = i + j*(nx+1);
2914  ind[1] = i + 1 +j*(nx+1);
2915  ind[2] = i + 1 + (j+1)*(nx+1);
2916  ind[3] = i + (j+1)*(nx+1);
2917  elements[k] = new Quadrilateral(ind);
2918  }
2919  }
2920  else
2921  {
2922  k = 0;
2923  for (j = 0; j < ny; j++)
2924  {
2925  for (i = 0; i < nx; i++)
2926  {
2927  ind[0] = i + j*(nx+1);
2928  ind[1] = i + 1 +j*(nx+1);
2929  ind[2] = i + 1 + (j+1)*(nx+1);
2930  ind[3] = i + (j+1)*(nx+1);
2931  elements[k] = new Quadrilateral(ind);
2932  k++;
2933  }
2934  }
2935  }
2936 
2937  // Sets boundary elements and the corresponding indices of vertices
2938  int m = (nx+1)*ny;
2939  for (i = 0; i < nx; i++)
2940  {
2941  boundary[i] = new Segment(i, i+1, 1);
2942  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
2943  }
2944  m = nx+1;
2945  for (j = 0; j < ny; j++)
2946  {
2947  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
2948  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
2949  }
2950  }
2951  // Creates triangular mesh
2952  else if (type == Element::TRIANGLE)
2953  {
2954  NumOfVertices = (nx+1) * (ny+1);
2955  NumOfElements = 2 * nx * ny;
2956  NumOfBdrElements = 2 * nx + 2 * ny;
2957 
2958  vertices.SetSize(NumOfVertices);
2959  elements.SetSize(NumOfElements);
2960  boundary.SetSize(NumOfBdrElements);
2961 
2962  double cx, cy;
2963  int ind[3];
2964 
2965  // Sets vertices and the corresponding coordinates
2966  k = 0;
2967  for (j = 0; j < ny+1; j++)
2968  {
2969  cy = ((double) j / ny) * sy;
2970  for (i = 0; i < nx+1; i++)
2971  {
2972  cx = ((double) i / nx) * sx;
2973  vertices[k](0) = cx;
2974  vertices[k](1) = cy;
2975  k++;
2976  }
2977  }
2978 
2979  // Sets the elements and the corresponding indices of vertices
2980  k = 0;
2981  for (j = 0; j < ny; j++)
2982  {
2983  for (i = 0; i < nx; i++)
2984  {
2985  ind[0] = i + j*(nx+1);
2986  ind[1] = i + 1 + (j+1)*(nx+1);
2987  ind[2] = i + (j+1)*(nx+1);
2988  elements[k] = new Triangle(ind);
2989  k++;
2990  ind[1] = i + 1 + j*(nx+1);
2991  ind[2] = i + 1 + (j+1)*(nx+1);
2992  elements[k] = new Triangle(ind);
2993  k++;
2994  }
2995  }
2996 
2997  // Sets boundary elements and the corresponding indices of vertices
2998  int m = (nx+1)*ny;
2999  for (i = 0; i < nx; i++)
3000  {
3001  boundary[i] = new Segment(i, i+1, 1);
3002  boundary[nx+i] = new Segment(m+i+1, m+i, 3);
3003  }
3004  m = nx+1;
3005  for (j = 0; j < ny; j++)
3006  {
3007  boundary[2*nx+j] = new Segment((j+1)*m, j*m, 4);
3008  boundary[2*nx+ny+j] = new Segment(j*m+nx, (j+1)*m+nx, 2);
3009  }
3010 
3011  // MarkTriMeshForRefinement(); // done in Finalize(...)
3012  }
3013  else
3014  {
3015  MFEM_ABORT("Unsupported element type.");
3016  }
3017 
3018  SetMeshGen();
3019  CheckElementOrientation();
3020 
3021  if (generate_edges == 1)
3022  {
3023  el_to_edge = new Table;
3024  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
3025  GenerateFaces();
3026  CheckBdrElementOrientation();
3027  }
3028  else
3029  {
3030  NumOfEdges = 0;
3031  }
3032 
3033  NumOfFaces = 0;
3034 
3035  attributes.Append(1);
3036  bdr_attributes.Append(1); bdr_attributes.Append(2);
3037  bdr_attributes.Append(3); bdr_attributes.Append(4);
3038 
3039  // Finalize(...) can be called after this method, if needed
3040 }
3041 
3042 void Mesh::Make1D(int n, double sx)
3043 {
3044  int j, ind[1];
3045 
3046  SetEmpty();
3047 
3048  Dim = 1;
3049  spaceDim = 1;
3050 
3051  NumOfVertices = n + 1;
3052  NumOfElements = n;
3053  NumOfBdrElements = 2;
3054  vertices.SetSize(NumOfVertices);
3055  elements.SetSize(NumOfElements);
3056  boundary.SetSize(NumOfBdrElements);
3057 
3058  // Sets vertices and the corresponding coordinates
3059  for (j = 0; j < n+1; j++)
3060  {
3061  vertices[j](0) = ((double) j / n) * sx;
3062  }
3063 
3064  // Sets elements and the corresponding indices of vertices
3065  for (j = 0; j < n; j++)
3066  {
3067  elements[j] = new Segment(j, j+1, 1);
3068  }
3069 
3070  // Sets the boundary elements
3071  ind[0] = 0;
3072  boundary[0] = new Point(ind, 1);
3073  ind[0] = n;
3074  boundary[1] = new Point(ind, 2);
3075 
3076  NumOfEdges = 0;
3077  NumOfFaces = 0;
3078 
3079  SetMeshGen();
3080  GenerateFaces();
3081 
3082  attributes.Append(1);
3083  bdr_attributes.Append(1); bdr_attributes.Append(2);
3084 }
3085 
3086 Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
3087 {
3088  Dim = mesh.Dim;
3089  spaceDim = mesh.spaceDim;
3090 
3091  NumOfVertices = mesh.NumOfVertices;
3092  NumOfElements = mesh.NumOfElements;
3093  NumOfBdrElements = mesh.NumOfBdrElements;
3094  NumOfEdges = mesh.NumOfEdges;
3095  NumOfFaces = mesh.NumOfFaces;
3096  nbInteriorFaces = mesh.nbInteriorFaces;
3097  nbBoundaryFaces = mesh.nbBoundaryFaces;
3098 
3099  meshgen = mesh.meshgen;
3100  mesh_geoms = mesh.mesh_geoms;
3101 
3102  // Create the new Mesh instance without a record of its refinement history
3103  sequence = 0;
3104  last_operation = Mesh::NONE;
3105 
3106  // Duplicate the elements
3107  elements.SetSize(NumOfElements);
3108  for (int i = 0; i < NumOfElements; i++)
3109  {
3110  elements[i] = mesh.elements[i]->Duplicate(this);
3111  }
3112 
3113  // Copy the vertices
3114  mesh.vertices.Copy(vertices);
3115 
3116  // Duplicate the boundary
3117  boundary.SetSize(NumOfBdrElements);
3118  for (int i = 0; i < NumOfBdrElements; i++)
3119  {
3120  boundary[i] = mesh.boundary[i]->Duplicate(this);
3121  }
3122 
3123  // Copy the element-to-face Table, el_to_face
3124  el_to_face = (mesh.el_to_face) ? new Table(*mesh.el_to_face) : NULL;
3125 
3126  // Copy the boundary-to-face Array, be_to_face.
3127  mesh.be_to_face.Copy(be_to_face);
3128 
3129  // Copy the element-to-edge Table, el_to_edge
3130  el_to_edge = (mesh.el_to_edge) ? new Table(*mesh.el_to_edge) : NULL;
3131 
3132  // Copy the boundary-to-edge Table, bel_to_edge (3D)
3133  bel_to_edge = (mesh.bel_to_edge) ? new Table(*mesh.bel_to_edge) : NULL;
3134 
3135  // Copy the boundary-to-edge Array, be_to_edge (2D)
3136  mesh.be_to_edge.Copy(be_to_edge);
3137 
3138  // Duplicate the faces and faces_info.
3139  faces.SetSize(mesh.faces.Size());
3140  for (int i = 0; i < faces.Size(); i++)
3141  {
3142  Element *face = mesh.faces[i]; // in 1D the faces are NULL
3143  faces[i] = (face) ? face->Duplicate(this) : NULL;
3144  }
3145  mesh.faces_info.Copy(faces_info);
3146  mesh.nc_faces_info.Copy(nc_faces_info);
3147 
3148  // Do NOT copy the element-to-element Table, el_to_el
3149  el_to_el = NULL;
3150 
3151  // Do NOT copy the face-to-edge Table, face_edge
3152  face_edge = NULL;
3153 
3154  // Copy the edge-to-vertex Table, edge_vertex
3155  edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
3156 
3157  // Copy the attributes and bdr_attributes
3158  mesh.attributes.Copy(attributes);
3159  mesh.bdr_attributes.Copy(bdr_attributes);
3160 
3161  // Deep copy the NURBSExtension.
3162 #ifdef MFEM_USE_MPI
3163  ParNURBSExtension *pNURBSext =
3164  dynamic_cast<ParNURBSExtension *>(mesh.NURBSext);
3165  if (pNURBSext)
3166  {
3167  NURBSext = new ParNURBSExtension(*pNURBSext);
3168  }
3169  else
3170 #endif
3171  {
3172  NURBSext = mesh.NURBSext ? new NURBSExtension(*mesh.NURBSext) : NULL;
3173  }
3174 
3175  // Deep copy the NCMesh.
3176 #ifdef MFEM_USE_MPI
3177  if (dynamic_cast<const ParMesh*>(&mesh))
3178  {
3179  ncmesh = NULL; // skip; will be done in ParMesh copy ctor
3180  }
3181  else
3182 #endif
3183  {
3184  ncmesh = mesh.ncmesh ? new NCMesh(*mesh.ncmesh) : NULL;
3185  }
3186 
3187  // Duplicate the Nodes, including the FiniteElementCollection and the
3188  // FiniteElementSpace
3189  if (mesh.Nodes && copy_nodes)
3190  {
3191  FiniteElementSpace *fes = mesh.Nodes->FESpace();
3192  const FiniteElementCollection *fec = fes->FEColl();
3193  FiniteElementCollection *fec_copy =
3194  FiniteElementCollection::New(fec->Name());
3195  FiniteElementSpace *fes_copy =
3196  new FiniteElementSpace(*fes, this, fec_copy);
3197  Nodes = new GridFunction(fes_copy);
3198  Nodes->MakeOwner(fec_copy);
3199  *Nodes = *mesh.Nodes;
3200  own_nodes = 1;
3201  }
3202  else
3203  {
3204  Nodes = mesh.Nodes;
3205  own_nodes = 0;
3206  }
3207 }
3208 
3209 Mesh::Mesh(const char *filename, int generate_edges, int refine,
3210  bool fix_orientation)
3211 {
3212  // Initialization as in the default constructor
3213  SetEmpty();
3214 
3215  named_ifgzstream imesh(filename);
3216  if (!imesh)
3217  {
3218  // Abort with an error message.
3219  MFEM_ABORT("Mesh file not found: " << filename << '\n');
3220  }
3221  else
3222  {
3223  Load(imesh, generate_edges, refine, fix_orientation);
3224  }
3225 }
3226 
3227 Mesh::Mesh(std::istream &input, int generate_edges, int refine,
3228  bool fix_orientation)
3229 {
3230  SetEmpty();
3231  Load(input, generate_edges, refine, fix_orientation);
3232 }
3233 
3234 void Mesh::ChangeVertexDataOwnership(double *vertex_data, int len_vertex_data,
3235  bool zerocopy)
3236 {
3237  // A dimension of 3 is now required since we use mfem::Vertex objects as PODs
3238  // and these object have a hardcoded double[3] entry
3239  MFEM_VERIFY(len_vertex_data >= NumOfVertices * 3,
3240  "Not enough vertices in external array : "
3241  "len_vertex_data = "<< len_vertex_data << ", "
3242  "NumOfVertices * 3 = " << NumOfVertices * 3);
3243  // Allow multiple calls to this method with the same vertex_data
3244  if (vertex_data == (double *)(vertices.GetData()))
3245  {
3246  MFEM_ASSERT(!vertices.OwnsData(), "invalid ownership");
3247  return;
3248  }
3249  if (!zerocopy)
3250  {
3251  memcpy(vertex_data, vertices.GetData(),
3252  NumOfVertices * 3 * sizeof(double));
3253  }
3254  // Vertex is POD double[3]
3255  vertices.MakeRef(reinterpret_cast<Vertex*>(vertex_data), NumOfVertices);
3256 }
3257 
3258 Mesh::Mesh(double *_vertices, int num_vertices,
3259  int *element_indices, Geometry::Type element_type,
3260  int *element_attributes, int num_elements,
3261  int *boundary_indices, Geometry::Type boundary_type,
3262  int *boundary_attributes, int num_boundary_elements,
3263  int dimension, int space_dimension)
3264 {
3265  if (space_dimension == -1)
3266  {
3267  space_dimension = dimension;
3268  }
3269 
3270  InitMesh(dimension, space_dimension, /*num_vertices*/ 0, num_elements,
3271  num_boundary_elements);
3272 
3273  int element_index_stride = Geometry::NumVerts[element_type];
3274  int boundary_index_stride = num_boundary_elements > 0 ?
3275  Geometry::NumVerts[boundary_type] : 0;
3276 
3277  // assuming Vertex is POD
3278  vertices.MakeRef(reinterpret_cast<Vertex*>(_vertices), num_vertices);
3279  NumOfVertices = num_vertices;
3280 
3281  for (int i = 0; i < num_elements; i++)
3282  {
3283  elements[i] = NewElement(element_type);
3284  elements[i]->SetVertices(element_indices + i * element_index_stride);
3285  elements[i]->SetAttribute(element_attributes[i]);
3286  }
3287  NumOfElements = num_elements;
3288 
3289  for (int i = 0; i < num_boundary_elements; i++)
3290  {
3291  boundary[i] = NewElement(boundary_type);
3292  boundary[i]->SetVertices(boundary_indices + i * boundary_index_stride);
3293  boundary[i]->SetAttribute(boundary_attributes[i]);
3294  }
3295  NumOfBdrElements = num_boundary_elements;
3296 
3297  FinalizeTopology();
3298 }
3299 
3300 Element *Mesh::NewElement(int geom)
3301 {
3302  switch (geom)
3303  {
3304  case Geometry::POINT: return (new Point);
3305  case Geometry::SEGMENT: return (new Segment);
3306  case Geometry::TRIANGLE: return (new Triangle);
3307  case Geometry::SQUARE: return (new Quadrilateral);
3308  case Geometry::TETRAHEDRON:
3309 #ifdef MFEM_USE_MEMALLOC
3310  return TetMemory.Alloc();
3311 #else
3312  return (new Tetrahedron);
3313 #endif
3314  case Geometry::CUBE: return (new Hexahedron);
3315  case Geometry::PRISM: return (new Wedge);
3316  default:
3317  MFEM_ABORT("invalid Geometry::Type, geom = " << geom);
3318  }
3319 
3320  return NULL;
3321 }
3322 
3323 Element *Mesh::ReadElementWithoutAttr(std::istream &input)
3324 {
3325  int geom, nv, *v;
3326  Element *el;
3327 
3328  input >> geom;
3329  el = NewElement(geom);
3330  MFEM_VERIFY(el, "Unsupported element type: " << geom);
3331  nv = el->GetNVertices();
3332  v = el->GetVertices();
3333  for (int i = 0; i < nv; i++)
3334  {
3335  input >> v[i];
3336  }
3337 
3338  return el;
3339 }
3340 
3341 void Mesh::PrintElementWithoutAttr(const Element *el, std::ostream &out)
3342 {
3343  out << el->GetGeometryType();
3344  const int nv = el->GetNVertices();
3345  const int *v = el->GetVertices();
3346  for (int j = 0; j < nv; j++)
3347  {
3348  out << ' ' << v[j];
3349  }
3350  out << '\n';
3351 }
3352 
3353 Element *Mesh::ReadElement(std::istream &input)
3354 {
3355  int attr;
3356  Element *el;
3357 
3358  input >> attr;
3359  el = ReadElementWithoutAttr(input);
3360  el->SetAttribute(attr);
3361 
3362  return el;
3363 }
3364 
3365 void Mesh::PrintElement(const Element *el, std::ostream &out)
3366 {
3367  out << el->GetAttribute() << ' ';
3368  PrintElementWithoutAttr(el, out);
3369 }
3370 
3371 void Mesh::SetMeshGen()
3372 {
3373  meshgen = mesh_geoms = 0;
3374  for (int i = 0; i < NumOfElements; i++)
3375  {
3376  const Element::Type type = GetElement(i)->GetType();
3377  switch (type)
3378  {
3379  case Element::TETRAHEDRON:
3380  mesh_geoms |= (1 << Geometry::TETRAHEDRON);
3381  case Element::TRIANGLE:
3382  mesh_geoms |= (1 << Geometry::TRIANGLE);
3383  case Element::SEGMENT:
3384  mesh_geoms |= (1 << Geometry::SEGMENT);
3385  case Element::POINT:
3386  mesh_geoms |= (1 << Geometry::POINT);
3387  meshgen |= 1;
3388  break;
3389 
3390  case Element::HEXAHEDRON:
3391  mesh_geoms |= (1 << Geometry::CUBE);
3392  case Element::QUADRILATERAL:
3393  mesh_geoms |= (1 << Geometry::SQUARE);
3394  mesh_geoms |= (1 << Geometry::SEGMENT);
3395  mesh_geoms |= (1 << Geometry::POINT);
3396  meshgen |= 2;
3397  break;
3398 
3399  case Element::WEDGE:
3400  mesh_geoms |= (1 << Geometry::PRISM);
3401  mesh_geoms |= (1 << Geometry::SQUARE);
3402  mesh_geoms |= (1 << Geometry::TRIANGLE);
3403  mesh_geoms |= (1 << Geometry::SEGMENT);
3404  mesh_geoms |= (1 << Geometry::POINT);
3405  meshgen |= 4;
3406  break;
3407 
3408  default:
3409  MFEM_ABORT("invalid element type: " << type);
3410  break;
3411  }
3412  }
3413 }
3414 
3415 void Mesh::Loader(std::istream &input, int generate_edges,
3416  std::string parse_tag)
3417 {
3418  int curved = 0, read_gf = 1;
3419  bool finalize_topo = true;
3420 
3421  if (!input)
3422  {
3423  MFEM_ABORT("Input stream is not open");
3424  }
3425 
3426  Clear();
3427 
3428  string mesh_type;
3429  input >> ws;
3430  getline(input, mesh_type);
3431  filter_dos(mesh_type);
3432 
3433  // MFEM's native mesh formats
3434  bool mfem_v10 = (mesh_type == "MFEM mesh v1.0");
3435  bool mfem_v11 = (mesh_type == "MFEM mesh v1.1");
3436  bool mfem_v12 = (mesh_type == "MFEM mesh v1.2");
3437  if (mfem_v10 || mfem_v11 || mfem_v12) // MFEM's own mesh formats
3438  {
3439  // Formats mfem_v12 and newer have a tag indicating the end of the mesh
3440  // section in the stream. A user provided parse tag can also be provided
3441  // via the arguments. For example, if this is called from parallel mesh
3442  // object, it can indicate to read until parallel mesh section begins.
3443  if ( mfem_v12 && parse_tag.empty() )
3444  {
3445  parse_tag = "mfem_mesh_end";
3446  }
3447  ReadMFEMMesh(input, mfem_v11, curved);
3448  }
3449  else if (mesh_type == "linemesh") // 1D mesh
3450  {
3451  ReadLineMesh(input);
3452  }
3453  else if (mesh_type == "areamesh2" || mesh_type == "curved_areamesh2")
3454  {
3455  if (mesh_type == "curved_areamesh2")
3456  {
3457  curved = 1;
3458  }
3459  ReadNetgen2DMesh(input, curved);
3460  }
3461  else if (mesh_type == "NETGEN" || mesh_type == "NETGEN_Neutral_Format")
3462  {
3463  ReadNetgen3DMesh(input);
3464  }
3465  else if (mesh_type == "TrueGrid")
3466  {
3467  ReadTrueGridMesh(input);
3468  }
3469  else if (mesh_type == "# vtk DataFile Version 3.0" ||
3470  mesh_type == "# vtk DataFile Version 2.0") // VTK
3471  {
3472  ReadVTKMesh(input, curved, read_gf, finalize_topo);
3473  }
3474  else if (mesh_type == "MFEM NURBS mesh v1.0")
3475  {
3476  ReadNURBSMesh(input, curved, read_gf);
3477  }
3478  else if (mesh_type == "MFEM INLINE mesh v1.0")
3479  {
3480  ReadInlineMesh(input, generate_edges);
3481  return; // done with inline mesh construction
3482  }
3483  else if (mesh_type == "$MeshFormat") // Gmsh
3484  {
3485  ReadGmshMesh(input, curved, read_gf);
3486  }
3487  else if
3488  ((mesh_type.size() > 2 &&
3489  mesh_type[0] == 'C' && mesh_type[1] == 'D' && mesh_type[2] == 'F') ||
3490  (mesh_type.size() > 3 &&
3491  mesh_type[1] == 'H' && mesh_type[2] == 'D' && mesh_type[3] == 'F'))
3492  {
3493  named_ifgzstream *mesh_input = dynamic_cast<named_ifgzstream *>(&input);
3494  if (mesh_input)
3495  {
3496 #ifdef MFEM_USE_NETCDF
3497  ReadCubit(mesh_input->filename.c_str(), curved, read_gf);
3498 #else
3499  MFEM_ABORT("NetCDF support requires configuration with"
3500  " MFEM_USE_NETCDF=YES");
3501  return;
3502 #endif
3503  }
3504  else
3505  {
3506  MFEM_ABORT("Can not determine Cubit mesh filename!"
3507  " Use mfem::named_ifgzstream for input.");
3508  return;
3509  }
3510  }
3511  else
3512  {
3513  MFEM_ABORT("Unknown input mesh format: " << mesh_type);
3514  return;
3515  }
3516 
3517  // at this point the following should be defined:
3518  // 1) Dim
3519  // 2) NumOfElements, elements
3520  // 3) NumOfBdrElements, boundary
3521  // 4) NumOfVertices, with allocated space in vertices
3522  // 5) curved
3523  // 5a) if curved == 0, vertices must be defined
3524  // 5b) if curved != 0 and read_gf != 0,
3525  // 'input' must point to a GridFunction
3526  // 5c) if curved != 0 and read_gf == 0,
3527  // vertices and Nodes must be defined
3528  // optional:
3529  // 1) el_to_edge may be allocated (as in the case of P2 VTK meshes)
3530  // 2) ncmesh may be allocated
3531 
3532  // FinalizeTopology() will:
3533  // - assume that generate_edges is true
3534  // - assume that refine is false
3535  // - does not check the orientation of regular and boundary elements
3536  if (finalize_topo)
3537  {
3538  FinalizeTopology();
3539  }
3540 
3541  if (curved && read_gf)
3542  {
3543  Nodes = new GridFunction(this, input);
3544  own_nodes = 1;
3545  spaceDim = Nodes->VectorDim();
3546  if (ncmesh) { ncmesh->spaceDim = spaceDim; }
3547  // Set the 'vertices' from the 'Nodes'
3548  for (int i = 0; i < spaceDim; i++)
3549  {
3550  Vector vert_val;
3551  Nodes->GetNodalValues(vert_val, i+1);
3552  for (int j = 0; j < NumOfVertices; j++)
3553  {
3554  vertices[j](i) = vert_val(j);
3555  }
3556  }
3557  }
3558 
3559  // If a parse tag was supplied, keep reading the stream until the tag is
3560  // encountered.
3561  if (mfem_v12)
3562  {
3563  string line;
3564  do
3565  {
3566  skip_comment_lines(input, '#');
3567  MFEM_VERIFY(input.good(), "Required mesh-end tag not found");
3568  getline(input, line);
3569  filter_dos(line);
3570  // mfem v1.2 may not have parse_tag in it, e.g. if trying to read a
3571  // serial mfem v1.2 mesh as parallel with "mfem_serial_mesh_end" as
3572  // parse_tag. That's why, regardless of parse_tag, we stop reading if
3573  // we find "mfem_mesh_end" which is required by mfem v1.2 format.
3574  if (line == "mfem_mesh_end") { break; }
3575  }
3576  while (line != parse_tag);
3577  }
3578 
3579  // Finalize(...) should be called after this, if needed.
3580 }
3581 
3582 Mesh::Mesh(Mesh *mesh_array[], int num_pieces)
3583 {
3584  int i, j, ie, ib, iv, *v, nv;
3585  Element *el;
3586  Mesh *m;
3587 
3588  SetEmpty();
3589 
3590  Dim = mesh_array[0]->Dimension();
3591  spaceDim = mesh_array[0]->SpaceDimension();
3592 
3593  if (mesh_array[0]->NURBSext)
3594  {
3595  // assuming the pieces form a partition of a NURBS mesh
3596  NURBSext = new NURBSExtension(mesh_array, num_pieces);
3597 
3598  NumOfVertices = NURBSext->GetNV();
3599  NumOfElements = NURBSext->GetNE();
3600 
3601  NURBSext->GetElementTopo(elements);
3602 
3603  // NumOfBdrElements = NURBSext->GetNBE();
3604  // NURBSext->GetBdrElementTopo(boundary);
3605 
3606  Array<int> lvert_vert, lelem_elem;
3607 
3608  // Here, for visualization purposes, we copy the boundary elements from
3609  // the individual pieces which include the interior boundaries. This
3610  // creates 'boundary' array that is different from the one generated by
3611  // the NURBSExtension which, in particular, makes the boundary-dof table
3612  // invalid. This, in turn, causes GetBdrElementTransformation to not
3613  // function properly.
3614  NumOfBdrElements = 0;
3615  for (i = 0; i < num_pieces; i++)
3616  {
3617  NumOfBdrElements += mesh_array[i]->GetNBE();
3618  }
3619  boundary.SetSize(NumOfBdrElements);
3620  vertices.SetSize(NumOfVertices);
3621  ib = 0;
3622  for (i = 0; i < num_pieces; i++)
3623  {
3624  m = mesh_array[i];
3625  m->NURBSext->GetVertexLocalToGlobal(lvert_vert);
3626  m->NURBSext->GetElementLocalToGlobal(lelem_elem);
3627  // copy the element attributes
3628  for (j = 0; j < m->GetNE(); j++)
3629  {
3630  elements[lelem_elem[j]]->SetAttribute(m->GetAttribute(j));
3631  }
3632  // copy the boundary
3633  for (j = 0; j < m->GetNBE(); j++)
3634  {
3635  el = m->GetBdrElement(j)->Duplicate(this);
3636  v = el->GetVertices();
3637  nv = el->GetNVertices();
3638  for (int k = 0; k < nv; k++)
3639  {
3640  v[k] = lvert_vert[v[k]];
3641  }
3642  boundary[ib++] = el;
3643  }
3644  // copy the vertices
3645  for (j = 0; j < m->GetNV(); j++)
3646  {
3647  vertices[lvert_vert[j]].SetCoords(m->SpaceDimension(),
3648  m->GetVertex(j));
3649  }
3650  }
3651  }
3652  else // not a NURBS mesh
3653  {
3654  NumOfElements = 0;
3655  NumOfBdrElements = 0;
3656  NumOfVertices = 0;
3657  for (i = 0; i < num_pieces; i++)
3658  {
3659  m = mesh_array[i];
3660  NumOfElements += m->GetNE();
3661  NumOfBdrElements += m->GetNBE();
3662  NumOfVertices += m->GetNV();
3663  }
3664  elements.SetSize(NumOfElements);
3665  boundary.SetSize(NumOfBdrElements);
3666  vertices.SetSize(NumOfVertices);
3667  ie = ib = iv = 0;
3668  for (i = 0; i < num_pieces; i++)
3669  {
3670  m = mesh_array[i];
3671  // copy the elements
3672  for (j = 0; j < m->GetNE(); j++)
3673  {
3674  el = m->GetElement(j)->Duplicate(this);
3675  v = el->GetVertices();
3676  nv = el->GetNVertices();
3677  for (int k = 0; k < nv; k++)
3678  {
3679  v[k] += iv;
3680  }
3681  elements[ie++] = el;
3682  }
3683  // copy the boundary elements
3684  for (j = 0; j < m->GetNBE(); j++)
3685  {
3686  el = m->GetBdrElement(j)->Duplicate(this);
3687  v = el->GetVertices();
3688  nv = el->GetNVertices();
3689  for (int k = 0; k < nv; k++)
3690  {
3691  v[k] += iv;
3692  }
3693  boundary[ib++] = el;
3694  }
3695  // copy the vertices
3696  for (j = 0; j < m->GetNV(); j++)
3697  {
3698  vertices[iv++].SetCoords(m->SpaceDimension(), m->GetVertex(j));
3699  }
3700  }
3701  }
3702 
3703  FinalizeTopology();
3704 
3705  // copy the nodes (curvilinear meshes)
3706  GridFunction *g = mesh_array[0]->GetNodes();
3707  if (g)
3708  {
3709  Array<GridFunction *> gf_array(num_pieces);
3710  for (i = 0; i < num_pieces; i++)
3711  {
3712  gf_array[i] = mesh_array[i]->GetNodes();
3713  }
3714  Nodes = new GridFunction(this, gf_array, num_pieces);
3715  own_nodes = 1;
3716  }
3717 
3718 #ifdef MFEM_DEBUG
3719  CheckElementOrientation(false);
3720  CheckBdrElementOrientation(false);
3721 #endif
3722 }
3723 
3724 Mesh::Mesh(Mesh *orig_mesh, int ref_factor, int ref_type)
3725 {
3726  Dim = orig_mesh->Dimension();
3727  MFEM_VERIFY(ref_factor >= 1, "the refinement factor must be >= 1");
3728  MFEM_VERIFY(ref_type == BasisType::ClosedUniform ||
3729  ref_type == BasisType::GaussLobatto, "invalid refinement type");
3730  MFEM_VERIFY(Dim == 1 || Dim == 2 || Dim == 3,
3731  "only implemented for Segment, Quadrilateral and Hexahedron "
3732  "elements in 1D/2D/3D");
3733  MFEM_VERIFY(orig_mesh->GetNumGeometries(Dim) <= 1,
3734  "meshes with mixed elements are not supported");
3735 
3736  // Construct a scalar H1 FE space of order ref_factor and use its dofs as
3737  // the indices of the new, refined vertices.
3738  H1_FECollection rfec(ref_factor, Dim, ref_type);
3739  FiniteElementSpace rfes(orig_mesh, &rfec);
3740 
3741  int r_bndr_factor = pow(ref_factor, Dim - 1);
3742  int r_elem_factor = ref_factor * r_bndr_factor;
3743 
3744  int r_num_vert = rfes.GetNDofs();
3745  int r_num_elem = orig_mesh->GetNE() * r_elem_factor;
3746  int r_num_bndr = orig_mesh->GetNBE() * r_bndr_factor;
3747 
3748  InitMesh(Dim, orig_mesh->SpaceDimension(), r_num_vert, r_num_elem,
3749  r_num_bndr);
3750 
3751  // Set the number of vertices, set the actual coordinates later
3752  NumOfVertices = r_num_vert;
3753  // Add refined elements and set vertex coordinates
3754  Array<int> rdofs;
3755  DenseMatrix phys_pts;
3756  int max_nv = 0;
3757 
3758  DenseMatrix node_coordinates(spaceDim*pow(2, Dim), r_num_elem);
3759  H1_FECollection vertex_fec(1, Dim);
3760 
3761  for (int el = 0; el < orig_mesh->GetNE(); el++)
3762  {
3763  Geometry::Type geom = orig_mesh->GetElementBaseGeometry(el);
3764  int attrib = orig_mesh->GetAttribute(el);
3765  int nvert = Geometry::NumVerts[geom];
3766  RefinedGeometry &RG = *GlobGeometryRefiner.Refine(geom, ref_factor);
3767 
3768  max_nv = std::max(max_nv, nvert);
3769  rfes.GetElementDofs(el, rdofs);
3770  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
3771  const FiniteElement *rfe = rfes.GetFE(el);
3772  orig_mesh->GetElementTransformation(el)->Transform(rfe->GetNodes(),
3773  phys_pts);
3774  const int *c2h_map = rfec.GetDofMap(geom);
3775  const int *vertex_map = vertex_fec.GetDofMap(geom);
3776  for (int i = 0; i < phys_pts.Width(); i++)
3777  {
3778  vertices[rdofs[i]].SetCoords(spaceDim, phys_pts.GetColumn(i));
3779  }
3780  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
3781  {
3782  Element *elem = NewElement(geom);
3783  elem->SetAttribute(attrib);
3784  int *v = elem->GetVertices();
3785  for (int k = 0; k < nvert; k++)
3786  {
3787  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
3788  v[k] = rdofs[c2h_map[cid]];
3789  }
3790  for (int k = 0; k < nvert; k++)
3791  {
3792  for (int j = 0; j < spaceDim; ++j)
3793  {
3794  node_coordinates(k*spaceDim + j, NumOfElements)
3795  = vertices[v[vertex_map[k]]](j);
3796  }
3797  }
3798  AddElement(elem);
3799  }
3800  }
3801 
3802  if (orig_mesh->GetNodes())
3803  {
3804  L2_FECollection fec_dg(1, Dim, BasisType::GaussLobatto);
3805  FiniteElementSpace fes_dg(this, &fec_dg, spaceDim, 1);
3806  GridFunction nodes_dg(&fes_dg, node_coordinates.Data());
3807  bool discont = orig_mesh->GetNodalFESpace()->IsDGSpace();
3808  Ordering::Type dof_ordering = orig_mesh->GetNodalFESpace()->GetOrdering();
3809  SetCurvature(1, discont, spaceDim, dof_ordering);
3810  Nodes->ProjectGridFunction(nodes_dg);
3811  }
3812 
3813  // Add refined boundary elements
3814  for (int el = 0; el < orig_mesh->GetNBE(); el++)
3815  {
3817  int attrib = orig_mesh->GetBdrAttribute(el);
3818  int nvert = Geometry::NumVerts[geom];
3819  RefinedGeometry &RG = *GlobGeometryRefiner.Refine(geom, ref_factor);
3820 
3821  rfes.GetBdrElementDofs(el, rdofs);
3822  MFEM_ASSERT(rdofs.Size() == RG.RefPts.Size(), "");
3823  if (Dim == 1)
3824  {
3825  // Dim == 1 is a special case because the boundary elements are
3826  // zero-dimensional points, and therefore don't have a DofMap
3827  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
3828  {
3829  Element *elem = NewElement(geom);
3830  elem->SetAttribute(attrib);
3831  int *v = elem->GetVertices();
3832  v[0] = rdofs[RG.RefGeoms[nvert*j]];
3833  AddBdrElement(elem);
3834  }
3835  }
3836  else
3837  {
3838  const int *c2h_map = rfec.GetDofMap(geom);
3839  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
3840  {
3841  Element *elem = NewElement(geom);
3842  elem->SetAttribute(attrib);
3843  int *v = elem->GetVertices();
3844  for (int k = 0; k < nvert; k++)
3845  {
3846  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
3847  v[k] = rdofs[c2h_map[cid]];
3848  }
3849  AddBdrElement(elem);
3850  }
3851  }
3852  }
3853 
3854  FinalizeTopology(false);
3855  sequence = orig_mesh->GetSequence() + 1;
3856  last_operation = Mesh::REFINE;
3857 
3858  // Setup the data for the coarse-fine refinement transformations
3859  CoarseFineTr.embeddings.SetSize(GetNE());
3860  if (orig_mesh->GetNE() > 0)
3861  {
3862  const int el = 0;
3863  Geometry::Type geom = orig_mesh->GetElementBaseGeometry(el);
3864  CoarseFineTr.point_matrices[geom].SetSize(Dim, max_nv, r_elem_factor);
3865  int nvert = Geometry::NumVerts[geom];
3866  RefinedGeometry &RG = *GlobGeometryRefiner.Refine(geom, ref_factor);
3867  const int *c2h_map = rfec.GetDofMap(geom);
3868  const IntegrationRule &r_nodes = rfes.GetFE(el)->GetNodes();
3869  for (int j = 0; j < RG.RefGeoms.Size()/nvert; j++)
3870  {
3871  DenseMatrix &Pj = CoarseFineTr.point_matrices[geom](j);
3872  for (int k = 0; k < nvert; k++)
3873  {
3874  int cid = RG.RefGeoms[k+nvert*j]; // local Cartesian index
3875  const IntegrationPoint &ip = r_nodes.IntPoint(c2h_map[cid]);
3876  ip.Get(Pj.GetColumn(k), Dim);
3877  }
3878  }
3879  }
3880  for (int el = 0; el < GetNE(); el++)
3881  {
3882  Embedding &emb = CoarseFineTr.embeddings[el];
3883  emb.parent = el / r_elem_factor;
3884  emb.matrix = el % r_elem_factor;
3885  }
3886 
3887  MFEM_ASSERT(CheckElementOrientation(false) == 0, "");
3888  MFEM_ASSERT(CheckBdrElementOrientation(false) == 0, "");
3889 }
3890 
3891 void Mesh::KnotInsert(Array<KnotVector *> &kv)
3892 {
3893  if (NURBSext == NULL)
3894  {
3895  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
3896  }
3897 
3898  if (kv.Size() != NURBSext->GetNKV())
3899  {
3900  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
3901  }
3902 
3903  NURBSext->ConvertToPatches(*Nodes);
3904 
3905  NURBSext->KnotInsert(kv);
3906 
3907  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
3908  sequence++;
3909 
3910  UpdateNURBS();
3911 }
3912 
3913 void Mesh::KnotInsert(Array<Vector *> &kv)
3914 {
3915  if (NURBSext == NULL)
3916  {
3917  mfem_error("Mesh::KnotInsert : Not a NURBS mesh!");
3918  }
3919 
3920  if (kv.Size() != NURBSext->GetNKV())
3921  {
3922  mfem_error("Mesh::KnotInsert : KnotVector array size mismatch!");
3923  }
3924 
3925  NURBSext->ConvertToPatches(*Nodes);
3926 
3927  NURBSext->KnotInsert(kv);
3928 
3929  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
3930  sequence++;
3931 
3932  UpdateNURBS();
3933 }
3934 
3935 void Mesh::NURBSUniformRefinement()
3936 {
3937  // do not check for NURBSext since this method is protected
3938  NURBSext->ConvertToPatches(*Nodes);
3939 
3940  NURBSext->UniformRefinement();
3941 
3942  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
3943  sequence++;
3944 
3945  UpdateNURBS();
3946 }
3947 
3948 void Mesh::DegreeElevate(int rel_degree, int degree)
3949 {
3950  if (NURBSext == NULL)
3951  {
3952  mfem_error("Mesh::DegreeElevate : Not a NURBS mesh!");
3953  }
3954 
3955  NURBSext->ConvertToPatches(*Nodes);
3956 
3957  NURBSext->DegreeElevate(rel_degree, degree);
3958 
3959  last_operation = Mesh::NONE; // FiniteElementSpace::Update is not supported
3960  sequence++;
3961 
3962  UpdateNURBS();
3963 }
3964 
3965 void Mesh::UpdateNURBS()
3966 {
3967  ResetLazyData();
3968 
3969  NURBSext->SetKnotsFromPatches();
3970 
3971  Dim = NURBSext->Dimension();
3972  spaceDim = Dim;
3973 
3974  if (NumOfElements != NURBSext->GetNE())
3975  {
3976  for (int i = 0; i < elements.Size(); i++)
3977  {
3978  FreeElement(elements[i]);
3979  }
3980  NumOfElements = NURBSext->GetNE();
3981  NURBSext->GetElementTopo(elements);
3982  }
3983 
3984  if (NumOfBdrElements != NURBSext->GetNBE())
3985  {
3986  for (int i = 0; i < boundary.Size(); i++)
3987  {
3988  FreeElement(boundary[i]);
3989  }
3990  NumOfBdrElements = NURBSext->GetNBE();
3991  NURBSext->GetBdrElementTopo(boundary);
3992  }
3993 
3994  Nodes->FESpace()->Update();
3995  Nodes->Update();
3996  NURBSext->SetCoordsFromPatches(*Nodes);
3997 
3998  if (NumOfVertices != NURBSext->GetNV())
3999  {
4000  NumOfVertices = NURBSext->GetNV();
4001  vertices.SetSize(NumOfVertices);
4002  int vd = Nodes->VectorDim();
4003  for (int i = 0; i < vd; i++)
4004  {
4005  Vector vert_val;
4006  Nodes->GetNodalValues(vert_val, i+1);
4007  for (int j = 0; j < NumOfVertices; j++)
4008  {
4009  vertices[j](i) = vert_val(j);
4010  }
4011  }
4012  }
4013 
4014  if (el_to_edge)
4015  {
4016  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
4017  if (Dim == 2)
4018  {
4019  GenerateFaces();
4020  }
4021  }
4022 
4023  if (el_to_face)
4024  {
4025  GetElementToFaceTable();
4026  GenerateFaces();
4027  }
4028 }
4029 
4030 void Mesh::LoadPatchTopo(std::istream &input, Array<int> &edge_to_knot)
4031 {
4032  SetEmpty();
4033 
4034  // Read MFEM NURBS mesh v1.0 format
4035  string ident;
4036 
4037  skip_comment_lines(input, '#');
4038 
4039  input >> ident; // 'dimension'
4040  input >> Dim;
4041  spaceDim = Dim;
4042 
4043  skip_comment_lines(input, '#');
4044 
4045  input >> ident; // 'elements'
4046  input >> NumOfElements;
4047  elements.SetSize(NumOfElements);
4048  for (int j = 0; j < NumOfElements; j++)
4049  {
4050  elements[j] = ReadElement(input);
4051  }
4052 
4053  skip_comment_lines(input, '#');
4054 
4055  input >> ident; // 'boundary'
4056  input >> NumOfBdrElements;
4057  boundary.SetSize(NumOfBdrElements);
4058  for (int j = 0; j < NumOfBdrElements; j++)
4059  {
4060  boundary[j] = ReadElement(input);
4061  }
4062 
4063  skip_comment_lines(input, '#');
4064 
4065  input >> ident; // 'edges'
4066  input >> NumOfEdges;
4067  edge_vertex = new Table(NumOfEdges, 2);
4068  edge_to_knot.SetSize(NumOfEdges);
4069  for (int j = 0; j < NumOfEdges; j++)
4070  {
4071  int *v = edge_vertex->GetRow(j);
4072  input >> edge_to_knot[j] >> v[0] >> v[1];
4073  if (v[0] > v[1])
4074  {
4075  edge_to_knot[j] = -1 - edge_to_knot[j];
4076  }
4077  }
4078 
4079  skip_comment_lines(input, '#');
4080 
4081  input >> ident; // 'vertices'
4082  input >> NumOfVertices;
4083  vertices.SetSize(0);
4084 
4085  FinalizeTopology();
4086  CheckBdrElementOrientation(); // check and fix boundary element orientation
4087 }
4088 
4090 {
4091  if (p.Size() >= v.Size())
4092  {
4093  for (int d = 0; d < v.Size(); d++)
4094  {
4095  v(d) = p(d);
4096  }
4097  }
4098  else
4099  {
4100  int d;
4101  for (d = 0; d < p.Size(); d++)
4102  {
4103  v(d) = p(d);
4104  }
4105  for ( ; d < v.Size(); d++)
4106  {
4107  v(d) = 0.0;
4108  }
4109  }
4110 }
4111 
4112 void Mesh::GetNodes(GridFunction &nodes) const
4113 {
4114  if (Nodes == NULL || Nodes->FESpace() != nodes.FESpace())
4115  {
4116  const int newSpaceDim = nodes.FESpace()->GetVDim();
4118  nodes.ProjectCoefficient(xyz);
4119  }
4120  else
4121  {
4122  nodes = *Nodes;
4123  }
4124 }
4125 
4126 void Mesh::SetNodalFESpace(FiniteElementSpace *nfes)
4127 {
4128  GridFunction *nodes = new GridFunction(nfes);
4129  SetNodalGridFunction(nodes, true);
4130 }
4131 
4132 void Mesh::EnsureNodes()
4133 {
4134  if (Nodes)
4135  {
4136  const FiniteElementCollection *fec = GetNodalFESpace()->FEColl();
4137  if (dynamic_cast<const H1_FECollection*>(fec)
4138  || dynamic_cast<const L2_FECollection*>(fec))
4139  {
4140  return;
4141  }
4142  else // Mesh using a legacy FE_Collection
4143  {
4144  const int order = GetNodalFESpace()->GetOrder(0);
4145  SetCurvature(order, false, -1, Ordering::byVDIM);
4146  }
4147  }
4148  else // First order H1 mesh
4149  {
4150  SetCurvature(1, false, -1, Ordering::byVDIM);
4151  }
4152 }
4153 
4154 void Mesh::SetNodalGridFunction(GridFunction *nodes, bool make_owner)
4155 {
4156  GetNodes(*nodes);
4157  NewNodes(*nodes, make_owner);
4158 }
4159 
4160 const FiniteElementSpace *Mesh::GetNodalFESpace() const
4161 {
4162  return ((Nodes) ? Nodes->FESpace() : NULL);
4163 }
4164 
4165 void Mesh::SetCurvature(int order, bool discont, int space_dim, int ordering)
4166 {
4167  space_dim = (space_dim == -1) ? spaceDim : space_dim;
4169  if (discont)
4170  {
4171  const int type = 1; // Gauss-Lobatto points
4172  nfec = new L2_FECollection(order, Dim, type);
4173  }
4174  else
4175  {
4176  nfec = new H1_FECollection(order, Dim);
4177  }
4178  FiniteElementSpace* nfes = new FiniteElementSpace(this, nfec, space_dim,
4179  ordering);
4180  SetNodalFESpace(nfes);
4181  Nodes->MakeOwner(nfec);
4182 }
4183 
4184 int Mesh::GetNumFaces() const
4185 {
4186  switch (Dim)
4187  {
4188  case 1: return GetNV();
4189  case 2: return GetNEdges();
4190  case 3: return GetNFaces();
4191  }
4192  return 0;
4193 }
4194 
4195 static int CountFacesByType(const Mesh &mesh, const FaceType type)
4196 {
4197  int e1, e2;
4198  int inf1, inf2;
4199  int nf = 0;
4200  for (int f = 0; f < mesh.GetNumFaces(); ++f)
4201  {
4202  mesh.GetFaceElements(f, &e1, &e2);
4203  mesh.GetFaceInfos(f, &inf1, &inf2);
4204  if ((type==FaceType::Interior && (e2>=0 || (e2<0 && inf2>=0))) ||
4205  (type==FaceType::Boundary && e2<0 && inf2<0) ) { nf++; }
4206  }
4207  return nf;
4208 }
4209 
4210 int Mesh::GetNFbyType(FaceType type) const
4211 {
4212  const bool isInt = type==FaceType::Interior;
4213  int &nf = isInt ? nbInteriorFaces : nbBoundaryFaces;
4214  if (nf<0) { nf = CountFacesByType(*this, type); }
4215  return nf;
4216 }
4217 
4218 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
4219 static const char *fixed_or_not[] = { "fixed", "NOT FIXED" };
4220 #endif
4221 
4222 int Mesh::CheckElementOrientation(bool fix_it)
4223 {
4224  int i, j, k, wo = 0, fo = 0, *vi = 0;
4225  double *v[4];
4226 
4227  if (Dim == 2 && spaceDim == 2)
4228  {
4229  DenseMatrix J(2, 2);
4230 
4231  for (i = 0; i < NumOfElements; i++)
4232  {
4233  if (Nodes == NULL)
4234  {
4235  vi = elements[i]->GetVertices();
4236  for (j = 0; j < 3; j++)
4237  {
4238  v[j] = vertices[vi[j]]();
4239  }
4240  for (j = 0; j < 2; j++)
4241  for (k = 0; k < 2; k++)
4242  {
4243  J(j, k) = v[j+1][k] - v[0][k];
4244  }
4245  }
4246  else
4247  {
4248  // only check the Jacobian at the center of the element
4249  GetElementJacobian(i, J);
4250  }
4251  if (J.Det() < 0.0)
4252  {
4253  if (fix_it)
4254  {
4255  switch (GetElementType(i))
4256  {
4257  case Element::TRIANGLE:
4258  mfem::Swap(vi[0], vi[1]);
4259  break;
4260  case Element::QUADRILATERAL:
4261  mfem::Swap(vi[1], vi[3]);
4262  break;
4263  default:
4264  MFEM_ABORT("Invalid 2D element type \""
4265  << GetElementType(i) << "\"");
4266  break;
4267  }
4268  fo++;
4269  }
4270  wo++;
4271  }
4272  }
4273  }
4274 
4275  if (Dim == 3)
4276  {
4277  DenseMatrix J(3, 3);
4278 
4279  for (i = 0; i < NumOfElements; i++)
4280  {
4281  vi = elements[i]->GetVertices();
4282  switch (GetElementType(i))
4283  {
4284  case Element::TETRAHEDRON:
4285  if (Nodes == NULL)
4286  {
4287  for (j = 0; j < 4; j++)
4288  {
4289  v[j] = vertices[vi[j]]();
4290  }
4291  for (j = 0; j < 3; j++)
4292  for (k = 0; k < 3; k++)
4293  {
4294  J(j, k) = v[j+1][k] - v[0][k];
4295  }
4296  }
4297  else
4298  {
4299  // only check the Jacobian at the center of the element
4300  GetElementJacobian(i, J);
4301  }
4302  if (J.Det() < 0.0)
4303  {
4304  wo++;
4305  if (fix_it)
4306  {
4307  mfem::Swap(vi[0], vi[1]);
4308  fo++;
4309  }
4310  }
4311  break;
4312 
4313  case Element::WEDGE:
4314  // only check the Jacobian at the center of the element
4315  GetElementJacobian(i, J);
4316  if (J.Det() < 0.0)
4317  {
4318  wo++;
4319  if (fix_it)
4320  {
4321  // how?
4322  }
4323  }
4324  break;
4325 
4326  case Element::HEXAHEDRON:
4327  // only check the Jacobian at the center of the element
4328  GetElementJacobian(i, J);
4329  if (J.Det() < 0.0)
4330  {
4331  wo++;
4332  if (fix_it)
4333  {
4334  // how?
4335  }
4336  }
4337  break;
4338 
4339  default:
4340  MFEM_ABORT("Invalid 3D element type \""
4341  << GetElementType(i) << "\"");
4342  break;
4343  }
4344  }
4345  }
4346 #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
4347  if (wo > 0)
4348  {
4349  mfem::out << "Elements with wrong orientation: " << wo << " / "
4350  << NumOfElements << " (" << fixed_or_not[(wo == fo) ? 0 : 1]
4351  << ")" << endl;
4352  }
4353 #endif
4354  return wo;
4355 }
4356 
4357 int Mesh::GetTriOrientation(const int *base, const int *test)
4358 {
4359  // Static method.
4360  // This function computes the index 'j' of the permutation that transforms
4361  // test into base: test[tri_orientation[j][i]]=base[i].
4362  // tri_orientation = Geometry::Constants<Geometry::TRIANGLE>::Orient
4363  int orient;
4364 
4365  if (test[0] == base[0])
4366  if (test[1] == base[1])
4367  {
4368  orient = 0; // (0, 1, 2)
4369  }
4370  else
4371  {
4372  orient = 5; // (0, 2, 1)
4373  }
4374  else if (test[0] == base[1])
4375  if (test[1] == base[0])
4376  {
4377  orient = 1; // (1, 0, 2)
4378  }
4379  else
4380  {
4381  orient = 2; // (1, 2, 0)
4382  }
4383  else // test[0] == base[2]
4384  if (test[1] == base[0])
4385  {
4386  orient = 4; // (2, 0, 1)
4387  }
4388  else
4389  {
4390  orient = 3; // (2, 1, 0)
4391  }
4392 
4393 #ifdef MFEM_DEBUG
4394  const int *aor = tri_t::Orient[orient];
4395  for (int j = 0; j < 3; j++)
4396  if (test[aor[j]] != base[j])
4397  {
4398  mfem_error("Mesh::GetTriOrientation(...)");
4399  }
4400 #endif
4401 
4402  return orient;
4403 }
4404 
4405 int Mesh::GetQuadOrientation(const int *base, const int *test)
4406 {
4407  int i;
4408 
4409  for (i = 0; i < 4; i++)
4410  if (test[i] == base[0])
4411  {
4412  break;
4413  }
4414 
4415 #ifdef MFEM_DEBUG
4416  int orient;
4417  if (test[(i+1)%4] == base[1])
4418  {
4419  orient = 2*i;
4420  }
4421  else
4422  {
4423  orient = 2*i+1;
4424  }
4425  const int *aor = quad_t::Orient[orient];
4426  for (int j = 0; j < 4; j++)
4427  if (test[aor[j]] != base[j])
4428  {
4429  mfem::err << "Mesh::GetQuadOrientation(...)" << endl;
4430  mfem::err << " base = [";
4431  for (int k = 0; k < 4; k++)
4432  {
4433  mfem::err << " " << base[k];
4434  }
4435  mfem::err << " ]\n test = [";
4436  for (int k = 0; k < 4; k++)
4437  {
4438  mfem::err << " " << test[k];
4439  }
4440  mfem::err << " ]" << endl;
4441  mfem_error();
4442  }
4443 #endif
4444 
4445  if (test[(i+1)%4] == base[1])
4446  {
4447  return 2*i;
4448  }
4449 
4450  return 2*i+1;
4451 }
4452 
4453 int Mesh::GetTetOrientation(const int *base, const int *test)
4454 {
4455  // Static method.
4456  // This function computes the index 'j' of the permutation that transforms
4457  // test into base: test[tet_orientation[j][i]]=base[i].
4458  // tet_orientation = Geometry::Constants<Geometry::TETRAHEDRON>::Orient
4459  int orient;
4460 
4461  if (test[0] == base[0])
4462  if (test[1] == base[1])
4463  if (test[2] == base[2])
4464  {
4465  orient = 0; // (0, 1, 2, 3)
4466  }
4467  else
4468  {
4469  orient = 1; // (0, 1, 3, 2)
4470  }
4471  else if (test[2] == base[1])
4472  if (test[3] == base[2])
4473  {
4474  orient = 2; // (0, 2, 3, 1)
4475  }
4476  else
4477  {
4478  orient = 3; // (0, 2, 1, 3)
4479  }
4480  else // test[3] == base[1]
4481  if (test[1] == base[2])
4482  {
4483  orient = 4; // (0, 3, 1, 2)
4484  }
4485  else
4486  {
4487  orient = 5; // (0, 3, 2, 1)
4488  }
4489  else if (test[1] == base[0])
4490  if (test[2] == base[1])
4491  if (test[0] == base[2])
4492  {
4493  orient = 6; // (1, 2, 0, 3)
4494  }
4495  else
4496  {
4497  orient = 7; // (1, 2, 3, 0)
4498  }
4499  else if (test[3] == base[1])
4500  if (test[2] == base[2])
4501  {
4502  orient = 8; // (1, 3, 2, 0)
4503  }
4504  else
4505  {
4506  orient = 9; // (1, 3, 0, 2)
4507  }
4508  else // test[0] == base[1]
4509  if (test[3] == base[2])
4510  {
4511  orient = 10; // (1, 0, 3, 2)
4512  }
4513  else
4514  {
4515  orient = 11; // (1, 0, 2, 3)
4516  }
4517  else if (test[2] == base[0])
4518  if (test[3] == base[1])
4519  if (test[0] == base[2])
4520  {
4521  orient = 12; // (2, 3, 0, 1)
4522  }
4523  else
4524  {
4525  orient = 13; // (2, 3, 1, 0)
4526  }
4527  else if (test[0] == base[1])
4528  if (test[1] == base[2])
4529  {
4530  orient = 14; // (2, 0, 1, 3)
4531  }
4532  else
4533  {
4534  orient = 15; // (2, 0, 3, 1)
4535  }
4536  else // test[1] == base[1]
4537  if (test[3] == base[2])
4538  {
4539  orient = 16; // (2, 1, 3, 0)
4540  }
4541  else
4542  {
4543  orient = 17; // (2, 1, 0, 3)
4544  }
4545  else // (test[3] == base[0])
4546  if (test[0] == base[1])
4547  if (test[2] == base[2])
4548  {
4549  orient = 18; // (3, 0, 2, 1)
4550  }
4551  else
4552  {
4553  orient = 19; // (3, 0, 1, 2)
4554  }
4555  else if (test[1] == base[1])
4556  if (test[0] == base[2])
4557  {
4558  orient = 20; // (3, 1, 0, 2)
4559  }
4560  else
4561  {
4562  orient = 21; // (3, 1, 2, 0)
4563  }
4564  else // test[2] == base[1]
4565  if (test[1] == base[2])
4566  {
4567  orient = 22; // (3, 2, 1, 0)
4568  }
4569  else
4570  {
4571  orient = 23; // (3, 2, 0, 1)
4572  }
4573 
4574 #ifdef MFEM_DEBUG
4575  const int *aor = tet_t::Orient[orient];
4576  for (int j = 0; j < 4; j++)
4577  if (test[aor[j]] != base[j])
4578  {
4579  mfem_error("Mesh::GetTetOrientation(...)");
4580  }
4581 #endif
4582 
4583  return orient;
4584 }
4585 
4586 int Mesh::CheckBdrElementOrientation(bool fix_it)
4587 {
4588  int wo = 0; // count wrong orientations
4589 
4590  if (Dim == 2)
4591  {
4592  if (el_to_edge == NULL) // edges were not generated
4593  {
4594  el_to_edge = new Table;
4595  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
4596  GenerateFaces(); // 'Faces' in 2D refers to the edges
4597  }
4598  for (int i = 0; i < NumOfBdrElements; i++)
4599  {
4600  if (faces_info[be_to_edge[i]].Elem2No < 0) // boundary face
4601  {
4602  int *bv = boundary[i]->GetVertices();
4603  int *fv = faces[be_to_edge[i]]->GetVertices();
4604  if (bv[0] != fv[0])
4605  {
4606  if (fix_it)
4607  {
4608  mfem::Swap<int>(bv[0], bv[1]);
4609  }
4610  wo++;
4611  }
4612  }
4613  }
4614  }
4615 
4616  if (Dim == 3)
4617  {
4618  for (int i = 0; i < NumOfBdrElements; i++)
4619  {
4620  const int fi = be_to_face[i];
4621 
4622  if (faces_info[fi].Elem2No >= 0) { continue; }
4623 
4624  // boundary face
4625  int *bv = boundary[i]->GetVertices();
4626  // Make sure the 'faces' are generated:
4627  MFEM_ASSERT(fi < faces.Size(), "internal error");
4628  const int *fv = faces[fi]->GetVertices();
4629  int orientation; // orientation of the bdr. elem. w.r.t. the
4630  // corresponding face element (that's the base)
4631  const Element::Type bdr_type = GetBdrElementType(i);
4632  switch (bdr_type)
4633  {
4634  case Element::TRIANGLE:
4635  {
4636  orientation = GetTriOrientation(fv, bv);
4637  break;
4638  }
4639  case Element::QUADRILATERAL:
4640  {
4641  orientation = GetQuadOrientation(fv, bv);
4642  break;
4643  }
4644  default:
4645  MFEM_ABORT("Invalid 2D boundary element type \""
4646  << bdr_type << "\"");
4647  orientation = 0; // suppress a warning
4648  break;
4649  }
4650 
4651  if (orientation % 2 == 0) { continue; }
4652  wo++;
4653  if (!fix_it) { continue; }
4654 
4655  switch (bdr_type)
4656  {
4657  case Element::TRIANGLE:
4658  {
4659  // swap vertices 0 and 1 so that we don't change the marked edge:
4660  // (0,1,2) -> (1,0,2)
4661  mfem::Swap<int>(bv[0], bv[1]);
4662  if (bel_to_edge)
4663  {
4664  int *be = bel_to_edge->GetRow(i);
4665  mfem::Swap<int>(be[1], be[2]);
4666  }
4667  break;
4668  }
4669  case Element::QUADRILATERAL:
4670  {
4671  mfem::Swap<int>(bv[0], bv[2]);
4672  if (bel_to_edge)
4673  {
4674  int *be = bel_to_edge->GetRow(i);
4675  mfem::Swap<int>(be[0], be[1]);
4676  mfem::Swap<int>(be[2], be[3]);
4677  }
4678  break;
4679  }
4680  default: // unreachable
4681  break;
4682  }
4683  }
4684  }
4685  // #if (!defined(MFEM_USE_MPI) || defined(MFEM_DEBUG))
4686 #ifdef MFEM_DEBUG
4687  if (wo > 0)
4688  {
4689  mfem::out << "Boundary elements with wrong orientation: " << wo << " / "
4690  << NumOfBdrElements << " (" << fixed_or_not[fix_it ? 0 : 1]
4691  << ")" << endl;
4692  }
4693 #endif
4694  return wo;
4695 }
4696 
4697 int Mesh::GetNumGeometries(int dim) const
4698 {
4699  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
4700  int num_geoms = 0;
4701  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
4702  {
4703  if (HasGeometry(Geometry::Type(g))) { num_geoms++; }
4704  }
4705  return num_geoms;
4706 }
4707 
4708 void Mesh::GetGeometries(int dim, Array<Geometry::Type> &el_geoms) const
4709 {
4710  MFEM_ASSERT(0 <= dim && dim <= Dim, "invalid dim: " << dim);
4711  el_geoms.SetSize(0);
4712  for (int g = Geometry::DimStart[dim]; g < Geometry::DimStart[dim+1]; g++)
4713  {
4714  if (HasGeometry(Geometry::Type(g)))
4715  {
4716  el_geoms.Append(Geometry::Type(g));
4717  }
4718  }
4719 }
4720 
4721 void Mesh::GetElementEdges(int i, Array<int> &edges, Array<int> &cor) const
4722 {
4723  if (el_to_edge)
4724  {
4725  el_to_edge->GetRow(i, edges);
4726  }
4727  else
4728  {
4729  mfem_error("Mesh::GetElementEdges(...) element to edge table "
4730  "is not generated.");
4731  }
4732 
4733  const int *v = elements[i]->GetVertices();
4734  const int ne = elements[i]->GetNEdges();
4735  cor.SetSize(ne);
4736  for (int j = 0; j < ne; j++)
4737  {
4738  const int *e = elements[i]->GetEdgeVertices(j);
4739  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
4740  }
4741 }
4742 
4743 void Mesh::GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const
4744 {
4745  if (Dim == 2)
4746  {
4747  edges.SetSize(1);
4748  cor.SetSize(1);
4749  edges[0] = be_to_edge[i];
4750  const int *v = boundary[i]->GetVertices();
4751  cor[0] = (v[0] < v[1]) ? (1) : (-1);
4752  }
4753  else if (Dim == 3)
4754  {
4755  if (bel_to_edge)
4756  {
4757  bel_to_edge->GetRow(i, edges);
4758  }
4759  else
4760  {
4761  mfem_error("Mesh::GetBdrElementEdges(...)");
4762  }
4763 
4764  const int *v = boundary[i]->GetVertices();
4765  const int ne = boundary[i]->GetNEdges();
4766  cor.SetSize(ne);
4767  for (int j = 0; j < ne; j++)
4768  {
4769  const int *e = boundary[i]->GetEdgeVertices(j);
4770  cor[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
4771  }
4772  }
4773 }
4774 
4775 void Mesh::GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const
4776 {
4777  if (Dim == 2)
4778  {
4779  edges.SetSize(1);
4780  edges[0] = i;
4781  o.SetSize(1);
4782  const int *v = faces[i]->GetVertices();
4783  o[0] = (v[0] < v[1]) ? (1) : (-1);
4784  }
4785 
4786  if (Dim != 3)
4787  {
4788  return;
4789  }
4790 
4791  GetFaceEdgeTable(); // generate face_edge Table (if not generated)
4792 
4793  face_edge->GetRow(i, edges);
4794 
4795  const int *v = faces[i]->GetVertices();
4796  const int ne = faces[i]->GetNEdges();
4797  o.SetSize(ne);
4798  for (int j = 0; j < ne; j++)
4799  {
4800  const int *e = faces[i]->GetEdgeVertices(j);
4801  o[j] = (v[e[0]] < v[e[1]]) ? (1) : (-1);
4802  }
4803 }
4804 
4805 void Mesh::GetEdgeVertices(int i, Array<int> &vert) const
4806 {
4807  // the two vertices are sorted: vert[0] < vert[1]
4808  // this is consistent with the global edge orientation
4809  // generate edge_vertex Table (if not generated)
4810  if (!edge_vertex) { GetEdgeVertexTable(); }
4811  edge_vertex->GetRow(i, vert);
4812 }
4813 
4814 Table *Mesh::GetFaceEdgeTable() const
4815 {
4816  if (face_edge)
4817  {
4818  return face_edge;
4819  }
4820 
4821  if (Dim != 3)
4822  {
4823  return NULL;
4824  }
4825 
4826 #ifdef MFEM_DEBUG
4827  if (faces.Size() != NumOfFaces)
4828  {
4829  mfem_error("Mesh::GetFaceEdgeTable : faces were not generated!");
4830  }
4831 #endif
4832 
4833  DSTable v_to_v(NumOfVertices);
4834  GetVertexToVertexTable(v_to_v);
4835 
4836  face_edge = new Table;
4837  GetElementArrayEdgeTable(faces, v_to_v, *face_edge);
4838 
4839  return (face_edge);
4840 }
4841 
4842 Table *Mesh::GetEdgeVertexTable() const
4843 {
4844  if (edge_vertex)
4845  {
4846  return edge_vertex;
4847  }
4848 
4849  DSTable v_to_v(NumOfVertices);
4850  GetVertexToVertexTable(v_to_v);
4851 
4852  int nedges = v_to_v.NumberOfEntries();
4853  edge_vertex = new Table(nedges, 2);
4854  for (int i = 0; i < NumOfVertices; i++)
4855  {
4856  for (DSTable::RowIterator it(v_to_v, i); !it; ++it)
4857  {
4858  int j = it.Index();
4859  edge_vertex->Push(j, i);
4860  edge_vertex->Push(j, it.Column());
4861  }
4862  }
4863  edge_vertex->Finalize();
4864 
4865  return edge_vertex;
4866 }
4867 
4868 Table *Mesh::GetVertexToElementTable()
4869 {
4870  int i, j, nv, *v;
4871 
4872  Table *vert_elem = new Table;
4873 
4874  vert_elem->MakeI(NumOfVertices);
4875 
4876  for (i = 0; i < NumOfElements; i++)
4877  {
4878  nv = elements[i]->GetNVertices();
4879  v = elements[i]->GetVertices();
4880  for (j = 0; j < nv; j++)
4881  {
4882  vert_elem->AddAColumnInRow(v[j]);
4883  }
4884  }
4885 
4886  vert_elem->MakeJ();
4887 
4888  for (i = 0; i < NumOfElements; i++)
4889  {
4890  nv = elements[i]->GetNVertices();
4891  v = elements[i]->GetVertices();
4892  for (j = 0; j < nv; j++)
4893  {
4894  vert_elem->AddConnection(v[j], i);
4895  }
4896  }
4897 
4898  vert_elem->ShiftUpI();
4899 
4900  return vert_elem;
4901 }
4902 
4903 Table *Mesh::GetFaceToElementTable() const
4904 {
4905  Table *face_elem = new Table;
4906 
4907  face_elem->MakeI(faces_info.Size());
4908 
4909  for (int i = 0; i < faces_info.Size(); i++)
4910  {
4911  if (faces_info[i].Elem2No >= 0)
4912  {
4913  face_elem->AddColumnsInRow(i, 2);
4914  }
4915  else
4916  {
4917  face_elem->AddAColumnInRow(i);
4918  }
4919  }
4920 
4921  face_elem->MakeJ();
4922 
4923  for (int i = 0; i < faces_info.Size(); i++)
4924  {
4925  face_elem->AddConnection(i, faces_info[i].Elem1No);
4926  if (faces_info[i].Elem2No >= 0)
4927  {
4928  face_elem->AddConnection(i, faces_info[i].Elem2No);
4929  }
4930  }
4931 
4932  face_elem->ShiftUpI();
4933 
4934  return face_elem;
4935 }
4936 
4937 void Mesh::GetElementFaces(int i, Array<int> &fcs, Array<int> &cor)
4938 const
4939 {
4940  int n, j;
4941 
4942  if (el_to_face)
4943  {
4944  el_to_face->GetRow(i, fcs);
4945  }
4946  else
4947  {
4948  mfem_error("Mesh::GetElementFaces(...) : el_to_face not generated.");
4949  }
4950 
4951  n = fcs.Size();
4952  cor.SetSize(n);
4953  for (j = 0; j < n; j++)
4954  if (faces_info[fcs[j]].Elem1No == i)
4955  {
4956  cor[j] = faces_info[fcs[j]].Elem1Inf % 64;
4957  }
4958 #ifdef MFEM_DEBUG
4959  else if (faces_info[fcs[j]].Elem2No == i)
4960  {
4961  cor[j] = faces_info[fcs[j]].Elem2Inf % 64;
4962  }
4963  else
4964  {
4965  mfem_error("Mesh::GetElementFaces(...) : 2");
4966  }
4967 #else
4968  else
4969  {
4970  cor[j] = faces_info[fcs[j]].Elem2Inf % 64;
4971  }
4972 #endif
4973 }
4974 
4975 void Mesh::GetBdrElementFace(int i, int *f, int *o) const
4976 {
4977  const int *bv, *fv;
4978 
4979  *f = be_to_face[i];
4980  bv = boundary[i]->GetVertices();
4981  fv = faces[be_to_face[i]]->GetVertices();
4982 
4983  // find the orientation of the bdr. elem. w.r.t.
4984  // the corresponding face element (that's the base)
4985  switch (GetBdrElementType(i))
4986  {
4987  case Element::TRIANGLE:
4988  *o = GetTriOrientation(fv, bv);
4989  break;
4990  case Element::QUADRILATERAL:
4991  *o = GetQuadOrientation(fv, bv);
4992  break;
4993  default:
4994  mfem_error("Mesh::GetBdrElementFace(...) 2");
4995  }
4996 }
4997 
4998 int Mesh::GetBdrElementEdgeIndex(int i) const
4999 {
5000  switch (Dim)
5001  {
5002  case 1: return boundary[i]->GetVertices()[0];
5003  case 2: return be_to_edge[i];
5004  case 3: return be_to_face[i];
5005  default: mfem_error("Mesh::GetBdrElementEdgeIndex: invalid dimension!");
5006  }
5007  return -1;
5008 }
5009 
5010 void Mesh::GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
5011 {
5012  int fid = GetBdrElementEdgeIndex(bdr_el);
5013  const FaceInfo &fi = faces_info[fid];
5014  MFEM_ASSERT(fi.Elem1Inf%64 == 0, "internal error"); // orientation == 0
5015  const int *fv = (Dim > 1) ? faces[fid]->GetVertices() : NULL;
5016  const int *bv = boundary[bdr_el]->GetVertices();
5017  int ori;
5018  switch (GetBdrElementBaseGeometry(bdr_el))
5019  {
5020  case Geometry::POINT: ori = 0; break;
5021  case Geometry::SEGMENT: ori = (fv[0] == bv[0]) ? 0 : 1; break;
5022  case Geometry::TRIANGLE: ori = GetTriOrientation(fv, bv); break;
5023  case Geometry::SQUARE: ori = GetQuadOrientation(fv, bv); break;
5024  default: MFEM_ABORT("boundary element type not implemented"); ori = 0;
5025  }
5026  el = fi.Elem1No;
5027  info = fi.Elem1Inf + ori;
5028 }
5029 
5030 Element::Type Mesh::GetElementType(int i) const
5031 {
5032  return elements[i]->GetType();
5033 }
5034 
5035 Element::Type Mesh::GetBdrElementType(int i) const
5036 {
5037  return boundary[i]->GetType();
5038 }
5039 
5040 void Mesh::GetPointMatrix(int i, DenseMatrix &pointmat) const
5041 {
5042  int k, j, nv;
5043  const int *v;
5044 
5045  v = elements[i]->GetVertices();
5046  nv = elements[i]->GetNVertices();
5047 
5048  pointmat.SetSize(spaceDim, nv);
5049  for (k = 0; k < spaceDim; k++)
5050  {
5051  for (j = 0; j < nv; j++)
5052  {
5053  pointmat(k, j) = vertices[v[j]](k);
5054  }
5055  }
5056 }
5057 
5058 void Mesh::GetBdrPointMatrix(int i,DenseMatrix &pointmat) const
5059 {
5060  int k, j, nv;
5061  const int *v;
5062 
5063  v = boundary[i]->GetVertices();
5064  nv = boundary[i]->GetNVertices();
5065 
5066  pointmat.SetSize(spaceDim, nv);
5067  for (k = 0; k < spaceDim; k++)
5068  for (j = 0; j < nv; j++)
5069  {
5070  pointmat(k, j) = vertices[v[j]](k);
5071  }
5072 }
5073 
5074 double Mesh::GetLength(int i, int j) const
5075 {
5076  const double *vi = vertices[i]();
5077  const double *vj = vertices[j]();
5078  double length = 0.;
5079 
5080  for (int k = 0; k < spaceDim; k++)
5081  {
5082  length += (vi[k]-vj[k])*(vi[k]-vj[k]);
5083  }
5084 
5085  return sqrt(length);
5086 }
5087 
5088 // static method
5089 void Mesh::GetElementArrayEdgeTable(const Array<Element*> &elem_array,
5090  const DSTable &v_to_v, Table &el_to_edge)
5091 {
5092  el_to_edge.MakeI(elem_array.Size());
5093  for (int i = 0; i < elem_array.Size(); i++)
5094  {
5095  el_to_edge.AddColumnsInRow(i, elem_array[i]->GetNEdges());
5096  }
5097  el_to_edge.MakeJ();
5098  for (int i = 0; i < elem_array.Size(); i++)
5099  {
5100  const int *v = elem_array[i]->GetVertices();
5101  const int ne = elem_array[i]->GetNEdges();
5102  for (int j = 0; j < ne; j++)
5103  {
5104  const int *e = elem_array[i]->GetEdgeVertices(j);
5105  el_to_edge.AddConnection(i, v_to_v(v[e[0]], v[e[1]]));
5106  }
5107  }
5108  el_to_edge.ShiftUpI();
5109 }
5110 
5111 void Mesh::GetVertexToVertexTable(DSTable &v_to_v) const
5112 {
5113  if (edge_vertex)
5114  {
5115  for (int i = 0; i < edge_vertex->Size(); i++)
5116  {
5117  const int *v = edge_vertex->GetRow(i);
5118  v_to_v.Push(v[0], v[1]);
5119  }
5120  }
5121  else
5122  {
5123  for (int i = 0; i < NumOfElements; i++)
5124  {
5125  const int *v = elements[i]->GetVertices();
5126  const int ne = elements[i]->GetNEdges();
5127  for (int j = 0; j < ne; j++)
5128  {
5129  const int *e = elements[i]->GetEdgeVertices(j);
5130  v_to_v.Push(v[e[0]], v[e[1]]);
5131  }
5132  }
5133  }
5134 }
5135 
5136 int Mesh::GetElementToEdgeTable(Table & e_to_f, Array<int> &be_to_f)
5137 {
5138  int i, NumberOfEdges;
5139 
5140  DSTable v_to_v(NumOfVertices);
5141  GetVertexToVertexTable(v_to_v);
5142 
5143  NumberOfEdges = v_to_v.NumberOfEntries();
5144 
5145  // Fill the element to edge table
5146  GetElementArrayEdgeTable(elements, v_to_v, e_to_f);
5147 
5148  if (Dim == 2)
5149  {
5150  // Initialize the indices for the boundary elements.
5151  be_to_f.SetSize(NumOfBdrElements);
5152  for (i = 0; i < NumOfBdrElements; i++)
5153  {
5154  const int *v = boundary[i]->GetVertices();
5155  be_to_f[i] = v_to_v(v[0], v[1]);
5156  }
5157  }
5158  else if (Dim == 3)
5159  {
5160  if (bel_to_edge == NULL)
5161  {
5162  bel_to_edge = new Table;
5163  }
5164  GetElementArrayEdgeTable(boundary, v_to_v, *bel_to_edge);
5165  }
5166  else
5167  {
5168  mfem_error("1D GetElementToEdgeTable is not yet implemented.");
5169  }
5170 
5171  // Return the number of edges
5172  return NumberOfEdges;
5173 }
5174 
5175 const Table & Mesh::ElementToElementTable()
5176 {
5177  if (el_to_el)
5178  {
5179  return *el_to_el;
5180  }
5181 
5182  // Note that, for ParNCMeshes, faces_info will contain also the ghost faces
5183  MFEM_ASSERT(faces_info.Size() >= GetNumFaces(), "faces were not generated!");
5184 
5185  Array<Connection> conn;
5186  conn.Reserve(2*faces_info.Size());
5187 
5188  for (int i = 0; i < faces_info.Size(); i++)
5189  {
5190  const FaceInfo &fi = faces_info[i];
5191  if (fi.Elem2No >= 0)
5192  {
5193  conn.Append(Connection(fi.Elem1No, fi.Elem2No));
5194  conn.Append(Connection(fi.Elem2No, fi.Elem1No));
5195  }
5196  else if (fi.Elem2Inf >= 0)
5197  {
5198  int nbr_elem_idx = NumOfElements - 1 - fi.Elem2No;
5199  conn.Append(Connection(fi.Elem1No, nbr_elem_idx));
5200  conn.Append(Connection(nbr_elem_idx, fi.Elem1No));
5201  }
5202  }
5203 
5204  conn.Sort();
5205  conn.Unique();
5206  el_to_el = new Table(NumOfElements, conn);
5207 
5208  return *el_to_el;
5209 }
5210 
5211 const Table & Mesh::ElementToFaceTable() const
5212 {
5213  if (el_to_face == NULL)
5214  {
5215  mfem_error("Mesh::ElementToFaceTable()");
5216  }
5217  return *el_to_face;
5218 }
5219 
5220 const Table & Mesh::ElementToEdgeTable() const
5221 {
5222  if (el_to_edge == NULL)
5223  {
5224  mfem_error("Mesh::ElementToEdgeTable()");
5225  }
5226  return *el_to_edge;
5227 }
5228 
5229 void Mesh::AddPointFaceElement(int lf, int gf, int el)
5230 {
5231  if (faces_info[gf].Elem1No == -1) // this will be elem1
5232  {
5233  // faces[gf] = new Point(&gf);
5234  faces_info[gf].Elem1No = el;
5235  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
5236  faces_info[gf].Elem2No = -1; // in case there's no other side
5237  faces_info[gf].Elem2Inf = -1; // face is not shared
5238  }
5239  else // this will be elem2
5240  {
5241  faces_info[gf].Elem2No = el;
5242  faces_info[gf].Elem2Inf = 64 * lf + 1;
5243  }
5244 }
5245 
5246 void Mesh::AddSegmentFaceElement(int lf, int gf, int el, int v0, int v1)
5247 {
5248  if (faces[gf] == NULL) // this will be elem1
5249  {
5250  faces[gf] = new Segment(v0, v1);
5251  faces_info[gf].Elem1No = el;
5252  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
5253  faces_info[gf].Elem2No = -1; // in case there's no other side
5254  faces_info[gf].Elem2Inf = -1; // face is not shared
5255  }
5256  else // this will be elem2
5257  {
5258  int *v = faces[gf]->GetVertices();
5259  faces_info[gf].Elem2No = el;
5260  if ( v[1] == v0 && v[0] == v1 )
5261  {
5262  faces_info[gf].Elem2Inf = 64 * lf + 1;
5263  }
5264  else if ( v[0] == v0 && v[1] == v1 )
5265  {
5266  // Temporarily allow even edge orientations: see the remark in
5267  // AddTriangleFaceElement().
5268  // Also, in a non-orientable surface mesh, the orientation will be even
5269  // for edges that connect elements with opposite orientations.
5270  faces_info[gf].Elem2Inf = 64 * lf;
5271  }
5272  else
5273  {
5274  MFEM_ABORT("internal error");
5275  }
5276  }
5277 }
5278 
5279 void Mesh::AddTriangleFaceElement(int lf, int gf, int el,
5280  int v0, int v1, int v2)
5281 {
5282  if (faces[gf] == NULL) // this will be elem1
5283  {
5284  faces[gf] = new Triangle(v0, v1, v2);
5285  faces_info[gf].Elem1No = el;
5286  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
5287  faces_info[gf].Elem2No = -1; // in case there's no other side
5288  faces_info[gf].Elem2Inf = -1; // face is not shared
5289  }
5290  else // this will be elem2
5291  {
5292  int orientation, vv[3] = { v0, v1, v2 };
5293  orientation = GetTriOrientation(faces[gf]->GetVertices(), vv);
5294  // In a valid mesh, we should have (orientation % 2 != 0), however, if
5295  // one of the adjacent elements has wrong orientation, both face
5296  // orientations can be even, until the element orientations are fixed.
5297  // MFEM_ASSERT(orientation % 2 != 0, "");
5298  faces_info[gf].Elem2No = el;
5299  faces_info[gf].Elem2Inf = 64 * lf + orientation;
5300  }
5301 }
5302 
5303 void Mesh::AddQuadFaceElement(int lf, int gf, int el,
5304  int v0, int v1, int v2, int v3)
5305 {
5306  if (faces_info[gf].Elem1No < 0) // this will be elem1
5307  {
5308  faces[gf] = new Quadrilateral(v0, v1, v2, v3);
5309  faces_info[gf].Elem1No = el;
5310  faces_info[gf].Elem1Inf = 64 * lf; // face lf with orientation 0
5311  faces_info[gf].Elem2No = -1; // in case there's no other side
5312  faces_info[gf].Elem2Inf = -1; // face is not shared
5313  }
5314  else // this will be elem2
5315  {
5316  int vv[4] = { v0, v1, v2, v3 };
5317  int oo = GetQuadOrientation(faces[gf]->GetVertices(), vv);
5318  // Temporarily allow even face orientations: see the remark in
5319  // AddTriangleFaceElement().
5320  // MFEM_ASSERT(oo % 2 != 0, "");
5321  faces_info[gf].Elem2No = el;
5322  faces_info[gf].Elem2Inf = 64 * lf + oo;
5323  }
5324 }
5325 
5326 void Mesh::GenerateFaces()
5327 {
5328  int i, nfaces = GetNumFaces();
5329 
5330  for (i = 0; i < faces.Size(); i++)
5331  {
5332  FreeElement(faces[i]);
5333  }
5334 
5335  // (re)generate the interior faces and the info for them
5336  faces.SetSize(nfaces);
5337  faces_info.SetSize(nfaces);
5338  for (i = 0; i < nfaces; i++)
5339  {
5340  faces[i] = NULL;
5341  faces_info[i].Elem1No = -1;
5342  faces_info[i].NCFace = -1;
5343  }
5344  for (i = 0; i < NumOfElements; i++)
5345  {
5346  const int *v = elements[i]->GetVertices();
5347  const int *ef;
5348  if (Dim == 1)
5349  {
5350  AddPointFaceElement(0, v[0], i);
5351  AddPointFaceElement(1, v[1], i);
5352  }
5353  else if (Dim == 2)
5354  {
5355  ef = el_to_edge->GetRow(i);
5356  const int ne = elements[i]->GetNEdges();
5357  for (int j = 0; j < ne; j++)
5358  {
5359  const int *e = elements[i]->GetEdgeVertices(j);
5360  AddSegmentFaceElement(j, ef[j], i, v[e[0]], v[e[1]]);
5361  }
5362  }
5363  else
5364  {
5365  ef = el_to_face->GetRow(i);
5366  switch (GetElementType(i))
5367  {
5368  case Element::TETRAHEDRON:
5369  {
5370  for (int j = 0; j < 4; j++)
5371  {
5372  const int *fv = tet_t::FaceVert[j];
5373  AddTriangleFaceElement(j, ef[j], i,
5374  v[fv[0]], v[fv[1]], v[fv[2]]);
5375  }
5376  break;
5377  }
5378  case Element::WEDGE:
5379  {
5380  for (int j = 0; j < 2; j++)
5381  {
5382  const int *fv = pri_t::FaceVert[j];
5383  AddTriangleFaceElement(j, ef[j], i,
5384  v[fv[0]], v[fv[1]], v[fv[2]]);
5385  }
5386  for (int j = 2; j < 5; j++)
5387  {
5388  const int *fv = pri_t::FaceVert[j];
5389  AddQuadFaceElement(j, ef[j], i,
5390  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
5391  }
5392  break;
5393  }
5394  case Element::HEXAHEDRON:
5395  {
5396  for (int j = 0; j < 6; j++)
5397  {
5398  const int *fv = hex_t::FaceVert[j];
5399  AddQuadFaceElement(j, ef[j], i,
5400  v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
5401  }
5402  break;
5403  }
5404  default:
5405  MFEM_ABORT("Unexpected type of Element.");
5406  }
5407  }
5408  }
5409 }
5410 
5411 void Mesh::GenerateNCFaceInfo()
5412 {
5413  MFEM_VERIFY(ncmesh, "missing NCMesh.");
5414 
5415  for (int i = 0; i < faces_info.Size(); i++)
5416  {
5417  faces_info[i].NCFace = -1;
5418  }
5419 
5420  const NCMesh::NCList &list =
5421  (Dim == 2) ? ncmesh->GetEdgeList() : ncmesh->GetFaceList();
5422 
5423  nc_faces_info.SetSize(0);
5424  nc_faces_info.Reserve(list.masters.Size() + list.slaves.Size());
5425 
5426  int nfaces = GetNumFaces();
5427 
5428  // add records for master faces
5429  for (int i = 0; i < list.masters.Size(); i++)
5430  {
5431  const NCMesh::Master &master = list.masters[i];
5432  if (master.index >= nfaces) { continue; }
5433 
5434  faces_info[master.index].NCFace = nc_faces_info.Size();
5435  nc_faces_info.Append(NCFaceInfo(false, master.local, NULL));
5436  // NOTE: one of the unused members stores local face no. to be used below
5437  }
5438 
5439  // add records for slave faces
5440  for (int i = 0; i < list.slaves.Size(); i++)
5441  {
5442  const NCMesh::Slave &slave = list.slaves[i];
5443 
5444  if (slave.index < 0 || // degenerate slave face
5445  slave.index >= nfaces || // ghost slave
5446  slave.master >= nfaces) // has ghost master
5447  {
5448  continue;
5449  }
5450 
5451  FaceInfo &slave_fi = faces_info[slave.index];
5452  FaceInfo &master_fi = faces_info[slave.master];
5453  NCFaceInfo &master_nc = nc_faces_info[master_fi.NCFace];
5454 
5455  slave_fi.NCFace = nc_faces_info.Size();
5456  slave_fi.Elem2No = master_fi.Elem1No;
5457  slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
5458  // NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
5459  // matrix. In 2D, the point matrix has the orientation of the parent
5460  // edge, so its columns need to be flipped when applying it, see
5461  // ApplyLocalSlaveTransformation.
5462 
5463  nc_faces_info.Append(
5464  NCFaceInfo(true, slave.master,
5465  list.point_matrices[slave.geom][slave.matrix]));
5466  }
5467 }
5468 
5469 STable3D *Mesh::GetFacesTable()
5470 {
5471  STable3D *faces_tbl = new STable3D(NumOfVertices);
5472  for (int i = 0; i < NumOfElements; i++)
5473  {
5474  const int *v = elements[i]->GetVertices();
5475  switch (GetElementType(i))
5476  {
5477  case Element::TETRAHEDRON:
5478  {
5479  for (int j = 0; j < 4; j++)
5480  {
5481  const int *fv = tet_t::FaceVert[j];
5482  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
5483  }
5484  break;
5485  }
5486  case Element::WEDGE:
5487  {
5488  for (int j = 0; j < 2; j++)
5489  {
5490  const int *fv = pri_t::FaceVert[j];
5491  faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]);
5492  }
5493  for (int j = 2; j < 5; j++)
5494  {
5495  const int *fv = pri_t::FaceVert[j];
5496  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
5497  }
5498  break;
5499  }
5500  case Element::HEXAHEDRON:
5501  {
5502  // find the face by the vertices with the smallest 3 numbers
5503  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
5504  for (int j = 0; j < 6; j++)
5505  {
5506  const int *fv = hex_t::FaceVert[j];
5507  faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]);
5508  }
5509  break;
5510  }
5511  default:
5512  MFEM_ABORT("Unexpected type of Element.");
5513  }
5514  }
5515  return faces_tbl;
5516 }
5517 
5518 STable3D *Mesh::GetElementToFaceTable(int ret_ftbl)
5519 {
5520  int i, *v;
5521  STable3D *faces_tbl;
5522 
5523  if (el_to_face != NULL)
5524  {
5525  delete el_to_face;
5526  }
5527  el_to_face = new Table(NumOfElements, 6); // must be 6 for hexahedra
5528  faces_tbl = new STable3D(NumOfVertices);
5529  for (i = 0; i < NumOfElements; i++)
5530  {
5531  v = elements[i]->GetVertices();
5532  switch (GetElementType(i))
5533  {
5534  case Element::TETRAHEDRON:
5535  {
5536  for (int j = 0; j < 4; j++)
5537  {
5538  const int *fv = tet_t::FaceVert[j];
5539  el_to_face->Push(
5540  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
5541  }
5542  break;
5543  }
5544  case Element::WEDGE:
5545  {
5546  for (int j = 0; j < 2; j++)
5547  {
5548  const int *fv = pri_t::FaceVert[j];
5549  el_to_face->Push(
5550  i, faces_tbl->Push(v[fv[0]], v[fv[1]], v[fv[2]]));
5551  }
5552  for (int j = 2; j < 5; j++)
5553  {
5554  const int *fv = pri_t::FaceVert[j];
5555  el_to_face->Push(
5556  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
5557  }
5558  break;
5559  }
5560  case Element::HEXAHEDRON:
5561  {
5562  // find the face by the vertices with the smallest 3 numbers
5563  // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1
5564  for (int j = 0; j < 6; j++)
5565  {
5566  const int *fv = hex_t::FaceVert[j];
5567  el_to_face->Push(
5568  i, faces_tbl->Push4(v[fv[0]], v[fv[1]], v[fv[2]], v[fv[3]]));
5569  }
5570  break;
5571  }
5572  default:
5573  MFEM_ABORT("Unexpected type of Element.");
5574  }
5575  }
5576  el_to_face->Finalize();
5577  NumOfFaces = faces_tbl->NumberOfElements();
5578  be_to_face.SetSize(NumOfBdrElements);
5579  for (i = 0; i < NumOfBdrElements; i++)
5580  {
5581  v = boundary[i]->GetVertices();
5582  switch (GetBdrElementType(i))
5583  {
5584  case Element::TRIANGLE:
5585  {
5586  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2]);
5587  break;
5588  }
5589  case Element::QUADRILATERAL:
5590  {
5591  be_to_face[i] = (*faces_tbl)(v[0], v[1], v[2], v[3]);
5592  break;
5593  }
5594  default:
5595  MFEM_ABORT("Unexpected type of boundary Element.");
5596  }
5597  }
5598 
5599  if (ret_ftbl)
5600  {
5601  return faces_tbl;
5602  }
5603  delete faces_tbl;
5604  return NULL;
5605 }
5606 
5607 // shift cyclically 3 integers so that the smallest is first
5608 static inline
5609 void Rotate3(int &a, int &b, int &c)
5610 {
5611  if (a < b)
5612  {
5613  if (a > c)
5614  {
5615  ShiftRight(a, b, c);
5616  }
5617  }
5618  else
5619  {
5620  if (b < c)
5621  {
5622  ShiftRight(c, b, a);
5623  }
5624  else
5625  {
5626  ShiftRight(a, b, c);
5627  }
5628  }
5629 }
5630 
5631 void Mesh::ReorientTetMesh()
5632 {
5633  if (Dim != 3 || !(meshgen & 1))
5634  {
5635  return;
5636  }
5637 
5638  ResetLazyData();
5639 
5640  DSTable *old_v_to_v = NULL;
5641  Table *old_elem_vert = NULL;
5642 
5643  if (Nodes)
5644  {
5645  PrepareNodeReorder(&old_v_to_v, &old_elem_vert);
5646  }
5647 
5648  for (int i = 0; i < NumOfElements; i++)
5649  {
5650  if (GetElementType(i) == Element::TETRAHEDRON)
5651  {
5652  int *v = elements[i]->GetVertices();
5653 
5654  Rotate3(v[0], v[1], v[2]);
5655  if (v[0] < v[3])
5656  {
5657  Rotate3(v[1], v[2], v[3]);
5658  }
5659  else
5660  {
5661  ShiftRight(v[0], v[1], v[3]);
5662  }
5663  }
5664  }
5665 
5666  for (int i = 0; i < NumOfBdrElements; i++)
5667  {
5668  if (GetBdrElementType(i) == Element::TRIANGLE)
5669  {
5670  int *v = boundary[i]->GetVertices();
5671 
5672  Rotate3(v[0], v[1], v[2]);
5673  }
5674  }
5675 
5676  if (!Nodes)
5677  {
5678  GetElementToFaceTable();
5679  GenerateFaces();
5680  if (el_to_edge)
5681  {
5682  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
5683  }
5684  }
5685  else
5686  {
5687  DoNodeReorder(old_v_to_v, old_elem_vert);
5688  delete old_elem_vert;
5689  delete old_v_to_v;
5690  }
5691 }
5692 
5693 int *Mesh::CartesianPartitioning(int nxyz[])
5694 {
5695  int *partitioning;
5696  double pmin[3] = { infinity(), infinity(), infinity() };
5697  double pmax[3] = { -infinity(), -infinity(), -infinity() };
5698  // find a bounding box using the vertices
5699  for (int vi = 0; vi < NumOfVertices; vi++)
5700  {
5701  const double *p = vertices[vi]();
5702  for (int i = 0; i < spaceDim; i++)
5703  {
5704  if (p[i] < pmin[i]) { pmin[i] = p[i]; }
5705  if (p[i] > pmax[i]) { pmax[i] = p[i]; }
5706  }
5707  }
5708 
5709  partitioning = new int[NumOfElements];
5710 
5711  // determine the partitioning using the centers of the elements
5712  double ppt[3];
5713  Vector pt(ppt, spaceDim);
5714  for (int el = 0; el < NumOfElements; el++)
5715  {
5716  GetElementTransformation(el)->Transform(
5717  Geometries.GetCenter(GetElementBaseGeometry(el)), pt);
5718  int part = 0;
5719  for (int i = spaceDim-1; i >= 0; i--)
5720  {
5721  int idx = (int)floor(nxyz[i]*((pt(i) - pmin[i])/(pmax[i] - pmin[i])));
5722  if (idx < 0) { idx = 0; }
5723  if (idx >= nxyz[i]) { idx = nxyz[i]-1; }
5724  part = part * nxyz[i] + idx;
5725  }
5726  partitioning[el] = part;
5727  }
5728 
5729  return partitioning;
5730 }
5731 
5732 int *Mesh::GeneratePartitioning(int nparts, int part_method)
5733 {
5734 #ifdef MFEM_USE_METIS
5735 
5736  int print_messages = 1;
5737  // If running in parallel, print messages only from rank 0.
5738 #ifdef MFEM_USE_MPI
5739  int init_flag, fin_flag;
5740  MPI_Initialized(&init_flag);
5741  MPI_Finalized(&fin_flag);
5742  if (init_flag && !fin_flag)
5743  {
5744  int rank;
5745  MPI_Comm_rank(GetGlobalMPI_Comm(), &rank);
5746  if (rank != 0) { print_messages = 0; }
5747  }
5748 #endif
5749 
5750  int i, *partitioning;
5751 
5752  ElementToElementTable();
5753 
5754  partitioning = new int[NumOfElements];
5755 
5756  if (nparts == 1)
5757  {
5758  for (i = 0; i < NumOfElements; i++)
5759  {
5760  partitioning[i] = 0;
5761  }
5762  }
5763  else if (NumOfElements <= nparts)
5764  {
5765  for (i = 0; i < NumOfElements; i++)
5766  {
5767  partitioning[i] = i;
5768  }
5769  }
5770  else
5771  {
5772  idx_t *I, *J, n;
5773 #ifndef MFEM_USE_METIS_5
5774  idx_t wgtflag = 0;
5775  idx_t numflag = 0;
5776  idx_t options[5];
5777 #else
5778  idx_t ncon = 1;
5779  idx_t err;
5780  idx_t options[40];
5781 #endif
5782  idx_t edgecut;
5783 
5784  // In case METIS have been compiled with 64bit indices
5785  bool freedata = false;
5786  idx_t mparts = (idx_t) nparts;
5787  idx_t *mpartitioning;
5788 
5789  n = NumOfElements;
5790  if (sizeof(idx_t) == sizeof(int))
5791  {
5792  I = (idx_t*) el_to_el->GetI();
5793  J = (idx_t*) el_to_el->GetJ();
5794  mpartitioning = (idx_t*) partitioning;
5795  }
5796  else
5797  {
5798  int *iI = el_to_el->GetI();
5799  int *iJ = el_to_el->GetJ();
5800  int m = iI[n];
5801  I = new idx_t[n+1];
5802  J = new idx_t[m];
5803  for (int k = 0; k < n+1; k++) { I[k] = iI[k]; }
5804  for (int k = 0; k < m; k++) { J[k] = iJ[k]; }
5805  mpartitioning = new idx_t[n];
5806  freedata = true;
5807  }
5808 #ifndef MFEM_USE_METIS_5
5809  options[0] = 0;
5810 #else
5811  METIS_SetDefaultOptions(options);
5812  options[METIS_OPTION_CONTIG] = 1; // set METIS_OPTION_CONTIG
5813 #endif
5814 
5815  // Sort the neighbor lists
5816  if (part_method >= 0 && part_method <= 2)
5817  {
5818  for (i = 0; i < n; i++)
5819  {
5820  // Sort in increasing order.
5821  // std::sort(J+I[i], J+I[i+1]);
5822 
5823  // Sort in decreasing order, as in previous versions of MFEM.
5824  std::sort(J+I[i], J+I[i+1], std::greater<idx_t>());
5825  }
5826  }
5827 
5828  // This function should be used to partition a graph into a small
5829  // number of partitions (less than 8).
5830  if (part_method == 0 || part_method == 3)
5831  {
5832 #ifndef MFEM_USE_METIS_5
5834  I,
5835  J,
5836  NULL,
5837  NULL,
5838  &wgtflag,
5839  &numflag,
5840  &mparts,
5841  options,
5842  &edgecut,
5843  mpartitioning);
5844 #else
5845  err = METIS_PartGraphRecursive(&n,
5846  &ncon,
5847  I,
5848  J,
5849  NULL,
5850  NULL,
5851  NULL,
5852  &mparts,
5853  NULL,
5854  NULL,
5855  options,
5856  &edgecut,
5857  mpartitioning);
5858  if (err != 1)
5859  {
5860  mfem_error("Mesh::GeneratePartitioning: "
5861  " error in METIS_PartGraphRecursive!");
5862  }
5863 #endif
5864  }
5865 
5866  // This function should be used to partition a graph into a large
5867  // number of partitions (greater than 8).
5868  if (part_method == 1 || part_method == 4)
5869  {
5870 #ifndef MFEM_USE_METIS_5
5872  I,
5873  J,
5874  NULL,
5875  NULL,
5876  &wgtflag,
5877  &numflag,
5878  &mparts,
5879  options,
5880  &edgecut,
5881  mpartitioning);
5882 #else
5883  err = METIS_PartGraphKway(&n,
5884  &ncon,
5885  I,
5886  J,
5887  NULL,
5888  NULL,
5889  NULL,
5890  &mparts,
5891  NULL,
5892  NULL,
5893  options,
5894  &edgecut,
5895  mpartitioning);
5896  if (err != 1)
5897  {
5898  mfem_error("Mesh::GeneratePartitioning: "
5899  " error in METIS_PartGraphKway!");
5900  }
5901 #endif
5902  }
5903 
5904  // The objective of this partitioning is to minimize the total
5905  // communication volume
5906  if (part_method == 2 || part_method == 5)
5907  {
5908 #ifndef MFEM_USE_METIS_5
5910  I,
5911  J,
5912  NULL,
5913  NULL,
5914  &wgtflag,
5915  &numflag,
5916  &mparts,
5917  options,
5918  &edgecut,
5919  mpartitioning);
5920 #else
5921  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
5922  err = METIS_PartGraphKway(&n,
5923  &ncon,
5924  I,
5925  J,
5926  NULL,
5927  NULL,
5928  NULL,
5929  &mparts,
5930  NULL,
5931  NULL,
5932  options,
5933  &edgecut,
5934  mpartitioning);
5935  if (err != 1)
5936  {
5937  mfem_error("Mesh::GeneratePartitioning: "
5938  " error in METIS_PartGraphKway!");
5939  }
5940 #endif
5941  }
5942 
5943 #ifdef MFEM_DEBUG
5944  if (print_messages)
5945  {
5946  mfem::out << "Mesh::GeneratePartitioning(...): edgecut = "
5947  << edgecut << endl;
5948  }
5949 #endif
5950  nparts = (int) mparts;
5951  if (mpartitioning != (idx_t*)partitioning)
5952  {
5953  for (int k = 0; k<NumOfElements; k++)
5954  {
5955  partitioning[k] = mpartitioning[k];
5956  }
5957  }
5958  if (freedata)
5959  {
5960  delete[] I;
5961  delete[] J;
5962  delete[] mpartitioning;
5963  }
5964  }
5965 
5966  delete el_to_el;
5967  el_to_el = NULL;
5968 
5969  // Check for empty partitionings (a "feature" in METIS)
5970  {
5971  Array< Pair<int,int> > psize(nparts);
5972  int empty_parts;
5973  for (i = 0; i < nparts; i++)
5974  {
5975  psize[i].one = 0;
5976  psize[i].two = i;
5977  }
5978 
5979  for (i = 0; i < NumOfElements; i++)
5980  {
5981  psize[partitioning[i]].one++;
5982  }
5983 
5984  empty_parts = 0;
5985  for (i = 0; i < nparts; i++)
5986  {
5987  if (psize[i].one == 0) { empty_parts++; }
5988  }
5989 
5990  // This code just split the largest partitionings in two.
5991  // Do we need to replace it with something better?
5992  while (empty_parts)
5993  {
5994  if (print_messages)
5995  {
5996  mfem::err << "Mesh::GeneratePartitioning(...): METIS returned "
5997  << empty_parts << " empty parts!"
5998  << " Applying a simple fix ..." << endl;
5999  }
6000 
6001  SortPairs<int,int>(psize, nparts);
6002 
6003  for (i = nparts-1; i > nparts-1-empty_parts; i--)
6004  {
6005  psize[i].one /= 2;
6006  }
6007 
6008  for (int j = 0; j < NumOfElements; j++)
6009  {
6010  for (i = nparts-1; i > nparts-1-empty_parts; i--)
6011  {
6012  if (psize[i].one == 0 || partitioning[j] != psize[i].two)
6013  {
6014  continue;
6015  }
6016  else
6017  {
6018  partitioning[j] = psize[nparts-1-i].two;
6019  psize[i].one--;
6020  }
6021  }
6022  }
6023 
6024  // Check for empty partitionings again
6025  for (i = 0; i < nparts; i++)
6026  {
6027  psize[i].one = 0;
6028  }
6029 
6030  for (i = 0; i < NumOfElements; i++)
6031  {
6032  psize[partitioning[i]].one++;
6033  }
6034 
6035  empty_parts = 0;
6036  for (i = 0; i < nparts; i++)
6037  {
6038  if (psize[i].one == 0) { empty_parts++; }
6039  }
6040 
6041  }
6042  }
6043 
6044  return partitioning;
6045 
6046 #else
6047 
6048  mfem_error("Mesh::GeneratePartitioning(...): "
6049  "MFEM was compiled without Metis.");
6050 
6051  return NULL;
6052 
6053 #endif
6054 }
6055 
6056 /* required: 0 <= partitioning[i] < num_part */
6058  const Array<int> &partitioning,
6059  Array<int> &component,
6060  Array<int> &num_comp)
6061 {
6062  int i, j, k;
6063  int num_elem, *i_elem_elem, *j_elem_elem;
6064 
6065  num_elem = elem_elem.Size();
6066  i_elem_elem = elem_elem.GetI();
6067  j_elem_elem = elem_elem.GetJ();
6068 
6069  component.SetSize(num_elem);
6070 
6071  Array<int> elem_stack(num_elem);
6072  int stack_p, stack_top_p, elem;
6073  int num_part;
6074 
6075  num_part = -1;
6076  for (i = 0; i < num_elem; i++)
6077  {
6078  if (partitioning[i] > num_part)
6079  {
6080  num_part = partitioning[i];
6081  }
6082  component[i] = -1;
6083  }
6084  num_part++;
6085 
6086  num_comp.SetSize(num_part);
6087  for (i = 0; i < num_part; i++)
6088  {
6089  num_comp[i] = 0;
6090  }
6091 
6092  stack_p = 0;
6093  stack_top_p = 0; // points to the first unused element in the stack
6094  for (elem = 0; elem < num_elem; elem++)
6095  {
6096  if (component[elem] >= 0)
6097  {
6098  continue;
6099  }
6100 
6101  component[elem] = num_comp[partitioning[elem]]++;
6102 
6103  elem_stack[stack_top_p++] = elem;
6104 
6105  for ( ; stack_p < stack_top_p; stack_p++)
6106  {
6107  i = elem_stack[stack_p];
6108  for (j = i_elem_elem[i]; j < i_elem_elem[i+1]; j++)
6109  {
6110  k = j_elem_elem[j];
6111  if (partitioning[k] == partitioning[i])
6112  {
6113  if (component[k] < 0)
6114  {
6115  component[k] = component[i];
6116  elem_stack[stack_top_p++] = k;
6117  }
6118  else if (component[k] != component[i])
6119  {
6120  mfem_error("FindPartitioningComponents");
6121  }
6122  }
6123  }
6124  }
6125  }
6126 }
6127 
6128 void Mesh::CheckPartitioning(int *partitioning)
6129 {
6130  int i, n_empty, n_mcomp;
6131  Array<int> component, num_comp;
6132  const Array<int> _partitioning(partitioning, GetNE());
6133 
6134  ElementToElementTable();
6135 
6136  FindPartitioningComponents(*el_to_el, _partitioning, component, num_comp);
6137 
6138  n_empty = n_mcomp = 0;
6139  for (i = 0; i < num_comp.Size(); i++)
6140  if (num_comp[i] == 0)
6141  {
6142  n_empty++;
6143  }
6144  else if (num_comp[i] > 1)
6145  {
6146  n_mcomp++;
6147  }
6148 
6149  if (n_empty > 0)
6150  {
6151  mfem::out << "Mesh::CheckPartitioning(...) :\n"
6152  << "The following subdomains are empty :\n";
6153  for (i = 0; i < num_comp.Size(); i++)
6154  if (num_comp[i] == 0)
6155  {
6156  mfem::out << ' ' << i;
6157  }
6158  mfem::out << endl;
6159  }
6160  if (n_mcomp > 0)
6161  {
6162  mfem::out << "Mesh::CheckPartitioning(...) :\n"
6163  << "The following subdomains are NOT connected :\n";
6164  for (i = 0; i < num_comp.Size(); i++)
6165  if (num_comp[i] > 1)
6166  {
6167  mfem::out << ' ' << i;
6168  }
6169  mfem::out << endl;
6170  }
6171  if (n_empty == 0 && n_mcomp == 0)
6172  mfem::out << "Mesh::CheckPartitioning(...) : "
6173  "All subdomains are connected." << endl;
6174 
6175  if (el_to_el)
6176  {
6177  delete el_to_el;
6178  }
6179  el_to_el = NULL;
6180 }
6181 
6182 // compute the coefficients of the polynomial in t:
6183 // c(0)+c(1)*t+...+c(d)*t^d = det(A+t*B)
6184 // where A, B are (d x d), d=2,3
6185 void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
6186 {
6187  const double *a = A.Data();
6188  const double *b = B.Data();
6189 
6190  c.SetSize(A.Width()+1);
6191  switch (A.Width())
6192  {
6193  case 2:
6194  {
6195  // det(A+t*B) = |a0 a2| / |a0 b2| + |b0 a2| \ |b0 b2|
6196  // |a1 a3| + \ |a1 b3| |b1 a3| / * t + |b1 b3| * t^2
6197  c(0) = a[0]*a[3]-a[1]*a[2];
6198  c(1) = a[0]*b[3]-a[1]*b[2]+b[0]*a[3]-b[1]*a[2];
6199  c(2) = b[0]*b[3]-b[1]*b[2];
6200  }
6201  break;
6202 
6203  case 3:
6204  {
6205  /* |a0 a3 a6|
6206  * det(A+t*B) = |a1 a4 a7| +
6207  * |a2 a5 a8|
6208 
6209  * / |b0 a3 a6| |a0 b3 a6| |a0 a3 b6| \
6210  * + | |b1 a4 a7| + |a1 b4 a7| + |a1 a4 b7| | * t +
6211  * \ |b2 a5 a8| |a2 b5 a8| |a2 a5 b8| /
6212 
6213  * / |a0 b3 b6| |b0 a3 b6| |b0 b3 a6| \
6214  * + | |a1 b4 b7| + |b1 a4 b7| + |b1 b4 a7| | * t^2 +
6215  * \ |a2 b5 b8| |b2 a5 b8| |b2 b5 a8| /
6216 
6217  * |b0 b3 b6|
6218  * + |b1 b4 b7| * t^3
6219  * |b2 b5 b8| */
6220  c(0) = (a[0] * (a[4] * a[8] - a[5] * a[7]) +
6221  a[1] * (a[5] * a[6] - a[3] * a[8]) +
6222  a[2] * (a[3] * a[7] - a[4] * a[6]));
6223 
6224  c(1) = (b[0] * (a[4] * a[8] - a[5] * a[7]) +
6225  b[1] * (a[5] * a[6] - a[3] * a[8]) +
6226  b[2] * (a[3] * a[7] - a[4] * a[6]) +
6227 
6228  a[0] * (b[4] * a[8] - b[5] * a[7]) +
6229  a[1] * (b[5] * a[6] - b[3] * a[8]) +
6230  a[2] * (b[3] * a[7] - b[4] * a[6]) +
6231 
6232  a[0] * (a[4] * b[8] - a[5] * b[7]) +
6233  a[1] * (a[5] * b[6] - a[3] * b[8]) +
6234  a[2] * (a[3] * b[7] - a[4] * b[6]));
6235 
6236  c(2) = (a[0] * (b[4] * b[8] - b[5] * b[7]) +
6237  a[1] * (b[5] * b[6] - b[3] * b[8]) +
6238  a[2] * (b[3] * b[7] - b[4] * b[6]) +
6239 
6240  b[0] * (a[4] * b[8] - a[5] * b[7]) +
6241  b[1] * (a[5] * b[6] - a[3] * b[8]) +
6242  b[2] * (a[3] * b[7] - a[4] * b[6]) +
6243 
6244  b[0] * (b[4] * a[8] - b[5] * a[7]) +
6245  b[1] * (b[5] * a[6] - b[3] * a[8]) +
6246  b[2] * (b[3] * a[7] - b[4] * a[6]));
6247 
6248  c(3) = (b[0] * (b[4] * b[8] - b[5] * b[7]) +
6249  b[1] * (b[5] * b[6] - b[3] * b[8]) +
6250  b[2] * (b[3] * b[7] - b[4] * b[6]));
6251  }
6252  break;
6253 
6254  default:
6255  mfem_error("DetOfLinComb(...)");
6256  }
6257 }
6258 
6259 // compute the real roots of
6260 // z(0)+z(1)*x+...+z(d)*x^d = 0, d=2,3;
6261 // the roots are returned in x, sorted in increasing order;
6262 // it is assumed that x is at least of size d;
6263 // return the number of roots counting multiplicity;
6264 // return -1 if all z(i) are 0.
6265 int FindRoots(const Vector &z, Vector &x)
6266 {
6267  int d = z.Size()-1;
6268  if (d > 3 || d < 0)
6269  {
6270  mfem_error("FindRoots(...)");
6271  }
6272 
6273  while (z(d) == 0.0)
6274  {
6275  if (d == 0)
6276  {
6277  return (-1);
6278  }
6279  d--;
6280  }
6281  switch (d)
6282  {
6283  case 0:
6284  {
6285  return 0;
6286  }
6287 
6288  case 1:
6289  {
6290  x(0) = -z(0)/z(1);
6291  return 1;
6292  }
6293 
6294  case 2:
6295  {
6296  double a = z(2), b = z(1), c = z(0);
6297  double D = b*b-4*a*c;
6298  if (D < 0.0)
6299  {
6300  return 0;
6301  }
6302  if (D == 0.0)
6303  {
6304  x(0) = x(1) = -0.5 * b / a;
6305  return 2; // root with multiplicity 2
6306  }
6307  if (b == 0.0)
6308  {
6309  x(0) = -(x(1) = fabs(0.5 * sqrt(D) / a));
6310  return 2;
6311  }
6312  else
6313  {
6314  double t;
6315  if (b > 0.0)
6316  {
6317  t = -0.5 * (b + sqrt(D));
6318  }
6319  else
6320  {
6321  t = -0.5 * (b - sqrt(D));
6322  }
6323  x(0) = t / a;
6324  x(1) = c / t;
6325  if (x(0) > x(1))
6326  {
6327  Swap<double>(x(0), x(1));
6328  }
6329  return 2;
6330  }
6331  }
6332 
6333  case 3:
6334  {
6335  double a = z(2)/z(3), b = z(1)/z(3), c = z(0)/z(3);
6336 
6337  // find the real roots of x^3 + a x^2 + b x + c = 0
6338  double Q = (a * a - 3 * b) / 9;
6339  double R = (2 * a * a * a - 9 * a * b + 27 * c) / 54;
6340  double Q3 = Q * Q * Q;
6341  double R2 = R * R;
6342 
6343  if (R2 == Q3)
6344  {
6345  if (Q == 0)
6346  {
6347  x(0) = x(1) = x(2) = - a / 3;
6348  }
6349  else
6350  {
6351  double sqrtQ = sqrt(Q);
6352 
6353  if (R > 0)
6354  {
6355  x(0) = -2 * sqrtQ - a / 3;
6356  x(1) = x(2) = sqrtQ - a / 3;
6357  }
6358  else
6359  {
6360  x(0) = x(1) = - sqrtQ - a / 3;
6361  x(2) = 2 * sqrtQ - a / 3;
6362  }
6363  }
6364  return 3;
6365  }
6366  else if (R2 < Q3)
6367  {
6368  double theta = acos(R / sqrt(Q3));
6369  double A = -2 * sqrt(Q);
6370  double x0, x1, x2;
6371  x0 = A * cos(theta / 3) - a / 3;
6372  x1 = A * cos((theta + 2.0 * M_PI) / 3) - a / 3;
6373  x2 = A * cos((theta - 2.0 * M_PI) / 3) - a / 3;
6374 
6375  /* Sort x0, x1, x2 */
6376  if (x0 > x1)
6377  {
6378  Swap<double>(x0, x1);
6379  }
6380  if (x1 > x2)
6381  {
6382  Swap<double>(x1, x2);
6383  if (x0 > x1)
6384  {
6385  Swap<double>(x0, x1);
6386  }
6387  }
6388  x(0) = x0;
6389  x(1) = x1;
6390  x(2) = x2;
6391  return 3;
6392  }
6393  else
6394  {
6395  double A;
6396  if (R >= 0.0)
6397  {
6398  A = -pow(sqrt(R2 - Q3) + R, 1.0/3.0);
6399  }
6400  else
6401  {
6402  A = pow(sqrt(R2 - Q3) - R, 1.0/3.0);
6403  }
6404  x(0) = A + Q / A - a / 3;
6405  return 1;
6406  }
6407  }
6408  }
6409  return 0;
6410 }
6411 
6412 void FindTMax(Vector &c, Vector &x, double &tmax,
6413  const double factor, const int Dim)
6414 {
6415  const double c0 = c(0);
6416  c(0) = c0 * (1.0 - pow(factor, -Dim));
6417  int nr = FindRoots(c, x);
6418  for (int j = 0; j < nr; j++)
6419  {
6420  if (x(j) > tmax)
6421  {
6422  break;
6423  }
6424  if (x(j) >= 0.0)
6425  {
6426  tmax = x(j);
6427  break;
6428  }
6429  }
6430  c(0) = c0 * (1.0 - pow(factor, Dim));
6431  nr = FindRoots(c, x);
6432  for (int j = 0; j < nr; j++)
6433  {
6434  if (x(j) > tmax)
6435  {
6436  break;
6437  }
6438  if (x(j) >= 0.0)
6439  {
6440  tmax = x(j);
6441  break;
6442  }
6443  }
6444 }
6445 
6446 void Mesh::CheckDisplacements(const Vector &displacements, double &tmax)
6447 {
6448  int nvs = vertices.Size();
6449  DenseMatrix P, V, DS, PDS(spaceDim), VDS(spaceDim);
6450  Vector c(spaceDim+1), x(spaceDim);
6451  const double factor = 2.0;
6452 
6453  // check for tangling assuming constant speed
6454  if (tmax < 1.0)
6455  {
6456  tmax = 1.0;
6457  }
6458  for (int i = 0; i < NumOfElements; i++)
6459  {
6460  Element *el = elements[i];
6461  int nv = el->GetNVertices();
6462  int *v = el->GetVertices();
6463  P.SetSize(spaceDim, nv);
6464  V.SetSize(spaceDim, nv);
6465  for (int j = 0; j < spaceDim; j++)
6466  for (int k = 0; k < nv; k++)
6467  {
6468  P(j, k) = vertices[v[k]](j);
6469  V(j, k) = displacements(v[k]+j*nvs);
6470  }
6471  DS.SetSize(nv, spaceDim);
6472  const FiniteElement *fe =
6473  GetTransformationFEforElementType(el->GetType());
6474  // check if det(P.DShape+t*V.DShape) > 0 for all x and 0<=t<=1
6475  switch (el->GetType())
6476  {
6477  case Element::TRIANGLE:
6478  case Element::TETRAHEDRON:
6479  {
6480  // DS is constant
6481  fe->CalcDShape(Geometries.GetCenter(fe->GetGeomType()), DS);
6482  Mult(P, DS, PDS);
6483  Mult(V, DS, VDS);
6484  DetOfLinComb(PDS, VDS, c);
6485  if (c(0) <= 0.0)
6486  {
6487  tmax = 0.0;
6488  }
6489  else
6490  {
6491  FindTMax(c, x, tmax, factor, Dim);
6492  }
6493  }
6494  break;
6495 
6496  case Element::QUADRILATERAL:
6497  {
6498  const IntegrationRule &ir = fe->GetNodes();
6499  for (int j = 0; j < nv; j++)
6500  {
6501  fe->CalcDShape(ir.IntPoint(j), DS);
6502  Mult(P, DS, PDS);
6503  Mult(V, DS, VDS);
6504  DetOfLinComb(PDS, VDS, c);
6505  if (c(0) <= 0.0)
6506  {
6507  tmax = 0.0;
6508  }
6509  else
6510  {
6511  FindTMax(c, x, tmax, factor, Dim);
6512  }
6513  }
6514  }
6515  break;
6516 
6517  default:
6518  mfem_error("Mesh::CheckDisplacements(...)");
6519  }
6520  }
6521 }
6522 
6523 void Mesh::MoveVertices(const Vector &displacements)
6524 {
6525  for (int i = 0, nv = vertices.Size(); i < nv; i++)
6526  for (int j = 0; j < spaceDim; j++)
6527  {
6528  vertices[i](j) += displacements(j*nv+i);
6529  }
6530 }
6531 
6532 void Mesh::GetVertices(Vector &vert_coord) const
6533 {
6534  int nv = vertices.Size();
6535  vert_coord.SetSize(nv*spaceDim);
6536  for (int i = 0; i < nv; i++)
6537  for (int j = 0; j < spaceDim; j++)
6538  {
6539  vert_coord(j*nv+i) = vertices[i](j);
6540  }
6541 }
6542 
6543 void Mesh::SetVertices(const Vector &vert_coord)
6544 {
6545  for (int i = 0, nv = vertices.Size(); i < nv; i++)
6546  for (int j = 0; j < spaceDim; j++)
6547  {
6548  vertices[i](j) = vert_coord(j*nv+i);
6549  }
6550 }
6551 
6552 void Mesh::GetNode(int i, double *coord) const
6553 {
6554  if (Nodes)
6555  {
6556  FiniteElementSpace *fes = Nodes->FESpace();
6557  for (int j = 0; j < spaceDim; j++)
6558  {
6559  coord[j] = (*Nodes)(fes->DofToVDof(i, j));
6560  }
6561  }
6562  else
6563  {
6564  for (int j = 0; j < spaceDim; j++)
6565  {
6566  coord[j] = vertices[i](j);
6567  }
6568  }
6569 }
6570 
6571 void Mesh::SetNode(int i, const double *coord)
6572 {
6573  if (Nodes)
6574  {
6575  FiniteElementSpace *fes = Nodes->FESpace();
6576  for (int j = 0; j < spaceDim; j++)
6577  {
6578  (*Nodes)(fes->DofToVDof(i, j)) = coord[j];
6579  }
6580  }
6581  else
6582  {
6583  for (int j = 0; j < spaceDim; j++)
6584  {
6585  vertices[i](j) = coord[j];
6586  }
6587 
6588  }
6589 }
6590 
6591 void Mesh::MoveNodes(const Vector &displacements)
6592 {
6593  if (Nodes)
6594  {
6595  (*Nodes) += displacements;
6596  }
6597  else
6598  {
6599  MoveVertices(displacements);
6600  }
6601 }
6602 
6603 void Mesh::GetNodes(Vector &node_coord) const
6604 {
6605  if (Nodes)
6606  {
6607  node_coord = (*Nodes);
6608  }
6609  else
6610  {
6611  GetVertices(node_coord);
6612  }
6613 }
6614 
6615 void Mesh::SetNodes(const Vector &node_coord)
6616 {
6617  if (Nodes)
6618  {
6619  (*Nodes) = node_coord;
6620  }
6621  else
6622  {
6623  SetVertices(node_coord);
6624  }
6625 }
6626 
6627 void Mesh::NewNodes(GridFunction &nodes, bool make_owner)
6628 {
6629  if (own_nodes) { delete Nodes; }
6630  Nodes = &nodes;
6631  spaceDim = Nodes->FESpace()->GetVDim();
6632  own_nodes = (int)make_owner;
6633 
6634  if (NURBSext != nodes.FESpace()->GetNURBSext())
6635  {
6636  delete NURBSext;
6637  NURBSext = nodes.FESpace()->StealNURBSext();
6638  }
6639 }
6640 
6641 void Mesh::SwapNodes(GridFunction *&nodes, int &own_nodes_)
6642 {
6643  mfem::Swap<GridFunction*>(Nodes, nodes);
6644  mfem::Swap<int>(own_nodes, own_nodes_);
6645  // TODO:
6646  // if (nodes)
6647  // nodes->FESpace()->MakeNURBSextOwner();
6648  // NURBSext = (Nodes) ? Nodes->FESpace()->StealNURBSext() : NULL;
6649 }
6650 
6651 void Mesh::AverageVertices(const int *indexes, int n, int result)
6652 {
6653  int j, k;
6654 
6655  for (k = 0; k < spaceDim; k++)
6656  {
6657  vertices[result](k) = vertices[indexes[0]](k);
6658  }
6659 
6660  for (j = 1; j < n; j++)
6661  for (k = 0; k < spaceDim; k++)
6662  {
6663  vertices[result](k) += vertices[indexes[j]](k);
6664  }
6665 
6666  for (k = 0; k < spaceDim; k++)
6667  {
6668  vertices[result](k) *= (1.0 / n);
6669  }
6670 }
6671 
6672 void Mesh::UpdateNodes()
6673 {
6674  if (Nodes)
6675  {
6676  Nodes->FESpace()->Update();
6677  Nodes->Update();
6678  }
6679 }
6680 
6681 void Mesh::UniformRefinement2D_base(bool update_nodes)
6682 {
6683  ResetLazyData();
6684 
6685  if (el_to_edge == NULL)
6686  {
6687  el_to_edge = new Table;
6688  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
6689  }
6690 
6691  int quad_counter = 0;
6692  for (int i = 0; i < NumOfElements; i++)
6693  {
6694  if (elements[i]->GetType() == Element::QUADRILATERAL)
6695  {
6696  quad_counter++;
6697  }
6698  }
6699 
6700  const int oedge = NumOfVertices;
6701  const int oelem = oedge + NumOfEdges;
6702 
6703  Array<Element*> new_elements;
6704  Array<Element*> new_boundary;
6705 
6706  vertices.SetSize(oelem + quad_counter);
6707  new_elements.SetSize(4 * NumOfElements);
6708  quad_counter = 0;
6709 
6710  for (int i = 0, j = 0; i < NumOfElements; i++)
6711  {
6712  const Element::Type el_type = elements[i]->GetType();
6713  const int attr = elements[i]->GetAttribute();
6714  int *v = elements[i]->GetVertices();
6715  const int *e = el_to_edge->GetRow(i);
6716  int vv[2];
6717 
6718  if (el_type == Element::TRIANGLE)
6719  {
6720  for (int ei = 0; ei < 3; ei++)
6721  {
6722  for (int k = 0; k < 2; k++)
6723  {
6724  vv[k] = v[tri_t::Edges[ei][k]];
6725  }
6726  AverageVertices(vv, 2, oedge+e[ei]);
6727  }
6728 
6729  new_elements[j++] =
6730  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
6731  new_elements[j++] =
6732  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
6733  new_elements[j++] =
6734  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
6735  new_elements[j++] =
6736  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
6737  }
6738  else if (el_type == Element::QUADRILATERAL)
6739  {
6740  const int qe = quad_counter;
6741  quad_counter++;
6742  AverageVertices(v, 4, oelem+qe);
6743 
6744  for (int ei = 0; ei < 4; ei++)
6745  {
6746  for (int k = 0; k < 2; k++)
6747  {
6748  vv[k] = v[quad_t::Edges[ei][k]];
6749  }
6750  AverageVertices(vv, 2, oedge+e[ei]);
6751  }
6752 
6753  new_elements[j++] =
6754  new Quadrilateral(v[0], oedge+e[0], oelem+qe, oedge+e[3], attr);
6755  new_elements[j++] =
6756  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oelem+qe, attr);
6757  new_elements[j++] =
6758  new Quadrilateral(oelem+qe, oedge+e[1], v[2], oedge+e[2], attr);
6759  new_elements[j++] =
6760  new Quadrilateral(oedge+e[3], oelem+qe, oedge+e[2], v[3], attr);
6761  }
6762  else
6763  {
6764  MFEM_ABORT("unknown element type: " << el_type);
6765  }
6766  FreeElement(elements[i]);
6767  }
6768  mfem::Swap(elements, new_elements);
6769 
6770  // refine boundary elements
6771  new_boundary.SetSize(2 * NumOfBdrElements);
6772  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
6773  {
6774  const int attr = boundary[i]->GetAttribute();
6775  int *v = boundary[i]->GetVertices();
6776 
6777  new_boundary[j++] = new Segment(v[0], oedge+be_to_edge[i], attr);
6778  new_boundary[j++] = new Segment(oedge+be_to_edge[i], v[1], attr);
6779 
6780  FreeElement(boundary[i]);
6781  }
6782  mfem::Swap(boundary, new_boundary);
6783 
6784  static const double A = 0.0, B = 0.5, C = 1.0;
6785  static double tri_children[2*3*4] =
6786  {
6787  A,A, B,A, A,B,
6788  B,B, A,B, B,A,
6789  B,A, C,A, B,B,
6790  A,B, B,B, A,C
6791  };
6792  static double quad_children[2*4*4] =
6793  {
6794  A,A, B,A, B,B, A,B, // lower-left
6795  B,A, C,A, C,B, B,B, // lower-right
6796  B,B, C,B, C,C, B,C, // upper-right
6797  A,B, B,B, B,C, A,C // upper-left
6798  };
6799 
6800  CoarseFineTr.point_matrices[Geometry::TRIANGLE]
6801  .UseExternalData(tri_children, 2, 3, 4);
6802  CoarseFineTr.point_matrices[Geometry::SQUARE]
6803  .UseExternalData(quad_children, 2, 4, 4);
6804  CoarseFineTr.embeddings.SetSize(elements.Size());
6805 
6806  for (int i = 0; i < elements.Size(); i++)
6807  {
6808  Embedding &emb = CoarseFineTr.embeddings[i];
6809  emb.parent = i / 4;
6810  emb.matrix = i % 4;
6811  }
6812 
6813  NumOfVertices = vertices.Size();
6814  NumOfElements = 4 * NumOfElements;
6815  NumOfBdrElements = 2 * NumOfBdrElements;
6816  NumOfFaces = 0;
6817 
6818  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
6819  GenerateFaces();
6820 
6821  last_operation = Mesh::REFINE;
6822  sequence++;
6823 
6824  if (update_nodes) { UpdateNodes(); }
6825 
6826 #ifdef MFEM_DEBUG
6827  if (!Nodes || update_nodes)
6828  {
6829  CheckElementOrientation(false);
6830  }
6831  CheckBdrElementOrientation(false);
6832 #endif
6833 }
6834 
6835 static inline double sqr(const double &x)
6836 {
6837  return x*x;
6838 }
6839 
6840 void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
6841  bool update_nodes)
6842 {
6843  ResetLazyData();
6844 
6845  if (el_to_edge == NULL)
6846  {
6847  el_to_edge = new Table;
6848  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
6849  }
6850 
6851  if (el_to_face == NULL)
6852  {
6853  GetElementToFaceTable();
6854  }
6855 
6856  Array<int> f2qf_loc;
6857  Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
6858  f2qf.SetSize(0);
6859 
6860  int NumOfQuadFaces = 0;
6861  if (HasGeometry(Geometry::SQUARE))
6862  {
6863  if (HasGeometry(Geometry::TRIANGLE))
6864  {
6865  f2qf.SetSize(faces.Size());
6866  for (int i = 0; i < faces.Size(); i++)
6867  {
6868  if (faces[i]->GetType() == Element::QUADRILATERAL)
6869  {
6870  f2qf[i] = NumOfQuadFaces;
6871  NumOfQuadFaces++;
6872  }
6873  }
6874  }
6875  else
6876  {
6877  NumOfQuadFaces = faces.Size();
6878  }
6879  }
6880 
6881  int hex_counter = 0;
6882  if (HasGeometry(Geometry::CUBE))
6883  {
6884  for (int i = 0; i < elements.Size(); i++)
6885  {
6886  if (elements[i]->GetType() == Element::HEXAHEDRON)
6887  {
6888  hex_counter++;
6889  }
6890  }
6891  }
6892 
6893  // Map from edge-index to vertex-index, needed for ReorientTetMesh() for
6894  // parallel meshes.
6895  Array<int> e2v;
6896  if (HasGeometry(Geometry::TETRAHEDRON))
6897  {
6898  e2v.SetSize(NumOfEdges);
6899 
6900  DSTable *v_to_v_ptr = v_to_v_p;
6901  if (!v_to_v_p)
6902  {
6903  v_to_v_ptr = new DSTable(NumOfVertices);
6904  GetVertexToVertexTable(*v_to_v_ptr);
6905  }
6906 
6907  Array<Pair<int,int> > J_v2v(NumOfEdges); // (second vertex id, edge id)
6908  J_v2v.SetSize(0);
6909  for (int i = 0; i < NumOfVertices; i++)
6910  {
6911  Pair<int,int> *row_start = J_v2v.end();
6912  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
6913  {
6914  J_v2v.Append(Pair<int,int>(it.Column(), it.Index()));
6915  }
6916  std::sort(row_start, J_v2v.end());
6917  }
6918 
6919  for (int i = 0; i < J_v2v.Size(); i++)
6920  {
6921  e2v[J_v2v[i].two] = i;
6922  }
6923 
6924  if (!v_to_v_p)
6925  {
6926  delete v_to_v_ptr;
6927  }
6928  else
6929  {
6930  for (int i = 0; i < NumOfVertices; i++)
6931  {
6932  for (DSTable::RowIterator it(*v_to_v_ptr, i); !it; ++it)
6933  {
6934  it.SetIndex(e2v[it.Index()]);
6935  }
6936  }
6937  }
6938  }
6939 
6940  // Offsets for new vertices from edges, faces (quads only), and elements
6941  // (hexes only); each of these entities generates one new vertex.
6942  const int oedge = NumOfVertices;
6943  const int oface = oedge + NumOfEdges;
6944  const int oelem = oface + NumOfQuadFaces;
6945 
6946  Array<Element*> new_elements;
6947  Array<Element*> new_boundary;
6948 
6949  vertices.SetSize(oelem + hex_counter);
6950  new_elements.SetSize(8 * NumOfElements);
6951  CoarseFineTr.embeddings.SetSize(new_elements.Size());
6952 
6953  hex_counter = 0;
6954  for (int i = 0, j = 0; i < NumOfElements; i++)
6955  {
6956  const Element::Type el_type = elements[i]->GetType();
6957  const int attr = elements[i]->GetAttribute();
6958  int *v = elements[i]->GetVertices();
6959  const int *e = el_to_edge->GetRow(i);
6960  int vv[4], ev[12];
6961 
6962  if (e2v.Size())
6963  {
6964  const int ne = el_to_edge->RowSize(i);
6965  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
6966  e = ev;
6967  }
6968 
6969  switch (el_type)
6970  {
6971  case Element::TETRAHEDRON:
6972  {
6973  for (int ei = 0; ei < 6; ei++)
6974  {
6975  for (int k = 0; k < 2; k++)
6976  {
6977  vv[k] = v[tet_t::Edges[ei][k]];
6978  }
6979  AverageVertices(vv, 2, oedge+e[ei]);
6980  }
6981 
6982  // Algorithm for choosing refinement type:
6983  // 0: smallest octahedron diagonal
6984  // 1: best aspect ratio
6985  const int rt_algo = 1;
6986  // Refinement type:
6987  // 0: (v0,v1)-(v2,v3), 1: (v0,v2)-(v1,v3), 2: (v0,v3)-(v1,v2)
6988  // 0: e0-e5, 1: e1-e4, 2: e2-e3
6989  int rt;
6990  ElementTransformation *T = GetElementTransformation(i);
6991  T->SetIntPoint(&Geometries.GetCenter(Geometry::TETRAHEDRON));
6992  const DenseMatrix &J = T->Jacobian();
6993  if (rt_algo == 0)
6994  {
6995  // smallest octahedron diagonal
6996  double len_sqr, min_len;
6997 
6998  min_len = sqr(J(0,0)-J(0,1)-J(0,2)) +
6999  sqr(J(1,0)-J(1,1)-J(1,2)) +
7000  sqr(J(2,0)-J(2,1)-J(2,2));
7001  rt = 0;
7002 
7003  len_sqr = sqr(J(0,1)-J(0,0)-J(0,2)) +
7004  sqr(J(1,1)-J(1,0)-J(1,2)) +
7005  sqr(J(2,1)-J(2,0)-J(2,2));
7006  if (len_sqr < min_len) { min_len = len_sqr; rt = 1; }
7007 
7008  len_sqr = sqr(J(0,2)-J(0,0)-J(0,1)) +
7009  sqr(J(1,2)-J(1,0)-J(1,1)) +
7010  sqr(J(2,2)-J(2,0)-J(2,1));
7011  if (len_sqr < min_len) { rt = 2; }
7012  }
7013  else
7014  {
7015  // best aspect ratio
7016  double Em_data[18], Js_data[9], Jp_data[9];
7017  DenseMatrix Em(Em_data, 3, 6);
7018  DenseMatrix Js(Js_data, 3, 3), Jp(Jp_data, 3, 3);
7019  double ar1, ar2, kappa, kappa_min;
7020 
7021  for (int s = 0; s < 3; s++)
7022  {
7023  for (int t = 0; t < 3; t++)
7024  {
7025  Em(t,s) = 0.5*J(t,s);
7026  }
7027  }
7028  for (int t = 0; t < 3; t++)
7029  {
7030  Em(t,3) = 0.5*(J(t,0)+J(t,1));
7031  Em(t,4) = 0.5*(J(t,0)+J(t,2));
7032  Em(t,5) = 0.5*(J(t,1)+J(t,2));
7033  }
7034 
7035  // rt = 0; Em: {0,5,1,2}, {0,5,2,4}
7036  for (int t = 0; t < 3; t++)
7037  {
7038  Js(t,0) = Em(t,5)-Em(t,0);
7039  Js(t,1) = Em(t,1)-Em(t,0);
7040  Js(t,2) = Em(t,2)-Em(t,0);
7041  }
7042  Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
7043  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7044  for (int t = 0; t < 3; t++)
7045  {
7046  Js(t,0) = Em(t,5)-Em(t,0);
7047  Js(t,1) = Em(t,2)-Em(t,0);
7048  Js(t,2) = Em(t,4)-Em(t,0);
7049  }
7050  Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
7051  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7052  kappa_min = std::max(ar1, ar2);
7053  rt = 0;
7054 
7055  // rt = 1; Em: {1,0,4,2}, {1,2,4,5}
7056  for (int t = 0; t < 3; t++)
7057  {
7058  Js(t,0) = Em(t,0)-Em(t,1);
7059  Js(t,1) = Em(t,4)-Em(t,1);
7060  Js(t,2) = Em(t,2)-Em(t,1);
7061  }
7062  Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
7063  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7064  for (int t = 0; t < 3; t++)
7065  {
7066  Js(t,0) = Em(t,2)-Em(t,1);
7067  Js(t,1) = Em(t,4)-Em(t,1);
7068  Js(t,2) = Em(t,5)-Em(t,1);
7069  }
7070  Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
7071  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7072  kappa = std::max(ar1, ar2);
7073  if (kappa < kappa_min) { kappa_min = kappa; rt = 1; }
7074 
7075  // rt = 2; Em: {2,0,1,3}, {2,1,5,3}
7076  for (int t = 0; t < 3; t++)
7077  {
7078  Js(t,0) = Em(t,0)-Em(t,2);
7079  Js(t,1) = Em(t,1)-Em(t,2);
7080  Js(t,2) = Em(t,3)-Em(t,2);
7081  }
7082  Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
7083  ar1 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7084  for (int t = 0; t < 3; t++)
7085  {
7086  Js(t,0) = Em(t,1)-Em(t,2);
7087  Js(t,1) = Em(t,5)-Em(t,2);
7088  Js(t,2) = Em(t,3)-Em(t,2);
7089  }
7090  Geometries.JacToPerfJac(Geometry::TETRAHEDRON, Js, Jp);
7091  ar2 = Jp.CalcSingularvalue(0)/Jp.CalcSingularvalue(2);
7092  kappa = std::max(ar1, ar2);
7093  if (kappa < kappa_min) { rt = 2; }
7094  }
7095 
7096  static const int mv_all[3][4][4] =
7097  {
7098  { {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1} }, // rt = 0
7099  { {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0} }, // rt = 1
7100  { {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3} } // rt = 2
7101  };
7102  const int (&mv)[4][4] = mv_all[rt];
7103 
7104 #ifndef MFEM_USE_MEMALLOC
7105  new_elements[j+0] =
7106  new Tetrahedron(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
7107  new_elements[j+1] =
7108  new Tetrahedron(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
7109  new_elements[j+2] =
7110  new Tetrahedron(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
7111  new_elements[j+3] =
7112  new Tetrahedron(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
7113 
7114  for (int k = 0; k < 4; k++)
7115  {
7116  new_elements[j+4+k] =
7117  new Tetrahedron(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
7118  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
7119  }
7120 #else
7121  Tetrahedron *tet;
7122  new_elements[j+0] = tet = TetMemory.Alloc();
7123  tet->Init(v[0], oedge+e[0], oedge+e[1], oedge+e[2], attr);
7124 
7125  new_elements[j+1] = tet = TetMemory.Alloc();
7126  tet->Init(oedge+e[0], v[1], oedge+e[3], oedge+e[4], attr);
7127 
7128  new_elements[j+2] = tet = TetMemory.Alloc();
7129  tet->Init(oedge+e[1], oedge+e[3], v[2], oedge+e[5], attr);
7130 
7131  new_elements[j+3] = tet = TetMemory.Alloc();
7132  tet->Init(oedge+e[2], oedge+e[4], oedge+e[5], v[3], attr);
7133 
7134  for (int k = 0; k < 4; k++)
7135  {
7136  new_elements[j+4+k] = tet = TetMemory.Alloc();
7137  tet->Init(oedge+e[mv[k][0]], oedge+e[mv[k][1]],
7138  oedge+e[mv[k][2]], oedge+e[mv[k][3]], attr);
7139  }
7140 #endif
7141  for (int k = 0; k < 4; k++)
7142  {
7143  CoarseFineTr.embeddings[j+k].parent = i;
7144  CoarseFineTr.embeddings[j+k].matrix = k;
7145  }
7146  for (int k = 0; k < 4; k++)
7147  {
7148  CoarseFineTr.embeddings[j+4+k].parent = i;
7149  CoarseFineTr.embeddings[j+4+k].matrix = 4*(rt+1)+k;
7150  }
7151 
7152  j += 8;
7153  }
7154  break;
7155 
7156  case Element::WEDGE:
7157  {
7158  const int *f = el_to_face->GetRow(i);
7159 
7160  for (int fi = 2; fi < 5; fi++)
7161  {
7162  for (int k = 0; k < 4; k++)
7163  {
7164  vv[k] = v[pri_t::FaceVert[fi][k]];
7165  }
7166  AverageVertices(vv, 4, oface + f2qf[f[fi]]);
7167  }
7168 
7169  for (int ei = 0; ei < 9; ei++)
7170  {
7171  for (int k = 0; k < 2; k++)
7172  {
7173  vv[k] = v[pri_t::Edges[ei][k]];
7174  }
7175  AverageVertices(vv, 2, oedge+e[ei]);
7176  }
7177 
7178  const int qf2 = f2qf[f[2]];
7179  const int qf3 = f2qf[f[3]];
7180  const int qf4 = f2qf[f[4]];
7181 
7182  new_elements[j++] =
7183  new Wedge(v[0], oedge+e[0], oedge+e[2],
7184  oedge+e[6], oface+qf2, oface+qf4, attr);
7185 
7186  new_elements[j++] =
7187  new Wedge(oedge+e[1], oedge+e[2], oedge+e[0],
7188  oface+qf3, oface+qf4, oface+qf2, attr);
7189 
7190  new_elements[j++] =
7191  new Wedge(oedge+e[0], v[1], oedge+e[1],
7192  oface+qf2, oedge+e[7], oface+qf3, attr);
7193 
7194  new_elements[j++] =
7195  new Wedge(oedge+e[2], oedge+e[1], v[2],
7196  oface+qf4, oface+qf3, oedge+e[8], attr);
7197 
7198  new_elements[j++] =
7199  new Wedge(oedge+e[6], oface+qf2, oface+qf4,
7200  v[3], oedge+e[3], oedge+e[5], attr);
7201 
7202  new_elements[j++] =
7203  new Wedge(oface+qf3, oface+qf4, oface+qf2,
7204  oedge+e[4], oedge+e[5], oedge+e[3], attr);
7205 
7206  new_elements[j++] =
7207  new Wedge(oface+qf2, oedge+e[7], oface+qf3,
7208  oedge+e[3], v[4], oedge+e[4], attr);
7209 
7210  new_elements[j++] =
7211  new Wedge(oface+qf4, oface+qf3, oedge+e[8],
7212  oedge+e[5], oedge+e[4], v[5], attr);
7213  }
7214  break;
7215 
7216  case Element::HEXAHEDRON:
7217  {
7218  const int *f = el_to_face->GetRow(i);
7219  const int he = hex_counter;
7220  hex_counter++;
7221 
7222  const int *qf;
7223  int qf_data[6];
7224  if (f2qf.Size() == 0)
7225  {
7226  qf = f;
7227  }
7228  else
7229  {
7230  for (int k = 0; k < 6; k++) { qf_data[k] = f2qf[f[k]]; }
7231  qf = qf_data;
7232  }
7233 
7234  AverageVertices(v, 8, oelem+he);
7235 
7236  for (int fi = 0; fi < 6; fi++)
7237  {
7238  for (int k = 0; k < 4; k++)
7239  {
7240  vv[k] = v[hex_t::FaceVert[fi][k]];
7241  }
7242  AverageVertices(vv, 4, oface + qf[fi]);
7243  }
7244 
7245  for (int ei = 0; ei < 12; ei++)
7246  {
7247  for (int k = 0; k < 2; k++)
7248  {
7249  vv[k] = v[hex_t::Edges[ei][k]];
7250  }
7251  AverageVertices(vv, 2, oedge+e[ei]);
7252  }
7253 
7254  new_elements[j++] =
7255  new Hexahedron(v[0], oedge+e[0], oface+qf[0],
7256  oedge+e[3], oedge+e[8], oface+qf[1],
7257  oelem+he, oface+qf[4], attr);
7258  new_elements[j++] =
7259  new Hexahedron(oedge+e[0], v[1], oedge+e[1],
7260  oface+qf[0], oface+qf[1], oedge+e[9],
7261  oface+qf[2], oelem+he, attr);
7262  new_elements[j++] =
7263  new Hexahedron(oface+qf[0], oedge+e[1], v[2],
7264  oedge+e[2], oelem+he, oface+qf[2],
7265  oedge+e[10], oface+qf[3], attr);
7266  new_elements[j++] =
7267  new Hexahedron(oedge+e[3], oface+qf[0], oedge+e[2],
7268  v[3], oface+qf[4], oelem+he,
7269  oface+qf[3], oedge+e[11], attr);
7270  new_elements[j++] =
7271  new Hexahedron(oedge+e[8], oface+qf[1], oelem+he,
7272  oface+qf[4], v[4], oedge+e[4],
7273  oface+qf[5], oedge+e[7], attr);
7274  new_elements[j++] =
7275  new Hexahedron(oface+qf[1], oedge+e[9], oface+qf[2],
7276  oelem+he, oedge+e[4], v[5],
7277  oedge+e[5], oface+qf[5], attr);
7278  new_elements[j++] =
7279  new Hexahedron(oelem+he, oface+qf[2], oedge+e[10],
7280  oface+qf[3], oface+qf[5], oedge+e[5],
7281  v[6], oedge+e[6], attr);
7282  new_elements[j++] =
7283  new Hexahedron(oface+qf[4], oelem+he, oface+qf[3],
7284  oedge+e[11], oedge+e[7], oface+qf[5],
7285  oedge+e[6], v[7], attr);
7286  }
7287  break;
7288 
7289  default:
7290  MFEM_ABORT("Unknown 3D element type \"" << el_type << "\"");
7291  break;
7292  }
7293  FreeElement(elements[i]);
7294  }
7295  mfem::Swap(elements, new_elements);
7296 
7297  // refine boundary elements
7298  new_boundary.SetSize(4 * NumOfBdrElements);
7299  for (int i = 0, j = 0; i < NumOfBdrElements; i++)
7300  {
7301  const Element::Type bdr_el_type = boundary[i]->GetType();
7302  const int attr = boundary[i]->GetAttribute();
7303  int *v = boundary[i]->GetVertices();
7304  const int *e = bel_to_edge->GetRow(i);
7305  int ev[4];
7306 
7307  if (e2v.Size())
7308  {
7309  const int ne = bel_to_edge->RowSize(i);
7310  for (int k = 0; k < ne; k++) { ev[k] = e2v[e[k]]; }
7311  e = ev;
7312  }
7313 
7314  if (bdr_el_type == Element::TRIANGLE)
7315  {
7316  new_boundary[j++] =
7317  new Triangle(v[0], oedge+e[0], oedge+e[2], attr);
7318  new_boundary[j++] =
7319  new Triangle(oedge+e[1], oedge+e[2], oedge+e[0], attr);
7320  new_boundary[j++] =
7321  new Triangle(oedge+e[0], v[1], oedge+e[1], attr);
7322  new_boundary[j++] =
7323  new Triangle(oedge+e[2], oedge+e[1], v[2], attr);
7324  }
7325  else if (bdr_el_type == Element::QUADRILATERAL)
7326  {
7327  const int qf =
7328  (f2qf.Size() == 0) ? be_to_face[i] : f2qf[be_to_face[i]];
7329 
7330  new_boundary[j++] =
7331  new Quadrilateral(v[0], oedge+e[0], oface+qf, oedge+e[3], attr);
7332  new_boundary[j++] =
7333  new Quadrilateral(oedge+e[0], v[1], oedge+e[1], oface+qf, attr);
7334  new_boundary[j++] =
7335  new Quadrilateral(oface+qf, oedge+e[1], v[2], oedge+e[2], attr);
7336  new_boundary[j++] =
7337  new Quadrilateral(oedge+e[3], oface+qf, oedge+e[2], v[3], attr);
7338  }
7339  else
7340  {
7341  MFEM_ABORT("boundary Element is not a triangle or a quad!");
7342  }
7343  FreeElement(boundary[i]);
7344  }
7345  mfem::Swap(boundary, new_boundary);
7346 
7347  static const double A = 0.0, B = 0.5, C = 1.0;
7348  static double tet_children[3*4*16] =
7349  {
7350  A,A,A, B,A,A, A,B,A, A,A,B,
7351  B,A,A, C,A,A, B,B,A, B,A,B,
7352  A,B,A, B,B,A, A,C,A, A,B,B,
7353  A,A,B, B,A,B, A,B,B, A,A,C,
7354  // edge coordinates:
7355  // 0 -> B,A,A 1 -> A,B,A 2 -> A,A,B
7356  // 3 -> B,B,A 4 -> B,A,B 5 -> A,B,B
7357  // rt = 0: {0,5,1,2}, {0,5,2,4}, {0,5,4,3}, {0,5,3,1}
7358  B,A,A, A,B,B, A,B,A, A,A,B,
7359  B,A,A, A,B,B, A,A,B, B,A,B,
7360  B,A,A, A,B,B, B,A,B, B,B,A,
7361  B,A,A, A,B,B, B,B,A, A,B,A,
7362  // rt = 1: {1,0,4,2}, {1,2,4,5}, {1,5,4,3}, {1,3,4,0}
7363  A,B,A, B,A,A, B,A,B, A,A,B,
7364  A,B,A, A,A,B, B,A,B, A,B,B,
7365  A,B,A, A,B,B, B,A,B, B,B,A,
7366  A,B,A, B,B,A, B,A,B, B,A,A,
7367  // rt = 2: {2,0,1,3}, {2,1,5,3}, {2,5,4,3}, {2,4,0,3}
7368  A,A,B, B,A,A, A,B,A, B,B,A,
7369  A,A,B, A,B,A, A,B,B, B,B,A,
7370  A,A,B, A,B,B, B,A,B, B,B,A,
7371  A,A,B, B,A,B, B,A,A, B,B,A
7372  };
7373  static double pri_children[3*6*8] =
7374  {
7375  A,A,A, B,A,A, A,B,A, A,A,B, B,A,B, A,B,B,
7376  B,B,A, A,B,A, B,A,A, B,B,B, A,B,B, B,A,B,
7377  B,A,A, C,A,A, B,B,A, B,A,B, C,A,B, B,B,B,
7378  A,B,A, B,B,A, A,C,A, A,B,B, B,B,B, A,C,B,
7379  A,A,B, B,A,B, A,B,B, A,A,C, B,A,C, A,B,C,
7380  B,B,B, A,B,B, B,A,B, B,B,C, A,B,C, B,A,C,
7381  B,A,B, C,A,B, B,B,B, B,A,C, C,A,C, B,B,C,
7382  A,B,B, B,B,B, A,C,B, A,B,C, B,B,C, A,C,C
7383  };
7384  static double hex_children[3*8*8] =
7385  {
7386  A,A,A, B,A,A, B,B,A, A,B,A, A,A,B, B,A,B, B,B,B, A,B,B,
7387  B,A,A, C,A,A, C,B,A, B,B,A, B,A,B, C,A,B, C,B,B, B,B,B,
7388  B,B,A, C,B,A, C,C,A, B,C,A, B,B,B, C,B,B, C,C,B, B,C,B,
7389  A,B,A, B,B,A, B,C,A, A,C,A, A,B,B, B,B,B, B,C,B, A,C,B,
7390  A,A,B, B,A,B, B,B,B, A,B,B, A,A,C, B,A,C, B,B,C, A,B,C,
7391  B,A,B, C,A,B, C,B,B, B,B,B, B,A,C, C,A,C, C,B,C, B,B,C,
7392  B,B,B, C,B,B, C,C,B, B,C,B, B,B,C, C,B,C, C,C,C, B,C,C,
7393  A,B,B, B,B,B, B,C,B, A,C,B, A,B,C, B,B,C, B,C,C, A,C,C
7394  };
7395 
7396  CoarseFineTr.point_matrices[Geometry::TETRAHEDRON]
7397  .UseExternalData(tet_children, 3, 4, 16);
7398  CoarseFineTr.point_matrices[Geometry::PRISM]
7399  .UseExternalData(pri_children, 3, 6, 8);
7400  CoarseFineTr.point_matrices[Geometry::CUBE]
7401  .UseExternalData(hex_children, 3, 8, 8);
7402 
7403  for (int i = 0; i < elements.Size(); i++)
7404  {
7405  // tetrahedron elements are handled above:
7406  if (elements[i]->GetType() == Element::TETRAHEDRON) { continue; }
7407 
7408  Embedding &emb = CoarseFineTr.embeddings[i];
7409  emb.parent = i / 8;
7410  emb.matrix = i % 8;
7411  }
7412 
7413  NumOfVertices = vertices.Size();
7414  NumOfElements = 8 * NumOfElements;
7415  NumOfBdrElements = 4 * NumOfBdrElements;
7416 
7417  GetElementToFaceTable();
7418  GenerateFaces();
7419 
7420 #ifdef MFEM_DEBUG
7421  CheckBdrElementOrientation(false);
7422 #endif
7423 
7424  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
7425 
7426  last_operation = Mesh::REFINE;
7427  sequence++;
7428 
7429  if (update_nodes) { UpdateNodes(); }
7430 }
7431 
7432 void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
7433 {
7434  int i, j, ind, nedges;
7435  Array<int> v;
7436 
7437  ResetLazyData();
7438 
7439  if (ncmesh)
7440  {
7441  MFEM_ABORT("Local and nonconforming refinements cannot be mixed.");
7442  }
7443 
7444  InitRefinementTransforms();
7445 
7446  if (Dim == 1) // --------------------------------------------------------
7447  {
7448  int cne = NumOfElements, cnv = NumOfVertices;
7449  NumOfVertices += marked_el.Size();
7450  NumOfElements += marked_el.Size();
7451  vertices.SetSize(NumOfVertices);
7452  elements.SetSize(NumOfElements);
7453  CoarseFineTr.embeddings.SetSize(NumOfElements);
7454 
7455  for (j = 0; j < marked_el.Size(); j++)
7456  {
7457  i = marked_el[j];
7458  Segment *c_seg = (Segment *)elements[i];
7459  int *vert = c_seg->GetVertices(), attr = c_seg->GetAttribute();
7460  int new_v = cnv + j, new_e = cne + j;
7461  AverageVertices(vert, 2, new_v);
7462  elements[new_e] = new Segment(new_v, vert[1], attr);
7463  vert[1] = new_v;
7464 
7465  CoarseFineTr.embeddings[i] = Embedding(i, 1);
7466  CoarseFineTr.embeddings[new_e] = Embedding(i, 2);
7467  }
7468 
7469  static double seg_children[3*2] = { 0.0,1.0, 0.0,0.5, 0.5,1.0 };
7470  CoarseFineTr.point_matrices[Geometry::SEGMENT].
7471  UseExternalData(seg_children, 1, 2, 3);
7472 
7473  GenerateFaces();
7474 
7475  } // end of 'if (Dim == 1)'
7476  else if (Dim == 2) // ---------------------------------------------------
7477  {
7478  // 1. Get table of vertex to vertex connections.
7479  DSTable v_to_v(NumOfVertices);
7480  GetVertexToVertexTable(v_to_v);
7481 
7482  // 2. Get edge to element connections in arrays edge1 and edge2
7483  nedges = v_to_v.NumberOfEntries();
7484  int *edge1 = new int[nedges];
7485  int *edge2 = new int[nedges];
7486  int *middle = new int[nedges];
7487 
7488  for (i = 0; i < nedges; i++)
7489  {
7490  edge1[i] = edge2[i] = middle[i] = -1;
7491  }
7492 
7493  for (i = 0; i < NumOfElements; i++)
7494  {
7495  elements[i]->GetVertices(v);
7496  for (j = 1; j < v.Size(); j++)
7497  {
7498  ind = v_to_v(v[j-1], v[j]);
7499  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
7500  }
7501  ind = v_to_v(v[0], v[v.Size()-1]);
7502  (edge1[ind] == -1) ? (edge1[ind] = i) : (edge2[ind] = i);
7503  }
7504 
7505  // 3. Do the red refinement.
7506  for (i = 0; i < marked_el.Size(); i++)
7507  {
7508  RedRefinement(marked_el[i], v_to_v, edge1, edge2, middle);
7509  }
7510 
7511  // 4. Do the green refinement (to get conforming mesh).
7512  int need_refinement;
7513  do
7514  {
7515  need_refinement = 0;
7516  for (i = 0; i < nedges; i++)
7517  {
7518  if (middle[i] != -1 && edge1[i] != -1)
7519  {
7520  need_refinement = 1;
7521  GreenRefinement(edge1[i], v_to_v, edge1, edge2, middle);
7522  }
7523  }
7524  }
7525  while (need_refinement == 1);
7526 
7527  // 5. Update the boundary elements.
7528  int v1[2], v2[2], bisect, temp;
7529  temp = NumOfBdrElements;
7530  for (i = 0; i < temp; i++)
7531  {
7532  boundary[i]->GetVertices(v);
7533  bisect = v_to_v(v[0], v[1]);
7534  if (middle[bisect] != -1) // the element was refined (needs updating)
7535  {
7536  if (boundary[i]->GetType() == Element::SEGMENT)
7537  {
7538  v1[0] = v[0]; v1[1] = middle[bisect];
7539  v2[0] = middle[bisect]; v2[1] = v[1];
7540 
7541  boundary[i]->SetVertices(v1);
7542  boundary.Append(new Segment(v2, boundary[i]->GetAttribute()));
7543  }
7544  else
7545  mfem_error("Only bisection of segment is implemented"
7546  " for bdr elem.");
7547  }
7548  }
7549  NumOfBdrElements = boundary.Size();
7550 
7551  // 6. Free the allocated memory.
7552  delete [] edge1;
7553  delete [] edge2;
7554  delete [] middle;
7555 
7556  if (el_to_edge != NULL)
7557  {
7558  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
7559  GenerateFaces();
7560  }
7561 
7562  }
7563  else if (Dim == 3) // ---------------------------------------------------
7564  {
7565  // 1. Hash table of vertex to vertex connections corresponding to refined
7566  // edges.
7567  HashTable<Hashed2> v_to_v;
7568 
7569  MFEM_VERIFY(GetNE() == 0 ||
7570  ((Tetrahedron*)elements[0])->GetRefinementFlag() != 0,
7571  "tetrahedral mesh is not marked for refinement:"
7572  " call Finalize(true)");
7573 
7574  // 2. Do the red refinement.
7575  int ii;
7576  switch (type)
7577  {
7578  case 1:
7579  for (i = 0; i < marked_el.Size(); i++)
7580  {
7581  Bisection(marked_el[i], v_to_v);
7582  }
7583  break;
7584  case 2:
7585  for (i = 0; i < marked_el.Size(); i++)
7586  {
7587  Bisection(marked_el[i], v_to_v);
7588 
7589  Bisection(NumOfElements - 1, v_to_v);
7590  Bisection(marked_el[i], v_to_v);
7591  }
7592  break;
7593  case 3:
7594  for (i = 0; i < marked_el.Size(); i++)
7595  {
7596  Bisection(marked_el[i], v_to_v);
7597 
7598  ii = NumOfElements - 1;
7599  Bisection(ii, v_to_v);
7600  Bisection(NumOfElements - 1, v_to_v);
7601  Bisection(ii, v_to_v);
7602 
7603  Bisection(marked_el[i], v_to_v);
7604  Bisection(NumOfElements-1, v_to_v);
7605  Bisection(marked_el[i], v_to_v);
7606  }
7607  break;
7608  }
7609 
7610  // 3. Do the green refinement (to get conforming mesh).
7611  int need_refinement;
7612  // int need_refinement, onoe, max_gen = 0;
7613  do
7614  {
7615  // int redges[2], type, flag;
7616  need_refinement = 0;
7617  // onoe = NumOfElements;
7618  // for (i = 0; i < onoe; i++)
7619  for (i = 0; i < NumOfElements; i++)
7620  {
7621  // ((Tetrahedron *)elements[i])->
7622  // ParseRefinementFlag(redges, type, flag);
7623  // if (flag > max_gen) max_gen = flag;
7624  if (elements[i]->NeedRefinement(v_to_v))
7625  {
7626  need_refinement = 1;
7627  Bisection(i, v_to_v);
7628  }
7629  }
7630  }
7631  while (need_refinement == 1);
7632 
7633  // mfem::out << "Maximum generation: " << max_gen << endl;
7634 
7635  // 4. Update the boundary elements.
7636  do
7637  {
7638  need_refinement = 0;
7639  for (i = 0; i < NumOfBdrElements; i++)
7640  if (boundary[i]->NeedRefinement(v_to_v))
7641  {
7642  need_refinement = 1;
7643  BdrBisection(i, v_to_v);
7644  }
7645  }
7646  while (need_refinement == 1);
7647 
7648  NumOfVertices = vertices.Size();
7649  NumOfBdrElements = boundary.Size();
7650 
7651  // 5. Update element-to-edge and element-to-face relations.
7652  if (el_to_edge != NULL)
7653  {
7654  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
7655  }
7656  if (el_to_face != NULL)
7657  {
7658  GetElementToFaceTable();
7659  GenerateFaces();
7660  }
7661 
7662  } // end 'if (Dim == 3)'
7663 
7664  last_operation = Mesh::REFINE;
7665  sequence++;
7666 
7667  UpdateNodes();
7668 
7669 #ifdef MFEM_DEBUG
7670  CheckElementOrientation(false);
7671 #endif
7672 }
7673 
7674 void Mesh::NonconformingRefinement(const Array<Refinement> &refinements,
7675  int nc_limit)
7676 {
7677  MFEM_VERIFY(!NURBSext, "Nonconforming refinement of NURBS meshes is "
7678  "not supported. Project the NURBS to Nodes first.");
7679 
7680  ResetLazyData();
7681 
7682  if (!ncmesh)
7683  {
7684  // start tracking refinement hierarchy
7685  ncmesh = new NCMesh(this);
7686  }
7687 
7688  if (!refinements.Size())
7689  {
7690  last_operation = Mesh::NONE;
7691  return;
7692  }
7693 
7694  // do the refinements
7695  ncmesh->MarkCoarseLevel();
7696  ncmesh->Refine(refinements);
7697 
7698  if (nc_limit > 0)
7699  {
7700  ncmesh->LimitNCLevel(nc_limit);
7701  }
7702 
7703  // create a second mesh containing the finest elements from 'ncmesh'
7704  Mesh* mesh2 = new Mesh(*ncmesh);
7705  ncmesh->OnMeshUpdated(mesh2);
7706 
7707  // now swap the meshes, the second mesh will become the old coarse mesh
7708  // and this mesh will be the new fine mesh
7709  Swap(*mesh2, false);
7710  delete mesh2;
7711 
7712  GenerateNCFaceInfo();
7713 
7714  last_operation = Mesh::REFINE;
7715  sequence++;
7716 
7717  if (Nodes) // update/interpolate curved mesh
7718  {
7719  Nodes->FESpace()->Update();
7720  Nodes->Update();
7721  }
7722 }
7723 
7724 double Mesh::AggregateError(const Array<double> &elem_error,
7725  const int *fine, int nfine, int op)
7726 {
7727  double error = 0.0;
7728  for (int i = 0; i < nfine; i++)
7729  {
7730  MFEM_VERIFY(fine[i] < elem_error.Size(), "");
7731 
7732  double err_fine = elem_error[fine[i]];
7733  switch (op)
7734  {
7735  case 0: error = std::min(error, err_fine); break;
7736  case 1: error += err_fine; break;
7737  case 2: error = std::max(error, err_fine); break;
7738  }
7739  }
7740  return error;
7741 }
7742 
7743 bool Mesh::NonconformingDerefinement(Array<double> &elem_error,
7744  double threshold, int nc_limit, int op)
7745 {
7746  MFEM_VERIFY(ncmesh, "Only supported for non-conforming meshes.");
7747  MFEM_VERIFY(!NURBSext, "Derefinement of NURBS meshes is not supported. "
7748  "Project the NURBS to Nodes first.");
7749 
7750  ResetLazyData();
7751 
7752  const Table &dt = ncmesh->GetDerefinementTable();
7753 
7754  Array<int> level_ok;
7755  if (nc_limit > 0)
7756  {
7757  ncmesh->CheckDerefinementNCLevel(dt, level_ok, nc_limit);
7758  }
7759 
7760  Array<int> derefs;
7761  for (int i = 0; i < dt.Size(); i++)
7762  {
7763  if (nc_limit > 0 && !level_ok[i]) { continue; }
7764 
7765  double error =
7766  AggregateError(elem_error, dt.GetRow(i), dt.RowSize(i), op);
7767 
7768  if (error < threshold) { derefs.Append(i); }
7769  }
7770 
7771  if (!derefs.Size()) { return false; }
7772 
7773  ncmesh->Derefine(derefs);
7774 
7775  Mesh* mesh2 = new Mesh(*ncmesh);
7776  ncmesh->OnMeshUpdated(mesh2);
7777 
7778  Swap(*mesh2, false);
7779  delete mesh2;
7780 
7781  GenerateNCFaceInfo();
7782 
7783  last_operation = Mesh::DEREFINE;
7784  sequence++;
7785 
7786  UpdateNodes();
7787 
7788  return true;
7789 }
7790 
7791 bool Mesh::DerefineByError(Array<double> &elem_error, double threshold,
7792  int nc_limit, int op)
7793 {
7794  // NOTE: the error array is not const because it will be expanded in parallel
7795  // by ghost element errors
7796  if (Nonconforming())
7797  {
7798  return NonconformingDerefinement(elem_error, threshold, nc_limit, op);
7799  }
7800  else
7801  {
7802  MFEM_ABORT("Derefinement is currently supported for non-conforming "
7803  "meshes only.");
7804  return false;
7805  }
7806 }
7807 
7808 bool Mesh::DerefineByError(const Vector &elem_error, double threshold,
7809  int nc_limit, int op)
7810 {
7811  Array<double> tmp(elem_error.Size());
7812  for (int i = 0; i < tmp.Size(); i++)
7813  {
7814  tmp[i] = elem_error(i);
7815  }
7816  return DerefineByError(tmp, threshold, nc_limit, op);
7817 }
7818 
7819 
7820 void Mesh::InitFromNCMesh(const NCMesh &ncmesh)
7821 {
7822  Dim = ncmesh.Dimension();
7823  spaceDim = ncmesh.SpaceDimension();
7824 
7825  DeleteTables();
7826 
7827  ncmesh.GetMeshComponents(*this);
7828 
7829  NumOfVertices = vertices.Size();
7830  NumOfElements = elements.Size();
7831  NumOfBdrElements = boundary.Size();
7832 
7833  SetMeshGen(); // set the mesh type: 'meshgen', ...
7834 
7835  NumOfEdges = NumOfFaces = 0;
7836  nbInteriorFaces = nbBoundaryFaces = -1;
7837 
7838  if (Dim > 1)
7839  {
7840  el_to_edge = new Table;
7841  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
7842  }
7843  if (Dim > 2)
7844  {
7845  GetElementToFaceTable();
7846  }
7847  GenerateFaces();
7848 #ifdef MFEM_DEBUG
7849  CheckBdrElementOrientation(false);
7850 #endif
7851 
7852  // NOTE: ncmesh->OnMeshUpdated() and GenerateNCFaceInfo() should be called
7853  // outside after this method.
7854 }
7855 
7856 Mesh::Mesh(const NCMesh &ncmesh)
7857 {
7858  Init();
7859  InitTables();
7860  InitFromNCMesh(ncmesh);
7861  SetAttributes();
7862 }
7863 
7864 void Mesh::Swap(Mesh& other, bool non_geometry)
7865 {
7866  mfem::Swap(Dim, other.Dim);
7867  mfem::Swap(spaceDim, other.spaceDim);
7868 
7869  mfem::Swap(NumOfVertices, other.NumOfVertices);
7870  mfem::Swap(NumOfElements, other.NumOfElements);
7871  mfem::Swap(NumOfBdrElements, other.NumOfBdrElements);
7872  mfem::Swap(NumOfEdges, other.NumOfEdges);
7873  mfem::Swap(NumOfFaces, other.NumOfFaces);
7874 
7875  mfem::Swap(meshgen, other.meshgen);
7876  mfem::Swap(mesh_geoms, other.mesh_geoms);
7877 
7878  mfem::Swap(elements, other.elements);
7879  mfem::Swap(vertices, other.vertices);
7880  mfem::Swap(boundary, other.boundary);
7881  mfem::Swap(faces, other.faces);
7882  mfem::Swap(faces_info, other.faces_info);
7883  mfem::Swap(nc_faces_info, other.nc_faces_info);
7884 
7885  mfem::Swap(el_to_edge, other.el_to_edge);
7886  mfem::Swap(el_to_face, other.el_to_face);
7887  mfem::Swap(el_to_el, other.el_to_el);
7888  mfem::Swap(be_to_edge, other.be_to_edge);
7889  mfem::Swap(bel_to_edge, other.bel_to_edge);
7890  mfem::Swap(be_to_face, other.be_to_face);
7891  mfem::Swap(face_edge, other.face_edge);
7892  mfem::Swap(edge_vertex, other.edge_vertex);
7893 
7894  mfem::Swap(attributes, other.attributes);
7895  mfem::Swap(bdr_attributes, other.bdr_attributes);
7896 
7897  mfem::Swap(geom_factors, other.geom_factors);
7898 
7899 #ifdef MFEM_USE_MEMALLOC
7900  TetMemory.Swap(other.TetMemory);
7901 #endif
7902 
7903  if (non_geometry)
7904  {
7905  mfem::Swap(NURBSext, other.NURBSext);
7906  mfem::Swap(ncmesh, other.ncmesh);
7907 
7908  mfem::Swap(Nodes, other.Nodes);
7909  mfem::Swap(own_nodes, other.own_nodes);
7910  }
7911 }
7912 
7913 void Mesh::GetElementData(const Array<Element*> &elem_array, int geom,
7914  Array<int> &elem_vtx, Array<int> &attr) const
7915 {
7916  // protected method
7917  const int nv = Geometry::NumVerts[geom];
7918  int num_elems = 0;
7919  for (int i = 0; i < elem_array.Size(); i++)
7920  {
7921  if (elem_array[i]->GetGeometryType() == geom)
7922  {
7923  num_elems++;
7924  }
7925  }
7926  elem_vtx.SetSize(nv*num_elems);
7927  attr.SetSize(num_elems);
7928  elem_vtx.SetSize(0);
7929  attr.SetSize(0);
7930  for (int i = 0; i < elem_array.Size(); i++)
7931  {
7932  Element *el = elem_array[i];
7933  if (el->GetGeometryType() != geom) { continue; }
7934 
7935  Array<int> loc_vtx(el->GetVertices(), nv);
7936  elem_vtx.Append(loc_vtx);
7937  attr.Append(el->GetAttribute());
7938  }
7939 }
7940 
7941 static Array<int>& AllElements(Array<int> &list, int nelem)
7942 {
7943  list.SetSize(nelem);
7944  for (int i = 0; i < nelem; i++) { list[i] = i; }
7945  return list;
7946 }
7947 
7948 void Mesh::UniformRefinement(int ref_algo)
7949 {
7950  Array<int> list;
7951 
7952  if (NURBSext)
7953  {
7954  NURBSUniformRefinement();
7955  }
7956  else if (ncmesh)
7957  {
7958  GeneralRefinement(AllElements(list, GetNE()));
7959  }
7960  else if (ref_algo == 1 && meshgen == 1 && Dim == 3)
7961  {
7962  // algorithm "B" for an all-tet mesh
7963  LocalRefinement(AllElements(list, GetNE()));
7964  }
7965  else
7966  {
7967  switch (Dim)
7968  {
7969  case 1: LocalRefinement(AllElements(list, GetNE())); break;
7970  case 2: UniformRefinement2D(); break;
7971  case 3: UniformRefinement3D(); break;
7972  default: MFEM_ABORT("internal error");
7973  }
7974  }
7975 }
7976 
7977 void Mesh::GeneralRefinement(const Array<Refinement> &refinements,
7978  int nonconforming, int nc_limit)
7979 {
7980  if (ncmesh)
7981  {
7982  nonconforming = 1;
7983  }
7984  else if (Dim == 1 || (Dim == 3 && (meshgen & 1)))
7985  {
7986  nonconforming = 0;
7987  }
7988  else if (nonconforming < 0)
7989  {
7990  // determine if nonconforming refinement is suitable
7991  if ((meshgen & 2) || (meshgen & 4))
7992  {
7993  nonconforming = 1; // tensor product elements and wedges
7994  }
7995  else
7996  {
7997  nonconforming = 0; // simplices
7998  }
7999  }
8000 
8001  if (nonconforming)
8002  {
8003  // non-conforming refinement (hanging nodes)
8004  NonconformingRefinement(refinements, nc_limit);
8005  }
8006  else
8007  {
8008  Array<int> el_to_refine(refinements.Size());
8009  for (int i = 0; i < refinements.Size(); i++)
8010  {
8011  el_to_refine[i] = refinements[i].index;
8012  }
8013 
8014  // infer 'type' of local refinement from first element's 'ref_type'
8015  int type, rt = (refinements.Size() ? refinements[0].ref_type : 7);
8016  if (rt == 1 || rt == 2 || rt == 4)
8017  {
8018  type = 1; // bisection
8019  }
8020  else if (rt == 3 || rt == 5 || rt == 6)
8021  {
8022  type = 2; // quadrisection
8023  }
8024  else
8025  {
8026  type = 3; // octasection
8027  }
8028 
8029  // red-green refinement and bisection, no hanging nodes
8030  LocalRefinement(el_to_refine, type);
8031  }
8032 }
8033 
8034 void Mesh::GeneralRefinement(const Array<int> &el_to_refine, int nonconforming,
8035  int nc_limit)
8036 {
8037  Array<Refinement> refinements(el_to_refine.Size());
8038  for (int i = 0; i < el_to_refine.Size(); i++)
8039  {
8040  refinements[i] = Refinement(el_to_refine[i]);
8041  }
8042  GeneralRefinement(refinements, nonconforming, nc_limit);
8043 }
8044 
8045 void Mesh::EnsureNCMesh(bool simplices_nonconforming)
8046 {
8047  MFEM_VERIFY(!NURBSext, "Cannot convert a NURBS mesh to an NC mesh. "
8048  "Project the NURBS to Nodes first.");
8049 
8050  if (!ncmesh)
8051  {
8052  if ((meshgen & 0x2) /* quads/hexes */ ||
8053  (meshgen & 0x4) /* wedges */ ||
8054  (simplices_nonconforming && (meshgen & 0x1)) /* simplices */)
8055  {
8056  ncmesh = new NCMesh(this);
8057  ncmesh->OnMeshUpdated(this);
8058  GenerateNCFaceInfo();
8059  }
8060  }
8061 }
8062 
8063 void Mesh::RandomRefinement(double prob, bool aniso, int nonconforming,
8064  int nc_limit)
8065 {
8066  Array<Refinement> refs;
8067  for (int i = 0; i < GetNE(); i++)
8068  {
8069  if ((double) rand() / RAND_MAX < prob)
8070  {
8071  int type = 7;
8072  if (aniso)
8073  {
8074  type = (Dim == 3) ? (rand() % 7 + 1) : (rand() % 3 + 1);
8075  }
8076  refs.Append(Refinement(i, type));
8077  }
8078  }
8079  GeneralRefinement(refs, nonconforming, nc_limit);
8080 }
8081 
8082 void Mesh::RefineAtVertex(const Vertex& vert, double eps, int nonconforming)
8083 {
8084  Array<int> v;
8085  Array<Refinement> refs;
8086  for (int i = 0; i < GetNE(); i++)
8087  {
8088  GetElementVertices(i, v);
8089  bool refine = false;
8090  for (int j = 0; j < v.Size(); j++)
8091  {
8092  double dist = 0.0;
8093  for (int l = 0; l < spaceDim; l++)
8094  {
8095  double d = vert(l) - vertices[v[j]](l);
8096  dist += d*d;
8097  }
8098  if (dist <= eps*eps) { refine = true; break; }
8099  }
8100  if (refine)
8101  {
8102  refs.Append(Refinement(i));
8103  }
8104  }
8105  GeneralRefinement(refs, nonconforming);
8106 }
8107 
8108 bool Mesh::RefineByError(const Array<double> &elem_error, double threshold,
8109  int nonconforming, int nc_limit)
8110 {
8111  MFEM_VERIFY(elem_error.Size() == GetNE(), "");
8112  Array<Refinement> refs;
8113  for (int i = 0; i < GetNE(); i++)
8114  {
8115  if (elem_error[i] > threshold)
8116  {
8117  refs.Append(Refinement(i));
8118  }
8119  }
8120  if (ReduceInt(refs.Size()))
8121  {
8122  GeneralRefinement(refs, nonconforming, nc_limit);
8123  return true;
8124  }
8125  return false;
8126 }
8127 
8128 bool Mesh::RefineByError(const Vector &elem_error, double threshold,
8129  int nonconforming, int nc_limit)
8130 {
8131  Array<double> tmp(const_cast<double*>(elem_error.GetData()),
8132  elem_error.Size());
8133  return RefineByError(tmp, threshold, nonconforming, nc_limit);
8134 }
8135 
8136 
8137 void Mesh::Bisection(int i, const DSTable &v_to_v,
8138  int *edge1, int *edge2, int *middle)
8139 {
8140  int *vert;
8141  int v[2][4], v_new, bisect, t;
8142  Element *el = elements[i];
8143  Vertex V;
8144 
8145  t = el->GetType();
8146  if (t == Element::TRIANGLE)
8147  {
8148  Triangle *tri = (Triangle *) el;
8149 
8150  vert = tri->GetVertices();
8151 
8152  // 1. Get the index for the new vertex in v_new.
8153  bisect = v_to_v(vert[0], vert[1]);
8154  MFEM_ASSERT(bisect >= 0, "");
8155 
8156  if (middle[bisect] == -1)
8157  {
8158  v_new = NumOfVertices++;
8159  for (int d = 0; d < spaceDim; d++)
8160  {
8161  V(d) = 0.5 * (vertices[vert[0]](d) + vertices[vert[1]](d));
8162  }
8163  vertices.Append(V);
8164 
8165  // Put the element that may need refinement (because of this
8166  // bisection) in edge1, or -1 if no more refinement is needed.
8167  if (edge1[bisect] == i)
8168  {
8169  edge1[bisect] = edge2[bisect];
8170  }
8171 
8172  middle[bisect] = v_new;
8173  }
8174  else
8175  {
8176  v_new = middle[bisect];
8177 
8178  // This edge will require no more refinement.
8179  edge1[bisect] = -1;
8180  }
8181 
8182  // 2. Set the node indices for the new elements in v[0] and v[1] so that
8183  // the edge marked for refinement is between the first two nodes.
8184  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
8185  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
8186 
8187  tri->SetVertices(v[0]); // changes vert[0..2] !!!
8188 
8189  Triangle* tri_new = new Triangle(v[1], tri->GetAttribute());
8190  elements.Append(tri_new);
8191 
8192  int tr = tri->GetTransform();
8193  tri_new->ResetTransform(tr);
8194 
8195  // record the sequence of refinements
8196  tri->PushTransform(4);
8197  tri_new->PushTransform(5);
8198 
8199  int coarse = FindCoarseElement(i);
8200  CoarseFineTr.embeddings[i].parent = coarse;
8201  CoarseFineTr.embeddings.Append(Embedding(coarse));
8202 
8203  // 3. edge1 and edge2 may have to be changed for the second triangle.
8204  if (v[1][0] < v_to_v.NumberOfRows() && v[1][1] < v_to_v.NumberOfRows())
8205  {
8206  bisect = v_to_v(v[1][0], v[1][1]);
8207  MFEM_ASSERT(bisect >= 0, "");
8208 
8209  if (edge1[bisect] == i)
8210  {
8211  edge1[bisect] = NumOfElements;
8212  }
8213  else if (edge2[bisect] == i)
8214  {
8215  edge2[bisect] = NumOfElements;
8216  }
8217  }
8218  NumOfElements++;
8219  }
8220  else
8221  {
8222  MFEM_ABORT("Bisection for now works only for triangles.");
8223  }
8224 }
8225 
8226 void Mesh::Bisection(int i, HashTable<Hashed2> &v_to_v)
8227 {
8228  int *vert;
8229  int v[2][4], v_new, bisect, t;
8230  Element *el = elements[i];
8231  Vertex V;
8232 
8233  t = el->GetType();
8234  if (t == Element::TETRAHEDRON)
8235  {
8236  int j, type, new_type, old_redges[2], new_redges[2][2], flag;
8237  Tetrahedron *tet = (Tetrahedron *) el;
8238 
8239  MFEM_VERIFY(tet->GetRefinementFlag() != 0,
8240  "TETRAHEDRON element is not marked for refinement.");
8241 
8242  vert = tet->GetVertices();
8243 
8244  // 1. Get the index for the new vertex in v_new.
8245  bisect = v_to_v.FindId(vert[0], vert[1]);
8246  if (bisect == -1)
8247  {
8248  v_new = NumOfVertices + v_to_v.GetId(vert[0],vert[1]);
8249  for (j = 0; j < 3; j++)
8250  {
8251  V(j) = 0.5 * (vertices[vert[0]](j) + vertices[vert[1]](j));
8252  }
8253  vertices.Append(V);
8254  }
8255  else
8256  {
8257  v_new = NumOfVertices + bisect;
8258  }
8259 
8260  // 2. Set the node indices for the new elements in v[2][4] so that
8261  // the edge marked for refinement is between the first two nodes.
8262  tet->ParseRefinementFlag(old_redges, type, flag);
8263 
8264  v[0][3] = v_new;
8265  v[1][3] = v_new;
8266  new_redges[0][0] = 2;
8267  new_redges[0][1] = 1;
8268  new_redges[1][0] = 2;
8269  new_redges[1][1] = 1;
8270  int tr1 = -1, tr2 = -1;
8271  switch (old_redges[0])
8272  {
8273  case 2:
8274  v[0][0] = vert[0]; v[0][1] = vert[2]; v[0][2] = vert[3];
8275  if (type == Tetrahedron::TYPE_PF) { new_redges[0][1] = 4; }
8276  tr1 = 0;
8277  break;
8278  case 3:
8279  v[0][0] = vert[3]; v[0][1] = vert[0]; v[0][2] = vert[2];
8280  tr1 = 2;
8281  break;
8282  case 5:
8283  v[0][0] = vert[2]; v[0][1] = vert[3]; v[0][2] = vert[0];
8284  tr1 = 4;
8285  }
8286  switch (old_redges[1])
8287  {
8288  case 1:
8289  v[1][0] = vert[2]; v[1][1] = vert[1]; v[1][2] = vert[3];
8290  if (type == Tetrahedron::TYPE_PF) { new_redges[1][0] = 3; }
8291  tr2 = 1;
8292  break;
8293  case 4:
8294  v[1][0] = vert[1]; v[1][1] = vert[3]; v[1][2] = vert[2];
8295  tr2 = 3;
8296  break;
8297  case 5:
8298  v[1][0] = vert[3]; v[1][1] = vert[2]; v[1][2] = vert[1];
8299  tr2 = 5;
8300  }
8301 
8302  int attr = tet->GetAttribute();
8303  tet->SetVertices(v[0]);
8304 
8305 #ifdef MFEM_USE_MEMALLOC
8306  Tetrahedron *tet2 = TetMemory.Alloc();
8307  tet2->SetVertices(v[1]);
8308  tet2->SetAttribute(attr);
8309 #else
8310  Tetrahedron *tet2 = new Tetrahedron(v[1], attr);
8311 #endif
8312  tet2->ResetTransform(tet->GetTransform());
8313  elements.Append(tet2);
8314 
8315  // record the sequence of refinements
8316  tet->PushTransform(tr1);
8317  tet2->PushTransform(tr2);
8318 
8319  int coarse = FindCoarseElement(i);
8320  CoarseFineTr.embeddings[i].parent = coarse;
8321  CoarseFineTr.embeddings.Append(Embedding(coarse));
8322 
8323  // 3. Set the bisection flag
8324  switch (type)
8325  {
8326  case Tetrahedron::TYPE_PU:
8327  new_type = Tetrahedron::TYPE_PF; break;
8328  case Tetrahedron::TYPE_PF:
8329  new_type = Tetrahedron::TYPE_A; break;
8330  default:
8331  new_type = Tetrahedron::TYPE_PU;
8332  }
8333 
8334  tet->CreateRefinementFlag(new_redges[0], new_type, flag+1);
8335  tet2->CreateRefinementFlag(new_redges[1], new_type, flag+1);
8336 
8337  NumOfElements++;
8338  }
8339  else
8340  {
8341  MFEM_ABORT("Bisection with HashTable for now works only for tetrahedra.");
8342  }
8343 }
8344 
8345 void Mesh::BdrBisection(int i, const HashTable<Hashed2> &v_to_v)
8346 {
8347  int *vert;
8348  int v[2][3], v_new, bisect, t;
8349  Element *bdr_el = boundary[i];
8350 
8351  t = bdr_el->GetType();
8352  if (t == Element::TRIANGLE)
8353  {
8354  Triangle *tri = (Triangle *) bdr_el;
8355 
8356  vert = tri->GetVertices();
8357 
8358  // 1. Get the index for the new vertex in v_new.
8359  bisect = v_to_v.FindId(vert[0], vert[1]);
8360  MFEM_ASSERT(bisect >= 0, "");
8361  v_new = NumOfVertices + bisect;
8362  MFEM_ASSERT(v_new != -1, "");
8363 
8364  // 2. Set the node indices for the new elements in v[0] and v[1] so that
8365  // the edge marked for refinement is between the first two nodes.
8366  v[0][0] = vert[2]; v[0][1] = vert[0]; v[0][2] = v_new;
8367  v[1][0] = vert[1]; v[1][1] = vert[2]; v[1][2] = v_new;
8368 
8369  tri->SetVertices(v[0]);
8370 
8371  boundary.Append(new Triangle(v[1], tri->GetAttribute()));
8372 
8373  NumOfBdrElements++;
8374  }
8375  else
8376  {
8377  MFEM_ABORT("Bisection of boundary elements with HashTable works only for"
8378  " triangles!");
8379  }
8380 }
8381 
8382 void Mesh::UniformRefinement(int i, const DSTable &v_to_v,
8383  int *edge1, int *edge2, int *middle)
8384 {
8385  Array<int> v;
8386  int j, v1[3], v2[3], v3[3], v4[3], v_new[3], bisect[3];
8387  Vertex V;
8388 
8389  if (elements[i]->GetType() == Element::TRIANGLE)
8390  {
8391  Triangle *tri0 = (Triangle*) elements[i];
8392  tri0->GetVertices(v);
8393 
8394  // 1. Get the indeces for the new vertices in array v_new
8395  bisect[0] = v_to_v(v[0],v[1]);
8396  bisect[1] = v_to_v(v[1],v[2]);
8397  bisect[2] = v_to_v(v[0],v[2]);
8398  MFEM_ASSERT(bisect[0] >= 0 && bisect[1] >= 0 && bisect[2] >= 0, "");
8399 
8400  for (j = 0; j < 3; j++) // for the 3 edges fix v_new
8401  {
8402  if (middle[bisect[j]] == -1)
8403  {
8404  v_new[j] = NumOfVertices++;
8405  for (int d = 0; d < spaceDim; d++)
8406  {
8407  V(d) = (vertices[v[j]](d) + vertices[v[(j+1)%3]](d))/2.;
8408  }
8409  vertices.Append(V);
8410 
8411  // Put the element that may need refinement (because of this
8412  // bisection) in edge1, or -1 if no more refinement is needed.
8413  if (edge1[bisect[j]] == i)
8414  {
8415  edge1[bisect[j]] = edge2[bisect[j]];
8416  }
8417 
8418  middle[bisect[j]] = v_new[j];
8419  }
8420  else
8421  {
8422  v_new[j] = middle[bisect[j]];
8423 
8424  // This edge will require no more refinement.
8425  edge1[bisect[j]] = -1;
8426  }
8427  }
8428 
8429  // 2. Set the node indeces for the new elements in v1, v2, v3 & v4 so that
8430  // the edges marked for refinement be between the first two nodes.
8431  v1[0] = v[0]; v1[1] = v_new[0]; v1[2] = v_new[2];
8432  v2[0] = v_new[0]; v2[1] = v[1]; v2[2] = v_new[1];
8433  v3[0] = v_new[2]; v3[1] = v_new[1]; v3[2] = v[2];
8434  v4[0] = v_new[1]; v4[1] = v_new[2]; v4[2] = v_new[0];
8435 
8436  Triangle* tri1 = new Triangle(v1, tri0->GetAttribute());
8437  Triangle* tri2 = new Triangle(v2, tri0->GetAttribute());
8438  Triangle* tri3 = new Triangle(v3, tri0->GetAttribute());
8439 
8440  elements.Append(tri1);
8441  elements.Append(tri2);
8442  elements.Append(tri3);
8443 
8444  tri0->SetVertices(v4);
8445 
8446  // record the sequence of refinements
8447  unsigned code = tri0->GetTransform();
8448  tri1->ResetTransform(code);
8449  tri2->ResetTransform(code);
8450  tri3->ResetTransform(code);
8451 
8452  tri0->PushTransform(3);
8453  tri1->PushTransform(0);
8454  tri2->PushTransform(1);
8455  tri3->PushTransform(2);
8456 
8457  // set parent indices
8458  int coarse = FindCoarseElement(i);
8459  CoarseFineTr.embeddings[i] = Embedding(coarse);
8460  CoarseFineTr.embeddings.Append(Embedding(coarse));
8461  CoarseFineTr.embeddings.Append(Embedding(coarse));
8462  CoarseFineTr.embeddings.Append(Embedding(coarse));
8463 
8464  NumOfElements += 3;
8465  }
8466  else
8467  {
8468  MFEM_ABORT("Uniform refinement for now works only for triangles.");
8469  }
8470 }
8471 
8472 void Mesh::InitRefinementTransforms()
8473 {
8474  // initialize CoarseFineTr
8475  CoarseFineTr.Clear();
8476  CoarseFineTr.embeddings.SetSize(NumOfElements);
8477  for (int i = 0; i < NumOfElements; i++)
8478  {
8479  elements[i]->ResetTransform(0);
8480  CoarseFineTr.embeddings[i] = Embedding(i);
8481  }
8482 }
8483 
8484 int Mesh::FindCoarseElement(int i)
8485 {
8486  int coarse;
8487  while ((coarse = CoarseFineTr.embeddings[i].parent) != i)
8488  {
8489  i = coarse;
8490  }
8491  return coarse;
8492 }
8493 
8494 const CoarseFineTransformations& Mesh::GetRefinementTransforms()
8495 {
8496  MFEM_VERIFY(GetLastOperation() == Mesh::REFINE, "");
8497 
8498  if (ncmesh)
8499  {
8500  return ncmesh->GetRefinementTransforms();
8501  }
8502 
8503  Mesh::GeometryList elem_geoms(*this);
8504  for (int i = 0; i < elem_geoms.Size(); i++)
8505  {
8506  const Geometry::Type geom = elem_geoms[i];
8507  if (CoarseFineTr.point_matrices[geom].SizeK()) { continue; }
8508 
8509  if (geom == Geometry::TRIANGLE ||
8510  geom == Geometry::TETRAHEDRON)
8511  {
8512  std::map<unsigned, int> mat_no;
8513  mat_no[0] = 1; // identity
8514 
8515  // assign matrix indices to element transformations
8516  for (int i = 0; i < elements.Size(); i++)
8517  {
8518  int index = 0;
8519  unsigned code = elements[i]->GetTransform();
8520  if (code)
8521  {
8522  int &matrix = mat_no[code];
8523  if (!matrix) { matrix = mat_no.size(); }
8524  index = matrix-1;
8525  }
8526  CoarseFineTr.embeddings[i].matrix = index;
8527  }
8528 
8529  DenseTensor &pmats = CoarseFineTr.point_matrices[geom];
8530  pmats.SetSize(Dim, Dim+1, mat_no.size());
8531 
8532  // calculate the point matrices used
8533  std::map<unsigned, int>::iterator it;
8534  for (it = mat_no.begin(); it != mat_no.end(); ++it)
8535  {
8536  if (geom == Geometry::TRIANGLE)
8537  {
8538  Triangle::GetPointMatrix(it->first, pmats(it->second-1));
8539  }
8540  else
8541  {
8542  Tetrahedron::GetPointMatrix(it->first, pmats(it->second-1));
8543  }
8544  }
8545  }
8546  else
8547  {
8548  MFEM_ABORT("Don't know how to construct CoarseFineTransformations for"
8549  " geom = " << geom);
8550  }
8551  }
8552 
8553  // NOTE: quads and hexes already have trivial transformations ready
8554  return CoarseFineTr;
8555 }
8556 
8557 void Mesh::PrintXG(std::ostream &out) const
8558 {
8559  MFEM_ASSERT(Dim==spaceDim, "2D Manifold meshes not supported");
8560  int i, j;
8561  Array<int> v;
8562 
8563  if (Dim == 2)
8564  {
8565  // Print the type of the mesh.
8566  if (Nodes == NULL)
8567  {
8568  out << "areamesh2\n\n";
8569  }
8570  else
8571  {
8572  out << "curved_areamesh2\n\n";
8573  }
8574 
8575  // Print the boundary elements.
8576  out << NumOfBdrElements << '\n';
8577  for (i = 0; i < NumOfBdrElements; i++)
8578  {
8579  boundary[i]->GetVertices(v);
8580 
8581  out << boundary[i]->GetAttribute();
8582  for (j = 0; j < v.Size(); j++)
8583  {
8584  out << ' ' << v[j] + 1;
8585  }
8586  out << '\n';
8587  }
8588 
8589  // Print the elements.
8590  out << NumOfElements << '\n';
8591  for (i = 0; i < NumOfElements; i++)
8592  {
8593  elements[i]->GetVertices(v);
8594 
8595  out << elements[i]->GetAttribute() << ' ' << v.Size();
8596  for (j = 0; j < v.Size(); j++)
8597  {
8598  out << ' ' << v[j] + 1;
8599  }
8600  out << '\n';
8601  }
8602 
8603  if (Nodes == NULL)
8604  {
8605  // Print the vertices.
8606  out << NumOfVertices << '\n';
8607  for (i = 0; i < NumOfVertices; i++)
8608  {
8609  out << vertices[i](0);
8610  for (j = 1; j < Dim; j++)
8611  {
8612  out << ' ' << vertices[i](j);
8613  }
8614  out << '\n';
8615  }
8616  }
8617  else
8618  {
8619  out << NumOfVertices << '\n';
8620  Nodes->Save(out);
8621  }
8622  }
8623  else // ===== Dim != 2 =====
8624  {
8625  if (Nodes)
8626  {
8627  mfem_error("Mesh::PrintXG(...) : Curved mesh in 3D");
8628  }
8629 
8630  if (meshgen == 1)
8631  {
8632  int nv;
8633  const int *ind;
8634 
8635  out << "NETGEN_Neutral_Format\n";
8636  // print the vertices
8637  out << NumOfVertices << '\n';
8638  for (i = 0; i < NumOfVertices; i++)
8639  {
8640  for (j = 0; j < Dim; j++)
8641  {
8642  out << ' ' << vertices[i](j);
8643  }
8644  out << '\n';
8645  }
8646 
8647  // print the elements
8648  out << NumOfElements << '\n';
8649  for (i = 0; i < NumOfElements; i++)
8650  {
8651  nv = elements[i]->GetNVertices();
8652  ind = elements[i]->GetVertices();
8653  out << elements[i]->GetAttribute();
8654  for (j = 0; j < nv; j++)
8655  {
8656  out << ' ' << ind[j]+1;
8657  }
8658  out << '\n';
8659  }
8660 
8661  // print the boundary information.
8662  out << NumOfBdrElements << '\n';
8663  for (i = 0; i < NumOfBdrElements; i++)
8664  {
8665  nv = boundary[i]->GetNVertices();
8666  ind = boundary[i]->GetVertices();
8667  out << boundary[i]->GetAttribute();
8668  for (j = 0; j < nv; j++)
8669  {
8670  out << ' ' << ind[j]+1;
8671  }
8672  out << '\n';
8673  }
8674  }
8675  else if (meshgen == 2) // TrueGrid
8676  {
8677  int nv;
8678  const int *ind;
8679 
8680  out << "TrueGrid\n"
8681  << "1 " << NumOfVertices << " " << NumOfElements
8682  << " 0 0 0 0 0 0 0\n"
8683  << "0 0 0 1 0 0 0 0 0 0 0\n"
8684  << "0 0 " << NumOfBdrElements << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
8685  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
8686  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
8687 
8688  for (i = 0; i < NumOfVertices; i++)
8689  out << i+1 << " 0.0 " << vertices[i](0) << ' ' << vertices[i](1)
8690  << ' ' << vertices[i](2) << " 0.0\n";
8691 
8692  for (i = 0; i < NumOfElements; i++)
8693  {
8694  nv = elements[i]->GetNVertices();
8695  ind = elements[i]->GetVertices();
8696  out << i+1 << ' ' << elements[i]->GetAttribute();
8697  for (j = 0; j < nv; j++)
8698  {
8699  out << ' ' << ind[j]+1;
8700  }
8701  out << '\n';
8702  }
8703 
8704  for (i = 0; i < NumOfBdrElements; i++)
8705  {
8706  nv = boundary[i]->GetNVertices();
8707  ind = boundary[i]->GetVertices();
8708  out << boundary[i]->GetAttribute();
8709  for (j = 0; j < nv; j++)
8710  {
8711  out << ' ' << ind[j]+1;
8712  }
8713  out << " 1.0 1.0 1.0 1.0\n";
8714  }
8715  }
8716  }
8717 
8718  out << flush;
8719 }
8720 
8721 void Mesh::Printer(std::ostream &out, std::string section_delimiter) const
8722 {
8723  int i, j;
8724 
8725  if (NURBSext)
8726  {
8727  // general format
8728  NURBSext->Print(out);
8729  out << '\n';
8730  Nodes->Save(out);
8731 
8732  // patch-wise format
8733  // NURBSext->ConvertToPatches(*Nodes);
8734  // NURBSext->Print(out);
8735 
8736  return;
8737  }
8738 
8739  out << (ncmesh ? "MFEM mesh v1.1\n" :
8740  section_delimiter.empty() ? "MFEM mesh v1.0\n" :
8741  "MFEM mesh v1.2\n");
8742 
8743  // optional
8744  out <<
8745  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
8746  "# POINT = 0\n"
8747  "# SEGMENT = 1\n"
8748  "# TRIANGLE = 2\n"
8749  "# SQUARE = 3\n"
8750  "# TETRAHEDRON = 4\n"
8751  "# CUBE = 5\n"
8752  "# PRISM = 6\n"
8753  "#\n";
8754 
8755  out << "\ndimension\n" << Dim
8756  << "\n\nelements\n" << NumOfElements << '\n';
8757  for (i = 0; i < NumOfElements; i++)
8758  {
8759  PrintElement(elements[i], out);
8760  }
8761 
8762  out << "\nboundary\n" << NumOfBdrElements << '\n';
8763  for (i = 0; i < NumOfBdrElements; i++)
8764  {
8765  PrintElement(boundary[i], out);
8766  }
8767 
8768  if (ncmesh)
8769  {
8770  out << "\nvertex_parents\n";
8771  ncmesh->PrintVertexParents(out);
8772 
8773  out << "\ncoarse_elements\n";
8774  ncmesh->PrintCoarseElements(out);
8775  }
8776 
8777  out << "\nvertices\n" << NumOfVertices << '\n';
8778  if (Nodes == NULL)
8779  {
8780  out << spaceDim << '\n';
8781  for (i = 0; i < NumOfVertices; i++)
8782  {
8783  out << vertices[i](0);
8784  for (j = 1; j < spaceDim; j++)
8785  {
8786  out << ' ' << vertices[i](j);
8787  }
8788  out << '\n';
8789  }
8790  out.flush();
8791  }
8792  else
8793  {
8794  out << "\nnodes\n";
8795  Nodes->Save(out);
8796  }
8797 
8798  if (!ncmesh && !section_delimiter.empty())
8799  {
8800  out << section_delimiter << endl; // only with format v1.2
8801  }
8802 }
8803 
8804 void Mesh::PrintTopo(std::ostream &out,const Array<int> &e_to_k) const
8805 {
8806  int i;
8807  Array<int> vert;
8808 
8809  out << "MFEM NURBS mesh v1.0\n";
8810 
8811  // optional
8812  out <<
8813  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
8814  "# SEGMENT = 1\n"
8815  "# SQUARE = 3\n"
8816  "# CUBE = 5\n"
8817  "#\n";
8818 
8819  out << "\ndimension\n" << Dim
8820  << "\n\nelements\n" << NumOfElements << '\n';
8821  for (i = 0; i < NumOfElements; i++)
8822  {
8823  PrintElement(elements[i], out);
8824  }
8825 
8826  out << "\nboundary\n" << NumOfBdrElements << '\n';
8827  for (i = 0; i < NumOfBdrElements; i++)
8828  {
8829  PrintElement(boundary[i], out);
8830  }
8831 
8832  out << "\nedges\n" << NumOfEdges << '\n';
8833  for (i = 0; i < NumOfEdges; i++)
8834  {
8835  edge_vertex->GetRow(i, vert);
8836  int ki = e_to_k[i];
8837  if (ki < 0)
8838  {
8839  ki = -1 - ki;
8840  }
8841  out << ki << ' ' << vert[0] << ' ' << vert[1] << '\n';
8842  }
8843  out << "\nvertices\n" << NumOfVertices << '\n';
8844 }
8845 
8846 #ifdef MFEM_USE_ADIOS2
8847 void Mesh::Print(adios2stream &out) const
8848 {
8849  out.Print(*this);
8850 }
8851 #endif
8852 
8853 void Mesh::PrintVTK(std::ostream &out)
8854 {
8855  out <<
8856  "# vtk DataFile Version 3.0\n"
8857  "Generated by MFEM\n"
8858  "ASCII\n"
8859  "DATASET UNSTRUCTURED_GRID\n";
8860 
8861  if (Nodes == NULL)
8862  {
8863  out << "POINTS " << NumOfVertices << " double\n";
8864  for (int i = 0; i < NumOfVertices; i++)
8865  {
8866  out << vertices[i](0);
8867  int j;
8868  for (j = 1; j < spaceDim; j++)
8869  {
8870  out << ' ' << vertices[i](j);
8871  }
8872  for ( ; j < 3; j++)
8873  {
8874  out << ' ' << 0.0;
8875  }
8876  out << '\n';
8877  }
8878  }
8879  else
8880  {
8881  Array<int> vdofs(3);
8882  out << "POINTS " << Nodes->FESpace()->GetNDofs() << " double\n";
8883  for (int i = 0; i < Nodes->FESpace()->GetNDofs(); i++)
8884  {
8885  vdofs.SetSize(1);
8886  vdofs[0] = i;
8887  Nodes->FESpace()->DofsToVDofs(vdofs);
8888  out << (*Nodes)(vdofs[0]);
8889  int j;
8890  for (j = 1; j < spaceDim; j++)
8891  {
8892  out << ' ' << (*Nodes)(vdofs[j]);
8893  }
8894  for ( ; j < 3; j++)
8895  {
8896  out << ' ' << 0.0;
8897  }
8898  out << '\n';
8899  }
8900  }
8901 
8902  int order = -1;
8903  if (Nodes == NULL)
8904  {
8905  int size = 0;
8906  for (int i = 0; i < NumOfElements; i++)
8907  {
8908  size += elements[i]->GetNVertices() + 1;
8909  }
8910  out << "CELLS " << NumOfElements << ' ' << size << '\n';
8911  for (int i = 0; i < NumOfElements; i++)
8912  {
8913  const int *v = elements[i]->GetVertices();
8914  const int nv = elements[i]->GetNVertices();
8915  out << nv;
8916  for (int j = 0; j < nv; j++)
8917  {
8918  out << ' ' << v[j];
8919  }
8920  out << '\n';
8921  }
8922  order = 1;
8923  }
8924  else
8925  {
8926  Array<int> dofs;
8927  int size = 0;
8928  for (int i = 0; i < NumOfElements; i++)
8929  {
8930  Nodes->FESpace()->GetElementDofs(i, dofs);
8931  MFEM_ASSERT(Dim != 0 || dofs.Size() == 1,
8932  "Point meshes should have a single dof per element");
8933  size += dofs.Size() + 1;
8934  }
8935  out << "CELLS " << NumOfElements << ' ' << size << '\n';
8936  const char *fec_name = Nodes->FESpace()->FEColl()->Name();
8937 
8938  if (!strcmp(fec_name, "Linear") ||
8939  !strcmp(fec_name, "H1_0D_P1") ||
8940  !strcmp(fec_name, "H1_1D_P1") ||
8941  !strcmp(fec_name, "H1_2D_P1") ||
8942  !strcmp(fec_name, "H1_3D_P1"))
8943  {
8944  order = 1;
8945  }
8946  else if (!strcmp(fec_name, "Quadratic") ||
8947  !strcmp(fec_name, "H1_1D_P2") ||
8948  !strcmp(fec_name, "H1_2D_P2") ||
8949  !strcmp(fec_name, "H1_3D_P2"))
8950  {
8951  order = 2;
8952  }
8953  if (order == -1)
8954  {
8955  mfem::err << "Mesh::PrintVTK : can not save '"
8956  << fec_name << "' elements!" << endl;
8957  mfem_error();
8958  }
8959  for (int i = 0; i < NumOfElements; i++)
8960  {
8961  Nodes->FESpace()->GetElementDofs(i, dofs);
8962  out << dofs.Size();
8963  if (order == 1)
8964  {
8965  for (int j = 0; j < dofs.Size(); j++)
8966  {
8967  out << ' ' << dofs[j];
8968  }
8969  }
8970  else if (order == 2)
8971  {
8972  const int *vtk_mfem;
8973  switch (elements[i]->GetGeometryType())
8974  {
8975  case Geometry::SEGMENT:
8976  case Geometry::TRIANGLE:
8977  case Geometry::SQUARE:
8978  vtk_mfem = vtk_quadratic_hex; break; // identity map
8979  case Geometry::TETRAHEDRON:
8980  vtk_mfem = vtk_quadratic_tet; break;
8981  case Geometry::PRISM:
8982  vtk_mfem = vtk_quadratic_wedge; break;
8983  case Geometry::CUBE:
8984  default:
8985  vtk_mfem = vtk_quadratic_hex; break;
8986  }
8987  for (int j = 0; j < dofs.Size(); j++)
8988  {
8989  out << ' ' << dofs[vtk_mfem[j]];
8990  }
8991  }
8992  out << '\n';
8993  }
8994  }
8995 
8996  out << "CELL_TYPES " << NumOfElements << '\n';
8997  for (int i = 0; i < NumOfElements; i++)
8998  {
8999  int vtk_cell_type = 5;
9000  Geometry::Type geom_type = GetElement(i)->GetGeometryType();
9001  if (order == 1)
9002  {
9003  switch (geom_type)
9004  {
9005  case Geometry::POINT: vtk_cell_type = 1; break;
9006  case Geometry::SEGMENT: vtk_cell_type = 3; break;
9007  case Geometry::TRIANGLE: vtk_cell_type = 5; break;
9008  case Geometry::SQUARE: vtk_cell_type = 9; break;
9009  case Geometry::TETRAHEDRON: vtk_cell_type = 10; break;
9010  case Geometry::CUBE: vtk_cell_type = 12; break;
9011  case Geometry::PRISM: vtk_cell_type = 13; break;
9012  default: break;
9013  }
9014  }
9015  else if (order == 2)
9016  {
9017  switch (geom_type)
9018  {
9019  case Geometry::SEGMENT: vtk_cell_type = 21; break;
9020  case Geometry::TRIANGLE: vtk_cell_type = 22; break;
9021  case Geometry::SQUARE: vtk_cell_type = 28; break;
9022  case Geometry::TETRAHEDRON: vtk_cell_type = 24; break;
9023  case Geometry::CUBE: vtk_cell_type = 29; break;
9024  case Geometry::PRISM: vtk_cell_type = 32; break;
9025  default: break;
9026  }
9027  }
9028 
9029  out << vtk_cell_type << '\n';
9030  }
9031 
9032  // write attributes
9033  out << "CELL_DATA " << NumOfElements << '\n'
9034  << "SCALARS material int\n"
9035  << "LOOKUP_TABLE default\n";
9036  for (int i = 0; i < NumOfElements; i++)
9037  {
9038  out << elements[i]->GetAttribute() << '\n';
9039  }
9040  out.flush();
9041 }
9042 
9043 void Mesh::PrintVTU(std::string fname,
9044  VTKFormat format,
9045  bool high_order_output,
9046  int compression_level,
9047  bool bdr)
9048 {
9049  int ref = (high_order_output && Nodes) ? Nodes->FESpace()->GetOrder(0) : 1;
9050  fname = fname + ".vtu";
9051  std::fstream out(fname.c_str(),std::ios::out);
9052  out << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"";
9053  if (compression_level != 0)
9054  {
9055  out << " compressor=\"vtkZLibDataCompressor\"";
9056  }
9057  out << " byte_order=\"" << VTKByteOrder() << "\">\n";
9058  out << "<UnstructuredGrid>\n";
9059  PrintVTU(out, ref, format, high_order_output, compression_level, bdr);
9060  out << "</Piece>\n"; // need to close the piece open in the PrintVTU method
9061  out << "</UnstructuredGrid>\n";
9062  out << "</VTKFile>" << std::endl;
9063 
9064  out.close();
9065 }
9066 
9067 void Mesh::PrintBdrVTU(std::string fname,
9068  VTKFormat format,
9069  bool high_order_output,
9070  int compression_level)
9071 {
9072  PrintVTU(fname, format, high_order_output, compression_level, true);
9073 }
9074 
9075 template <typename T>
9076 void WriteBinaryOrASCII(std::ostream &out, std::vector<char> &buf, const T &val,
9077  const char *suffix, VTKFormat format)
9078 {
9079  if (format == VTKFormat::ASCII) { out << val << suffix; }
9080  else { bin_io::AppendBytes(buf, val); }
9081 }
9082 
9083 // Ensure ASCII output of uint8_t to stream is integer rather than character
9084 template <>
9085 void WriteBinaryOrASCII<uint8_t>(std::ostream &out, std::vector<char> &buf,
9086  const uint8_t &val, const char *suffix,
9087  VTKFormat format)
9088 {
9089  if (format == VTKFormat::ASCII) { out << static_cast<int>(val) << suffix; }
9090  else { bin_io::AppendBytes(buf, val); }
9091 }
9092 
9093 template <>
9094 void WriteBinaryOrASCII<double>(std::ostream &out, std::vector<char> &buf,
9095  const double &val, const char *suffix,
9096  VTKFormat format)
9097 {
9098  if (format == VTKFormat::BINARY32)
9099  {
9100  bin_io::AppendBytes<float>(buf, float(val));
9101  }
9102  else if (format == VTKFormat::BINARY)
9103  {
9104  bin_io::AppendBytes(buf, val);
9105  }
9106  else
9107  {
9108  out << val << suffix;
9109  }
9110 }
9111 
9112 template <>
9113 void WriteBinaryOrASCII<float>(std::ostream &out, std::vector<char> &buf,
9114  const float &val, const char *suffix,
9115  VTKFormat format)
9116 {
9117  if (format == VTKFormat::BINARY) { bin_io::AppendBytes<double>(buf, val); }
9118  else if (format == VTKFormat::BINARY32) { bin_io::AppendBytes(buf, val); }
9119  else { out << val << suffix; }
9120 }
9121 
9122 void WriteBase64WithSizeAndClear(std::ostream &out, std::vector<char> &buf,
9123  int compression_level)
9124 {
9125  WriteVTKEncodedCompressed(out, buf.data(), buf.size(), compression_level);
9126  out << '\n';
9127  buf.clear();
9128 }
9129 
9130 void Mesh::PrintVTU(std::ostream &out, int ref, VTKFormat format,
9131  bool high_order_output, int compression_level,
9132  bool bdr_elements)
9133 {
9134  RefinedGeometry *RefG;
9135  DenseMatrix pmat;
9136 
9137  const char *fmt_str = (format == VTKFormat::ASCII) ? "ascii" : "binary";
9138  const char *type_str = (format != VTKFormat::BINARY32) ? "Float64" : "Float32";
9139  std::vector<char> buf;
9140 
9141  auto get_geom = [&](int i)
9142  {
9143  if (bdr_elements) { return GetBdrElementBaseGeometry(i); }
9144  else { return GetElementBaseGeometry(i); }
9145  };
9146 
9147  int ne = bdr_elements ? GetNBE() : GetNE();
9148  // count the points, cells, size
9149  int np = 0, nc_ref = 0, size = 0;
9150  for (int i = 0; i < ne; i++)
9151  {
9152  Geometry::Type geom = get_geom(i);
9153  int nv = Geometries.GetVertices(geom)->GetNPoints();
9154  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9155  np += RefG->RefPts.GetNPoints();
9156  nc_ref += RefG->RefGeoms.Size() / nv;
9157  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
9158  }
9159 
9160  out << "<Piece NumberOfPoints=\"" << np << "\" NumberOfCells=\""
9161  << (high_order_output ? ne : nc_ref) << "\">\n";
9162 
9163  // print out the points
9164  out << "<Points>\n";
9165  out << "<DataArray type=\"" << type_str
9166  << "\" NumberOfComponents=\"3\" format=\"" << fmt_str << "\">\n";
9167  for (int i = 0; i < ne; i++)
9168  {
9169  RefG = GlobGeometryRefiner.Refine(get_geom(i), ref, 1);
9170 
9171  if (bdr_elements)
9172  {
9173  GetBdrElementTransformation(i)->Transform(RefG->RefPts, pmat);
9174  }
9175  else
9176  {
9177  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
9178  }
9179 
9180  for (int j = 0; j < pmat.Width(); j++)
9181  {
9182  WriteBinaryOrASCII(out, buf, pmat(0,j), " ", format);
9183  if (pmat.Height() > 1)
9184  {
9185  WriteBinaryOrASCII(out, buf, pmat(1,j), " ", format);
9186  }
9187  else
9188  {
9189  WriteBinaryOrASCII(out, buf, 0.0, " ", format);
9190  }
9191  if (pmat.Height() > 2)
9192  {
9193  WriteBinaryOrASCII(out, buf, pmat(2,j), "", format);
9194  }
9195  else
9196  {
9197  WriteBinaryOrASCII(out, buf, 0.0, "", format);
9198  }
9199  if (format == VTKFormat::ASCII) { out << '\n'; }
9200  }
9201  }
9202  if (format != VTKFormat::ASCII)
9203  {
9204  WriteBase64WithSizeAndClear(out, buf, compression_level);
9205  }
9206  out << "</DataArray>" << std::endl;
9207  out << "</Points>" << std::endl;
9208 
9209  out << "<Cells>" << std::endl;
9210  out << "<DataArray type=\"Int32\" Name=\"connectivity\" format=\""
9211  << fmt_str << "\">" << std::endl;
9212  // connectivity
9213  std::vector<int> offset;
9214 
9215  np = 0;
9216  if (high_order_output)
9217  {
9218  Array<int> local_connectivity;
9219  for (int iel = 0; iel < ne; iel++)
9220  {
9221  Geometry::Type geom = get_geom(iel);
9222  CreateVTKElementConnectivity(local_connectivity, geom, ref);
9223  int nnodes = local_connectivity.Size();
9224  for (int i=0; i<nnodes; ++i)
9225  {
9226  WriteBinaryOrASCII(out, buf, np+local_connectivity[i], " ", format);
9227  }
9228  if (format == VTKFormat::ASCII) { out << '\n'; }
9229  np += nnodes;
9230  offset.push_back(np);
9231  }
9232  }
9233  else
9234  {
9235  int coff = 0;
9236  for (int i = 0; i < ne; i++)
9237  {
9238  Geometry::Type geom = get_geom(i);
9239  int nv = Geometries.GetVertices(geom)->GetNPoints();
9240  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9241  Array<int> &RG = RefG->RefGeoms;
9242  for (int j = 0; j < RG.Size(); )
9243  {
9244  coff = coff+nv;
9245  offset.push_back(coff);
9246  for (int k = 0; k < nv; k++, j++)
9247  {
9248  WriteBinaryOrASCII(out, buf, np + RG[j], " ", format);
9249  }
9250  if (format == VTKFormat::ASCII) { out << '\n'; }
9251  }
9252  np += RefG->RefPts.GetNPoints();
9253  }
9254  }
9255  if (format != VTKFormat::ASCII)
9256  {
9257  WriteBase64WithSizeAndClear(out, buf, compression_level);
9258  }
9259  out << "</DataArray>" << std::endl;
9260 
9261  out << "<DataArray type=\"Int32\" Name=\"offsets\" format=\""
9262  << fmt_str << "\">" << std::endl;
9263  // offsets
9264  for (size_t ii=0; ii<offset.size(); ii++)
9265  {
9266  WriteBinaryOrASCII(out, buf, offset[ii], "\n", format);
9267  }
9268  if (format != VTKFormat::ASCII)
9269  {
9270  WriteBase64WithSizeAndClear(out, buf, compression_level);
9271  }
9272  out << "</DataArray>" << std::endl;
9273  out << "<DataArray type=\"UInt8\" Name=\"types\" format=\""
9274  << fmt_str << "\">" << std::endl;
9275  // cell types
9276  for (int i = 0; i < ne; i++)
9277  {
9278  Geometry::Type geom = get_geom(i);
9279  uint8_t vtk_cell_type = 5;
9280 
9281  // VTK element types defined at: https://git.io/JvZLm
9282  switch (geom)
9283  {
9284  case Geometry::POINT:
9285  vtk_cell_type = 1;
9286  break;
9287  case Geometry::SEGMENT:
9288  vtk_cell_type = high_order_output ? 68 : 3;
9289  break;
9290  case Geometry::TRIANGLE:
9291  vtk_cell_type = high_order_output ? 69 : 5;
9292  break;
9293  case Geometry::SQUARE:
9294  vtk_cell_type = high_order_output ? 70 : 9;
9295  break;
9296  case Geometry::TETRAHEDRON:
9297  vtk_cell_type = high_order_output ? 71 : 10;
9298  break;
9299  case Geometry::CUBE:
9300  vtk_cell_type = high_order_output ? 72 : 12;
9301  break;
9302  case Geometry::PRISM:
9303  vtk_cell_type = high_order_output ? 73 : 13;
9304  break;
9305  default:
9306  MFEM_ABORT("Unrecognized VTK element type \"" << geom << "\"");
9307  break;
9308  }
9309 
9310  if (high_order_output)
9311  {
9312  WriteBinaryOrASCII(out, buf, vtk_cell_type, "\n", format);
9313  }
9314  else
9315  {
9316  int nv = Geometries.GetVertices(geom)->GetNPoints();
9317  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9318  Array<int> &RG = RefG->RefGeoms;
9319  for (int j = 0; j < RG.Size(); j += nv)
9320  {
9321  WriteBinaryOrASCII(out, buf, vtk_cell_type, "\n", format);
9322  }
9323  }
9324  }
9325  if (format != VTKFormat::ASCII)
9326  {
9327  WriteBase64WithSizeAndClear(out, buf, compression_level);
9328  }
9329  out << "</DataArray>" << std::endl;
9330  out << "</Cells>" << std::endl;
9331 
9332  out << "<CellData Scalars=\"attribute\">" << std::endl;
9333  out << "<DataArray type=\"Int32\" Name=\"attribute\" format=\""
9334  << fmt_str << "\">" << std::endl;
9335  for (int i = 0; i < ne; i++)
9336  {
9337  int attr = bdr_elements ? GetBdrAttribute(i) : GetAttribute(i);
9338  if (high_order_output)
9339  {
9340  WriteBinaryOrASCII(out, buf, attr, "\n", format);
9341  }
9342  else
9343  {
9344  Geometry::Type geom = get_geom(i);
9345  int nv = Geometries.GetVertices(geom)->GetNPoints();
9346  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9347  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
9348  {
9349  WriteBinaryOrASCII(out, buf, attr, "\n", format);
9350  }
9351  }
9352  }
9353  if (format != VTKFormat::ASCII)
9354  {
9355  WriteBase64WithSizeAndClear(out, buf, compression_level);
9356  }
9357  out << "</DataArray>" << std::endl;
9358  out << "</CellData>" << std::endl;
9359 }
9360 
9361 
9362 void Mesh::PrintVTK(std::ostream &out, int ref, int field_data)
9363 {
9364  int np, nc, size;
9365  RefinedGeometry *RefG;
9366  DenseMatrix pmat;
9367 
9368  out <<
9369  "# vtk DataFile Version 3.0\n"
9370  "Generated by MFEM\n"
9371  "ASCII\n"
9372  "DATASET UNSTRUCTURED_GRID\n";
9373 
9374  // additional dataset information
9375  if (field_data)
9376  {
9377  out << "FIELD FieldData 1\n"
9378  << "MaterialIds " << 1 << " " << attributes.Size() << " int\n";
9379  for (int i = 0; i < attributes.Size(); i++)
9380  {
9381  out << ' ' << attributes[i];
9382  }
9383  out << '\n';
9384  }
9385 
9386  // count the points, cells, size
9387  np = nc = size = 0;
9388  for (int i = 0; i < GetNE(); i++)
9389  {
9390  Geometry::Type geom = GetElementBaseGeometry(i);
9391  int nv = Geometries.GetVertices(geom)->GetNPoints();
9392  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9393  np += RefG->RefPts.GetNPoints();
9394  nc += RefG->RefGeoms.Size() / nv;
9395  size += (RefG->RefGeoms.Size() / nv) * (nv + 1);
9396  }
9397  out << "POINTS " << np << " double\n";
9398  // write the points
9399  for (int i = 0; i < GetNE(); i++)
9400  {
9401  RefG = GlobGeometryRefiner.Refine(
9402  GetElementBaseGeometry(i), ref, 1);
9403 
9404  GetElementTransformation(i)->Transform(RefG->RefPts, pmat);
9405 
9406  for (int j = 0; j < pmat.Width(); j++)
9407  {
9408  out << pmat(0, j) << ' ';
9409  if (pmat.Height() > 1)
9410  {
9411  out << pmat(1, j) << ' ';
9412  if (pmat.Height() > 2)
9413  {
9414  out << pmat(2, j);
9415  }
9416  else
9417  {
9418  out << 0.0;
9419  }
9420  }
9421  else
9422  {
9423  out << 0.0 << ' ' << 0.0;
9424  }
9425  out << '\n';
9426  }
9427  }
9428 
9429  // write the cells
9430  out << "CELLS " << nc << ' ' << size << '\n';
9431  np = 0;
9432  for (int i = 0; i < GetNE(); i++)
9433  {
9434  Geometry::Type geom = GetElementBaseGeometry(i);
9435  int nv = Geometries.GetVertices(geom)->GetNPoints();
9436  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9437  Array<int> &RG = RefG->RefGeoms;
9438 
9439  for (int j = 0; j < RG.Size(); )
9440  {
9441  out << nv;
9442  for (int k = 0; k < nv; k++, j++)
9443  {
9444  out << ' ' << np + RG[j];
9445  }
9446  out << '\n';
9447  }
9448  np += RefG->RefPts.GetNPoints();
9449  }
9450  out << "CELL_TYPES " << nc << '\n';
9451  for (int i = 0; i < GetNE(); i++)
9452  {
9453  Geometry::Type geom = GetElementBaseGeometry(i);
9454  int nv = Geometries.GetVertices(geom)->GetNPoints();
9455  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9456  Array<int> &RG = RefG->RefGeoms;
9457  int vtk_cell_type = 5;
9458 
9459  switch (geom)
9460  {
9461  case Geometry::POINT: vtk_cell_type = 1; break;
9462  case Geometry::SEGMENT: vtk_cell_type = 3; break;
9463  case Geometry::TRIANGLE: vtk_cell_type = 5; break;
9464  case Geometry::SQUARE: vtk_cell_type = 9; break;
9465  case Geometry::TETRAHEDRON: vtk_cell_type = 10; break;
9466  case Geometry::CUBE: vtk_cell_type = 12; break;
9467  case Geometry::PRISM: vtk_cell_type = 13; break;
9468  default:
9469  MFEM_ABORT("Unrecognized VTK element type \"" << geom << "\"");
9470  break;
9471  }
9472 
9473  for (int j = 0; j < RG.Size(); j += nv)
9474  {
9475  out << vtk_cell_type << '\n';
9476  }
9477  }
9478  // write attributes (materials)
9479  out << "CELL_DATA " << nc << '\n'
9480  << "SCALARS material int\n"
9481  << "LOOKUP_TABLE default\n";
9482  for (int i = 0; i < GetNE(); i++)
9483  {
9484  Geometry::Type geom = GetElementBaseGeometry(i);
9485  int nv = Geometries.GetVertices(geom)->GetNPoints();
9486  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9487  int attr = GetAttribute(i);
9488  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
9489  {
9490  out << attr << '\n';
9491  }
9492  }
9493 
9494  if (Dim > 1)
9495  {
9496  Array<int> coloring;
9497  srand((unsigned)time(0));
9498  double a = double(rand()) / (double(RAND_MAX) + 1.);
9499  int el0 = (int)floor(a * GetNE());
9500  GetElementColoring(coloring, el0);
9501  out << "SCALARS element_coloring int\n"
9502  << "LOOKUP_TABLE default\n";
9503  for (int i = 0; i < GetNE(); i++)
9504  {
9505  Geometry::Type geom = GetElementBaseGeometry(i);
9506  int nv = Geometries.GetVertices(geom)->GetNPoints();
9507  RefG = GlobGeometryRefiner.Refine(geom, ref, 1);
9508  for (int j = 0; j < RefG->RefGeoms.Size(); j += nv)
9509  {
9510  out << coloring[i] + 1 << '\n';
9511  }
9512  }
9513  }
9514 
9515  // prepare to write data
9516  out << "POINT_DATA " << np << '\n' << flush;
9517 }
9518 
9519 void Mesh::GetElementColoring(Array<int> &colors, int el0)
9520 {
9521  int delete_el_to_el = (el_to_el) ? (0) : (1);
9522  const Table &el_el = ElementToElementTable();
9523  int num_el = GetNE(), stack_p, stack_top_p, max_num_col;
9524  Array<int> el_stack(num_el);
9525 
9526  const int *i_el_el = el_el.GetI();
9527  const int *j_el_el = el_el.GetJ();
9528 
9529  colors.SetSize(num_el);
9530  colors = -2;
9531  max_num_col = 1;
9532  stack_p = stack_top_p = 0;
9533  for (int el = el0; stack_top_p < num_el; el=(el+1)%num_el)
9534  {
9535  if (colors[el] != -2)
9536  {
9537  continue;
9538  }
9539 
9540  colors[el] = -1;
9541  el_stack[stack_top_p++] = el;
9542 
9543  for ( ; stack_p < stack_top_p; stack_p++)
9544  {
9545  int i = el_stack[stack_p];
9546  int num_nb = i_el_el[i+1] - i_el_el[i];
9547  if (max_num_col < num_nb + 1)
9548  {
9549  max_num_col = num_nb + 1;
9550  }
9551  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
9552  {
9553  int k = j_el_el[j];
9554  if (colors[k] == -2)
9555  {
9556  colors[k] = -1;
9557  el_stack[stack_top_p++] = k;
9558  }
9559  }
9560  }
9561  }
9562 
9563  Array<int> col_marker(max_num_col);
9564 
9565  for (stack_p = 0; stack_p < stack_top_p; stack_p++)
9566  {
9567  int i = el_stack[stack_p], col;
9568  col_marker = 0;
9569  for (int j = i_el_el[i]; j < i_el_el[i+1]; j++)
9570  {
9571  col = colors[j_el_el[j]];
9572  if (col != -1)
9573  {
9574  col_marker[col] = 1;
9575  }
9576  }
9577 
9578  for (col = 0; col < max_num_col; col++)
9579  if (col_marker[col] == 0)
9580  {
9581  break;
9582  }
9583 
9584  colors[i] = col;
9585  }
9586 
9587  if (delete_el_to_el)
9588  {
9589  delete el_to_el;
9590  el_to_el = NULL;
9591  }
9592 }
9593 
9594 void Mesh::PrintWithPartitioning(int *partitioning, std::ostream &out,
9595  int elem_attr) const
9596 {
9597  if (Dim != 3 && Dim != 2) { return; }
9598 
9599  int i, j, k, l, nv, nbe, *v;
9600 
9601  out << "MFEM mesh v1.0\n";
9602 
9603  // optional
9604  out <<
9605  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
9606  "# POINT = 0\n"
9607  "# SEGMENT = 1\n"
9608  "# TRIANGLE = 2\n"
9609  "# SQUARE = 3\n"
9610  "# TETRAHEDRON = 4\n"
9611  "# CUBE = 5\n"
9612  "# PRISM = 6\n"
9613  "#\n";
9614 
9615  out << "\ndimension\n" << Dim
9616  << "\n\nelements\n" << NumOfElements << '\n';
9617  for (i = 0; i < NumOfElements; i++)
9618  {
9619  out << int((elem_attr) ? partitioning[i]+1 : elements[i]->GetAttribute())
9620  << ' ' << elements[i]->GetGeometryType();
9621  nv = elements[i]->GetNVertices();
9622  v = elements[i]->GetVertices();
9623  for (j = 0; j < nv; j++)
9624  {
9625  out << ' ' << v[j];
9626  }
9627  out << '\n';
9628  }
9629  nbe = 0;
9630  for (i = 0; i < faces_info.Size(); i++)
9631  {
9632  if ((l = faces_info[i].Elem2No) >= 0)
9633  {
9634  k = partitioning[faces_info[i].Elem1No];
9635  l = partitioning[l];
9636  if (k != l)
9637  {
9638  nbe++;
9639  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
9640  {
9641  nbe++;
9642  }
9643  }
9644  }
9645  else
9646  {
9647  nbe++;
9648  }
9649  }
9650  out << "\nboundary\n" << nbe << '\n';
9651  for (i = 0; i < faces_info.Size(); i++)
9652  {
9653  if ((l = faces_info[i].Elem2No) >= 0)
9654  {
9655  k = partitioning[faces_info[i].Elem1No];
9656  l = partitioning[l];
9657  if (k != l)
9658  {
9659  nv = faces[i]->GetNVertices();
9660  v = faces[i]->GetVertices();
9661  out << k+1 << ' ' << faces[i]->GetGeometryType();
9662  for (j = 0; j < nv; j++)
9663  {
9664  out << ' ' << v[j];
9665  }
9666  out << '\n';
9667  if (!Nonconforming() || !IsSlaveFace(faces_info[i]))
9668  {
9669  out << l+1 << ' ' << faces[i]->GetGeometryType();
9670  for (j = nv-1; j >= 0; j--)
9671  {
9672  out << ' ' << v[j];
9673  }
9674  out << '\n';
9675  }
9676  }
9677  }
9678  else
9679  {
9680  k = partitioning[faces_info[i].Elem1No];
9681  nv = faces[i]->GetNVertices();
9682  v = faces[i]->GetVertices();
9683  out << k+1 << ' ' << faces[i]->GetGeometryType();
9684  for (j = 0; j < nv; j++)
9685  {
9686  out << ' ' << v[j];
9687  }
9688  out << '\n';
9689  }
9690  }
9691  out << "\nvertices\n" << NumOfVertices << '\n';
9692  if (Nodes == NULL)
9693  {
9694  out << spaceDim << '\n';
9695  for (i = 0; i < NumOfVertices; i++)
9696  {
9697  out << vertices[i](0);
9698  for (j = 1; j < spaceDim; j++)
9699  {
9700  out << ' ' << vertices[i](j);
9701  }
9702  out << '\n';
9703  }
9704  out.flush();
9705  }
9706  else
9707  {
9708  out << "\nnodes\n";
9709  Nodes->Save(out);
9710  }
9711 }
9712 
9713 void Mesh::PrintElementsWithPartitioning(int *partitioning,
9714  std::ostream &out,
9715  int interior_faces)
9716 {
9717  MFEM_ASSERT(Dim == spaceDim, "2D Manifolds not supported\n");
9718  if (Dim != 3 && Dim != 2) { return; }
9719 
9720  int i, j, k, l, s;
9721 
9722  int nv;
9723  const int *ind;
9724 
9725  int *vcount = new int[NumOfVertices];
9726  for (i = 0; i < NumOfVertices; i++)
9727  {
9728  vcount[i] = 0;
9729  }
9730  for (i = 0; i < NumOfElements; i++)
9731  {
9732  nv = elements[i]->GetNVertices();
9733  ind = elements[i]->GetVertices();
9734  for (j = 0; j < nv; j++)
9735  {
9736  vcount[ind[j]]++;
9737  }
9738  }
9739 
9740  int *voff = new int[NumOfVertices+1];
9741  voff[0] = 0;
9742  for (i = 1; i <= NumOfVertices; i++)
9743  {
9744  voff[i] = vcount[i-1] + voff[i-1];
9745  }
9746 
9747  int **vown = new int*[NumOfVertices];
9748  for (i = 0; i < NumOfVertices; i++)
9749  {
9750  vown[i] = new int[vcount[i]];
9751  }
9752 
9753  // 2D
9754  if (Dim == 2)
9755  {
9756  int nv, nbe;
9757  int *ind;
9758 
9759  Table edge_el;
9760  Transpose(ElementToEdgeTable(), edge_el);
9761 
9762  // Fake printing of the elements.
9763  for (i = 0; i < NumOfElements; i++)
9764  {
9765  nv = elements[i]->GetNVertices();
9766  ind = elements[i]->GetVertices();
9767  for (j = 0; j < nv; j++)
9768  {
9769  vcount[ind[j]]--;
9770  vown[ind[j]][vcount[ind[j]]] = i;
9771  }
9772  }
9773 
9774  for (i = 0; i < NumOfVertices; i++)
9775  {
9776  vcount[i] = voff[i+1] - voff[i];
9777  }
9778 
9779  nbe = 0;
9780  for (i = 0; i < edge_el.Size(); i++)
9781  {
9782  const int *el = edge_el.GetRow(i);
9783  if (edge_el.RowSize(i) > 1)
9784  {
9785  k = partitioning[el[0]];
9786  l = partitioning[el[1]];
9787  if (interior_faces || k != l)
9788  {
9789  nbe += 2;
9790  }
9791  }
9792  else
9793  {
9794  nbe++;
9795  }
9796  }
9797 
9798  // Print the type of the mesh and the boundary elements.
9799  out << "areamesh2\n\n" << nbe << '\n';
9800 
9801  for (i = 0; i < edge_el.Size(); i++)
9802  {
9803  const int *el = edge_el.GetRow(i);
9804  if (edge_el.RowSize(i) > 1)
9805  {
9806  k = partitioning[el[0]];
9807  l = partitioning[el[1]];
9808  if (interior_faces || k != l)
9809  {
9810  Array<int> ev;
9811  GetEdgeVertices(i,ev);
9812  out << k+1; // attribute
9813  for (j = 0; j < 2; j++)
9814  for (s = 0; s < vcount[ev[j]]; s++)
9815  if (vown[ev[j]][s] == el[0])
9816  {
9817  out << ' ' << voff[ev[j]]+s+1;
9818  }
9819  out << '\n';
9820  out << l+1; // attribute
9821  for (j = 1; j >= 0; j--)
9822  for (s = 0; s < vcount[ev[j]]; s++)
9823  if (vown[ev[j]][s] == el[1])
9824  {
9825  out << ' ' << voff[ev[j]]+s+1;
9826  }
9827  out << '\n';
9828  }
9829  }
9830  else
9831  {
9832  k = partitioning[el[0]];
9833  Array<int> ev;
9834  GetEdgeVertices(i,ev);
9835  out << k+1; // attribute
9836  for (j = 0; j < 2; j++)
9837  for (s = 0; s < vcount[ev[j]]; s++)
9838  if (vown[ev[j]][s] == el[0])
9839  {
9840  out << ' ' << voff[ev[j]]+s+1;
9841  }
9842  out << '\n';
9843  }
9844  }
9845 
9846  // Print the elements.
9847  out << NumOfElements << '\n';
9848  for (i = 0; i < NumOfElements; i++)
9849  {
9850  nv = elements[i]->GetNVertices();
9851  ind = elements[i]->GetVertices();
9852  out << partitioning[i]+1 << ' '; // use subdomain number as attribute
9853  out << nv << ' ';
9854  for (j = 0; j < nv; j++)
9855  {
9856  out << ' ' << voff[ind[j]]+vcount[ind[j]]--;
9857  vown[ind[j]][vcount[ind[j]]] = i;
9858  }
9859  out << '\n';
9860  }
9861 
9862  for (i = 0; i < NumOfVertices; i++)
9863  {
9864  vcount[i] = voff[i+1] - voff[i];
9865  }
9866 
9867  // Print the vertices.
9868  out << voff[NumOfVertices] << '\n';
9869  for (i = 0; i < NumOfVertices; i++)
9870  for (k = 0; k < vcount[i]; k++)
9871  {
9872  for (j = 0; j < Dim; j++)
9873  {
9874  out << vertices[i](j) << ' ';
9875  }
9876  out << '\n';
9877  }
9878  }
9879  // Dim is 3
9880  else if (meshgen == 1)
9881  {
9882  out << "NETGEN_Neutral_Format\n";
9883  // print the vertices
9884  out << voff[NumOfVertices] << '\n';
9885  for (i = 0; i < NumOfVertices; i++)
9886  for (k = 0; k < vcount[i]; k++)
9887  {
9888  for (j = 0; j < Dim; j++)
9889  {
9890  out << ' ' << vertices[i](j);
9891  }
9892  out << '\n';
9893  }
9894 
9895  // print the elements
9896  out << NumOfElements << '\n';
9897  for (i = 0; i < NumOfElements; i++)
9898  {
9899  nv = elements[i]->GetNVertices();
9900  ind = elements[i]->GetVertices();
9901  out << partitioning[i]+1; // use subdomain number as attribute
9902  for (j = 0; j < nv; j++)
9903  {
9904  out << ' ' << voff[ind[j]]+vcount[ind[j]]--;
9905  vown[ind[j]][vcount[ind[j]]] = i;
9906  }
9907  out << '\n';
9908  }
9909 
9910  for (i = 0; i < NumOfVertices; i++)
9911  {
9912  vcount[i] = voff[i+1] - voff[i];
9913  }
9914 
9915  // print the boundary information.
9916  int k, l, nbe;
9917  nbe = 0;
9918  for (i = 0; i < NumOfFaces; i++)
9919  if ((l = faces_info[i].Elem2No) >= 0)
9920  {
9921  k = partitioning[faces_info[i].Elem1No];
9922  l = partitioning[l];
9923  if (interior_faces || k != l)
9924  {
9925  nbe += 2;
9926  }
9927  }
9928  else
9929  {
9930  nbe++;
9931  }
9932 
9933  out << nbe << '\n';
9934  for (i = 0; i < NumOfFaces; i++)
9935  if ((l = faces_info[i].Elem2No) >= 0)
9936  {
9937  k = partitioning[faces_info[i].Elem1No];
9938  l = partitioning[l];
9939  if (interior_faces || k != l)
9940  {
9941  nv = faces[i]->GetNVertices();
9942  ind = faces[i]->GetVertices();
9943  out << k+1; // attribute
9944  for (j = 0; j < nv; j++)
9945  for (s = 0; s < vcount[ind[j]]; s++)
9946  if (vown[ind[j]][s] == faces_info[i].Elem1No)
9947  {
9948  out << ' ' << voff[ind[j]]+s+1;
9949  }
9950  out << '\n';
9951  out << l+1; // attribute
9952  for (j = nv-1; j >= 0; j--)
9953  for (s = 0; s < vcount[ind[j]]; s++)
9954  if (vown[ind[j]][s] == faces_info[i].Elem2No)
9955  {
9956  out << ' ' << voff[ind[j]]+s+1;
9957  }
9958  out << '\n';
9959  }
9960  }
9961  else
9962  {
9963  k = partitioning[faces_info[i].Elem1No];
9964  nv = faces[i]->GetNVertices();
9965  ind = faces[i]->GetVertices();
9966  out << k+1; // attribute
9967  for (j = 0; j < nv; j++)
9968  for (s = 0; s < vcount[ind[j]]; s++)
9969  if (vown[ind[j]][s] == faces_info[i].Elem1No)
9970  {
9971  out << ' ' << voff[ind[j]]+s+1;
9972  }
9973  out << '\n';
9974  }
9975  }
9976  // Dim is 3
9977  else if (meshgen == 2) // TrueGrid
9978  {
9979  // count the number of the boundary elements.
9980  int k, l, nbe;
9981  nbe = 0;
9982  for (i = 0; i < NumOfFaces; i++)
9983  if ((l = faces_info[i].Elem2No) >= 0)
9984  {
9985  k = partitioning[faces_info[i].Elem1No];
9986  l = partitioning[l];
9987  if (interior_faces || k != l)
9988  {
9989  nbe += 2;
9990  }
9991  }
9992  else
9993  {
9994  nbe++;
9995  }
9996 
9997 
9998  out << "TrueGrid\n"
9999  << "1 " << voff[NumOfVertices] << " " << NumOfElements
10000  << " 0 0 0 0 0 0 0\n"
10001  << "0 0 0 1 0 0 0 0 0 0 0\n"
10002  << "0 0 " << nbe << " 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
10003  << "0.0 0.0 0.0 0 0 0.0 0.0 0 0.0\n"
10004  << "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n";
10005 
10006  for (i = 0; i < NumOfVertices; i++)
10007  for (k = 0; k < vcount[i]; k++)
10008  out << voff[i]+k << " 0.0 " << vertices[i](0) << ' '
10009  << vertices[i](1) << ' ' << vertices[i](2) << " 0.0\n";
10010 
10011  for (i = 0; i < NumOfElements; i++)
10012  {
10013  nv = elements[i]->GetNVertices();
10014  ind = elements[i]->GetVertices();
10015  out << i+1 << ' ' << partitioning[i]+1; // partitioning as attribute
10016  for (j = 0; j < nv; j++)
10017  {
10018  out << ' ' << voff[ind[j]]+vcount[ind[j]]--;
10019  vown[ind[j]][vcount[ind[j]]] = i;
10020  }
10021  out << '\n';
10022  }
10023 
10024  for (i = 0; i < NumOfVertices; i++)
10025  {
10026  vcount[i] = voff[i+1] - voff[i];
10027  }
10028 
10029  // boundary elements
10030  for (i = 0; i < NumOfFaces; i++)
10031  if ((l = faces_info[i].Elem2No) >= 0)
10032  {
10033  k = partitioning[faces_info[i].Elem1No];
10034  l = partitioning[l];
10035  if (interior_faces || k != l)
10036  {
10037  nv = faces[i]->GetNVertices();
10038  ind = faces[i]->GetVertices();
10039  out << k+1; // attribute
10040  for (j = 0; j < nv; j++)
10041  for (s = 0; s < vcount[ind[j]]; s++)
10042  if (vown[ind[j]][s] == faces_info[i].Elem1No)
10043  {
10044  out << ' ' << voff[ind[j]]+s+1;
10045  }
10046  out << " 1.0 1.0 1.0 1.0\n";
10047  out << l+1; // attribute
10048  for (j = nv-1; j >= 0; j--)
10049  for (s = 0; s < vcount[ind[j]]; s++)
10050  if (vown[ind[j]][s] == faces_info[i].Elem2No)
10051  {
10052  out << ' ' << voff[ind[j]]+s+1;
10053  }
10054  out << " 1.0 1.0 1.0 1.0\n";
10055  }
10056  }
10057  else
10058  {
10059  k = partitioning[faces_info[i].Elem1No];
10060  nv = faces[i]->GetNVertices();
10061  ind = faces[i]->GetVertices();
10062  out << k+1; // attribute
10063  for (j = 0; j < nv; j++)
10064  for (s = 0; s < vcount[ind[j]]; s++)
10065  if (vown[ind[j]][s] == faces_info[i].Elem1No)
10066  {
10067  out << ' ' << voff[ind[j]]+s+1;
10068  }
10069  out << " 1.0 1.0 1.0 1.0\n";
10070  }
10071  }
10072 
10073  out << flush;
10074 
10075  for (i = 0; i < NumOfVertices; i++)
10076  {
10077  delete [] vown[i];
10078  }
10079 
10080  delete [] vcount;
10081  delete [] voff;
10082  delete [] vown;
10083 }
10084 
10085 void Mesh::PrintSurfaces(const Table & Aface_face, std::ostream &out) const
10086 {
10087  int i, j;
10088 
10089  if (NURBSext)
10090  {
10091  mfem_error("Mesh::PrintSurfaces"
10092  " NURBS mesh is not supported!");
10093  return;
10094  }
10095 
10096  out << "MFEM mesh v1.0\n";
10097 
10098  // optional
10099  out <<
10100  "\n#\n# MFEM Geometry Types (see mesh/geom.hpp):\n#\n"
10101  "# POINT = 0\n"
10102  "# SEGMENT = 1\n"
10103  "# TRIANGLE = 2\n"
10104  "# SQUARE = 3\n"
10105  "# TETRAHEDRON = 4\n"
10106  "# CUBE = 5\n"
10107  "# PRISM = 6\n"
10108  "#\n";
10109 
10110  out << "\ndimension\n" << Dim
10111  << "\n\nelements\n" << NumOfElements << '\n';
10112  for (i = 0; i < NumOfElements; i++)
10113  {
10114  PrintElement(elements[i], out);
10115  }
10116 
10117  out << "\nboundary\n" << Aface_face.Size_of_connections() << '\n';
10118  const int * const i_AF_f = Aface_face.GetI();
10119  const int * const j_AF_f = Aface_face.GetJ();
10120 
10121  for (int iAF=0; iAF < Aface_face.Size(); ++iAF)
10122  for (const int * iface = j_AF_f + i_AF_f[iAF];
10123  iface < j_AF_f + i_AF_f[iAF+1];
10124  ++iface)
10125  {
10126  out << iAF+1 << ' ';
10127  PrintElementWithoutAttr(faces[*iface],out);
10128  }
10129 
10130  out << "\nvertices\n" << NumOfVertices << '\n';
10131  if (Nodes == NULL)
10132  {
10133  out << spaceDim << '\n';
10134  for (i = 0; i < NumOfVertices; i++)
10135  {
10136  out << vertices[i](0);
10137  for (j = 1; j < spaceDim; j++)
10138  {
10139  out << ' ' << vertices[i](j);
10140  }
10141  out << '\n';
10142  }
10143  out.flush();
10144  }
10145  else
10146  {
10147  out << "\nnodes\n";
10148  Nodes->Save(out);
10149  }
10150 }
10151 
10152 void Mesh::ScaleSubdomains(double sf)
10153 {
10154  int i,j,k;
10155  Array<int> vert;
10156  DenseMatrix pointmat;
10157  int na = attributes.Size();
10158  double *cg = new double[na*spaceDim];
10159  int *nbea = new int[na];
10160 
10161  int *vn = new int[NumOfVertices];
10162  for (i = 0; i < NumOfVertices; i++)
10163  {
10164  vn[i] = 0;
10165  }
10166  for (i = 0; i < na; i++)
10167  {
10168  for (j = 0; j < spaceDim; j++)
10169  {
10170  cg[i*spaceDim+j] = 0.0;
10171  }
10172  nbea[i] = 0;
10173  }
10174 
10175  for (i = 0; i < NumOfElements; i++)
10176  {
10177  GetElementVertices(i, vert);
10178  for (k = 0; k < vert.Size(); k++)
10179  {
10180  vn[vert[k]] = 1;
10181  }
10182  }
10183 
10184  for (i = 0; i < NumOfElements; i++)
10185  {
10186  int bea = GetAttribute(i)-1;
10187  GetPointMatrix(i, pointmat);
10188  GetElementVertices(i, vert);
10189 
10190  for (k = 0; k < vert.Size(); k++)
10191  if (vn[vert[k]] == 1)
10192  {
10193  nbea[bea]++;
10194  for (j = 0; j < spaceDim; j++)
10195  {
10196  cg[bea*spaceDim+j] += pointmat(j,k);
10197  }
10198  vn[vert[k]] = 2;
10199  }
10200  }
10201 
10202  for (i = 0; i < NumOfElements; i++)
10203  {
10204  int bea = GetAttribute(i)-1;
10205  GetElementVertices (i, vert);
10206 
10207  for (k = 0; k < vert.Size(); k++)
10208  if (vn[vert[k]])
10209  {
10210  for (j = 0; j < spaceDim; j++)
10211  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
10212  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
10213  vn[vert[k]] = 0;
10214  }
10215  }
10216 
10217  delete [] cg;
10218  delete [] nbea;
10219  delete [] vn;
10220 }
10221 
10222 void Mesh::ScaleElements(double sf)
10223 {
10224  int i,j,k;
10225  Array<int> vert;
10226  DenseMatrix pointmat;
10227  int na = NumOfElements;
10228  double *cg = new double[na*spaceDim];
10229  int *nbea = new int[na];
10230 
10231  int *vn = new int[NumOfVertices];
10232  for (i = 0; i < NumOfVertices; i++)
10233  {
10234  vn[i] = 0;
10235  }
10236  for (i = 0; i < na; i++)
10237  {
10238  for (j = 0; j < spaceDim; j++)
10239  {
10240  cg[i*spaceDim+j] = 0.0;
10241  }
10242  nbea[i] = 0;
10243  }
10244 
10245  for (i = 0; i < NumOfElements; i++)
10246  {
10247  GetElementVertices(i, vert);
10248  for (k = 0; k < vert.Size(); k++)
10249  {
10250  vn[vert[k]] = 1;
10251  }
10252  }
10253 
10254  for (i = 0; i < NumOfElements; i++)
10255  {
10256  int bea = i;
10257  GetPointMatrix(i, pointmat);
10258  GetElementVertices(i, vert);
10259 
10260  for (k = 0; k < vert.Size(); k++)
10261  if (vn[vert[k]] == 1)
10262  {
10263  nbea[bea]++;
10264  for (j = 0; j < spaceDim; j++)
10265  {
10266  cg[bea*spaceDim+j] += pointmat(j,k);
10267  }
10268  vn[vert[k]] = 2;
10269  }
10270  }
10271 
10272  for (i = 0; i < NumOfElements; i++)
10273  {
10274  int bea = i;
10275  GetElementVertices(i, vert);
10276 
10277  for (k = 0; k < vert.Size(); k++)
10278  if (vn[vert[k]])
10279  {
10280  for (j = 0; j < spaceDim; j++)
10281  vertices[vert[k]](j) = sf*vertices[vert[k]](j) +
10282  (1-sf)*cg[bea*spaceDim+j]/nbea[bea];
10283  vn[vert[k]] = 0;
10284  }
10285  }
10286 
10287  delete [] cg;
10288  delete [] nbea;
10289  delete [] vn;
10290 }
10291 
10292 void Mesh::Transform(void (*f)(const Vector&, Vector&))
10293 {
10294  // TODO: support for different new spaceDim.
10295  if (Nodes == NULL)
10296  {
10297  Vector vold(spaceDim), vnew(NULL, spaceDim);
10298  for (int i = 0; i < vertices.Size(); i++)
10299  {
10300  for (int j = 0; j < spaceDim; j++)
10301  {
10302  vold(j) = vertices[i](j);
10303  }
10304  vnew.SetData(vertices[i]());
10305  (*f)(vold, vnew);
10306  }
10307  }
10308  else
10309  {
10310  GridFunction xnew(Nodes->FESpace());
10311  VectorFunctionCoefficient f_pert(spaceDim, f);
10312  xnew.ProjectCoefficient(f_pert);
10313  *Nodes = xnew;
10314  }
10315 }
10316 
10317 void Mesh::Transform(VectorCoefficient &deformation)
10318 {
10319  MFEM_VERIFY(spaceDim == deformation.GetVDim(),
10320  "incompatible vector dimensions");
10321  if (Nodes == NULL)
10322  {
10323  LinearFECollection fec;
10324  FiniteElementSpace fes(this, &fec, spaceDim, Ordering::byVDIM);
10325  GridFunction xnew(&fes);
10326  xnew.ProjectCoefficient(deformation);
10327  for (int i = 0; i < NumOfVertices; i++)
10328  for (int d = 0; d < spaceDim; d++)
10329  {
10330  vertices[i](d) = xnew(d + spaceDim*i);
10331  }
10332  }
10333  else
10334  {
10335  GridFunction xnew(Nodes->FESpace());
10336  xnew.ProjectCoefficient(deformation);
10337  *Nodes = xnew;
10338  }
10339 }
10340 
10341 void Mesh::RemoveUnusedVertices()
10342 {
10343  if (NURBSext || ncmesh) { return; }
10344 
10345  Array<int> v2v(GetNV());
10346  v2v = -1;
10347  for (int i = 0; i < GetNE(); i++)
10348  {
10349  Element *el = GetElement(i);
10350  int nv = el->GetNVertices();
10351  int *v = el->GetVertices();
10352  for (int j = 0; j < nv; j++)
10353  {
10354  v2v[v[j]] = 0;
10355  }
10356  }
10357  for (int i = 0; i < GetNBE(); i++)
10358  {
10359  Element *el = GetBdrElement(i);
10360  int *v = el->GetVertices();
10361  int nv = el->GetNVertices();
10362  for (int j = 0; j < nv; j++)
10363  {
10364  v2v[v[j]] = 0;
10365  }
10366  }
10367  int num_vert = 0;
10368  for (int i = 0; i < v2v.Size(); i++)
10369  {
10370  if (v2v[i] == 0)
10371  {
10372  vertices[num_vert] = vertices[i];
10373  v2v[i] = num_vert++;
10374  }
10375  }
10376 
10377  if (num_vert == v2v.Size()) { return; }
10378 
10379  Vector nodes_by_element;
10380  Array<int> vdofs;
10381  if (Nodes)
10382  {
10383  int s = 0;
10384  for (int i = 0; i < GetNE(); i++)
10385  {
10386  Nodes->FESpace()->GetElementVDofs(i, vdofs);
10387  s += vdofs.Size();
10388  }
10389  nodes_by_element.SetSize(s);
10390  s = 0;
10391  for (int i = 0; i < GetNE(); i++)
10392  {
10393  Nodes->FESpace()->GetElementVDofs(i, vdofs);
10394  Nodes->GetSubVector(vdofs, &nodes_by_element(s));
10395  s += vdofs.Size();
10396  }
10397  }
10398  vertices.SetSize(num_vert);
10399  NumOfVertices = num_vert;
10400  for (int i = 0; i < GetNE(); i++)
10401  {
10402  Element *el = GetElement(i);
10403  int *v = el->GetVertices();
10404  int nv = el->GetNVertices();
10405  for (int j = 0; j < nv; j++)
10406  {
10407  v[j] = v2v[v[j]];
10408  }
10409  }
10410  for (int i = 0; i < GetNBE(); i++)
10411  {
10412  Element *el = GetBdrElement(i);
10413  int *v = el->GetVertices();
10414  int nv = el->GetNVertices();
10415  for (int j = 0; j < nv; j++)
10416  {
10417  v[j] = v2v[v[j]];
10418  }
10419  }
10420  DeleteTables();
10421  if (Dim > 1)
10422  {
10423  // generate el_to_edge, be_to_edge (2D), bel_to_edge (3D)
10424  el_to_edge = new Table;
10425  NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
10426  }
10427  if (Dim > 2)
10428  {
10429  // generate el_to_face, be_to_face
10430  GetElementToFaceTable();
10431  }
10432  // Update faces and faces_info
10433  GenerateFaces();
10434  if (Nodes)
10435  {
10436  Nodes->FESpace()->Update();
10437  Nodes->Update();
10438  int s = 0;
10439  for (int i = 0; i < GetNE(); i++)
10440  {
10441  Nodes->FESpace()->GetElementVDofs(i, vdofs);
10442  Nodes->SetSubVector(vdofs, &nodes_by_element(s));
10443  s += vdofs.Size();
10444  }
10445  }
10446 }
10447 
10448 void Mesh::RemoveInternalBoundaries()
10449 {
10450  if (NURBSext || ncmesh) { return; }
10451 
10452  int num_bdr_elem = 0;
10453  int new_bel_to_edge_nnz = 0;
10454  for (int i = 0; i < GetNBE(); i++)
10455  {
10456  if (FaceIsInterior(GetBdrElementEdgeIndex(i)))
10457  {
10458  FreeElement(boundary[i]);
10459  }
10460  else
10461  {
10462  num_bdr_elem++;
10463  if (Dim == 3)
10464  {
10465  new_bel_to_edge_nnz += bel_to_edge->RowSize(i);
10466  }
10467  }
10468  }
10469 
10470  if (num_bdr_elem == GetNBE()) { return; }
10471 
10472  Array<Element *> new_boundary(num_bdr_elem);
10473  Array<int> new_be_to_edge, new_be_to_face;
10474  Table *new_bel_to_edge = NULL;
10475  new_boundary.SetSize(0);
10476  if (Dim == 2)
10477  {
10478  new_be_to_edge.Reserve(num_bdr_elem);
10479  }
10480  else if (Dim == 3)
10481  {
10482  new_be_to_face.Reserve(num_bdr_elem);
10483  new_bel_to_edge = new Table;
10484  new_bel_to_edge->SetDims(num_bdr_elem, new_bel_to_edge_nnz);
10485  }
10486  for (int i = 0; i < GetNBE(); i++)
10487  {
10488  if (!FaceIsInterior(GetBdrElementEdgeIndex(i)))
10489  {
10490  new_boundary.Append(boundary[i]);
10491  if (Dim == 2)
10492  {
10493  new_be_to_edge.Append(be_to_edge[i]);
10494  }
10495  else if (Dim == 3)
10496  {
10497  int row = new_be_to_face.Size();
10498  new_be_to_face.Append(be_to_face[i]);
10499  int *e = bel_to_edge->GetRow(i);
10500  int ne = bel_to_edge->RowSize(i);
10501  int *new_e = new_bel_to_edge->GetRow(row);
10502  for (int j = 0; j < ne; j++)
10503  {
10504  new_e[j] = e[j];
10505  }
10506  new_bel_to_edge->GetI()[row+1] = new_bel_to_edge->GetI()[row] + ne;
10507  }
10508  }
10509  }
10510 
10511  NumOfBdrElements = new_boundary.Size();
10512  mfem::Swap(boundary, new_boundary);
10513 
10514  if (Dim == 2)
10515  {
10516  mfem::Swap(be_to_edge, new_be_to_edge);
10517  }
10518  else if (Dim == 3)
10519  {
10520  mfem::Swap(be_to_face, new_be_to_face);
10521  delete bel_to_edge;
10522  bel_to_edge = new_bel_to_edge;
10523  }
10524 
10525  Array<int> attribs(num_bdr_elem);
10526  for (int i = 0; i < attribs.Size(); i++)
10527  {
10528  attribs[i] = GetBdrAttribute(i);
10529  }
10530  attribs.Sort();
10531  attribs.Unique();
10532  bdr_attributes.DeleteAll();
10533  attribs.Copy(bdr_attributes);
10534 }
10535 
10536 void Mesh::FreeElement(Element *E)
10537 {
10538 #ifdef MFEM_USE_MEMALLOC
10539  if (E)
10540  {
10541  if (E->GetType() == Element::TETRAHEDRON)
10542  {
10543  TetMemory.Free((Tetrahedron*) E);
10544  }
10545  else
10546  {
10547  delete E;
10548  }
10549  }
10550 #else
10551  delete E;
10552 #endif
10553 }
10554 
10555 std::ostream &operator<<(std::ostream &out, const Mesh &mesh)
10556 {
10557  mesh.Print(out);
10558  return out;
10559 }
10560 
10561 int Mesh::FindPoints(DenseMatrix &point_mat, Array<int>& elem_ids,
10562  Array<IntegrationPoint>& ips, bool warn,
10563  InverseElementTransformation *inv_trans)
10564 {
10565  const int npts = point_mat.Width();
10566  if (!npts) { return 0; }
10567  MFEM_VERIFY(point_mat.Height() == spaceDim,"Invalid points matrix");
10568  elem_ids.SetSize(npts);
10569  ips.SetSize(npts);
10570  elem_ids = -1;
10571  if (!GetNE()) { return 0; }
10572 
10573  double *data = point_mat.GetData();
10574  InverseElementTransformation *inv_tr = inv_trans;
10575  inv_tr = inv_tr ? inv_tr : new InverseElementTransformation;
10576 
10577  // For each point in 'point_mat', find the element whose center is closest.
10578  Vector min_dist(npts);
10579  Array<int> e_idx(npts);
10580  min_dist = std::numeric_limits<double>::max();
10581  e_idx = -1;
10582 
10583  Vector pt(spaceDim);
10584  for (int i = 0; i < GetNE(); i++)
10585  {
10586  GetElementTransformation(i)->Transform(
10587  Geometries.GetCenter(GetElementBaseGeometry(i)), pt);
10588  for (int k = 0; k < npts; k++)
10589  {
10590  double dist = pt.DistanceTo(data+k*spaceDim);
10591  if (dist < min_dist(k))
10592  {
10593  min_dist(k) = dist;
10594  e_idx[k] = i;
10595  }
10596  }
10597  }
10598 
10599  // Checks if the points lie in the closest element
10600  int pts_found = 0;
10601  pt.NewDataAndSize(NULL, spaceDim);
10602  for (int k = 0; k < npts; k++)
10603  {
10604  pt.SetData(data+k*spaceDim);
10605  inv_tr->SetTransformation(*GetElementTransformation(e_idx[k]));
10606  int res = inv_tr->Transform(pt, ips[k]);
10607  if (res == InverseElementTransformation::Inside)
10608  {
10609  elem_ids[k] = e_idx[k];
10610  pts_found++;
10611  }
10612  }
10613  if (pts_found != npts)
10614  {
10615  Array<int> vertices;
10616  Table *vtoel = GetVertexToElementTable();
10617  for (int k = 0; k < npts; k++)
10618  {
10619  if (elem_ids[k] != -1) { continue; }
10620  // Try all vertex-neighbors of element e_idx[k]
10621  pt.SetData(data+k*spaceDim);
10622  GetElementVertices(e_idx[k], vertices);
10623  for (int v = 0; v < vertices.Size(); v++)
10624  {
10625  int vv = vertices[v];
10626  int ne = vtoel->RowSize(vv);
10627  const int* els = vtoel->GetRow(vv);
10628  for (int e = 0; e < ne; e++)
10629  {
10630  if (els[e] == e_idx[k]) { continue; }
10631  inv_tr->SetTransformation(*GetElementTransformation(els[e]));
10632  int res = inv_tr->Transform(pt, ips[k]);
10633  if (res == InverseElementTransformation::Inside)
10634  {
10635  elem_ids[k] = els[e];
10636  pts_found++;
10637  goto next_point;
10638  }
10639  }
10640  }
10641  // Try neighbors for non-conforming meshes
10642  if (ncmesh)
10643  {
10644  Array<int> neigh;
10645  int le = ncmesh->leaf_elements[e_idx[k]];
10646  ncmesh->FindNeighbors(le,neigh);
10647  for (int e = 0; e < neigh.Size(); e++)
10648  {
10649  int nn = neigh[e];
10650  if (ncmesh->IsGhost(ncmesh->elements[nn])) { continue; }
10651  int el = ncmesh->elements[nn].index;
10652  inv_tr->SetTransformation(*GetElementTransformation(el));
10653  int res = inv_tr->Transform(pt, ips[k]);
10654  if (res == InverseElementTransformation::Inside)
10655  {
10656  elem_ids[k] = el;
10657  pts_found++;
10658  goto next_point;
10659  }
10660  }
10661  }
10662  next_point: ;
10663  }
10664  delete vtoel;
10665  }
10666  if (inv_trans == NULL) { delete inv_tr; }
10667 
10668  if (warn && pts_found != npts)
10669  {
10670  MFEM_WARNING((npts-pts_found) << " points were not found");
10671  }
10672  return pts_found;
10673 }
10674 
10675 
10676 GeometricFactors::GeometricFactors(const Mesh *mesh, const IntegrationRule &ir,
10677  int flags)
10678 {
10679  this->mesh = mesh;
10680  IntRule = &ir;
10681  computed_factors = flags;
10682 
10683  const GridFunction *nodes = mesh->GetNodes();
10684  const FiniteElementSpace *fespace = nodes->FESpace();
10685  const FiniteElement *fe = fespace->GetFE(0);
10686  const int dim = fe->GetDim();
10687  const int vdim = fespace->GetVDim();
10688  const int NE = fespace->GetNE();
10689  const int ND = fe->GetDof();
10690  const int NQ = ir.GetNPoints();
10691 
10692  // For now, we are not using tensor product evaluation
10693  const Operator *elem_restr = fespace->GetElementRestriction(
10694  ElementDofOrdering::NATIVE);
10695 
10696  unsigned eval_flags = 0;
10697  if (flags & GeometricFactors::COORDINATES)
10698  {
10699  X.SetSize(vdim*NQ*NE);
10700  eval_flags |= QuadratureInterpolator::VALUES;
10701  }
10702  if (flags & GeometricFactors::JACOBIANS)
10703  {
10704  J.SetSize(dim*vdim*NQ*NE);
10705  eval_flags |= QuadratureInterpolator::DERIVATIVES;
10706  }
10707  if (flags & GeometricFactors::DETERMINANTS)
10708  {
10709  detJ.SetSize(NQ*NE);
10710  eval_flags |= QuadratureInterpolator::DETERMINANTS;
10711  }
10712 
10713  const QuadratureInterpolator *qi = fespace->GetQuadratureInterpolator(ir);
10714  // For now, we are not using tensor product evaluation (not implemented)
10715  qi->DisableTensorProducts();
10716  qi->SetOutputLayout(QVectorLayout::byNODES);
10717  if (elem_restr)
10718  {
10719  Vector Enodes(vdim*ND*NE);
10720  elem_restr->Mult(*nodes, Enodes);
10721  qi->Mult(Enodes, eval_flags, X, J, detJ);
10722  }
10723  else
10724  {
10725  qi->Mult(*nodes, eval_flags, X, J, detJ);
10726  }
10727 }
10728 
10729 FaceGeometricFactors::FaceGeometricFactors(const Mesh *mesh,
10730  const IntegrationRule &ir,
10731  int flags, FaceType type)
10732  : type(type)
10733 {
10734  this->mesh = mesh;
10735  IntRule = &ir;
10736  computed_factors = flags;
10737 
10738  const GridFunction *nodes = mesh->GetNodes();
10739  const FiniteElementSpace *fespace = nodes->FESpace();
10740  const int vdim = fespace->GetVDim();
10741  const int NF = fespace->GetNFbyType(type);
10742  const int NQ = ir.GetNPoints();
10743 
10744  const Operator *face_restr = fespace->GetFaceRestriction(
10746  type,
10748  Vector Fnodes(face_restr->Height());
10749  face_restr->Mult(*nodes, Fnodes);
10750 
10751  unsigned eval_flags = 0;
10753  {
10754  X.SetSize(vdim*NQ*NF);
10755  eval_flags |= FaceQuadratureInterpolator::VALUES;
10756  }
10757  if (flags & FaceGeometricFactors::JACOBIANS)
10758  {
10759  J.SetSize(vdim*vdim*NQ*NF);
10761  }
10763  {
10764  detJ.SetSize(NQ*NF);
10766  }
10767  if (flags & FaceGeometricFactors::NORMALS)
10768  {
10769  normal.SetSize(vdim*NQ*NF);
10771  }
10772 
10774  ir, type);
10775  qi->Mult(Fnodes, eval_flags, X, J, detJ, normal);
10776 }
10777 
10779  const double _s)
10780  : VectorCoefficient(dim), n(_n), s(_s), tip(p, dim-1)
10781 {
10782 }
10783 
10785  const IntegrationPoint &ip)
10786 {
10787  V.SetSize(vdim);
10788  T.Transform(ip, tip);
10789  V(0) = p[0];
10790  if (vdim == 2)
10791  {
10792  V(1) = s * ((ip.y + layer) / n);
10793  }
10794  else
10795  {
10796  V(1) = p[1];
10797  V(2) = s * ((ip.z + layer) / n);
10798  }
10799 }
10800 
10801 
10802 Mesh *Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
10803 {
10804  if (mesh->Dimension() != 1)
10805  {
10806  mfem::err << "Extrude1D : Not a 1D mesh!" << endl;
10807  mfem_error();
10808  }
10809 
10810  int nvy = (closed) ? (ny) : (ny + 1);
10811  int nvt = mesh->GetNV() * nvy;
10812 
10813  Mesh *mesh2d;
10814 
10815  if (closed)
10816  {
10817  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny, mesh->GetNBE()*ny);
10818  }
10819  else
10820  mesh2d = new Mesh(2, nvt, mesh->GetNE()*ny,
10821  mesh->GetNBE()*ny+2*mesh->GetNE());
10822 
10823  // vertices
10824  double vc[2];
10825  for (int i = 0; i < mesh->GetNV(); i++)
10826  {
10827  vc[0] = mesh->GetVertex(i)[0];
10828  for (int j = 0; j < nvy; j++)
10829  {
10830  vc[1] = sy * (double(j) / ny);
10831  mesh2d->AddVertex(vc);
10832  }
10833  }
10834  // elements
10835  Array<int> vert;
10836  for (int i = 0; i < mesh->GetNE(); i++)
10837  {
10838  const Element *elem = mesh->GetElement(i);
10839  elem->GetVertices(vert);
10840  const int attr = elem->GetAttribute();
10841  for (int j = 0; j < ny; j++)
10842  {
10843  int qv[4];
10844  qv[0] = vert[0] * nvy + j;
10845  qv[1] = vert[1] * nvy + j;
10846  qv[2] = vert[1] * nvy + (j + 1) % nvy;
10847  qv[3] = vert[0] * nvy + (j + 1) % nvy;
10848 
10849  mesh2d->AddQuad(qv, attr);
10850  }
10851  }
10852  // 2D boundary from the 1D boundary
10853  for (int i = 0; i < mesh->GetNBE(); i++)
10854  {
10855  const Element *elem = mesh->GetBdrElement(i);
10856  elem->GetVertices(vert);
10857  const int attr = elem->GetAttribute();
10858  for (int j = 0; j < ny; j++)
10859  {
10860  int sv[2];
10861  sv[0] = vert[0] * nvy + j;
10862  sv[1] = vert[0] * nvy + (j + 1) % nvy;
10863 
10864  if (attr%2)
10865  {
10866  Swap<int>(sv[0], sv[1]);
10867  }
10868 
10869  mesh2d->AddBdrSegment(sv, attr);
10870  }
10871  }
10872 
10873  if (!closed)
10874  {
10875  // 2D boundary from the 1D elements (bottom + top)
10876  int nba = (mesh->bdr_attributes.Size() > 0 ?
10877  mesh->bdr_attributes.Max() : 0);
10878  for (int i = 0; i < mesh->GetNE(); i++)
10879  {
10880  const Element *elem = mesh->GetElement(i);
10881  elem->GetVertices(vert);
10882  const int attr = nba + elem->GetAttribute();
10883  int sv[2];
10884  sv[0] = vert[0] * nvy;
10885  sv[1] = vert[1] * nvy;
10886 
10887  mesh2d->AddBdrSegment(sv, attr);
10888 
10889  sv[0] = vert[1] * nvy + ny;
10890  sv[1] = vert[0] * nvy + ny;
10891 
10892  mesh2d->AddBdrSegment(sv, attr);
10893  }
10894  }
10895 
10896  mesh2d->FinalizeQuadMesh(1, 0, false);
10897 
10898  GridFunction *nodes = mesh->GetNodes();
10899  if (nodes)
10900  {
10901  // duplicate the fec of the 1D mesh so that it can be deleted safely
10902  // along with its nodes, fes and fec
10903  FiniteElementCollection *fec2d = NULL;
10904  FiniteElementSpace *fes2d;
10905  const char *name = nodes->FESpace()->FEColl()->Name();
10906  string cname = name;
10907  if (cname == "Linear")
10908  {
10909  fec2d = new LinearFECollection;
10910  }
10911  else if (cname == "Quadratic")
10912  {
10913  fec2d = new QuadraticFECollection;
10914  }
10915  else if (cname == "Cubic")
10916  {
10917  fec2d = new CubicFECollection;
10918  }
10919  else if (!strncmp(name, "H1_", 3))
10920  {
10921  fec2d = new H1_FECollection(atoi(name + 7), 2);
10922  }
10923  else if (!strncmp(name, "L2_T", 4))
10924  {
10925  fec2d = new L2_FECollection(atoi(name + 10), 2, atoi(name + 4));
10926  }
10927  else if (!strncmp(name, "L2_", 3))
10928  {
10929  fec2d = new L2_FECollection(atoi(name + 7), 2);
10930  }
10931  else
10932  {
10933  delete mesh2d;
10934  mfem::err << "Extrude1D : The mesh uses unknown FE collection : "
10935  << cname << endl;
10936  mfem_error();
10937  }
10938  fes2d = new FiniteElementSpace(mesh2d, fec2d, 2);
10939  mesh2d->SetNodalFESpace(fes2d);
10940  GridFunction *nodes2d = mesh2d->GetNodes();
10941  nodes2d->MakeOwner(fec2d);
10942 
10943  NodeExtrudeCoefficient ecoeff(2, ny, sy);
10944  Vector lnodes;
10945  Array<int> vdofs2d;
10946  for (int i = 0; i < mesh->GetNE(); i++)
10947  {
10949  for (int j = ny-1; j >= 0; j--)
10950  {
10951  fes2d->GetElementVDofs(i*ny+j, vdofs2d);
10952  lnodes.SetSize(vdofs2d.Size());
10953  ecoeff.SetLayer(j);
10954  fes2d->GetFE(i*ny+j)->Project(ecoeff, T, lnodes);
10955  nodes2d->SetSubVector(vdofs2d, lnodes);
10956  }
10957  }
10958  }
10959  return mesh2d;
10960 }
10961 
10962 Mesh *Extrude2D(Mesh *mesh, const int nz, const double sz)
10963 {
10964  if (mesh->Dimension() != 2)
10965  {
10966  mfem::err << "Extrude2D : Not a 2D mesh!" << endl;
10967  mfem_error();
10968  }
10969 
10970  int nvz = nz + 1;
10971  int nvt = mesh->GetNV() * nvz;
10972 
10973  Mesh *mesh3d = new Mesh(3, nvt, mesh->GetNE()*nz,
10974  mesh->GetNBE()*nz+2*mesh->GetNE());
10975 
10976  bool wdgMesh = false;
10977  bool hexMesh = false;
10978 
10979  // vertices
10980  double vc[3];
10981  for (int i = 0; i < mesh->GetNV(); i++)
10982  {
10983  vc[0] = mesh->GetVertex(i)[0];
10984  vc[1] = mesh->GetVertex(i)[1];
10985  for (int j = 0; j < nvz; j++)
10986  {
10987  vc[2] = sz * (double(j) / nz);
10988  mesh3d->AddVertex(vc);
10989  }
10990  }
10991  // elements
10992  Array<int> vert;
10993  for (int i = 0; i < mesh->GetNE(); i++)
10994  {
10995  const Element *elem = mesh->GetElement(i);
10996  elem->GetVertices(vert);
10997  const int attr = elem->GetAttribute();
10999  switch (geom)
11000  {
11001  case Geometry::TRIANGLE:
11002  wdgMesh = true;
11003  for (int j = 0; j < nz; j++)
11004  {
11005  int pv[6];
11006  pv[0] = vert[0] * nvz + j;
11007  pv[1] = vert[1] * nvz + j;
11008  pv[2] = vert[2] * nvz + j;
11009  pv[3] = vert[0] * nvz + (j + 1) % nvz;
11010  pv[4] = vert[1] * nvz + (j + 1) % nvz;
11011  pv[5] = vert[2] * nvz + (j + 1) % nvz;
11012 
11013  mesh3d->AddWedge(pv, attr);
11014  }
11015  break;
11016  case Geometry::SQUARE:
11017  hexMesh = true;
11018  for (int j = 0; j < nz; j++)
11019  {
11020  int hv[8];
11021  hv[0] = vert[0] * nvz + j;
11022  hv[1] = vert[1] * nvz + j;
11023  hv[2] = vert[2] * nvz + j;
11024  hv[3] = vert[3] * nvz + j;
11025  hv[4] = vert[0] * nvz + (j + 1) % nvz;
11026  hv[5] = vert[1] * nvz + (j + 1) % nvz;
11027  hv[6] = vert[2] * nvz + (j + 1) % nvz;
11028  hv[7] = vert[3] * nvz + (j + 1) % nvz;
11029 
11030  mesh3d->AddHex(hv, attr);
11031  }
11032  break;
11033  default:
11034  mfem::err << "Extrude2D : Invalid 2D element type \'"
11035  << geom << "\'" << endl;
11036  mfem_error();
11037  break;
11038  }
11039  }
11040  // 3D boundary from the 2D boundary
11041  for (int i = 0; i < mesh->GetNBE(); i++)
11042  {
11043  const Element *elem = mesh->GetBdrElement(i);
11044  elem->GetVertices(vert);
11045  const int attr = elem->GetAttribute();
11046  for (int j = 0; j < nz; j++)
11047  {
11048  int qv[4];
11049  qv[0] = vert[0] * nvz + j;
11050  qv[1] = vert[1] * nvz + j;
11051  qv[2] = vert[1] * nvz + (j + 1) % nvz;
11052  qv[3] = vert[0] * nvz + (j + 1) % nvz;
11053 
11054  mesh3d->AddBdrQuad(qv, attr);
11055  }
11056  }
11057 
11058  // 3D boundary from the 2D elements (bottom + top)
11059  int nba = (mesh->bdr_attributes.Size() > 0 ?
11060  mesh->bdr_attributes.Max() : 0);
11061  for (int i = 0; i < mesh->GetNE(); i++)
11062  {
11063  const Element *elem = mesh->GetElement(i);
11064  elem->GetVertices(vert);
11065  const int attr = nba + elem->GetAttribute();
11067  switch (geom)
11068  {
11069  case Geometry::TRIANGLE:
11070  {
11071  int tv[3];
11072  tv[0] = vert[0] * nvz;
11073  tv[1] = vert[2] * nvz;
11074  tv[2] = vert[1] * nvz;
11075 
11076  mesh3d->AddBdrTriangle(tv, attr);
11077 
11078  tv[0] = vert[0] * nvz + nz;
11079  tv[1] = vert[1] * nvz + nz;
11080  tv[2] = vert[2] * nvz + nz;
11081 
11082  mesh3d->AddBdrTriangle(tv, attr);
11083  }
11084  break;
11085  case Geometry::SQUARE:
11086  {
11087  int qv[4];
11088  qv[0] = vert[0] * nvz;
11089  qv[1] = vert[3] * nvz;
11090  qv[2] = vert[2] * nvz;
11091  qv[3] = vert[1] * nvz;
11092 
11093  mesh3d->AddBdrQuad(qv, attr);
11094 
11095  qv[0] = vert[0] * nvz + nz;
11096  qv[1] = vert[1] * nvz + nz;
11097  qv[2] = vert[2] * nvz + nz;
11098  qv[3] = vert[3] * nvz + nz;
11099 
11100  mesh3d->AddBdrQuad(qv, attr);
11101  }
11102  break;
11103  default:
11104  mfem::err << "Extrude2D : Invalid 2D element type \'"
11105  << geom << "\'" << endl;
11106  mfem_error();
11107  break;
11108  }
11109  }
11110 
11111  if ( hexMesh && wdgMesh )
11112  {
11113  mesh3d->FinalizeMesh(0, false);
11114  }
11115  else if ( hexMesh )
11116  {
11117  mesh3d->FinalizeHexMesh(1, 0, false);
11118  }
11119  else if ( wdgMesh )
11120  {
11121  mesh3d->FinalizeWedgeMesh(1, 0, false);
11122  }
11123 
11124  GridFunction *nodes = mesh->GetNodes();
11125  if (nodes)
11126  {
11127  // duplicate the fec of the 2D mesh so that it can be deleted safely
11128  // along with its nodes, fes and fec
11129  FiniteElementCollection *fec3d = NULL;
11130  FiniteElementSpace *fes3d;
11131  const char *name = nodes->FESpace()->FEColl()->Name();
11132  string cname = name;
11133  if (cname == "Linear")
11134  {
11135  fec3d = new LinearFECollection;
11136  }
11137  else if (cname == "Quadratic")
11138  {
11139  fec3d = new QuadraticFECollection;
11140  }
11141  else if (cname == "Cubic")
11142  {
11143  fec3d = new CubicFECollection;
11144  }
11145  else if (!strncmp(name, "H1_", 3))
11146  {
11147  fec3d = new H1_FECollection(atoi(name + 7), 3);
11148  }
11149  else if (!strncmp(name, "L2_T", 4))
11150  {
11151  fec3d = new L2_FECollection(atoi(name + 10), 3, atoi(name + 4));
11152  }
11153  else if (!strncmp(name, "L2_", 3))
11154  {
11155  fec3d = new L2_FECollection(atoi(name + 7), 3);
11156  }
11157  else
11158  {
11159  delete mesh3d;
11160  mfem::err << "Extrude3D : The mesh uses unknown FE collection : "
11161  << cname << endl;
11162  mfem_error();
11163  }
11164  fes3d = new FiniteElementSpace(mesh3d, fec3d, 3);
11165  mesh3d->SetNodalFESpace(fes3d);
11166  GridFunction *nodes3d = mesh3d->GetNodes();
11167  nodes3d->MakeOwner(fec3d);
11168 
11169  NodeExtrudeCoefficient ecoeff(3, nz, sz);
11170  Vector lnodes;
11171  Array<int> vdofs3d;
11172  for (int i = 0; i < mesh->GetNE(); i++)
11173  {
11175  for (int j = nz-1; j >= 0; j--)
11176  {
11177  fes3d->GetElementVDofs(i*nz+j, vdofs3d);
11178  lnodes.SetSize(vdofs3d.Size());
11179  ecoeff.SetLayer(j);
11180  fes3d->GetFE(i*nz+j)->Project(ecoeff, T, lnodes);
11181  nodes3d->SetSubVector(vdofs3d, lnodes);
11182  }
11183  }
11184  }
11185  return mesh3d;
11186 }
11187 
11188 #ifdef MFEM_DEBUG
11189 void Mesh::DebugDump(std::ostream &out) const
11190 {
11191  // dump vertices and edges (NCMesh "nodes")
11192  out << NumOfVertices + NumOfEdges << "\n";
11193  for (int i = 0; i < NumOfVertices; i++)
11194  {
11195  const double *v = GetVertex(i);
11196  out << i << " " << v[0] << " " << v[1] << " " << v[2]
11197  << " 0 0 " << i << " -1 0\n";
11198  }
11199 
11200  Array<int> ev;
11201  for (int i = 0; i < NumOfEdges; i++)
11202  {
11203  GetEdgeVertices(i, ev);
11204  double mid[3] = {0, 0, 0};
11205  for (int j = 0; j < 2; j++)
11206  {
11207  for (int k = 0; k < spaceDim; k++)
11208  {
11209  mid[k] += GetVertex(ev[j])[k];
11210  }
11211  }
11212  out << NumOfVertices+i << " "
11213  << mid[0]/2 << " " << mid[1]/2 << " " << mid[2]/2 << " "
11214  << ev[0] << " " << ev[1] << " -1 " << i << " 0\n";
11215  }
11216 
11217  // dump elements
11218  out << NumOfElements << "\n";
11219  for (int i = 0; i < NumOfElements; i++)
11220  {
11221  const Element* e = elements[i];
11222  out << e->GetNVertices() << " ";
11223  for (int j = 0; j < e->GetNVertices(); j++)
11224  {
11225  out << e->GetVertices()[j] << " ";
11226  }
11227  out << e->GetAttribute() << " 0 " << i << "\n";
11228  }
11229 
11230  // dump faces
11231  out << "0\n";
11232 }
11233 #endif
11234 
11235 }
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:245
Abstract class for all finite elements.
Definition: fe.hpp:235
const IntegrationRule * IntRule
Definition: mesh.hpp:1442
int GetNFbyType(FaceType type) const
Returns the number of faces according to the requested type.
Definition: fespace.hpp:444
int Size() const
For backward compatibility define Size to be synonym of Width()
Definition: densemat.hpp:87
Geometry::Type GetGeometryType() const
Definition: element.hpp:52
Mesh * Make3D(int nsteps, double rstep, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:370
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:412
int Size() const
Return the logical size of the array.
Definition: array.hpp:124
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:521
void Get(double *p, const int dim) const
Definition: intrules.hpp:51
virtual void Print(std::ostream &out=mfem::out) const
Definition: mesh.hpp:1234
void METIS_PartGraphVKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
int GetDim() const
Returns the reference space dimension for the finite element.
Definition: fe.hpp:309
int GetNDofs() const
Returns number of degrees of freedom.
Definition: fespace.hpp:397
int * GetJ()
Definition: table.hpp:114
Arc::Index insert_arc(Node::Index i, Node::Index j, Float w=1, Float b=1)
Definition: gecko.cpp:678
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition: mesh.hpp:1053
void Init(int ind1, int ind2, int ind3, int ind4, int attr=1, int ref_flag=0)
Initialize the vertex indices and the attribute of a Tetrahedron.
Definition: tetrahedron.cpp:43
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:794
void NewDataAndSize(double *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition: vector.hpp:134
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
int DofToVDof(int dof, int vd, int ndofs=-1) const
Definition: fespace.cpp:144
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T...
Definition: array.hpp:242
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition: array.hpp:278
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition: fespace.cpp:2233
int AddQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1293
virtual Element * Duplicate(Mesh *m) const =0
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Definition: intrules.cpp:915
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:4805
Vector J
Jacobians of the element transformations at all quadrature points.
Definition: mesh.hpp:1472
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:78
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:10784
Base class for vector Coefficients that optionally depend on time and space.
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:85
void METIS_PartGraphRecursive(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Given a coefficient and a transformation, compute its projection (approximation) in the local finite ...
Definition: fe.cpp:130
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
Array< Slave > slaves
Definition: ncmesh.hpp:196
Array< Element * > boundary
Definition: mesh.hpp:91
void JacToPerfJac(int GeomType, const DenseMatrix &J, DenseMatrix &PJ) const
Definition: geom.cpp:734
int own_nodes
Definition: mesh.hpp:177
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition: mesh.cpp:4697
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:459
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:740
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:173
void MakeOwner(FiniteElementCollection *_fec)
Make the GridFunction the owner of fec and fes.
Definition: gridfunc.hpp:115
const Geometry::Type geom
Definition: ex1.cpp:40
double Det() const
Definition: densemat.cpp:451
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:294
int NumOfEdges
Definition: mesh.hpp:70
virtual int Transform(const Vector &pt, IntegrationPoint &ip)
Given a point, pt, in physical space, find its reference coordinates, ip.
Definition: eltrans.cpp:324
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:192
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:476
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:71
void ShiftRight(int &a, int &b, int &c)
Definition: mesh.hpp:1513
void SetDims(int rows, int nnz)
Definition: table.cpp:144
int Push(int a, int b)
Definition: table.hpp:241
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:85
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:831
A specialized ElementTransformation class representing a face and its two neighboring elements...
Definition: eltrans.hpp:467
unsigned matrix
index into NCList::point_matrices[geom]
Definition: ncmesh.hpp:182
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:495
unsigned int uint
Definition: gecko.hpp:204
void WriteBinaryOrASCII< float >(std::ostream &out, std::vector< char > &buf, const float &val, const char *suffix, VTKFormat format)
Definition: mesh.cpp:9113
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition: mesh.hpp:1478
void GetMeshComponents(Mesh &mesh) const
Fill Mesh::{vertices,elements,boundary} for the current finest level.
Definition: ncmesh.cpp:2042
int Push(int r, int c, int f)
Check to see if this entry is in the table and add it to the table if it is not there. Returns the number assigned to the table entry.
Definition: stable3d.cpp:64
Piecewise-(bi/tri)linear continuous finite elements.
Definition: fe_coll.hpp:428
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
GridFunction * Nodes
Definition: mesh.hpp:176
int Size() const
Returns the size of the vector.
Definition: vector.hpp:160
int NumOfElements
Definition: mesh.hpp:69
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:191
Mesh * Extrude1D(Mesh *mesh, const int ny, const double sy, const bool closed)
Extrude a 1D mesh.
Definition: mesh.cpp:10802
void Save(std::ostream &out, int fmt=0) const
Save the Array to the stream out using the format fmt. The format fmt can be:
Definition: array.cpp:40
int idxtype
Definition: mesh.cpp:42
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:511
void SetSize(int i, int j, int k)
Definition: densemat.hpp:771
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:737
void FinalizeWedgeMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a wedge Mesh.
Definition: mesh.cpp:2397
void order(Functional *functional, uint iterations=1, uint window=2, uint period=2, uint seed=0, Progress *progress=0)
Definition: gecko.cpp:1231
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
double kappa
Definition: ex24.cpp:54
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition: mesh.hpp:1394
Data type for vertex.
Definition: vertex.hpp:22
void GetElementLocalToGlobal(Array< int > &lelem_elem)
Definition: nurbs.cpp:2903
void SetOutputLayout(QVectorLayout out_layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
virtual void Transform(const IntegrationPoint &, Vector &)
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Definition: eltrans.cpp:479
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Data type quadrilateral element.
The inverse transformation of a given ElementTransformation.
Definition: eltrans.hpp:172
double * GetData() const
Returns the matrix data array.
Definition: densemat.hpp:100
const IntegrationPoint & GetCenter(int GeomType)
Return the center of the given Geometry::Type, GeomType.
Definition: geom.hpp:70
void GetVertexLocalToGlobal(Array< int > &lvert_vert)
Definition: nurbs.cpp:2893
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:169
virtual int OrderJ() const =0
Return the order of the elements of the Jacobian of the transformation.
void DebugDump(std::ostream &out) const
Output an NCMesh-compatible debug dump.
Definition: mesh.cpp:11189
Mesh * Extrude2D(Mesh *mesh, const int nz, const double sz)
Extrude a 2D mesh.
Definition: mesh.cpp:10962
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:834
void Print(const Mesh &mesh, const adios2stream::mode print_mode=mode::sync)
int Size_of_connections() const
Definition: table.hpp:98
Data type Wedge element.
Definition: wedge.hpp:22
Array< Element * > faces
Definition: mesh.hpp:92
const IntegrationRule * GetVertices(int GeomType)
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType...
Definition: geom.cpp:225
void FinalizeHexMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a hexahedral Mesh.
Definition: mesh.cpp:2432
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:28
void DeleteAll()
Delete the whole array.
Definition: array.hpp:821
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:108
int master
master number (in Mesh numbering)
Definition: ncmesh.hpp:181
Array< NCFaceInfo > nc_faces_info
Definition: mesh.hpp:154
Table * el_to_face
Definition: mesh.hpp:157
void SetTransformation(ElementTransformation &Trans)
Set a new forward ElementTransformation, Trans.
Definition: eltrans.hpp:279
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2032
Structure for storing face geometric factors: coordinates, Jacobians, determinants of the Jacobians...
Definition: mesh.hpp:1438
int AddBdrTriangle(int v1, int v2, int v3, int attr=1)
Definition: mesh.cpp:1423
Mesh * Make2D(int nsteps, double rstep, double phi, double aspect, int order, bool sfc)
Definition: polar-nc.cpp:49
const Operator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition: fespace.cpp:894
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:4184
void DisableTensorProducts(bool disable=true) const
Disable the use of tensor product evaluations, for tensor-product elements, e.g. quads and hexes...
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe.hpp:312
Piecewise-(bi)cubic continuous finite elements.
Definition: fe_coll.hpp:506
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:427
uint rank(Node::Index i) const
Definition: gecko.hpp:672
double Weight() const
Definition: densemat.cpp:508
PointFiniteElement PointFE
Definition: point.cpp:30
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: segment.cpp:40
const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:376
Data type hexahedron element.
Definition: hexahedron.hpp:22
void WriteBase64WithSizeAndClear(std::ostream &out, std::vector< char > &buf, int compression_level)
Definition: mesh.cpp:9122
Geometry Geometries
Definition: fe.cpp:12850
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:248
long GetSequence() const
Definition: mesh.hpp:1227
void GetVertexDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:1995
int AddVertex(double x, double y=0.0, double z=0.0)
Definition: mesh.cpp:1232
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition: eltrans.hpp:388
const int * GetDofMap(Geometry::Type GeomType) const
Get the Cartesian to local H1 dof map.
Definition: fe_coll.cpp:1853
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:203
uint Index
Definition: gecko.hpp:595
FaceType
Definition: mesh.hpp:45
Symmetric 3D Table stored as an array of rows each of which has a stack of column, floor, number nodes. The number of the node is assigned by counting the nodes from zero as they are pushed into the table. Diagonals of any kind are not allowed so the row, column and floor must all be different for each node. Only one node is stored for all 6 symmetric entries that are indexable by unique triplets of row, column, and floor.
Definition: stable3d.hpp:34
void DetOfLinComb(const DenseMatrix &A, const DenseMatrix &B, Vector &c)
Definition: mesh.cpp:6185
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:65
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:726
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: triangle.hpp:61
IntegrationPointTransformation Loc1
Definition: eltrans.hpp:511
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:153
A class that performs interpolation from an E-vector to quadrature point values and/or derivatives (Q...
double b
Definition: lissajous.cpp:42
void CreateRefinementFlag(int refinement_edges[2], int type, int flag=0)
Definition: tetrahedron.cpp:71
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.
Float cost() const
Definition: gecko.cpp:856
const DenseMatrix & Jacobian()
Return the Jacobian matrix of the transformation at the currently set IntegrationPoint, using the method SetIntPoint().
Definition: eltrans.hpp:111
Type
Ordering methods:
Definition: fespace.hpp:32
Timing object.
Definition: tic_toc.hpp:34
void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *)
void AddConnection(int r, int c)
Definition: table.hpp:80
void Reset()
Force the reevaluation of the Jacobian in the next call.
Definition: eltrans.hpp:81
A pair of objects.
Definition: sort_pairs.hpp:23
void WriteBinaryOrASCII< uint8_t >(std::ostream &out, std::vector< char > &buf, const uint8_t &val, const char *suffix, VTKFormat format)
Definition: mesh.cpp:9085
Type
Constants for the classes derived from Element.
Definition: element.hpp:41
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:68
virtual void GetElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:1696
NURBSExtension * StealNURBSext()
Definition: fespace.cpp:1548
Array< DenseMatrix * > point_matrices[Geometry::NumGeom]
List of unique point matrices for each slave geometry.
Definition: ncmesh.hpp:199
VTKFormat
Definition: vtk.hpp:22
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition: fe.hpp:382
int mesh_geoms
Definition: mesh.hpp:78
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:142
int AddBdrSegment(int v1, int v2, int attr=1)
Definition: mesh.cpp:1409
void Transpose(const Table &A, Table &At, int _ncols_A)
Transpose a Table.
Definition: table.cpp:414
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:1520
void SetLayer(const int l)
Definition: mesh.hpp:1497
int GetAttribute() const
Return element&#39;s attribute.
Definition: element.hpp:55
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition: array.hpp:275
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition: fespace.hpp:710
double Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition: eltrans.hpp:123
int nbBoundaryFaces
Definition: mesh.hpp:75
Data type triangle element.
Definition: triangle.hpp:23
void WriteBinaryOrASCII(std::ostream &out, std::vector< char > &buf, const T &val, const char *suffix, VTKFormat format)
Definition: mesh.cpp:9076
const Element * GetElement(int i) const
Definition: mesh.hpp:819
virtual void SetVertices(const int *ind)
Set the vertices according to the given input.
Definition: triangle.cpp:45
IntegrationRule RefPts
Definition: geom.hpp:243
signed char local
local number within &#39;element&#39;
Definition: ncmesh.hpp:157
double Float
Definition: gecko.hpp:208
void Sort()
Sorts the array in ascending order. This requires operator&lt; to be defined for T.
Definition: array.hpp:234
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
Definition: geom.cpp:942
int GetVDim()
Returns dimension of the vector.
void SetNodalFESpace(FiniteElementSpace *nfes)
Definition: mesh.cpp:4126
virtual void ResetTransform(int tr)
Set current coarse-fine transformation number.
Definition: tetrahedron.hpp:81
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:389
Vector normal
Normals at all quadrature points.
Definition: mesh.hpp:1485
A class for non-conforming AMR on higher-order hexahedral, prismatic, quadrilateral or triangular mes...
Definition: ncmesh.hpp:102
void SetData(double *d)
Definition: vector.hpp:121
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:595
int Dimension() const
Definition: mesh.hpp:788
prob_type prob
Definition: ex25.cpp:149
int NumOfBdrElements
Definition: mesh.hpp:69
Table * el_to_edge
Definition: mesh.hpp:156
void GetColumn(int c, Vector &col) const
Definition: densemat.cpp:1289
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
Definition: triangle.cpp:188
A class that performs interpolation from a face E-vector to quadrature point values and/or derivative...
double DistanceTo(const double *p) const
Compute the Euclidean distance to another vector.
Definition: vector.hpp:594
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: triangle.hpp:62
class H1_WedgeElement WedgeFE
void FindPartitioningComponents(Table &elem_elem, const Array< int > &partitioning, Array< int > &component, Array< int > &num_comp)
Definition: mesh.cpp:6057
Data type tetrahedron element.
Definition: tetrahedron.hpp:22
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2007
List of mesh geometries stored as Array&lt;Geometry::Type&gt;.
Definition: mesh.hpp:861
A general vector function coefficient.
int SpaceDimension() const
Definition: mesh.hpp:789
virtual const Operator * GetFaceRestriction(ElementDofOrdering e_ordering, FaceType, L2FaceValues mul=L2FaceValues::DoubleValued) const
Return an Operator that converts L-vectors to E-vectors on each face.
Definition: fespace.cpp:922
virtual unsigned GetTransform() const
Return current coarse-fine transformation.
Definition: tetrahedron.hpp:82
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
Definition: mesh.cpp:1031
double * Data() const
Returns the matrix data array.
Definition: densemat.hpp:96
virtual const int * DofOrderForOrientation(Geometry::Type GeomType, int Or) const =0
Returns an array, say p, that maps a local permuted index i to a local base index: base_i = p[i]...
void Swap(Array< T > &, Array< T > &)
Definition: array.hpp:611
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:201
virtual void PushTransform(int tr)
Add &#39;tr&#39; to the current chain of coarse-fine transformations.
Definition: tetrahedron.hpp:85
void FinalizeMesh(int refine=0, bool fix_orientation=true)
Finalize the construction of any type of Mesh.
Definition: mesh.cpp:2462
const NURBSExtension * GetNURBSext() const
Definition: fespace.hpp:316
Table * el_to_el
Definition: mesh.hpp:158
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
Definition: mesh.cpp:1037
int SpaceDimension() const
Definition: ncmesh.hpp:115
Nonconforming edge/face within a bigger edge/face.
Definition: ncmesh.hpp:179
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:87
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe.hpp:315
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
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int attr=1)
Definition: mesh.cpp:1342
const IntegrationRule * IntRule
Definition: mesh.hpp:1398
Vector X
Mapped (physical) coordinates of all quadrature points.
Definition: mesh.hpp:1463
void AddAColumnInRow(int r)
Definition: table.hpp:77
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:654
int AddBdrQuad(int v1, int v2, int v3, int v4, int attr=1)
Definition: mesh.cpp:1437
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
Definition: array.cpp:103
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition: eltrans.cpp:533
int FindRoots(const Vector &z, Vector &x)
Definition: mesh.cpp:6265
Array< Vertex > vertices
Definition: mesh.hpp:90
int Push4(int r, int c, int f, int t)
Check to see if this entry is in the table and add it to the table if it is not there. The entry is addressed by the three smallest values of (r,c,f,t). Returns the number assigned to the table entry.
Definition: stable3d.cpp:135
Helper struct for defining a connectivity table, see Table::MakeFromList.
Definition: table.hpp:27
class Linear3DFiniteElement TetrahedronFE
Definition: fe.cpp:12837
A class to initialize the size of a Tensor.
Definition: dtensor.hpp:54
Array< Element * > elements
Definition: mesh.hpp:85
void ShiftUpI()
Definition: table.cpp:119
Linear2DFiniteElement TriangleFE
Definition: fe.cpp:12833
int meshgen
Definition: mesh.hpp:77
Table * bel_to_edge
Definition: mesh.hpp:160
Evaluate the values at quadrature points.
virtual void GetVertices(Array< int > &v) const
Returns the indices of the element&#39;s vertices.
virtual void GetBdrElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom for i&#39;th boundary element.
Definition: fespace.cpp:1815
double a
Definition: lissajous.cpp:41
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:203
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:734
int nbInteriorFaces
Definition: mesh.hpp:75
Array< int > be_to_edge
Definition: mesh.hpp:159
virtual const char * Name() const
Definition: fe_coll.hpp:61
Class for integration point with weight.
Definition: intrules.hpp:25
A standard isoparametric element transformation.
Definition: eltrans.hpp:348
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: mesh.cpp:336
void WriteBinaryOrASCII< double >(std::ostream &out, std::vector< char > &buf, const double &val, const char *suffix, VTKFormat format)
Definition: mesh.cpp:9094
const FiniteElementSpace * GetNodalFESpace() const
Definition: mesh.cpp:4160
Table * face_edge
Definition: mesh.hpp:162
void FinalizeQuadMesh(int generate_edges=0, int refine=0, bool fix_orientation=true)
Finalize the construction of a quadrilateral Mesh.
Definition: mesh.cpp:1547
Array< Master > masters
Definition: ncmesh.hpp:195
NodeExtrudeCoefficient(const int dim, const int _n, const double _s)
Definition: mesh.cpp:10778
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2020
void Mult(const Vector &e_vec, unsigned eval_flags, Vector &q_val, Vector &q_der, Vector &q_det) const
Interpolate the E-vector e_vec to quadrature points.
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition: fespace.cpp:950
const char * VTKByteOrder()
Definition: vtk.cpp:461
void MakeJ()
Definition: table.cpp:95
int dim
Definition: ex24.cpp:53
Table * edge_vertex
Definition: mesh.hpp:163
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition: eltrans.hpp:368
signed char geom
Geometry::Type (faces only) (char to save RAM)
Definition: ncmesh.hpp:158
void FindTMax(Vector &c, Vector &x, double &tmax, const double factor, const int Dim)
Definition: mesh.cpp:6412
IsoparametricTransformation Transf
Definition: eltrans.hpp:451
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th element in t...
Definition: fespace.cpp:1798
int index(int i, int j, int nx, int ny)
Definition: life.cpp:241
ElementTransformation * Elem1
Definition: eltrans.hpp:509
void WriteVTKEncodedCompressed(std::ostream &out, const void *bytes, uint32_t nbytes, int compression_level)
Definition: vtk.cpp:418
double CalcSingularvalue(const int i) const
Return the i-th singular value (decreasing order) of NxN matrix, N=1,2,3.
Definition: densemat.cpp:1226
Lexicographic ordering for tensor-product FiniteElements.
Array< FaceInfo > faces_info
Definition: mesh.hpp:153
double infinity()
Define a shortcut for std::numeric_limits&lt;double&gt;::infinity()
Definition: vector.hpp:45
virtual int GetNVertices() const =0
int parent
Element index in the coarse mesh.
Definition: ncmesh.hpp:49
void SetAttribute(const int attr)
Set element&#39;s attribute.
Definition: element.hpp:58
virtual void ProjectCoefficient(Coefficient &coeff)
Definition: gridfunc.cpp:2252
Piecewise-(bi)quadratic continuous finite elements.
Definition: fe_coll.hpp:455
int Dimension() const
Definition: ncmesh.hpp:114
void AppendBytes(std::vector< char > &vec, const T &val)
Definition: binaryio.hpp:45
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
Definition: sparsemat.hpp:630
NCMesh * ncmesh
Optional non-conforming mesh extension.
Definition: mesh.hpp:204
Geometry::Type GetBdrElementBaseGeometry(int i) const
Definition: mesh.hpp:839
int AddWedge(int v1, int v2, int v3, int v4, int v5, int v6, int attr=1)
Definition: mesh.cpp:1328
int Dim
Definition: mesh.hpp:66
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:42
BiLinear2DFiniteElement QuadrilateralFE
Evaluate the derivatives at quadrature points.
Vector data type.
Definition: vector.hpp:51
Data type point element.
Definition: point.hpp:22
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:414
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:6603
int NumberOfEntries() const
Definition: table.hpp:240
virtual void PushTransform(int tr)
Add &#39;tr&#39; to the current chain of coarse-fine transformations.
Definition: triangle.hpp:65
void CreateVTKElementConnectivity(Array< int > &con, Geometry::Type geom, int ref)
Definition: vtk.cpp:357
int * GetI()
Definition: table.hpp:113
int GetId(int p1, int p2)
Get id of item whose parents are p1, p2... Create it if it doesn&#39;t exist.
Definition: hash.hpp:280
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:159
void XYZ_VectorFunction(const Vector &p, Vector &v)
Definition: mesh.cpp:4089
int spaceDim
Definition: mesh.hpp:67
Defines the coarse-fine transformations of all fine elements.
Definition: ncmesh.hpp:60
const std::string filename
Definition: zstr.hpp:805
MemAlloc< Tetrahedron, 1024 > TetMemory
Definition: mesh.hpp:185
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag)
Definition: tetrahedron.cpp:55
Node::Index insert_node(Float length=1)
Definition: gecko.cpp:656
TriLinear3DFiniteElement HexahedronFE
Definition: hexahedron.cpp:52
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
int RowSize(int i) const
Definition: table.hpp:108
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition: densemat.hpp:90
int NumOfVertices
Definition: mesh.hpp:69
Array< int > be_to_face
Definition: mesh.hpp:161
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
int NumberOfRows() const
Definition: table.hpp:239
Abstract operator.
Definition: operator.hpp:24
int FindId(int p1, int p2) const
Find id of item whose parents are p1, p2... Return -1 if it doesn&#39;t exist.
Definition: hash.hpp:371
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition: eltrans.hpp:391
virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const =0
Evaluate the gradients of all shape functions of a scalar finite element in reference space at the gi...
int index
Mesh number.
Definition: ncmesh.hpp:155
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:728
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:378
Abstract data type element.
Definition: element.hpp:28
int GetAttribute(int i) const
Return the attribute of element i.
Definition: mesh.hpp:1047
Data type line segment element.
Definition: segment.hpp:22
Linear1DFiniteElement SegmentFE
Definition: segment.cpp:49
Array< GeometricFactors * > geom_factors
Optional geometric factors.
Definition: mesh.hpp:205
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition: fespace.hpp:421
MPI_Comm GetGlobalMPI_Comm()
Get MFEM&#39;s &quot;global&quot; MPI communicator.
Definition: globals.cpp:62
int NumberOfElements()
Return the number of elements added to the table.
Definition: stable3d.hpp:70
Array< int > RefGeoms
Definition: geom.hpp:244
virtual Type GetType() const =0
Returns element&#39;s type.
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition: mesh.hpp:199
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:823
Defines the position of a fine element within a coarse element.
Definition: ncmesh.hpp:46
int idx_t
Definition: mesh.cpp:41
int matrix
Index into the DenseTensor corresponding to the parent Geometry::Type stored in CoarseFineTransformat...
Definition: ncmesh.hpp:52
Arbitrary order &quot;L2-conforming&quot; discontinuous finite elements.
Definition: fe_coll.hpp:221
double f(const Vector &p)
Class used to extrude the nodes of a mesh.
Definition: mesh.hpp:1489
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:108
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:979
int NumOfFaces
Definition: mesh.hpp:70