MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
pa.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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 "../tmop_tools.hpp"
14#include "../gridfunc.hpp"
16
17namespace mfem
18{
19
21 const FiniteElementSpace &fes)
22{
23 MFEM_VERIFY(PA.enabled, "PA extension setup has not been done!");
24 MFEM_VERIFY(PA.fes == &fes, "");
25 // TODO: we need a more robust way to check that the 'fes' used when
26 // AssemblePA() was called has not been modified or completely destroyed and
27 // a new object created at the same address.
28
29 // Form the Vector of node positions, depending on what's the input.
30 Vector xe(de.Size());
31 xe.UseDevice(true);
32 if (x_0)
33 {
34 // The input is the displacement.
35 add(PA.X0, de, xe);
36 }
37 else { xe = de; }
38
39 if (PA.Jtr_needs_update || targetC->UsesPhysicalCoordinates())
40 {
42 PA.Jtr_debug_grad = true;
43 }
44
45 if (PA.dim == 2)
46 {
49 }
50
51 if (PA.dim == 3)
52 {
55 }
56}
57
59{
60 const MemoryType mt =
62 // Return immediately if limiting is not enabled
63 if (lim_coeff == nullptr) { return; }
64 MFEM_VERIFY(lim_nodes0, "internal error");
65
66 MFEM_VERIFY(PA.enabled, "AssemblePA_Limiting but PA is not enabled!");
67 MFEM_VERIFY(lim_func, "No TMOP_LimiterFunction specification!")
68 MFEM_VERIFY(
69 dynamic_cast<TMOP_QuadraticLimiter *>(lim_func) ||
70 dynamic_cast<TMOP_ExponentialLimiter *>(lim_func),
71 "Only TMOP_QuadraticLimiter and TMOP_ExponentialLimiter are supported");
72
73 const FiniteElementSpace *fes = PA.fes;
74 const int NE = PA.ne;
75 if (NE == 0) { return; } // Quick return for empty processors
76 const IntegrationRule &ir = *PA.ir;
77
79
80 // H0 for lim_coeff, (dim x dim) Q-vector
81 PA.H0.UseDevice(true);
82 PA.H0.SetSize(PA.dim * PA.dim * PA.nq * NE, mt);
83
84 // lim_coeff -> PA.C0 (Q-vector)
85 PA.C0.UseDevice(true);
86 if (auto *cQ = dynamic_cast<ConstantCoefficient *>(lim_coeff))
87 {
88 PA.C0.SetSize(1, Device::GetMemoryType());
89 PA.C0.HostWrite();
90 PA.C0(0) = cQ->constant;
91 }
92 else
93 {
94 PA.C0.SetSize(PA.nq * PA.ne, Device::GetMemoryType());
95 auto C0 = Reshape(PA.C0.HostWrite(), PA.nq, PA.ne);
96 for (int e = 0; e < NE; ++e)
97 {
99 for (int q = 0; q < ir.GetNPoints(); ++q)
100 {
101 C0(q, e) = lim_coeff->Eval(T, ir.IntPoint(q));
102 }
103 }
104 }
105
106 // lim_nodes0 -> PA.XL (E-vector)
107 MFEM_VERIFY(lim_nodes0->FESpace()->GetVSize() == fes->GetVSize(), "");
108 const Operator *n0_R = fes->GetElementRestriction(ordering);
109 PA.XL.SetSize(n0_R->Height(), Device::GetMemoryType());
110 PA.XL.UseDevice(true);
111 n0_R->Mult(*lim_nodes0, PA.XL);
112
113 // Limiting distances: lim_dist -> PA.LD (E-vector)
114 // TODO: remove the hack for the case lim_dist == NULL.
115 const FiniteElementSpace *limfes = (lim_dist) ? lim_dist->FESpace() : fes;
116 const FiniteElement &lim_fe = *limfes->GetTypicalFE();
117 PA.maps_lim = &lim_fe.GetDofToQuad(ir, DofToQuad::TENSOR);
118 PA.LD.SetSize(NE * lim_fe.GetDof(), Device::GetMemoryType());
119 PA.LD.UseDevice(true);
120 if (lim_dist)
121 {
122 const Operator *ld_R = limfes->GetElementRestriction(ordering);
123 ld_R->Mult(*lim_dist, PA.LD);
124 }
125 else { PA.LD = 1.0; }
126}
127
129 const IntegrationRule &ir,
130 const Vector &xe,
131 DenseTensor &Jtr) const
132{
133 MFEM_VERIFY(Jtr.SizeI() == Jtr.SizeJ() && Jtr.SizeI() > 1, "");
134 const int dim = Jtr.SizeI();
135 bool done = false;
136 if (dim == 2) { done = ComputeAllElementTargets<2>(fes, ir, xe, Jtr); }
137 if (dim == 3) { done = ComputeAllElementTargets<3>(fes, ir, xe, Jtr); }
138
139 if (!done) { ComputeAllElementTargets_Fallback(fes, ir, xe, Jtr); }
140}
141
143 const IntegrationRule &ir,
144 const Vector &xe,
145 DenseTensor &Jtr) const
146{
147 ComputeAllElementTargets_Fallback(fes, ir, xe, Jtr);
148}
149
150// Code paths leading to ComputeElementTargets:
151// - GetElementEnergy(elfun) which is done through GetGridFunctionEnergyPA(x)
152// - AssembleElementVectorExact(elfun)
153// - AssembleElementGradExact(elfun)
154// - EnableNormalization(x) -> ComputeNormalizationEnergies(x)
155// - (AssembleElementVectorFD(elfun))
156// - (AssembleElementGradFD(elfun))
157// ============================================================================
158// - TargetConstructor():
159// - IDEAL_SHAPE_UNIT_SIZE: Wideal
160// - IDEAL_SHAPE_EQUAL_SIZE: α * Wideal
161// - IDEAL_SHAPE_GIVEN_SIZE: β * Wideal
162// - GIVEN_SHAPE_AND_SIZE: β * Wideal
163// - AnalyticAdaptTC(elfun):
164// - GIVEN_FULL: matrix_tspec->Eval(Jtr(elfun))
165// - DiscreteAdaptTC():
166// - IDEAL_SHAPE_GIVEN_SIZE: size^{1.0/dim} * Jtr(i) (size)
167// - GIVEN_SHAPE_AND_SIZE: Jtr(i) *= D_rho (ratio)
168// Jtr(i) *= Q_phi (skew)
169// Jtr(i) *= R_theta (orientation)
171{
172 PA.Jtr_needs_update = false;
173 PA.Jtr_debug_grad = false;
174 const FiniteElementSpace *fes = PA.fes;
175 if (PA.ne == 0) { return; } // Quick return for empty processors
176 const IntegrationRule &ir = *PA.ir;
177
178 const FiniteElement &fe = *fes->GetTypicalFE();
179 MFEM_VERIFY(PA.ir == &EnergyIntegrationRule(fe),
180 "TMOP_Integrator::ComputeAllElementTargets() called with "
181 "different IntegrationRule than the one used in AssemblePA()!");
182
183 // Compute PA.Jtr for all elements
185}
186
188{
189 Vector x_loc;
190 if (periodic)
191 {
192 GetPeriodicPositions(*x_0, d_loc, *x_0->FESpace(), *PA.fes, x_loc);
193 }
194 else
195 {
196 x_loc.SetSize(x_0->Size());
197 add(*x_0, d_loc, x_loc);
198 }
199
200 // Both are constant or not specified.
201 if (PA.MC.Size() == 1 && PA.C0.Size() == 1) { return; }
202
203 // Coefficients are always evaluated on the CPU for now.
204 PA.MC.HostWrite();
205 PA.C0.HostWrite();
206
207 const IntegrationRule &ir = *PA.ir;
208 auto T = new IsoparametricTransformation;
209 for (int e = 0; e < PA.ne; ++e)
210 {
211 // Uses the node positions in x_loc.
212 PA.fes->GetMesh()->GetElementTransformation(e, x_loc, T);
213
214 if (PA.MC.Size() > 1)
215 {
216 for (int q = 0; q < PA.nq; ++q)
217 {
218 PA.MC(q + e * PA.nq) = metric_coeff->Eval(*T, ir.IntPoint(q));
219 }
220 }
221
222 if (PA.C0.Size() > 1)
223 {
224 for (int q = 0; q < PA.nq; ++q)
225 {
226 PA.C0(q + e * PA.nq) = lim_coeff->Eval(*T, ir.IntPoint(q));
227 }
228 }
229 }
230
231 delete T;
232}
233
235{
236 const MemoryType mt =
238 PA.enabled = true;
239 PA.fes = &fes;
240 Mesh *mesh = fes.GetMesh();
241 const int ne = PA.ne = mesh->GetNE();
242 if (ne == 0) { return; } // Quick return for empty processors
243 const int dim = PA.dim = mesh->Dimension();
244
245 MFEM_VERIFY(PA.dim == 2 || PA.dim == 3, "Not yet implemented!");
246 MFEM_VERIFY(mesh->GetNumGeometries(dim) <= 1,
247 "TMOP+PA does not support mixed meshes.");
248 MFEM_VERIFY(mesh->HasGeometry(Geometry::SQUARE) ||
250 "TMOP+PA only supports squares and cubes.");
251 MFEM_VERIFY(!fes.IsVariableOrder(), "variable orders are not supported");
252 MFEM_VERIFY(fes.GetOrdering() == Ordering::byNODES,
253 "TMOP+PAP only supports Ordering::byNODES!");
254
255 const FiniteElement &fe = *fes.GetTypicalFE();
256 PA.ir = &EnergyIntegrationRule(fe);
257 const IntegrationRule &ir = *PA.ir;
258 const int nq = PA.nq = ir.GetNPoints();
260 PA.maps = &fe.GetDofToQuad(ir, mode);
261 // Note - initial mesh. TODO delete this?
263
264 // Initial node positions.
265 // PA.X0 is also updated in TMOP_Integrator::SetInitialMeshPos.
266 if (x_0 != nullptr)
267 {
269 auto n0_R = x_0->FESpace()->GetElementRestriction(ord);
270 PA.X0.UseDevice(true);
271 PA.X0.SetSize(n0_R->Height(), Device::GetMemoryType());
272 n0_R->Mult(*x_0, PA.X0);
273 }
274
275 // Energy vector, scalar Q-vector
276 PA.E.UseDevice(true);
277 PA.E.SetSize(ne * nq, Device::GetDeviceMemoryType());
278
279 // H for Grad, (dim x dim) Q-vector
280 PA.H.UseDevice(true);
281 PA.H.SetSize(dim * dim * dim * dim * nq * ne, mt);
282
283 // Scalar Q-vector of '1', used to compute sums via dot product
284 PA.O.UseDevice(true);
285 PA.O.SetSize(ne * nq, Device::GetDeviceMemoryType());
286 PA.O = 1.0;
287
288 if (metric_coeff)
289 {
290 if (auto cc = dynamic_cast<ConstantCoefficient *>(metric_coeff))
291 {
292 PA.MC.SetSize(1, Device::GetMemoryType());
293 PA.MC.HostWrite();
294 PA.MC(0) = cc->constant;
295 }
296 else
297 {
298 PA.MC.SetSize(PA.nq * PA.ne, Device::GetMemoryType());
299 auto M0 = Reshape(PA.MC.HostWrite(), PA.nq, PA.ne);
300 for (int e = 0; e < PA.ne; ++e)
301 {
302 ElementTransformation &T = *PA.fes->GetElementTransformation(e);
303 for (int q = 0; q < ir.GetNPoints(); ++q)
304 {
305 // Note that this is always on the initial mesh.
306 M0(q,e) = metric_coeff->Eval(T, ir.IntPoint(q));
307 }
308 }
309 }
310 }
311 else
312 {
313 PA.MC.SetSize(1, Device::GetMemoryType());
314 PA.MC.HostWrite();
315 PA.MC(0) = 1.0;
316 }
317
318 // Setup ref->target Jacobians, PA.Jtr, (dim x dim) Q-vector, DenseTensor
319 PA.Jtr.SetSize(dim, dim, PA.ne * PA.nq, mt);
320 PA.Jtr_needs_update = true;
321 PA.Jtr_debug_grad = false;
322
323 // Limiting: lim_coeff -> PA.C0, lim_nodes0 -> PA.XL, lim_dist -> PA.LD, PA.H0
325}
326
328{
329 // This method must be called after AssembleGradPA().
330
331 MFEM_VERIFY(PA.Jtr_needs_update == false, "");
332
334 {
335 MFEM_VERIFY(PA.Jtr_debug_grad == true,
336 "AssembleGradPA() was not called"
337 " or Jtr was overwritten by another method!");
338 }
339
340 if (PA.dim == 2)
341 {
344 }
345
346 if (PA.dim == 3)
347 {
350 }
351}
352
353void TMOP_Integrator::AddMultPA(const Vector &de, Vector &ye) const
354{
355 // This method must be called after AssemblePA().
356
357 // Form the Vector of node positions, depending on what's the input.
358 Vector xe(de.Size());
359 xe.UseDevice(true);
360 if (x_0)
361 {
362 // The input is the displacement.
363 add(PA.X0, de, xe);
364 }
365 else { xe = de; }
366
367 if (PA.Jtr_needs_update || targetC->UsesPhysicalCoordinates())
368 {
370 }
371
372 if (PA.dim == 2)
373 {
374 AddMultPA_2D(xe, ye);
375 if (lim_coeff) { AddMultPA_C0_2D(xe, ye); }
376 }
377
378 if (PA.dim == 3)
379 {
380 AddMultPA_3D(xe, ye);
381 if (lim_coeff) { AddMultPA_C0_3D(xe, ye); }
382 }
383}
384
386{
387 // This method must be called after AssembleGradPA().
388
389 MFEM_VERIFY(PA.Jtr_needs_update == false, "");
390
392 {
393 MFEM_VERIFY(PA.Jtr_debug_grad == true,
394 "AssembleGradPA() was not called or "
395 "Jtr was overwritten by another method!");
396 }
397
398 if (PA.dim == 2)
399 {
400 AddMultGradPA_2D(re, ce);
401 if (lim_coeff) { AddMultGradPA_C0_2D(re, ce); }
402 }
403
404 if (PA.dim == 3)
405 {
406 AddMultGradPA_3D(re, ce);
407 if (lim_coeff) { AddMultGradPA_C0_3D(re, ce); }
408 }
409}
410
412{
413 // This method must be called after AssemblePA().
414
415 // Form the Vector of node positions, depending on what's the input.
416 Vector xe(de.Size());
417 xe.UseDevice(true);
418 if (x_0)
419 {
420 // The input is the displacement.
421 add(PA.X0, de, xe);
422 }
423 else { xe = de; }
424
425 real_t energy = 0.0;
426
427 if (PA.Jtr_needs_update || targetC->UsesPhysicalCoordinates())
428 {
430 }
431
432 if (PA.dim == 2)
433 {
434 GetLocalStateEnergyPA_2D(xe, energy);
435 if (lim_coeff) { energy += GetLocalStateEnergyPA_C0_2D(xe); }
436 }
437
438 if (PA.dim == 3)
439 {
440 GetLocalStateEnergyPA_3D(xe, energy);
441 if (lim_coeff) { energy += GetLocalStateEnergyPA_C0_3D(xe); }
442 }
443
444 return energy;
445}
446
447} // namespace mfem
void ComputeAllElementTargets(const FiniteElementSpace &fes, const IntegrationRule &ir, const Vector &xe, DenseTensor &Jtr) const override
Computes reference-to-target transformation Jacobians for all quadrature points in all elements.
Definition pa.cpp:142
bool UseDevice() const
Return the device flag of the Memory object used by the Array.
Definition array.hpp:151
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:281
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Definition device.hpp:277
Mode
Type of data stored in the arrays B, Bt, G, and Gt.
Definition fe_base.hpp:154
@ TENSOR
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
Definition fe_base.hpp:165
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:678
ElementTransformation * GetElementTransformation(int i) const
Definition fespace.hpp:905
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:854
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition fespace.cpp:1480
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:826
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3860
Abstract class for all finite elements.
Definition fe_base.hpp:247
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:375
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:337
FiniteElementSpace * FESpace()
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:629
Mesh data type.
Definition mesh.hpp:65
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
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:883
bool HasGeometry(Geometry::Type geom) const
Return true iff the given geom is encountered in the mesh. Geometries of dimensions lower than Dimens...
Definition mesh.hpp:1340
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition mesh.cpp:7558
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:1453
void AddMultGradPA(const Vector &, Vector &) const override
Method for partially assembled gradient action.
Definition pa.cpp:385
real_t GetLocalStateEnergyPA_C0_2D(const Vector &) const
TMOP_LimiterFunction * lim_func
Definition tmop.hpp:2035
void ComputeAllElementTargets(const Vector &xe=Vector()) const
Definition pa.cpp:170
void AddMultPA_C0_3D(const Vector &, Vector &) const
void AssembleDiagonalPA_2D(Vector &) const
Coefficient * lim_coeff
Definition tmop.hpp:2031
const GridFunction * lim_dist
Definition tmop.hpp:2033
void AssembleDiagonalPA_C0_3D(Vector &) const
void AddMultGradPA_2D(const Vector &, Vector &) const
void AssembleGradPA_C0_2D(const Vector &) const
const TargetConstructor * targetC
Definition tmop.hpp:2015
void GetLocalStateEnergyPA_2D(const Vector &x, real_t &energy) const
const GridFunction * lim_nodes0
Definition tmop.hpp:2030
const IntegrationRule * ir
Definition tmop.hpp:2139
void AssemblePA(const FiniteElementSpace &) override
Method defining partial assembly.
Definition pa.cpp:234
void AssembleGradDiagonalPA(Vector &) const override
Method for computing the diagonal of the gradient with partial assembly.
Definition pa.cpp:327
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:2138
void AssemblePA_Limiting()
Definition pa.cpp:58
const IntegrationRule & EnergyIntegrationRule(const FiniteElement &el) const
Definition tmop.hpp:2199
void AddMultPA_2D(const Vector &, Vector &) const
void AddMultPA_3D(const Vector &, Vector &) const
void AssembleGradPA_C0_3D(const Vector &) const
void AssembleGradPA_2D(const Vector &) const
struct mfem::TMOP_Integrator::@26 PA
Coefficient * metric_coeff
Definition tmop.hpp:2023
const GridFunction * x_0
Definition tmop.hpp:2010
void AddMultPA(const Vector &, Vector &) const override
Method for partially assembled action.
Definition pa.cpp:353
void AddMultGradPA_C0_2D(const Vector &, Vector &) const
void AssembleDiagonalPA_3D(Vector &) const
void UpdateCoefficientsPA(const Vector &d_loc)
Definition pa.cpp:187
void AssembleGradPA_3D(const Vector &) const
void GetLocalStateEnergyPA_3D(const Vector &, real_t &energy) const
void AssembleGradPA(const Vector &, const FiniteElementSpace &) override
Prepare the integrator for partial assembly (PA) gradient evaluations on the given FE space fes at th...
Definition pa.cpp:20
void AddMultPA_C0_2D(const Vector &, Vector &) const
real_t GetLocalStateEnergyPA(const Vector &) const override
Compute the local (to the MPI rank) energy with partial assembly.
Definition pa.cpp:411
void AddMultGradPA_C0_3D(const Vector &, Vector &) const
Default limiter function in TMOP_Integrator.
Definition tmop.hpp:1422
bool UsesPhysicalCoordinates() const
Return true if the methods ComputeElementTargets(), ComputeAllElementTargets(), and ComputeElementTar...
Definition tmop.hpp:1682
void ComputeAllElementTargets_Fallback(const FiniteElementSpace &fes, const IntegrationRule &ir, const Vector &xe, DenseTensor &Jtr) const
Definition tmop.cpp:2432
bool ComputeAllElementTargets(const FiniteElementSpace &fes, const IntegrationRule &ir, const Vector &xe, DenseTensor &Jtr) const
Vector data type.
Definition vector.hpp:82
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:584
int dim
Definition ex24.cpp:53
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:414
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:138
void GetPeriodicPositions(const Vector &x_0, const Vector &dx, const FiniteElementSpace &fesL2, const FiniteElementSpace &fesH1, Vector &x)
float real_t
Definition config.hpp:46
MemoryType
Memory types supported by MFEM.
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:47