MFEM  v4.6.0
Finite element discretization library
transfermap.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.hpp"
13 #include "transfermap.hpp"
14 #include "submesh_utils.hpp"
15 
16 using namespace mfem;
17 
19  const GridFunction &dst)
20 {
21  const FiniteElementSpace *parentfes = nullptr, *subfes1 = nullptr,
22  *subfes2 = nullptr;
23 
24  if (SubMesh::IsSubMesh(src.FESpace()->GetMesh()) &&
26  {
27  SubMesh* src_sm = static_cast<SubMesh*>(src.FESpace()->GetMesh());
28  SubMesh* dst_sm = static_cast<SubMesh*>(dst.FESpace()->GetMesh());
29 
30  // There is no immediate relation and both src and dst come from a
31  // SubMesh, check if they have an equivalent root parent.
32  if (SubMeshUtils::GetRootParent(*src_sm) !=
34  {
35  MFEM_ABORT("Can't find a relation between the two GridFunctions");
36  }
37 
39 
40  {
41  Mesh * parent_mesh =
42  const_cast<Mesh *>(SubMeshUtils::GetRootParent(*src_sm));
43 
44  int parent_dim = parent_mesh->Dimension();
45  int src_sm_dim = src_sm->Dimension();
46  int dst_sm_dim = dst_sm->Dimension();
47 
48  bool root_fes_reset = false;
49  if (src_sm_dim == parent_dim - 1 && dst_sm_dim == parent_dim - 1)
50  {
51  const FiniteElementSpace *src_fes = src.FESpace();
52  const FiniteElementSpace *dst_fes = dst.FESpace();
53 
54  const FiniteElementCollection *src_fec = src_fes->FEColl();
55  const FiniteElementCollection *dst_fec = dst_fes->FEColl();
56 
57  const L2_FECollection *src_l2_fec =
58  dynamic_cast<const L2_FECollection*>(src_fec);
59  const L2_FECollection *dst_l2_fec =
60  dynamic_cast<const L2_FECollection*>(dst_fec);
61 
62  if (src_l2_fec != NULL && dst_l2_fec != NULL)
63  {
64  // Source and destination are both lower dimension L2 spaces.
65  // Transfer them as the trace of an RT space if possible.
66 
67  int src_mt = src_fec->GetMapType(src_sm_dim);
68  int dst_mt = dst_fec->GetMapType(dst_sm_dim);
69 
70  int src_bt = src_l2_fec->GetBasisType();
71  int dst_bt = dst_l2_fec->GetBasisType();
72 
73  int src_p = src_fec->GetOrder();
74  int dst_p = dst_fec->GetOrder();
75 
76  if (src_mt == FiniteElement::INTEGRAL &&
77  dst_mt == FiniteElement::INTEGRAL &&
78  src_bt == BasisType::GaussLegendre &&
79  dst_bt == BasisType::GaussLegendre &&
80  src_p == dst_p)
81  {
82  // The subspaces are consistent with the trace of an RT space
83  root_fec_.reset(new RT_FECollection(src_p, parent_dim));
84  root_fes_.reset(new FiniteElementSpace(
85  const_cast<Mesh *>(
87  root_fec_.get()));
88  root_fes_reset = true;
89  }
90  }
91  }
92 
93  if (!root_fes_reset)
94  {
95  root_fes_.reset(new FiniteElementSpace(
96  *src.FESpace(),
97  const_cast<Mesh *>(
98  SubMeshUtils::GetRootParent(*src_sm))));
99  }
100  }
101 
102  subfes1 = src.FESpace();
103  subfes2 = dst.FESpace();
104 
106  *root_fes_,
107  src_sm->GetFrom(),
108  src_sm->GetParentElementIDMap(),
109  sub1_to_parent_map_);
110 
112  *root_fes_,
113  dst_sm->GetFrom(),
114  dst_sm->GetParentElementIDMap(),
115  sub2_to_parent_map_);
116 
117  z_.SetSize(root_fes_->GetVSize());
118  }
119  else if (SubMesh::IsSubMesh(src.FESpace()->GetMesh()))
120  {
122  SubMesh* src_sm = static_cast<SubMesh*>(src.FESpace()->GetMesh());
123  subfes1 = src.FESpace();
124  parentfes = dst.FESpace();
126  *parentfes,
127  src_sm->GetFrom(),
128  src_sm->GetParentElementIDMap(),
129  sub1_to_parent_map_);
130  }
131  else if (SubMesh::IsSubMesh(dst.FESpace()->GetMesh()))
132  {
134  SubMesh* dst_sm = static_cast<SubMesh*>(dst.FESpace()->GetMesh());
135  subfes1 = dst.FESpace();
136  parentfes = src.FESpace();
138  *parentfes,
139  dst_sm->GetFrom(),
140  dst_sm->GetParentElementIDMap(),
141  sub1_to_parent_map_);
142  }
143  else
144  {
145  MFEM_ABORT("Trying to do a transfer between GridFunctions but none of them is defined on a SubMesh");
146  }
147 }
148 
150  GridFunction &dst) const
151 {
152  if (category_ == TransferCategory::ParentToSubMesh)
153  {
154  // dst = S1^T src
155  src.HostRead();
156  dst.HostWrite(); // dst is fully overwritten
157  for (int i = 0; i < sub1_to_parent_map_.Size(); i++)
158  {
159  double s = 1.0;
160  int j = FiniteElementSpace::DecodeDof(sub1_to_parent_map_[i], s);
161  dst(i) = s * src(j);
162  }
163 
164  CorrectFaceOrientations(*dst.FESpace(), src, dst);
165  }
166  else if (category_ == TransferCategory::SubMeshToParent)
167  {
168  // dst = G S1 src
169  // = G z
170  //
171  // G is identity if the partitioning matches
172 
173  src.HostRead();
174  dst.HostReadWrite(); // dst is only partially overwritten
175  for (int i = 0; i < sub1_to_parent_map_.Size(); i++)
176  {
177  double s = 1.0;
178  int j = FiniteElementSpace::DecodeDof(sub1_to_parent_map_[i], s);
179  dst(j) = s * src(i);
180  }
181 
182  CorrectFaceOrientations(*src.FESpace(), src, dst,
183  &sub1_to_parent_map_);
184  }
185  else if (category_ == TransferCategory::SubMeshToSubMesh)
186  {
187  // dst = S2^T G (S1 src (*) S2 dst)
188  //
189  // G is identity if the partitioning matches
190 
191  src.HostRead();
192  dst.HostReadWrite();
193 
194  z_ = 0.0;
195 
196  for (int i = 0; i < sub2_to_parent_map_.Size(); i++)
197  {
198  double s = 1.0;
199  int j = FiniteElementSpace::DecodeDof(sub2_to_parent_map_[i], s);
200  z_(j) = s * dst(i);
201  }
202 
203  CorrectFaceOrientations(*dst.FESpace(), dst, z_,
204  &sub2_to_parent_map_);
205 
206  for (int i = 0; i < sub1_to_parent_map_.Size(); i++)
207  {
208  double s = 1.0;
209  int j = FiniteElementSpace::DecodeDof(sub1_to_parent_map_[i], s);
210  z_(j) = s * src(i);
211  }
212 
213  CorrectFaceOrientations(*src.FESpace(), src, z_,
214  &sub1_to_parent_map_);
215 
216  for (int i = 0; i < sub2_to_parent_map_.Size(); i++)
217  {
218  double s = 1.0;
219  int j = FiniteElementSpace::DecodeDof(sub2_to_parent_map_[i], s);
220  dst(i) = s * z_(j);
221  }
222 
223  CorrectFaceOrientations(*dst.FESpace(), z_, dst);
224  }
225  else
226  {
227  MFEM_ABORT("unknown TransferCategory: " << category_);
228  }
229 }
230 
231 void TransferMap::CorrectFaceOrientations(const FiniteElementSpace &fes,
232  const Vector &src,
233  Vector &dst,
234  const Array<int> *sub_to_parent_map)
235 {
236  const FiniteElementCollection * fec = fes.FEColl();
237 
238  SubMesh * mesh = dynamic_cast<SubMesh*>(fes.GetMesh());
239 
240  const Array<int>& parent_face_ori = mesh->GetParentFaceOrientations();
241 
242  if (parent_face_ori.Size() == 0) { return; }
243 
244  VDofTransformation vdoftrans(fes.GetVDim(),
245  fes.GetOrdering());
246 
247  int dim = mesh->Dimension();
248  bool face = (dim == 3);
249 
250  Array<int> vdofs;
251  Array<int> Fo(1);
252  Vector face_vector;
253 
254  for (int i = 0; i < (face ? mesh->GetNumFaces() : mesh->GetNE()); i++)
255  {
256  if (parent_face_ori[i] == 0) { continue; }
257 
258  Geometry::Type geom = face ? mesh->GetFaceGeometry(i) :
259  mesh->GetElementGeometry(i);;
260 
261  StatelessDofTransformation * doftrans =
262  fec->DofTransformationForGeometry(geom);
263 
264  if (doftrans == NULL) { continue; }
265 
266  vdoftrans.SetDofTransformation(*doftrans);
267 
268  Fo[0] = parent_face_ori[i];
269  vdoftrans.SetFaceOrientations(Fo);
270 
271  if (face)
272  {
273  fes.GetFaceVDofs(i, vdofs);
274  }
275  else
276  {
277  fes.GetElementVDofs(i, vdofs);
278  }
279 
280  if (sub_to_parent_map)
281  {
282  src.GetSubVector(vdofs, face_vector);
283  vdoftrans.TransformPrimal(face_vector);
284  }
285  else
286  {
287  dst.GetSubVector(vdofs, face_vector);
288  vdoftrans.InvTransformPrimal(face_vector);
289  }
290 
291  for (int j = 0; j < vdofs.Size(); j++)
292  {
293  double s = 1.0;
294  int k = FiniteElementSpace::DecodeDof(vdofs[j], s);
295 
296  if (sub_to_parent_map)
297  {
298  double sps = 1.0;
299  int spk = FiniteElementSpace::DecodeDof((*sub_to_parent_map)[k],
300  sps);
301  s *= sps;
302  k = spk;
303  }
304 
305  dst[k] = s * face_vector[j];
306  }
307  }
308 }
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.
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
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
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:517
const Array< int > & GetParentElementIDMap() const
Get the parent element id map.
Definition: submesh.hpp:108
void Transfer(const GridFunction &src, GridFunction &dst) const
Transfer the source GridFunction to the destination GridFunction.
virtual const double * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:457
static int DecodeDof(int dof)
Helper to return the DOF associated with a sign encoded DOF.
Definition: fespace.hpp:996
void GetFaceVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified face, including the DOFs for the edge...
Definition: fespace.cpp:318
int GetOrder() const
Return the order (polynomial degree) of the FE collection, corresponding to the order/degree returned...
Definition: fe_coll.hpp:225
Geometry::Type GetFaceGeometry(int i) const
Return the Geometry::Type associated with face i.
Definition: mesh.cpp:1421
virtual double * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:465
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:579
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:723
static bool IsSubMesh(const Mesh *m)
Check if Mesh m is a SubMesh.
Definition: submesh.hpp:172
const Array< int > & GetParentFaceOrientations() const
Get the relative face orientations.
Definition: submesh.hpp:128
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:691
Arbitrary order H(div)-conforming Raviart-Thomas finite elements.
Definition: fe_coll.hpp:380
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
Geometry::Type GetElementGeometry(int i) const
Definition: mesh.hpp:1228
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
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
RT GetRootParent(const T &m)
Identify the root parent of a given SubMesh.
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:1086
virtual int GetMapType(int dim) const
Definition: fe_coll.cpp:60
From GetFrom() const
Get the From indicator.
Definition: submesh.hpp:98
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:721
int dim
Definition: ex24.cpp:53
Subdomain representation of a topological parent in another Mesh.
Definition: submesh.hpp:42
int Size() const
Return the logical size of the array.
Definition: array.hpp:141
Vector data type.
Definition: vector.hpp:58
virtual StatelessDofTransformation * DofTransformationForGeometry(Geometry::Type GeomType) const
Returns a DoF transformation object compatible with this basis and geometry type. ...
Definition: fe_coll.hpp:68
RefCoord s[3]
int GetBasisType() const
Definition: fe_coll.hpp:368
TransferMap(const GridFunction &src, const GridFunction &dst)
Construct a new TransferMap object which transfers degrees of freedom from the source GridFunction to...
Definition: transfermap.cpp:18
virtual double * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:473
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition: fe_coll.hpp:327