MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
gridfunction-bounds.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// ---------------------------------------------------------------------
13// Compute bounds of the given grid-function
14// ---------------------------------------------------------------------
15//
16// This miniapp computes piecewise linear bounds on a given gridfunction, and
17// visualizes the lower and upper bound for each element. The bounding approach
18// is based on the method described in:
19//
20// (1) Section 3 of Mittal et al., "General Field Evaluation in High-Order
21// Meshes on GPUs"
22// and
23// (2) Dzanic et al., "A method for bounding high-order finite element
24// functions: Applications to mesh validity and bounds-preserving limiters".
25//
26//
27// Compile with: make gridfunction-bounds
28//
29// Sample runs:
30// mpirun -np 4 gridfunction-bounds
31// mpirun -np 4 gridfunction-bounds -nb 100 -ref 5 -bt 2 -l2
32
33#include "mfem.hpp"
34#include <memory>
35#include <iostream>
36#include <fstream>
37
38using namespace mfem;
39using namespace std;
40
41void VisualizeField(ParMesh &pmesh, ParGridFunction &input,
42 char *title, int pos_x, int pos_y);
43
44int main (int argc, char *argv[])
45{
46 // 0. Initialize MPI and HYPRE.
47 Mpi::Init(argc, argv);
49
50 // Set the method's default parameters.
51 const char *mesh_file = "../gslib/triple-pt-1.mesh";
52 const char *sltn_file = "../gslib/triple-pt-1.gf";
53 int ref = 2;
54 bool visualization = true;
55 bool visit = false;
56 int b_type = -1;
57 bool continuous = true;
58 int nbrute = 0;
59
60 // Parse command-line options.
61 OptionsParser args(argc, argv);
62 args.AddOption(&mesh_file, "-m", "--mesh",
63 "Mesh file to use.");
64 args.AddOption(&sltn_file, "-s", "--sltn",
65 "Solution file to use.");
66 args.AddOption(&ref, "-ref", "--piecewise-linear-ref-factor",
67 "Scaling factor for resolution of piecewise linear bounds."
68 " If less than 2, the resolution is picked automatically");
69 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
70 "--no-visualization",
71 "Enable or disable GLVis visualization.");
72 args.AddOption(&visit, "-visit", "--visit", "-no-visit",
73 "--no-visit",
74 "Enable or disable VisIt output.");
75 args.AddOption(&b_type, "-bt", "--basis-type",
76 "Project input function to a different bases. "
77 "-1 = don't project (default)."
78 "0 = Gauss-Legendre nodes. "
79 "1 = Gauss-Lobatto nodes. "
80 "2 = uniformly spaced nodes. ");
81 args.AddOption(&continuous, "-h1", "--h1", "-l2", "--l2",
82 "Use continuous or discontinuous space.");
83 args.AddOption(&nbrute, "-nb", "--nbrute",
84 "Brute force search for minimum in an array of nxnxn points "
85 "in each element.");
86 args.ParseCheck();
87
88 Mesh mesh(mesh_file, 1, 1, false);
89 const int dim = mesh.Dimension();
90 if (continuous && b_type != -1)
91 {
92 MFEM_VERIFY(b_type > 0, "Continuous space do not support GL nodes. "
93 "Please use basis type: 1 for Lagrange interpolants on GLL "
94 " nodes 2 for positive bases on uniformly spaced nodes.");
95 }
96
97 std::unique_ptr<int[]> partition(
99 );
100
101 ifstream mat_stream_1(sltn_file);
102 std::unique_ptr<GridFunction> func(new GridFunction(&mesh, mat_stream_1));
103
104 ParMesh pmesh(MPI_COMM_WORLD, mesh, partition.get());
105 ParGridFunction pfunc(&pmesh, func.get(), partition.get());
106 int func_order = func->FESpace()->GetMaxElementOrder();
107 int vdim = pfunc.FESpace()->GetVDim();
108 int nel = pmesh.GetNE();
109
110 func.reset();
111 mesh.Clear();
112 partition.reset();
113
114 // Project input function based on user input
115 ParGridFunction *pfunc_proj = NULL;
116 if (b_type >= 0)
117 {
118 FiniteElementCollection *fec = NULL;
119 if (continuous)
120 {
121 fec = new H1_FECollection(func_order, dim, b_type);
122 }
123 else
124 {
125 fec = new L2_FECollection(func_order, dim, b_type);
126 }
127 int ordering = pfunc.FESpace()->GetOrdering();
128 ParFiniteElementSpace *fes = new ParFiniteElementSpace(&pmesh, fec,
129 vdim, ordering);
130 pfunc_proj = new ParGridFunction(fes);
131 pfunc_proj->MakeOwner(fec);
132 pfunc_proj->ProjectGridFunction(pfunc);
133 if (Mpi::Root())
134 {
135 cout << "fec name orig: " << pfunc.FESpace()->FEColl()->Name() <<
136 endl;
137 cout << "fec name: " << fec->Name() << endl;
138 }
139 }
140 else
141 {
142 pfunc_proj = &pfunc;
143 if (Mpi::Root())
144 {
145 cout << "fec name: " << pfunc.FESpace()->FEColl()->Name() << endl;
146 }
147 }
148
149 L2_FECollection fec_pc(0, dim);
150 ParFiniteElementSpace fes_pc(&pmesh, &fec_pc, vdim, Ordering::byNODES);
151 ParGridFunction lowerb(&fes_pc), upperb(&fes_pc);
152
153 // Compute bounds
154 pfunc_proj->GetElementBounds(lowerb, upperb, ref);
155
156 Vector bound_min(vdim), bound_max(vdim);
157 for (int d = 0; d < vdim; d++)
158 {
159 Vector lowerT(lowerb.GetData() + d*nel, nel);
160 Vector upperT(upperb.GetData() + d*nel, nel);
161 bound_min(d) = lowerT.Min();
162 bound_max(d) = upperT.Max();
163 }
164
165 MPI_Allreduce(MPI_IN_PLACE, bound_min.GetData(), vdim,
166 MPITypeMap<real_t>::mpi_type, MPI_MIN, pmesh.GetComm());
167 MPI_Allreduce(MPI_IN_PLACE, bound_max.GetData(), vdim,
168 MPITypeMap<real_t>::mpi_type, MPI_MAX, pmesh.GetComm());
169
170 // GLVis Visualization
171 if (visualization)
172 {
173 char title1[] = "Input gridfunction";
174 VisualizeField(pmesh, pfunc, title1, 0, 0);
175 if (b_type >= 0)
176 {
177 char title1p[] = "Projected gridfunction";
178 VisualizeField(pmesh, *pfunc_proj, title1p, 0, 400);
179 }
180 char title2[] = "Element-wise lower bound";
181 VisualizeField(pmesh, lowerb, title2, 400, 0);
182 char title3[] = "Element-wise upper bound";
183 VisualizeField(pmesh, upperb, title3, 800, 0);
184 }
185
186 // Visit Visualization
187 if (visit)
188 {
189 VisItDataCollection visit_dc("jacobian-determinant-bounds", &pmesh);
191 visit_dc.RegisterField("input-function", &pfunc);
192 if (b_type >= 0)
193 {
194 visit_dc.RegisterField("projected-function", pfunc_proj);
195 }
196 visit_dc.RegisterField("lower-bound", &lowerb);
197 visit_dc.RegisterField("upper-bound", &upperb);
198 visit_dc.Save();
199 }
200
201 if (nbrute > 0)
202 {
203 Vector global_min(vdim), global_max(vdim);
204 global_min = numeric_limits<real_t>::max();
205 global_max = numeric_limits<real_t>::min();
206 // search for the minimum value of pfunc_proj in each element at
207 // an array of integration points
208 for (int e = 0; e < pmesh.GetNE(); e++)
209 {
211 for (int k = 0; k < (dim > 2 ? nbrute : 1); k++)
212 {
213 ip.z = k/(nbrute-1.0);
214 for (int j = 0; j < (dim > 1 ? nbrute : 1); j++)
215 {
216 ip.y = j/(nbrute-1.0);
217 for (int i = 0; i < nbrute; i++)
218 {
219 ip.x = i/(nbrute-1.0);
220 for (int d = 0; d < vdim; d++)
221 {
222 real_t val = pfunc_proj->GetValue(e, ip, d+1);
223 global_min(d) = min(global_min(d), val);
224 global_max(d) = max(global_max(d), val);
225 }
226 }
227 }
228 }
229 }
230
231 MPI_Allreduce(MPI_IN_PLACE, global_min.GetData(), vdim,
232 MPITypeMap<real_t>::mpi_type, MPI_MIN, pmesh.GetComm());
233 MPI_Allreduce(MPI_IN_PLACE, global_max.GetData(), vdim,
234 MPITypeMap<real_t>::mpi_type, MPI_MAX, pmesh.GetComm());
235 if (Mpi::Root())
236 {
237 for (int d = 0; d < vdim; d++)
238 {
239 cout << "Brute force and bounding comparison for component " <<
240 d << endl;
241 cout << "Brute force minimum and minimum bound: " << global_min(d)
242 << " " << bound_min(d) << endl;
243
244 cout << "Brute force maximum and maximum bound: " << global_max(d)
245 << " " << bound_max(d) << endl;
246
247 cout << "The difference in bounds is: " <<
248 global_min(d)-bound_min(d) << " " <<
249 bound_max(d)-global_max(d) << endl;
250 }
251 }
252 }
253
254 if (nbrute == 0 && Mpi::Root())
255 {
256 for (int d = 0; d < vdim; d++)
257 {
258 cout << "Minimum bound for component " << d << " is " <<
259 bound_min(d) << endl;
260 cout << "Maximum bound for component " << d << " is " <<
261 bound_max(d) << endl;
262 }
263 }
264
265 if (b_type >= 0)
266 {
267 delete pfunc_proj;
268 }
269 return 0;
270}
271
273 char *title, int pos_x, int pos_y)
274{
275 socketstream sock;
276 if (pmesh.GetMyRank() == 0)
277 {
278 sock.open("localhost", 19916);
279 sock << "solution\n";
280 }
281 pmesh.PrintAsOne(sock);
282 input.SaveAsOne(sock);
283 if (pmesh.GetMyRank() == 0)
284 {
285 sock << "window_title '"<< title << "'\n"
286 << "window_geometry "
287 << pos_x << " " << pos_y << " " << 400 << " " << 400 << "\n"
288 << "keys jRmclApppppppppppp//]]]]]]]]" << endl;
289 }
290}
virtual void SetFormat(int fmt)
Set the desired output mesh and data format.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
virtual const char * Name() const
Definition fe_coll.hpp:79
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:854
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:856
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:819
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:32
PLBound GetElementBounds(Vector &lower, Vector &upper, const int ref_factor=1, const int vdim=-1) const
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec_owned and fes.
Definition gridfunc.hpp:123
FiniteElementSpace * FESpace()
void ProjectGridFunction(const GridFunction &src)
Project the src GridFunction to this GridFunction, both of which must be on the same mesh.
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:279
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.cpp:33
Class for integration point with weight.
Definition intrules.hpp:35
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:350
Mesh data type.
Definition mesh.hpp:65
void Clear()
Clear the contents of the Mesh.
Definition mesh.hpp:827
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
int * GeneratePartitioning(int nparts, int part_method=1)
Definition mesh.cpp:8749
static bool Root()
Return true if the rank in MPI_COMM_WORLD is zero.
static int WorldSize()
Return the size of MPI_COMM_WORLD.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
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
Abstract parallel finite element space.
Definition pfespace.hpp:31
Class for parallel grid function.
Definition pgridfunc.hpp:50
real_t GetValue(int i, const IntegrationPoint &ip, int vdim=1) const override
void SaveAsOne(const char *fname, int precision=16) const
Class for parallel meshes.
Definition pmesh.hpp:34
MPI_Comm GetComm() const
Definition pmesh.hpp:405
int GetMyRank() const
Definition pmesh.hpp:407
void PrintAsOne(std::ostream &out=mfem::out, const std::string &comments="") const
Definition pmesh.cpp:4994
Vector data type.
Definition vector.hpp:82
real_t Max() const
Returns the maximal element of the vector.
Definition vector.cpp:1200
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
real_t Min() const
Returns the minimal element of the vector.
Definition vector.cpp:1154
Data collection with VisIt I/O routines.
void Save() override
Save the collection and a VisIt root file.
void RegisterField(const std::string &field_name, GridFunction *gf) override
Add a grid function to the collection and update the root file.
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
int dim
Definition ex24.cpp:53
double func_order
Definition findpts.cpp:73
int main()
void VisualizeField(socketstream &sock, const char *vishost, int visport, GridFunction &gf, const char *title, int x, int y, int w, int h, const char *keys, bool vec)
float real_t
Definition config.hpp:46
Helper struct to convert a C++ type to an MPI type.