MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
lor-transfer.cpp
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// --------------------------------------------------------------
13// LOR Transfer Miniapp: Map functions between HO and LOR spaces
14// --------------------------------------------------------------
15//
16// This miniapp visualizes the maps between a high-order (HO) finite element
17// space, typically using high-order functions on a high-order mesh, and a
18// low-order refined (LOR) finite element space, typically defined by 0th or 1st
19// order functions on a low-order refinement of the HO mesh.
20//
21// The grid transfer operators are represented using either
22// InterpolationGridTransfer or L2ProjectionGridTransfer (depending on the
23// options requested by the user). The two transfer operators are then:
24//
25// 1. R: HO -> LOR, defined by GridTransfer::ForwardOperator
26// 2. P: LOR -> HO, defined by GridTransfer::BackwardOperator
27//
28// While defined generally, these operators have some nice properties for
29// particular finite element spaces. For example they satisfy PR=I, plus mass
30// conservation in both directions for L2 fields.
31//
32// Compile with: make lor-transfer
33//
34// Sample runs: lor-transfer
35// lor-transfer -h1
36// lor-transfer -ea -w
37// lor-transfer -t
38// lor-transfer -m ../../data/star-q2.mesh -lref 5 -p 4
39// lor-transfer -m ../../data/star-mixed.mesh -lref 3 -p 2
40// lor-transfer -lref 4 -o 4 -lo 0 -p 1
41// lor-transfer -lref 5 -o 4 -lo 0 -p 1
42// lor-transfer -lref 5 -o 4 -lo 3 -p 2
43// lor-transfer -lref 5 -o 4 -lo 0 -p 3
44
45#include "mfem.hpp"
46#include <fstream>
47#include <iostream>
48
49using namespace std;
50using namespace mfem;
51
52int problem = 1; // problem type
53
54int Wx = 0, Wy = 0; // window position
55int Ww = 350, Wh = 350; // window size
56int offx = Ww+5, offy = Wh+25; // window offsets
57
58string space;
59string direction;
60
61// Exact functions to project
62real_t RHO_exact(const Vector &x);
63real_t W_exact(const Vector &x);
64real_t weight(const Vector &x);
65
66// Helper functions
67void visualize(VisItDataCollection &, string, int, int, int visport = 19916);
69
70int main(int argc, char *argv[])
71{
72 // Parse command-line options.
73 const char *mesh_file = "../../data/star.mesh";
74 int order = 3;
75 int lref = order+1;
76 int lorder = 0;
77 bool vis = true;
78 bool useH1 = false;
79 int visport = 19916;
80 bool use_pointwise_transfer = false;
81 bool use_weighted_transfer = false;
82 const char *device_config = "cpu";
83 bool use_ea = false;
84
85 OptionsParser args(argc, argv);
86 args.AddOption(&mesh_file, "-m", "--mesh",
87 "Mesh file to use.");
88 args.AddOption(&problem, "-p", "--problem",
89 "Problem type (see the RHO_exact function).");
90 args.AddOption(&order, "-o", "--order",
91 "Finite element order (polynomial degree) or -1 for"
92 " isoparametric space.");
93 args.AddOption(&lref, "-lref", "--lor-ref-level", "LOR refinement level.");
94 args.AddOption(&lorder, "-lo", "--lor-order",
95 "LOR space order (polynomial degree, zero by default).");
96 args.AddOption(&vis, "-vis", "--visualization", "-no-vis",
97 "--no-visualization",
98 "Enable or disable GLVis visualization.");
99 args.AddOption(&useH1, "-h1", "--use-h1", "-l2", "--use-l2",
100 "Use H1 spaces instead of L2.");
101 args.AddOption(&use_pointwise_transfer, "-t", "--use-pointwise-transfer",
102 "-no-t", "--dont-use-pointwise-transfer",
103 "Use pointwise transfer operators instead of L2 projection.");
104 args.AddOption(&use_weighted_transfer, "-w", "--use-weighted-transfer",
105 "-no-w", "--dont-use-weighted-transfer",
106 "Use coefficient-weighted L2 projection.");
107 args.AddOption(&device_config, "-d", "--device",
108 "Device configuration string, see Device::Configure().");
109 args.AddOption(&use_ea, "-ea", "--ea-version", "-no-ea",
110 "--no-ea-version", "Use element assembly version.");
111 args.ParseCheck();
112
113 // Configure device
114 Device device(device_config);
115
116 if (use_weighted_transfer && !use_pointwise_transfer)
117 {
118 if (problem != 5)
119 {
120 cout << "Switching to positive problem = 5 for weighted transfer.\n";
121 }
122 problem = 5;
123 }
124
125 // Read the mesh from the given mesh file.
126 Mesh mesh(mesh_file, 1, 1);
127 int dim = mesh.Dimension();
128
129 // Create the low-order refined mesh
130 int basis_lor = BasisType::GaussLobatto; // BasisType::ClosedUniform;
131 Mesh mesh_lor = Mesh::MakeRefined(mesh, lref, basis_lor);
132
133 // Create spaces
134 FiniteElementCollection *fec, *fec_lor;
135 if (useH1)
136 {
137 space = "H1";
138 if (lorder == 0)
139 {
140 lorder = 1;
141 cerr << "Switching the H1 LOR space order from 0 to 1\n";
142 }
143 fec = new H1_FECollection(order, dim);
144 fec_lor = new H1_FECollection(lorder, dim);
145 }
146 else
147 {
148 space = "L2";
149 fec = new L2_FECollection(order, dim);
150 fec_lor = new L2_FECollection(lorder, dim);
151 }
152
153 FiniteElementSpace fespace(&mesh, fec);
154 FiniteElementSpace fespace_lor(&mesh_lor, fec_lor);
155
156 FunctionCoefficient weight_fn_coeff(weight);
157 CoefficientWithOrder weight_coeff;
158 if (use_weighted_transfer)
159 {
160 weight_coeff.coeff = &weight_fn_coeff;
161 weight_coeff.order = 2;
162 }
163
164 GridFunction rho(&fespace);
165 GridFunction rho_lor(&fespace_lor);
166
167 // Data collections for vis/analysis
168 VisItDataCollection HO_dc("HO", &mesh);
169 HO_dc.RegisterField("density", &rho);
170 VisItDataCollection LOR_dc("LOR", &mesh_lor);
171 LOR_dc.RegisterField("density", &rho_lor);
172
173 BilinearForm M_ho(&fespace);
175 M_ho.Assemble();
176 M_ho.Finalize();
177
178 BilinearForm M_lor(&fespace_lor);
180 M_lor.Assemble();
181 M_lor.Finalize();
182
183 // HO projections
184 direction = "HO -> LOR @ HO";
186 rho.ProjectCoefficient(RHO);
187 // Make sure AMR constraints are satisfied
188 rho.SetTrueVector();
189 rho.SetFromTrueVector();
190
191 real_t ho_mass = compute_mass(rho, -1.0, "HO ", weight_coeff);
192 if (vis) { visualize(HO_dc, "HO", Wx, Wy, visport); Wx += offx; }
193
194 GridTransfer *gt;
195 if (use_pointwise_transfer)
196 {
197 gt = new InterpolationGridTransfer(fespace, fespace_lor);
198 }
199 else
200 {
201 gt = new L2ProjectionGridTransfer(fespace, fespace_lor, weight_coeff,
202 weight_coeff);
203 }
204
205 // Configure element assembly for device acceleration
206 gt->UseEA(use_ea);
207
208 const Operator &R = gt->ForwardOperator();
209
210 // HO->LOR restriction
211 direction = "HO -> LOR @ LOR";
212 R.Mult(rho, rho_lor);
213 compute_mass(rho_lor, ho_mass, "R(HO) ", weight_coeff);
214 if (vis) { visualize(LOR_dc, "R(HO)", Wx, Wy, visport); Wx += offx; }
215
216 if (use_weighted_transfer && !use_pointwise_transfer)
217 {
218 // Transfer velocity while conserving rho-weighted momentum.
219 GridFunctionCoefficient rho_coeff(&rho);
220 GridFunctionCoefficient rho_lor_coeff(&rho_lor);
221 ProductCoefficient prod_coeff(weight_fn_coeff, rho_coeff);
222 ProductCoefficient prod_lor_coeff(weight_fn_coeff, rho_lor_coeff);
223 CoefficientWithOrder prod_weight(prod_coeff, order + 2);
224 CoefficientWithOrder prod_lor_weight(prod_lor_coeff, lorder + 2);
225
226 GridFunction w(&fespace), w_lor(&fespace_lor);
228 w.ProjectCoefficient(W);
229
230 cout << '\n';
231 const real_t ho_momentum = compute_mass(w, -1.0, "rho w HO ", prod_weight);
232
233 L2ProjectionGridTransfer vel_gt(fespace, fespace_lor, prod_weight,
234 prod_lor_weight);
235 vel_gt.UseEA(use_ea);
236 vel_gt.ForwardOperator().Mult(w, w_lor);
237 compute_mass(w_lor, ho_momentum, "rho w LOR", prod_lor_weight);
238
239 if (vel_gt.SupportsBackwardsOperator())
240 {
241 GridFunction w_prev = w;
242 vel_gt.BackwardOperator().Mult(w_lor, w);
243 compute_mass(w, ho_momentum, "P(rho w) ", prod_weight);
244
245 w_prev -= w;
246 cout.precision(12);
247 cout << "|w - P(R(w))|_∞ = " << w_prev.Normlinf() << "\n\n";
248 }
249 }
250
252 {
253 const Operator &P = gt->BackwardOperator();
254 // LOR->HO prolongation
255 direction = "HO -> LOR @ HO";
256 GridFunction rho_prev = rho;
257 P.Mult(rho_lor, rho);
258 compute_mass(rho, ho_mass, "P(R(HO)) ", weight_coeff);
259 if (vis) { visualize(HO_dc, "P(R(HO))", Wx, Wy, visport); Wx = 0; Wy += offy; }
260
261 rho_prev -= rho;
262 cout.precision(12);
263 cout << "|HO - P(R(HO))|_∞ = " << rho_prev.Normlinf() << endl;
264 }
265
266 // HO* to LOR* dual fields
267 LinearForm M_rho(&fespace), M_rho_lor(&fespace_lor);
268 if (!use_pointwise_transfer && gt->SupportsBackwardsOperator())
269 {
270 const Operator &P = gt->BackwardOperator();
271 M_ho.Mult(rho, M_rho);
272 P.MultTranspose(M_rho, M_rho_lor);
273 cout << "HO -> LOR dual field: " << abs(M_rho.Sum()-M_rho_lor.Sum()) << "\n\n";
274 }
275
276 // LOR projections
277 direction = "LOR -> HO @ LOR";
278 rho_lor.ProjectCoefficient(RHO);
279 GridFunction rho_lor_prev = rho_lor;
280 real_t lor_mass = compute_mass(rho_lor, -1.0, "LOR ", weight_coeff);
281 if (vis) { visualize(LOR_dc, "LOR", Wx, Wy, visport); Wx += offx; }
282
284 {
285 const Operator &P = gt->BackwardOperator();
286 // Prolongate to HO space
287 direction = "LOR -> HO @ HO";
288 P.Mult(rho_lor, rho);
289 compute_mass(rho, lor_mass, "P(LOR) ", weight_coeff);
290 if (vis) { visualize(HO_dc, "P(LOR)", Wx, Wy, visport); Wx += offx; }
291
292 // Restrict back to LOR space. This won't give the original function because
293 // the rho_lor doesn't necessarily live in the range of R.
294 direction = "LOR -> HO @ LOR";
295 R.Mult(rho, rho_lor);
296 compute_mass(rho_lor, lor_mass, "R(P(LOR))", weight_coeff);
297 if (vis) { visualize(LOR_dc, "R(P(LOR))", Wx, Wy, visport); }
298
299 rho_lor_prev -= rho_lor;
300 cout.precision(12);
301 cout << "|LOR - R(P(LOR))|_∞ = " << rho_lor_prev.Normlinf() << endl;
302 }
303
304 // LOR* to HO* dual fields
305 if (!use_pointwise_transfer)
306 {
307 M_lor.Mult(rho_lor, M_rho_lor);
308 R.MultTranspose(M_rho_lor, M_rho);
309 cout << "LOR -> HO dual field: " << abs(M_rho.Sum() - M_rho_lor.Sum()) << '\n';
310 }
311
312 delete gt;
313 delete fec;
314 delete fec_lor;
315
316 return 0;
317}
318
319
321{
322 switch (problem)
323 {
324 case 1: // smooth field
325 return x(1)+0.25*cos(2*M_PI*x.Norml2());
326 case 2: // cubic function
327 return x(1)*x(1)*x(1) + 2*x(0)*x(1) + x(0);
328 case 3: // sharp gradient
329 return M_PI/2-atan(5*(2*x.Norml2()-1));
330 case 4: // basis function
331 return (x.Norml2() < 0.1) ? 1 : 0;
332 case 5: // positive function
333 return 2.0 + 2*x(0)*x(0) + 3*x(1)*x(1) - x(0)*x(1) + 0.1*sin(x.Norml2());
334 default:
335 return 1.0;
336 }
337}
338
339
341{
342 return x(1) + 0.25*cos(2*M_PI*x.Norml2());
343}
344
345
347{
348 return x(0)*x(0) + x(1)*x(1) + 1.0;
349}
350
351
352void visualize(VisItDataCollection &dc, string prefix, int x, int y,
353 int visport)
354{
355 int w = Ww, h = Wh;
356
357 char vishost[] = "localhost";
358
359 socketstream sol_sockL2(vishost, visport);
360 sol_sockL2.precision(8);
361 sol_sockL2 << "solution\n" << *dc.GetMesh() << *dc.GetField("density")
362 << "window_geometry " << x << " " << y << " " << w << " " << h
363 << "plot_caption '" << space << " " << prefix << " Density'"
364 << "window_title '" << direction << "'" << flush;
365}
366
367
368real_t compute_mass(GridFunction &gf, real_t oldmass, string prefix,
369 CoefficientWithOrder mass_coeff)
370{
371 FiniteElementSpace &fes = *gf.FESpace();
372 Mesh &mesh = *fes.GetMesh();
373
374 // Integration order is a * (element order) + b.
375 const int a = 2;
376 const int b = mesh.GetTypicalElementTransformation()->OrderW() +
377 mass_coeff.order;
378
379 ConstantCoefficient one(1.0);
380 Coefficient &coeff = mass_coeff ? *mass_coeff.coeff : one;
381 DomainLFIntegrator *integ = new DomainLFIntegrator(coeff, a, b);
382
383 LinearForm lf(&fes);
384 lf.AddDomainIntegrator(integ);
385 lf.Assemble();
386
387 const real_t newmass = lf(gf);
388 cout.precision(18);
389 cout << space << " " << prefix << " mass = " << newmass;
390 if (oldmass >= 0)
391 {
392 cout.precision(4);
393 cout << " (" << fabs(newmass-oldmass)*100/oldmass << "%)";
394 }
395 cout << endl;
396 return newmass;
397}
@ GaussLobatto
Closed type.
Definition fe_base.hpp:36
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator. Assumes ownership of bfi.
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY....
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication: .
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
A coefficient that is constant across space and time.
GridFunction * GetField(const std::string &field_name)
Get a pointer to a grid function in the collection.
Mesh * GetMesh()
Get a pointer to the mesh in the collection.
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:129
Class for domain integration .
Definition lininteg.hpp:108
virtual int OrderW() const =0
Return the order of the determinant of the Jacobian (weight) of the transformation.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:639
A general function coefficient.
Coefficient defined by a GridFunction. This coefficient is mesh dependent.
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
void SetTrueVector()
Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:187
void SetFromTrueVector()
Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:193
FiniteElementSpace * FESpace()
virtual void ProjectCoefficient(Coefficient &coeff, ProjectType type=ProjectType::DEFAULT)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Base class for transfer algorithms that construct transfer Operators between two finite element (FE) ...
Definition transfer.hpp:32
void UseEA(bool use_ea_)
Definition transfer.hpp:78
virtual bool SupportsBackwardsOperator() const
Definition transfer.hpp:117
virtual const Operator & ForwardOperator()=0
Return an Operator that transfers GridFunctions from the domain FE space to GridFunctions in the rang...
virtual const Operator & BackwardOperator()=0
Return an Operator that transfers GridFunctions from the range FE space back to GridFunctions in the ...
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:291
Transfer data between a coarse mesh and an embedded refined mesh using interpolation.
Definition transfer.hpp:139
Transfer data in L2 and H1 finite element spaces between a coarse mesh and an embedded refined mesh u...
Definition transfer.hpp:198
const Operator & BackwardOperator() override
Return an Operator that transfers GridFunctions from the range FE space back to GridFunctions in the ...
bool SupportsBackwardsOperator() const override
const Operator & ForwardOperator() override
Return an Operator that transfers GridFunctions from the domain FE space to GridFunctions in the rang...
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:369
Vector with associated FE space and LinearFormIntegrators.
void AddDomainIntegrator(LinearFormIntegrator *lfi)
Adds new Domain Integrator. Assumes ownership of lfi.
void Assemble()
Assembles the linear form i.e. sums over all domain/bdr integrators.
Mesh data type.
Definition mesh.hpp:67
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
ElementTransformation * GetTypicalElementTransformation()
If the local mesh is not empty return GetElementTransformation(0); otherwise, return the identity tra...
Definition mesh.cpp:394
static Mesh MakeRefined(Mesh &orig_mesh, int ref_factor, int ref_type)
Create a refined (by any factor) version of orig_mesh.
Definition mesh.cpp:4823
Abstract operator.
Definition operator.hpp:27
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
Definition operator.hpp:102
void ParseCheck(std::ostream &out=mfem::out)
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
Definition optparser.hpp:82
Scalar coefficient defined as the product of two scalar coefficients or a scalar and a scalar coeffic...
Vector data type.
Definition vector.hpp:82
real_t Normlinf() const
Returns the l_infinity norm of the vector.
Definition vector.cpp:1004
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:968
real_t Sum() const
Return the sum of the vector entries.
Definition vector.cpp:1246
Data collection with VisIt I/O routines.
void RegisterField(const std::string &field_name, GridFunction *gf) override
Add a grid function to the collection and update the root file.
int dim
Definition ex24.cpp:53
int main()
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
real_t weight(const Vector &x)
int Ww
real_t compute_mass(GridFunction &, real_t, string, CoefficientWithOrder)
void visualize(VisItDataCollection &, string, int, int, int visport=19916)
int Wy
int Wx
int problem
int offx
real_t W_exact(const Vector &x)
int Wh
string direction
real_t RHO_exact(const Vector &x)
string space
int offy
float real_t
Definition config.hpp:46
const char vishost[]
STL namespace.
MFEM_HOST_DEVICE real_t abs(const Complex &z)