MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
tmop_pa.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, 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 "../tmop.hpp"
13#include "../linearform.hpp"
14#include "../pgridfunc.hpp"
15#include "../tmop_tools.hpp"
19
20namespace mfem
21{
22
24 const FiniteElementSpace &fes)
25{
26 MFEM_VERIFY(PA.enabled, "PA extension setup has not been done!");
27 MFEM_VERIFY(PA.fes == &fes, "");
28 // TODO: we need a more robust way to check that the 'fes' used when
29 // AssemblePA() was called has not been modified or completely destroyed and
30 // a new object created at the same address.
31
32 if (PA.Jtr_needs_update || targetC->UsesPhysicalCoordinates())
33 {
35 PA.Jtr_debug_grad = true;
36 }
37
38 if (PA.dim == 2)
39 {
42 }
43
44 if (PA.dim == 3)
45 {
48 }
49}
50
52{
53 const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
55 // Return immediately if limiting is not enabled
56 if (lim_coeff == nullptr) { return; }
57 MFEM_VERIFY(lim_nodes0, "internal error");
58
59 MFEM_VERIFY(PA.enabled, "AssemblePA_Limiting but PA is not enabled!");
60 MFEM_VERIFY(lim_func, "No TMOP_LimiterFunction specification!")
61 MFEM_VERIFY(dynamic_cast<TMOP_QuadraticLimiter*>(lim_func) ||
62 dynamic_cast<TMOP_ExponentialLimiter*>(lim_func),
63 "Only TMOP_QuadraticLimiter and TMOP_ExponentialLimiter are supported");
64
65 const FiniteElementSpace *fes = PA.fes;
66 const int NE = PA.ne;
67 if (NE == 0) { return; } // Quick return for empty processors
68 const IntegrationRule &ir = *PA.ir;
69
71
72 // H0 for lim_coeff, (dim x dim) Q-vector
73 PA.H0.UseDevice(true);
74 PA.H0.SetSize(PA.dim * PA.dim * PA.nq * NE, mt);
75
76 // lim_coeff -> PA.C0 (Q-vector)
77 PA.C0.UseDevice(true);
78 if (ConstantCoefficient* cQ =
79 dynamic_cast<ConstantCoefficient*>(lim_coeff))
80 {
81 PA.C0.SetSize(1, Device::GetMemoryType());
82 PA.C0.HostWrite();
83 PA.C0(0) = cQ->constant;
84 }
85 else
86 {
87 PA.C0.SetSize(PA.nq * PA.ne, Device::GetMemoryType());
88 auto C0 = Reshape(PA.C0.HostWrite(), PA.nq, PA.ne);
89 for (int e = 0; e < NE; ++e)
90 {
92 for (int q = 0; q < ir.GetNPoints(); ++q)
93 {
94 C0(q,e) = lim_coeff->Eval(T, ir.IntPoint(q));
95 }
96 }
97 }
98
99 // lim_nodes0 -> PA.X0 (E-vector)
100 MFEM_VERIFY(lim_nodes0->FESpace() == fes, "");
101 const Operator *n0_R = fes->GetElementRestriction(ordering);
102 PA.X0.SetSize(n0_R->Height(), Device::GetMemoryType());
103 PA.X0.UseDevice(true);
104 n0_R->Mult(*lim_nodes0, PA.X0);
105
106 // Limiting distances: lim_dist -> PA.LD (E-vector)
107 // TODO: remove the hack for the case lim_dist == NULL.
108 const FiniteElementSpace *limfes = (lim_dist) ? lim_dist->FESpace() : fes;
109 const FiniteElement &lim_fe = *limfes->GetFE(0);
110 PA.maps_lim = &lim_fe.GetDofToQuad(ir, DofToQuad::TENSOR);
111 PA.LD.SetSize(NE*lim_fe.GetDof(), Device::GetMemoryType());
112 PA.LD.UseDevice(true);
113 if (lim_dist)
114 {
115 const Operator *ld_R = limfes->GetElementRestriction(ordering);
116 ld_R->Mult(*lim_dist, PA.LD);
117 }
118 else
119 {
120 PA.LD = 1.0;
121 }
122}
123
125 const IntegrationRule &ir,
126 const Vector &xe,
127 DenseTensor &Jtr) const
128{
129 MFEM_VERIFY(Jtr.SizeI() == Jtr.SizeJ() && Jtr.SizeI() > 1, "");
130 const int dim = Jtr.SizeI();
131 bool done = false;
132 if (dim == 2) { done = ComputeAllElementTargets<2>(fes, ir, xe, Jtr); }
133 if (dim == 3) { done = ComputeAllElementTargets<3>(fes, ir, xe, Jtr); }
134
135 if (!done) { ComputeAllElementTargets_Fallback(fes, ir, xe, Jtr); }
136}
137
139 const IntegrationRule &ir,
140 const Vector &xe,
141 DenseTensor &Jtr) const
142{
143 ComputeAllElementTargets_Fallback(fes, ir, xe, Jtr);
144}
145
146
147// Code paths leading to ComputeElementTargets:
148// - GetElementEnergy(elfun) which is done through GetGridFunctionEnergyPA(x)
149// - AssembleElementVectorExact(elfun)
150// - AssembleElementGradExact(elfun)
151// - EnableNormalization(x) -> ComputeNormalizationEnergies(x)
152// - (AssembleElementVectorFD(elfun))
153// - (AssembleElementGradFD(elfun))
154// ============================================================================
155// - TargetConstructor():
156// - IDEAL_SHAPE_UNIT_SIZE: Wideal
157// - IDEAL_SHAPE_EQUAL_SIZE: α * Wideal
158// - IDEAL_SHAPE_GIVEN_SIZE: β * Wideal
159// - GIVEN_SHAPE_AND_SIZE: β * Wideal
160// - AnalyticAdaptTC(elfun):
161// - GIVEN_FULL: matrix_tspec->Eval(Jtr(elfun))
162// - DiscreteAdaptTC():
163// - IDEAL_SHAPE_GIVEN_SIZE: size^{1.0/dim} * Jtr(i) (size)
164// - GIVEN_SHAPE_AND_SIZE: Jtr(i) *= D_rho (ratio)
165// Jtr(i) *= Q_phi (skew)
166// Jtr(i) *= R_theta (orientation)
168{
169 PA.Jtr_needs_update = false;
170 PA.Jtr_debug_grad = false;
171 const FiniteElementSpace *fes = PA.fes;
172 if (PA.ne == 0) { return; } // Quick return for empty processors
173 const IntegrationRule &ir = *PA.ir;
174
175 // Compute PA.Jtr for all elements
177}
178
180{
181 // Both are constant or not specified.
182 if (PA.MC.Size() == 1 && PA.C0.Size() == 1) { return; }
183
184 // Coefficients are always evaluated on the CPU for now.
185 PA.MC.HostWrite();
186 PA.C0.HostWrite();
187
188 const IntegrationRule &ir = *PA.ir;
189 auto T = new IsoparametricTransformation;
190 for (int e = 0; e < PA.ne; ++e)
191 {
192 // Uses the node positions in x_loc.
193 PA.fes->GetMesh()->GetElementTransformation(e, x_loc, T);
194
195 if (PA.MC.Size() > 1)
196 {
197 for (int q = 0; q < PA.nq; ++q)
198 {
199 PA.MC(q + e * PA.nq) = metric_coeff->Eval(*T, ir.IntPoint(q));
200 }
201 }
202
203 if (PA.C0.Size() > 1)
204 {
205 for (int q = 0; q < PA.nq; ++q)
206 {
207 PA.C0(q + e * PA.nq) = lim_coeff->Eval(*T, ir.IntPoint(q));
208 }
209 }
210 }
211
212 delete T;
213}
214
216{
217 const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
219 PA.enabled = true;
220 PA.fes = &fes;
221 Mesh *mesh = fes.GetMesh();
222 const int ne = PA.ne = mesh->GetNE();
223 if (ne == 0) { return; } // Quick return for empty processors
224 const int dim = PA.dim = mesh->Dimension();
225 MFEM_VERIFY(PA.dim == 2 || PA.dim == 3, "Not yet implemented!");
226 MFEM_VERIFY(mesh->GetNumGeometries(dim) <= 1,
227 "mixed meshes are not supported");
228 MFEM_VERIFY(!fes.IsVariableOrder(), "variable orders are not supported");
229 const FiniteElement &fe = *fes.GetFE(0);
230 PA.ir = &EnergyIntegrationRule(fe);
231 const IntegrationRule &ir = *PA.ir;
232 MFEM_VERIFY(fes.GetOrdering() == Ordering::byNODES,
233 "PA Only supports Ordering::byNODES!");
234
235 const int nq = PA.nq = ir.GetNPoints();
237 PA.maps = &fe.GetDofToQuad(ir, mode);
239
240 // Energy vector, scalar Q-vector
241 PA.E.UseDevice(true);
242 PA.E.SetSize(ne*nq, Device::GetDeviceMemoryType());
243
244 // H for Grad, (dim x dim) Q-vector
245 PA.H.UseDevice(true);
246 PA.H.SetSize(dim*dim * dim*dim * nq*ne, mt);
247
248 // Scalar Q-vector of '1', used to compute sums via dot product
249 PA.O.SetSize(ne*nq, Device::GetDeviceMemoryType());
250 PA.O = 1.0;
251
252 if (metric_coeff)
253 {
254 if (auto cc = dynamic_cast<ConstantCoefficient *>(metric_coeff))
255 {
256 PA.MC.SetSize(1, Device::GetMemoryType());
257 PA.MC.HostWrite();
258 PA.MC(0) = cc->constant;
259 }
260 else
261 {
262 PA.MC.SetSize(PA.nq * PA.ne, Device::GetMemoryType());
263 auto M0 = Reshape(PA.MC.HostWrite(), PA.nq, PA.ne);
264 for (int e = 0; e < PA.ne; ++e)
265 {
266 ElementTransformation& T = *PA.fes->GetElementTransformation(e);
267 for (int q = 0; q < ir.GetNPoints(); ++q)
268 {
269 M0(q,e) = metric_coeff->Eval(T, ir.IntPoint(q));
270 }
271 }
272 }
273 }
274 else
275 {
276 PA.MC.SetSize(1, Device::GetMemoryType());
277 PA.MC.HostWrite();
278 PA.MC(0) = 1.0;
279 }
280
281 // Setup ref->target Jacobians, PA.Jtr, (dim x dim) Q-vector, DenseTensor
282 PA.Jtr.SetSize(dim, dim, PA.ne*PA.nq, mt);
283 PA.Jtr_needs_update = true;
284 PA.Jtr_debug_grad = false;
285
286 // Limiting: lim_coeff -> PA.C0, lim_nodes0 -> PA.X0, lim_dist -> PA.LD, PA.H0
288}
289
291{
292 // This method must be called after AssembleGradPA().
293
294 MFEM_VERIFY(PA.Jtr_needs_update == false, "");
295
297 {
298 MFEM_VERIFY(PA.Jtr_debug_grad == true, "AssembleGradPA() was not called"
299 " or Jtr was overwritten by another method!");
300 }
301
302 if (PA.dim == 2)
303 {
306 }
307
308 if (PA.dim == 3)
309 {
312 }
313}
314
315void TMOP_Integrator::AddMultPA(const Vector &xe, Vector &ye) const
316{
317 // This method must be called after AssemblePA().
318
319 if (PA.Jtr_needs_update || targetC->UsesPhysicalCoordinates())
320 {
322 }
323
324 if (PA.dim == 2)
325 {
326 AddMultPA_2D(xe,ye);
327 if (lim_coeff) { AddMultPA_C0_2D(xe,ye); }
328 }
329
330 if (PA.dim == 3)
331 {
332 AddMultPA_3D(xe,ye);
333 if (lim_coeff) { AddMultPA_C0_3D(xe,ye); }
334 }
335}
336
338{
339 // This method must be called after AssembleGradPA().
340
341 MFEM_VERIFY(PA.Jtr_needs_update == false, "");
342
344 {
345 MFEM_VERIFY(PA.Jtr_debug_grad == true, "AssembleGradPA() was not called or "
346 "Jtr was overwritten by another method!");
347 }
348
349 if (PA.dim == 2)
350 {
351 AddMultGradPA_2D(re,ce);
352 if (lim_coeff) { AddMultGradPA_C0_2D(re,ce); }
353 }
354
355 if (PA.dim == 3)
356 {
357 AddMultGradPA_3D(re,ce);
358 if (lim_coeff) { AddMultGradPA_C0_3D(re,ce); }
359 }
360}
361
363{
364 // This method must be called after AssemblePA().
365
366 real_t energy = 0.0;
367
368 if (PA.Jtr_needs_update || targetC->UsesPhysicalCoordinates())
369 {
371 }
372
373 if (PA.dim == 2)
374 {
375 energy = GetLocalStateEnergyPA_2D(xe);
376 if (lim_coeff) { energy += GetLocalStateEnergyPA_C0_2D(xe); }
377 }
378
379 if (PA.dim == 3)
380 {
381 energy = GetLocalStateEnergyPA_3D(xe);
382 if (lim_coeff) { energy += GetLocalStateEnergyPA_C0_3D(xe); }
383 }
384
385 return energy;
386}
387
388} // namespace mfem
virtual void ComputeAllElementTargets(const FiniteElementSpace &fes, const IntegrationRule &ir, const Vector &xe, DenseTensor &Jtr) const
Computes reference-to-target transformation Jacobians for all quadrature points in all elements.
Definition tmop_pa.cpp:138
bool UseDevice() const
Return the device flag of the Memory object used by the Array.
Definition array.hpp:129
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the coefficient in the element described by T at the point ip.
A coefficient that is constant across space and time.
Rank 3 tensor (array of matrices)
int SizeJ() const
int SizeI() const
static MemoryType GetMemoryType()
(DEPRECATED) Equivalent to GetDeviceMemoryType().
Definition device.hpp:278
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Definition device.hpp:274
Mode
Type of data stored in the arrays B, Bt, G, and Gt.
Definition fe_base.hpp:150
@ TENSOR
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
Definition fe_base.hpp:161
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:220
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:581
ElementTransformation * GetElementTransformation(int i) const
Returns ElementTransformation for the i-th element.
Definition fespace.hpp:773
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3168
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:725
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition fespace.cpp:1336
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:559
Abstract class for all finite elements.
Definition fe_base.hpp:239
virtual const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Definition fe_base.cpp:365
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:329
FiniteElementSpace * FESpace()
Definition gridfunc.hpp:696
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:259
A standard isoparametric element transformation.
Definition eltrans.hpp:363
Mesh data type.
Definition mesh.hpp:56
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1226
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1160
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors corresponding to the given integration rule.
Definition mesh.cpp:856
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition mesh.cpp:6961
Abstract operator.
Definition operator.hpp:25
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
Exponential limiter function in TMOP_Integrator.
Definition tmop.hpp:1224
virtual void AssembleGradPA(const Vector &, const FiniteElementSpace &)
Prepare the integrator for partial assembly (PA) gradient evaluations on the given FE space fes at th...
Definition tmop_pa.cpp:23
real_t GetLocalStateEnergyPA_C0_2D(const Vector &) const
TMOP_LimiterFunction * lim_func
Definition tmop.hpp:1765
void ComputeAllElementTargets(const Vector &xe=Vector()) const
Definition tmop_pa.cpp:167
virtual void AddMultGradPA(const Vector &, Vector &) const
Method for partially assembled gradient action.
Definition tmop_pa.cpp:337
void AddMultPA_C0_3D(const Vector &, Vector &) const
virtual void AssembleGradDiagonalPA(Vector &) const
Method for computing the diagonal of the gradient with partial assembly.
Definition tmop_pa.cpp:290
real_t GetLocalStateEnergyPA_2D(const Vector &) const
void AssembleDiagonalPA_2D(Vector &) const
Coefficient * lim_coeff
Definition tmop.hpp:1761
const GridFunction * lim_dist
Definition tmop.hpp:1763
void AssembleDiagonalPA_C0_3D(Vector &) const
virtual real_t GetLocalStateEnergyPA(const Vector &) const
Compute the local (to the MPI rank) energy with partial assembly.
Definition tmop_pa.cpp:362
void AddMultGradPA_2D(const Vector &, Vector &) const
void AssembleGradPA_C0_2D(const Vector &) const
virtual void AddMultPA(const Vector &, Vector &) const
Method for partially assembled action.
Definition tmop_pa.cpp:315
const TargetConstructor * targetC
Definition tmop.hpp:1745
const GridFunction * lim_nodes0
Definition tmop.hpp:1760
const IntegrationRule * ir
Definition tmop.hpp:1868
void AssembleDiagonalPA_C0_2D(Vector &) const
real_t GetLocalStateEnergyPA_C0_3D(const Vector &) const
void AddMultGradPA_3D(const Vector &, Vector &) const
const FiniteElementSpace * fes
Definition tmop.hpp:1867
virtual void AssemblePA(const FiniteElementSpace &)
Method defining partial assembly.
Definition tmop_pa.cpp:215
const IntegrationRule & EnergyIntegrationRule(const FiniteElement &el) const
Definition tmop.hpp:1929
void AddMultPA_2D(const Vector &, Vector &) const
struct mfem::TMOP_Integrator::@23 PA
void UpdateCoefficientsPA(const Vector &x_loc)
Definition tmop_pa.cpp:179
void AddMultPA_3D(const Vector &, Vector &) const
void AssembleGradPA_C0_3D(const Vector &) const
void AssembleGradPA_2D(const Vector &) const
Coefficient * metric_coeff
Definition tmop.hpp:1753
void AddMultGradPA_C0_2D(const Vector &, Vector &) const
void AssembleDiagonalPA_3D(Vector &) const
void AssembleGradPA_3D(const Vector &) const
real_t GetLocalStateEnergyPA_3D(const Vector &) const
void AddMultPA_C0_2D(const Vector &, Vector &) const
void AddMultGradPA_C0_3D(const Vector &, Vector &) const
Default limiter function in TMOP_Integrator.
Definition tmop.hpp:1193
bool UsesPhysicalCoordinates() const
Return true if the methods ComputeElementTargets(), ComputeAllElementTargets(), and ComputeElementTar...
Definition tmop.hpp:1426
void ComputeAllElementTargets_Fallback(const FiniteElementSpace &fes, const IntegrationRule &ir, const Vector &xe, DenseTensor &Jtr) const
Definition tmop.cpp:1562
bool ComputeAllElementTargets(const FiniteElementSpace &fes, const IntegrationRule &ir, const Vector &xe, DenseTensor &Jtr) const
Vector data type.
Definition vector.hpp:80
int dim
Definition ex24.cpp:53
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
Definition dtensor.hpp:131
float real_t
Definition config.hpp:43
MemoryType
Memory types supported by MFEM.
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:75
@ LEXICOGRAPHIC
Lexicographic ordering for tensor-product FiniteElements.