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