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