MFEM  v4.6.0
Finite element discretization library
submesh_utils.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include "submesh_utils.hpp"
13 
14 namespace mfem
15 {
16 namespace SubMeshUtils
17 {
18 int UniqueIndexGenerator::Get(int i, bool &new_index)
19 {
20  auto f = idx.find(i);
21  if (f == idx.end())
22  {
23  idx[i] = counter;
24  new_index = true;
25  return counter++;
26  }
27  else
28  {
29  new_index = false;
30  return (*f).second;
31  }
32 }
33 
34 bool ElementHasAttribute(const Element &el, const Array<int> &attributes)
35 {
36  for (int a = 0; a < attributes.Size(); a++)
37  {
38  if (el.GetAttribute() == attributes[a])
39  {
40  return true;
41  }
42  }
43  return false;
44 }
45 
46 std::tuple< Array<int>, Array<int> >
47 AddElementsToMesh(const Mesh& parent,
48  Mesh& mesh,
49  const Array<int> &attributes,
50  bool from_boundary)
51 {
52  Array<int> parent_vertex_ids, parent_element_ids;
53  UniqueIndexGenerator vertex_ids;
54  const int ne = from_boundary ? parent.GetNBE() : parent.GetNE();
55  for (int i = 0; i < ne; i++)
56  {
57  const Element *pel = from_boundary ?
58  parent.GetBdrElement(i) : parent.GetElement(i);
59  if (!ElementHasAttribute(*pel, attributes)) { continue; }
60 
61  Array<int> v;
62  pel->GetVertices(v);
63  Array<int> submesh_v(v.Size());
64 
65  for (int iv = 0; iv < v.Size(); iv++)
66  {
67  bool new_vertex;
68  int mesh_vertex_id = v[iv];
69  int submesh_vertex_id = vertex_ids.Get(mesh_vertex_id, new_vertex);
70  if (new_vertex)
71  {
72  mesh.AddVertex(parent.GetVertex(mesh_vertex_id));
73  parent_vertex_ids.Append(mesh_vertex_id);
74  }
75  submesh_v[iv] = submesh_vertex_id;
76  }
77 
78  Element *el = mesh.NewElement(from_boundary ?
79  parent.GetBdrElementType(i) : parent.GetElementType(i));
80  el->SetVertices(submesh_v);
81  el->SetAttribute(pel->GetAttribute());
82  mesh.AddElement(el);
83  parent_element_ids.Append(i);
84  }
85  return std::tuple<Array<int>, Array<int>>(parent_vertex_ids,
86  parent_element_ids);
87 }
88 
90  const FiniteElementSpace& parentfes,
91  const SubMesh::From& from,
92  const Array<int>& parent_element_ids,
93  Array<int>& vdof_to_vdof_map)
94 {
95  auto *m = subfes.GetMesh();
96  vdof_to_vdof_map.SetSize(subfes.GetVSize());
97 
98  const int vdim = parentfes.GetVDim();
99 
101  DenseMatrix T;
102  Array<int> z1;
103  for (int i = 0; i < m->GetNE(); i++)
104  {
105  Array<int> parent_vdofs;
106  if (from == SubMesh::From::Domain)
107  {
108  parentfes.GetElementVDofs(parent_element_ids[i], parent_vdofs);
109  }
110  else if (from == SubMesh::From::Boundary)
111  {
112  if (parentfes.IsDGSpace())
113  {
114  MFEM_ASSERT(static_cast<const L2_FECollection*>
115  (parentfes.FEColl())->GetBasisType() == BasisType::GaussLobatto,
116  "Only BasisType::GaussLobatto is supported for L2 spaces");
117 
118  auto pm = parentfes.GetMesh();
119 
120  int face_info, parent_volel_id;
121  pm->GetBdrElementAdjacentElement2(parent_element_ids[i],
122  parent_volel_id,
123  face_info);
124  pm->GetLocalFaceTransformation(
125  pm->GetBdrElementType(parent_element_ids[i]),
126  pm->GetElementType(parent_volel_id),
127  Tr.Transf,
128  face_info);
129 
130  Geometry::Type face_geom =
131  pm->GetBdrElementBaseGeometry(parent_element_ids[i]);
132  const FiniteElement *face_el =
133  parentfes.GetTraceElement(parent_element_ids[i], face_geom);
134  MFEM_VERIFY(dynamic_cast<const NodalFiniteElement*>(face_el),
135  "Nodal Finite Element is required");
136 
137  face_el->GetTransferMatrix(*parentfes.GetFE(parent_volel_id),
138  Tr.Transf,
139  T);
140 
141  parentfes.GetElementVDofs(parent_volel_id, z1);
142 
143  parent_vdofs.SetSize(vdim * T.Height());
144  for (int j = 0; j < T.Height(); j++)
145  {
146  for (int k = 0; k < T.Width(); k++)
147  {
148  if (T(j, k) != 0.0)
149  {
150  for (int vd=0; vd<vdim; vd++)
151  {
152  int sub_vdof = j + T.Height() * vd;
153  int parent_vdof = k + T.Width() * vd;
154  parent_vdofs[sub_vdof] =
155  z1[static_cast<int>(parent_vdof)];
156  }
157  }
158  }
159  }
160  }
161  else
162  {
163  parentfes.GetBdrElementVDofs(parent_element_ids[i], parent_vdofs);
164  }
165  }
166  else
167  {
168  MFEM_ABORT("SubMesh::From type unknown");
169  }
170 
171  Array<int> sub_vdofs;
172  subfes.GetElementVDofs(i, sub_vdofs);
173 
174  MFEM_ASSERT(parent_vdofs.Size() == sub_vdofs.Size(), "internal error");
175  for (int j = 0; j < parent_vdofs.Size(); j++)
176  {
177  double sub_sign = 1.0;
178  int sub_vdof = subfes.DecodeDof(sub_vdofs[j], sub_sign);
179 
180  double parent_sign = 1.0;
181  int parent_vdof = parentfes.DecodeDof(parent_vdofs[j], parent_sign);
182 
183  vdof_to_vdof_map[sub_vdof] =
184  (sub_sign * parent_sign > 0.0) ? parent_vdof : (-1-parent_vdof);
185  }
186  }
187 }
188 
189 Array<int> BuildFaceMap(const Mesh& pm, const Mesh& sm,
190  const Array<int> &parent_element_ids)
191 {
192  // TODO: Check if parent is really a parent of mesh
193 
194  Array<int> pfids(sm.GetNumFaces());
195  pfids = -1;
196  for (int i = 0; i < sm.GetNE(); i++)
197  {
198  int peid = parent_element_ids[i];
199 
200  Array<int> sel_faces, pel_faces, o;
201  if (pm.Dimension() == 2)
202  {
203  sm.GetElementEdges(i, sel_faces, o);
204  pm.GetElementEdges(peid, pel_faces, o);
205  }
206  else
207  {
208  sm.GetElementFaces(i, sel_faces, o);
209  pm.GetElementFaces(peid, pel_faces, o);
210  }
211 
212  MFEM_ASSERT(sel_faces.Size() == pel_faces.Size(), "internal error");
213 
214  for (int j = 0; j < sel_faces.Size(); j++)
215  {
216  if (pfids[sel_faces[j]] != -1)
217  {
218  MFEM_ASSERT(pfids[sel_faces[j]] == pel_faces[j], "internal error");
219  }
220  pfids[sel_faces[j]] = pel_faces[j];
221  }
222  }
223  return pfids;
224 }
225 
226 } // namespace SubMeshUtils
227 } // namespace mfem
std::unordered_map< int, int > idx
Abstract class for all finite elements.
Definition: fe_base.hpp:233
Convenience object to create unique indices.
void BuildVdofToVdofMap(const FiniteElementSpace &subfes, const FiniteElementSpace &parentfes, const SubMesh::From &from, const Array< int > &parent_element_ids, Array< int > &vdof_to_vdof_map)
Build the vdof to vdof mapping between two FiniteElementSpace objects.
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Definition: mesh.cpp:6298
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
int Dimension() const
Dimension of the reference space used within the elements.
Definition: mesh.hpp:1020
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:5668
static int DecodeDof(int dof)
Helper to return the DOF associated with a sign encoded DOF.
Definition: fespace.hpp:996
Element::Type GetBdrElementType(int i) const
Returns the type of boundary element i.
Definition: mesh.cpp:6649
int GetAttribute() const
Return element&#39;s attribute.
Definition: element.hpp:55
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
const FiniteElement * GetTraceElement(int i, Geometry::Type geom_type) const
Return the trace element from element &#39;i&#39; to the given &#39;geom_type&#39;.
Definition: fespace.cpp:3239
virtual void SetVertices(const int *ind)
Set the indices the element according to the input.
Definition: element.cpp:17
const Element * GetElement(int i) const
Return pointer to the i&#39;th element object.
Definition: mesh.hpp:1143
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:1089
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th element in t...
Definition: fespace.cpp:2841
Element * NewElement(int geom)
Definition: mesh.cpp:3901
std::function< double(const Vector &)> f(double mass_coeff)
Definition: lor_mms.hpp:30
int Get(int i, bool &new_index)
Returns the unique index from an index set.
void GetBdrElementAdjacentElement2(int bdr_el, int &el, int &info) const
For the given boundary element, bdr_el, return its adjacent element and its info, i...
Definition: mesh.cpp:6622
int AddVertex(double x, double y=0.0, double z=0.0)
Definition: mesh.cpp:1626
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
Definition: mesh.cpp:6514
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:759
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:723
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:1125
int AddElement(Element *elem)
Definition: mesh.cpp:1829
virtual void GetTransferMatrix(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const
Return interpolation matrix, I, which maps dofs from a coarse element, fe, to the fine dofs on this f...
Definition: fe_base.cpp:119
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:702
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i&#39;th element. The returned indices are offsets into an ...
Definition: fespace.cpp:281
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:555
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:219
std::tuple< Array< int >, Array< int > > AddElementsToMesh(const Mesh &parent, Mesh &mesh, const Array< int > &attributes, bool from_boundary)
Given a Mesh parent and another Mesh mesh using the list of attributes in attributes, this function adds matching elements with those attributes from parent to mesh.
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:687
Array< int > BuildFaceMap(const Mesh &pm, const Mesh &sm, const Array< int > &parent_element_ids)
Given two meshes that have a parent to SubMesh relationship create a face map, using a SubMesh to par...
From
Indicator from which part of the parent Mesh the SubMesh is created.
Definition: submesh.hpp:46
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:1086
double a
Definition: lissajous.cpp:41
Element::Type GetElementType(int i) const
Returns the type of element i.
Definition: mesh.cpp:6644
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for i&#39;th boundary element. The returned indices are offsets int...
Definition: fespace.cpp:297
bool ElementHasAttribute(const Element &el, const Array< int > &attributes)
Given an element el and a list of attributes, determine if that element is in at least one attribute ...
IsoparametricTransformation Transf
Definition: eltrans.hpp:464
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition: fespace.hpp:709
void SetAttribute(const int attr)
Set element&#39;s attribute.
Definition: element.hpp:58
int Size() const
Return the logical size of the array.
Definition: array.hpp:141
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition: fespace.hpp:1274
const Element * GetBdrElement(int i) const
Return pointer to the i&#39;th boundary element object.
Definition: mesh.hpp:1158
Abstract data type element.
Definition: element.hpp:28