MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
tmop_tools.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, 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#ifndef MFEM_TMOP_TOOLS_HPP
13#define MFEM_TMOP_TOOLS_HPP
14
15#include "bilinearform.hpp"
16#include "pbilinearform.hpp"
17#include "tmop.hpp"
18#include "gslib.hpp"
19
20namespace mfem
21{
22
23// Performs the full remap advection loop.
25{
26private:
27 RK4Solver ode_solver;
28 Vector nodes0;
29 Vector field0;
30 const real_t dt_scale;
31 const AssemblyLevel al;
33
34 void ComputeAtNewPositionScalar(const Vector &new_mesh_nodes,
35 Vector &new_field);
36
37public:
39 real_t timestep_scale = 0.5)
41 ode_solver(), nodes0(), field0(), dt_scale(timestep_scale), al(al) { }
42
43 void SetInitialField(const Vector &init_nodes,
44 const Vector &init_field) override;
45
47 {
48 MFEM_ABORT("Not supported by AdvectorCG.");
49 }
50
51 /// Perform advection-based remap. Assumptions:
52 /// nodes0 and new_mesh_nodes have the same topology;
53 /// new_field is of the same FE space as field0.
54 void ComputeAtNewPosition(const Vector &new_mesh_nodes,
55 Vector &new_field,
56 int nodes_ordering = Ordering::byNODES) override;
57
58 void ComputeAtGivenPositions(const Vector &positions,
59 Vector &values,
60 int p_ordering = Ordering::byNODES) override
61 {
62 MFEM_ABORT("Not supported by AdvectorCG.");
63 }
64
65 /// Set the memory type used for large memory allocations. This memory type
66 /// is used when constructing the AdvectorCGOper but currently only for the
67 /// parallel variant.
68 void SetMemoryType(MemoryType mt) { opt_mt = mt; }
69};
70
71#ifdef MFEM_USE_GSLIB
73{
74private:
75 Vector nodes0;
76 GridFunction field0_gf;
77 FindPointsGSLIB *finder;
78 // FE space for the nodes of the solution GridFunction, not owned.
79 const FiniteElementSpace *fes_new_field;
80
81public:
82 InterpolatorFP() : finder(NULL), fes_new_field(NULL) { }
83
84 void SetInitialField(const Vector &init_nodes,
85 const Vector &init_field) override;
86
87 /// Must be called when the FE space of the final field is different than
88 /// the FE space of the initial field. This also includes the case when
89 /// the initial and final fields are on different meshes.
90 virtual void SetNewFieldFESpace(const FiniteElementSpace &fes) override
91 {
92 fes_new_field = &fes;
93 }
94
95 /// Perform interpolation-based remap.
96 /// Assumptions when SetNewFieldFESpace() has not been called:
97 /// new_field is of the same FE space and mesh as field0.
98 void ComputeAtNewPosition(const Vector &new_mesh_nodes,
99 Vector &new_field,
100 int nodes_ordering = Ordering::byNODES) override;
101
102 /// Direct interpolation of field0_gf at the given positions.
103 void ComputeAtGivenPositions(const Vector &positions,
104 Vector &values,
105 int p_ordering = Ordering::byNODES) override;
106
108 {
109 return finder;
110 }
111
113 {
114 if (finder) { finder->FreeData(); }
115 delete finder;
116 }
117};
118#endif
119
120/// Performs a single remap advection step in serial.
122{
123protected:
124 const Vector &x0;
128 mutable BilinearForm M, K;
130
131public:
132 /** Here @a fes is the FESpace of the function that will be moved. Note
133 that Mult() moves the nodes of the mesh corresponding to @a fes. */
137
138 void Mult(const Vector &ind, Vector &di_dt) const override;
139};
140
141#ifdef MFEM_USE_MPI
142/// Performs a single remap advection step in parallel.
144{
145protected:
146 const Vector &x0;
152
153public:
154 /** Here @a pfes is the ParFESpace of the function that will be moved. Note
155 that Mult() moves the nodes of the mesh corresponding to @a pfes.
156 @a mt is used to set the memory type of the integrators. */
157 ParAdvectorCGOper(const Vector &x_start, GridFunction &vel,
161
162 void Mult(const Vector &ind, Vector &di_dt) const override;
163};
164#endif
165
167{
168protected:
169 // 0 - Newton, 1 - LBFGS.
172
173 // Starting mesh positions. Updated by the call to Mult().
174 // This solver solves for d, where the final mesh is x = x_0 + d.
175 // The displacement d is always the tdof vector of an H1 function.
176 // For periodic meshes, x_0 is an L2 function, and the relation
177 // x = x_0 + d is used only per element with appropriate transitions.
179 mutable bool periodic = false;
180
181 // Line search step is rejected if min(detJ) <= min_detJ_limit.
183
184 // Surface fitting variables.
185 mutable real_t surf_fit_avg_err_prvs = 10000.0;
187 mutable bool surf_fit_coeff_update = false;
191 mutable int surf_fit_adapt_count = 0;
195
196 // Minimum determinant over the whole mesh. Used for mesh untangling.
197 real_t *min_det_ptr = nullptr;
198 // Flag to compute minimum determinant and maximum metric in ProcessNewState,
199 // which is required for TMOP_WorstCaseUntangleOptimizer_Metric.
200 mutable bool compute_metric_quantile_flag = true;
201
202 // Quadrature points that are checked for negative Jacobians etc.
204 // These fields are relevant for mixed meshes.
207 // Determinant lower-bound data used by the line search.
208 bool detJpr_pos_bound = false;
209 std::unique_ptr<GridFunction> det_gf;
210 std::unique_ptr<PLBound> det_plb;
212
214
216 {
217 if (IntegRules)
218 {
219 return IntegRules->Get(el.GetGeomType(), integ_order);
220 }
221 return ir;
222 }
223
224 /// Compute the minimum det(Jpt) of the trial mesh at quadrature points
225 /// (computes det(Jpr) and scales by the det of ideal target element).
226 real_t ComputeMinDet(const Vector &d_loc,
227 const FiniteElementSpace &fes) const;
228
229 /// Compute a lower bound for det(Jpt) of the trial mesh,
230 /// (computes det(Jpr) and scales by the det of ideal target element).
232 const FiniteElementSpace &fes) const;
233
236
237 /** @name Methods for adaptive surface fitting weight. */
238 ///@{
239 /// Get the average and maximum surface fitting error at the marked nodes.
240 /// If there is more than 1 TMOP integrator, we get the maximum of the
241 /// average and maximum error over all integrators.
242 virtual void GetSurfaceFittingError(const Vector &d_loc,
243 real_t &err_avg, real_t &err_max) const;
244
245 /// Update surface fitting weight as surf_fit_weight *= factor.
246 void UpdateSurfaceFittingWeight(real_t factor) const;
247
248 /// Get the surface fitting weight for all the TMOP integrators.
249 void GetSurfaceFittingWeight(Array<real_t> &weights) const;
250 ///@}
251
252 /// Check if surface fitting is enabled.
253 bool IsSurfaceFittingEnabled() const;
254
255public:
256#ifdef MFEM_USE_MPI
257 TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule, int type = 0)
258 : LBFGSSolver(comm), solver_type(type), parallel(true), x_0(),
259 ir(irule), IntegRules(NULL), integ_order(-1) { }
260#endif
261 TMOPNewtonSolver(const IntegrationRule &irule, int type = 0)
262 : LBFGSSolver(), solver_type(type), parallel(false), x_0(),
263 ir(irule), IntegRules(NULL), integ_order(-1) { }
264
265 /// Prescribe a set of integration rules; relevant for mixed meshes.
266 /** If called, this function has priority over the IntegrationRule given to
267 the constructor of the class. */
268 void SetIntegrationRules(IntegrationRules &irules, int order)
269 {
270 IntegRules = &irules;
271 integ_order = order;
272 }
273
274 void SetMinDetPtr(real_t *md_ptr) { min_det_ptr = md_ptr; }
275
276 /** @brief Ensure a positive lower bound for the Jacobian determinant in
277 tensor-product elements during line-search.
278 @note The solver creates and updates its own determinant GridFunction
279 from @a mesh while testing trial mesh positions. When @a mesh is a
280 ParMesh, the internal determinant field is a ParGridFunction. The
281 @a ref_factor controls the number of control points used by the PLBound
282 object, and @a max_recursion_depth controls the depth used by the
283 minimum-value estimator.
284
285 The determinant is represented by a high-order GridFunction computed
286 at the mesh nodes. The order is chosen s.t. interpolating the det at
287 some quad point would be equivalent to computing the det directly at the
288 same quad point using the mesh positions.
289 */
290 void EnsurePositiveDeterminantBound(Mesh &mesh, int ref_factor,
291 int max_recursion_depth = 0);
292
293 /// Update internal determinant GridFunction after a mesh topology change.
295
296 /// Set the memory type for temporary memory allocations.
298
299 /// Compute scaling factor for the node movement direction using line-search.
300 /// We impose constraints on TMOP energy, gradient, minimum Jacobian of
301 /// the mesh, and (optionally) on the surface fitting error.
302 real_t ComputeScalingFactor(const Vector &d, const Vector &b) const override;
303
304 /// Given the new displacements @a d (tdof Vector), update
305 /// (i) discrete functions at new nodal positions, and
306 /// (ii) surface fitting weight.
307 void ProcessNewState(const Vector &dx) const override;
308
309 /** @name Methods for adaptive surface fitting.
310 \brief These methods control the behavior of the weight and the
311 termination of the solver. (Experimental)
312
313 Adaptive fitting weight: The weight is modified after each
314 TMOPNewtonSolver iteration as:
315 w_{k+1} = w_{k} * \ref surf_fit_scale_factor if the relative
316 change in average fitting error < \ref surf_fit_err_rel_change_limit.
317 When converging based on the residual, we enforce the fitting weight
318 to be at-most \ref surf_fit_weight_limit, and increase it only if the
319 fitting error is below user prescribed threshold
320 (\ref surf_fit_max_err_limit).
321 See \ref SetAdaptiveSurfaceFittingScalingFactor and
322 \ref SetAdaptiveSurfaceFittingRelativeChangeThreshold.
323
324 Note that the solver stops if the maximum surface fitting error
325 does not sufficiently decrease for \ref surf_fit_adapt_count_limit (default 10)
326 consecutive increments of the fitting weight during weight adaptation.
327 This typically occurs when the mesh cannot align with the level-set
328 without degrading element quality.
329 See \ref SetMaxNumberofIncrementsForAdaptiveFitting.
330
331 Convergence criterion: There are two modes, residual- and error-based,
332 which can be toggled using \ref SetSurfaceFittingConvergenceBasedOnError.
333
334 (i) Residual based (default): Stop when the norm of the gradient of the
335 TMOP objective reaches the prescribed tolerance. This method is best used
336 with a reasonable value for \ref surf_fit_weight_limit when the
337 adaptive surface fitting scheme is used. See method
338 \ref SetSurfaceFittingWeightLimit.
339
340 (ii) Error based: Stop when the maximum fitting error
341 reaches the user-prescribed threshold, \ref surf_fit_max_err_limit.
342 In this case, \ref surf_fit_weight_limit is ignored during weight
343 adaptation.
344 */
345 ///@{
347 {
348 MFEM_VERIFY(factor > 1.0, "Scaling factor must be greater than 1.");
349 surf_fit_scale_factor = factor;
350 }
355 /// Used for stopping based on the number of consecutive failed weight
356 /// adaptation iterations.
357 // TODO: Rename to SetMaxNumberofIncrementsForAdaptiveSurfaceFitting
358 // in future.
363 /// Used for error-based surface fitting termination.
369 /// Could be used with both error-based or residual-based convergence.
371 {
372 surf_fit_max_err_limit = max_error;
373 }
374 /// Used for residual-based surface fitting termination.
379 /// Toggle convergence based on residual or error.
381 {
384 {
385 MFEM_VERIFY(surf_fit_max_err_limit >= 0,
386 "Fitting error based convergence requires the user to "
387 "first set the error threshold."
388 "See SetTerminationWithMaxSurfaceFittingError");
389 }
390 }
391 ///@}
392
393 /// Set minimum determinant enforced during line-search.
395 {
396 min_detJ_limit = threshold;
397 }
398
399 /// Optimizes the mesh positions given by @a x.
400 void Mult(const Vector &b, Vector &x) const override;
401
402 void SetSolver(Solver &solver) override
403 {
404 if (solver_type == 0)
405 {
407 }
408 else if (solver_type == 1)
409 {
411 }
412 else { MFEM_ABORT("Invalid type"); }
413 }
414 void SetPreconditioner(Solver &pr) override { SetSolver(pr); }
415};
416
417void vis_tmop_metric_s(int order, TMOP_QualityMetric &qm,
418 const TargetConstructor &tc, Mesh &pmesh,
419 char *title, int position);
420#ifdef MFEM_USE_MPI
421void vis_tmop_metric_p(int order, TMOP_QualityMetric &qm,
422 const TargetConstructor &tc, ParMesh &pmesh,
423 char *title, int position);
424#endif
425
426// Compute x = x_0 + d, where x and x_0 are L2, d is H1p, all ldof vectors.
427void GetPeriodicPositions(const Vector &x_0, const Vector &dx,
428 const FiniteElementSpace &fesL2,
429 const FiniteElementSpace &fesH1, Vector &x);
430}
431
432#endif
FiniteElementSpace * fes
Definition tmop.hpp:1514
AdvectorCG(AssemblyLevel al=AssemblyLevel::LEGACY, real_t timestep_scale=0.5)
void SetInitialField(const Vector &init_nodes, const Vector &init_field) override
void SetNewFieldFESpace(const FiniteElementSpace &fes) override
void ComputeAtGivenPositions(const Vector &positions, Vector &values, int p_ordering=Ordering::byNODES) override
Using the source mesh and field given by SetInitialField(), compute corresponding values at specified...
void ComputeAtNewPosition(const Vector &new_mesh_nodes, Vector &new_field, int nodes_ordering=Ordering::byNODES) override
void SetMemoryType(MemoryType mt)
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary collection of points....
Definition gslib.hpp:115
virtual void FreeData()
Cleans up memory allocated internally by gslib.
Definition gslib.cpp:2984
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
Abstract class for all finite elements.
Definition fe_base.hpp:294
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition fe_base.hpp:407
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
Container class for integration rules.
Definition intrules.hpp:430
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
void ComputeAtGivenPositions(const Vector &positions, Vector &values, int p_ordering=Ordering::byNODES) override
Direct interpolation of field0_gf at the given positions.
virtual void SetNewFieldFESpace(const FiniteElementSpace &fes) override
void SetInitialField(const Vector &init_nodes, const Vector &init_field) override
void ComputeAtNewPosition(const Vector &new_mesh_nodes, Vector &new_field, int nodes_ordering=Ordering::byNODES) override
const FindPointsGSLIB * GetFindPointsGSLIB() const
void SetSolver(Solver &solver) override
Set the linear solver for inverting the Jacobian.
Definition solvers.hpp:919
Mesh data type.
Definition mesh.hpp:67
virtual void SetSolver(Solver &solver)
Set the linear solver for inverting the Jacobian.
Definition solvers.hpp:828
Performs a single remap advection step in parallel.
ParAdvectorCGOper(const Vector &x_start, GridFunction &vel, ParFiniteElementSpace &pfes, AssemblyLevel al=AssemblyLevel::LEGACY, MemoryType mt=MemoryType::DEFAULT)
VectorGridFunctionCoefficient u_coeff
void Mult(const Vector &ind, Vector &di_dt) const override
Operator application: y=A(x).
const AssemblyLevel al
Class for parallel bilinear form.
Abstract parallel finite element space.
Definition pfespace.hpp:31
The classical explicit fourth-order Runge-Kutta method, RK4.
Definition ode.hpp:327
Performs a single remap advection step in serial.
VectorGridFunctionCoefficient u_coeff
SerialAdvectorCGOper(const Vector &x_start, GridFunction &vel, FiniteElementSpace &fes, AssemblyLevel al=AssemblyLevel::LEGACY)
const AssemblyLevel al
void Mult(const Vector &ind, Vector &di_dt) const override
Operator application: y=A(x).
Base class for solvers.
Definition operator.hpp:855
void SetAdaptiveSurfaceFittingScalingFactor(real_t factor)
real_t ComputeScalingFactor(const Vector &d, const Vector &b) const override
virtual void GetSurfaceFittingError(const Vector &d_loc, real_t &err_avg, real_t &err_max) const
void SetMinimumDeterminantThreshold(real_t threshold)
Set minimum determinant enforced during line-search.
std::unique_ptr< GridFunction > det_gf
void Mult(const Vector &b, Vector &x) const override
Optimizes the mesh positions given by x.
void SetPreconditioner(Solver &pr) override
This should be called before SetOperator.
void SetTempMemoryType(MemoryType mt)
Set the memory type for temporary memory allocations.
bool IsSurfaceFittingEnabled() const
Check if surface fitting is enabled.
void EnsurePositiveDeterminantBound(Mesh &mesh, int ref_factor, int max_recursion_depth=0)
Ensure a positive lower bound for the Jacobian determinant in tensor-product elements during line-sea...
real_t MinDetJpr_3D(const FiniteElementSpace *, const Vector &) const
std::unique_ptr< PLBound > det_plb
const IntegrationRule & ir
IntegrationRules * IntegRules
void SetIntegrationRules(IntegrationRules &irules, int order)
Prescribe a set of integration rules; relevant for mixed meshes.
const IntegrationRule & GetIntegrationRule(const FiniteElement &el) const
void UpdateDeterminantBoundGridFunction()
Update internal determinant GridFunction after a mesh topology change.
void UpdateSurfaceFittingWeight(real_t factor) const
Update surface fitting weight as surf_fit_weight *= factor.
real_t MinDetJpr_2D(const FiniteElementSpace *, const Vector &) const
void SetAdaptiveSurfaceFittingRelativeChangeThreshold(real_t threshold)
void SetMaxNumberofIncrementsForAdaptiveFitting(int count)
void ProcessNewState(const Vector &dx) const override
void SetMinDetPtr(real_t *md_ptr)
void SetSurfaceFittingMaxErrorLimit(real_t max_error)
Could be used with both error-based or residual-based convergence.
TMOPNewtonSolver(const IntegrationRule &irule, int type=0)
void SetSurfaceFittingConvergenceBasedOnError(bool mode)
Toggle convergence based on residual or error.
void SetTerminationWithMaxSurfaceFittingError(real_t max_error)
Used for error-based surface fitting termination.
real_t ComputeMinDet(const Vector &d_loc, const FiniteElementSpace &fes) const
real_t ComputeDetJptLowerBound(const Vector &d_loc, const FiniteElementSpace &fes) const
void SetSolver(Solver &solver) override
Set the linear solver for inverting the Jacobian.
void GetSurfaceFittingWeight(Array< real_t > &weights) const
Get the surface fitting weight for all the TMOP integrators.
void SetSurfaceFittingWeightLimit(real_t weight)
Used for residual-based surface fitting termination.
TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule, int type=0)
Base abstract class for first order time dependent operators.
Definition operator.hpp:367
Vector coefficient defined by a vector GridFunction.
Vector data type.
Definition vector.hpp:82
real_t b
Definition lissajous.cpp:42
real_t weight(const Vector &x)
AssemblyLevel
Enumeration defining the assembly level for bilinear and nonlinear form classes derived from Operator...
void vis_tmop_metric_s(int order, TMOP_QualityMetric &qm, const TargetConstructor &tc, Mesh &mesh, char *title, int position)
void vis_tmop_metric_p(int order, TMOP_QualityMetric &qm, const TargetConstructor &tc, ParMesh &pmesh, char *title, int position)
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.
void vel(const Vector &x, real_t t, Vector &u)