libMesh
Loading...
Searching...
No Matches
calculator.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19// Open the input mesh and corresponding solution file named in command line
20// arguments, parse the function specified in a command line argument,
21// Project its value onto the mesh, and output the new solution.
22
23
24// libMesh includes
25#include "L2system.h"
26#include "libmesh/libmesh.h"
27#include "libmesh/dof_map.h"
28#include "libmesh/enum_norm_type.h"
29#include "libmesh/equation_systems.h"
30#include "libmesh/getpot.h"
31#include "libmesh/mesh.h"
32#include "libmesh/mesh_tools.h"
33#include "libmesh/newton_solver.h"
34#include "libmesh/numeric_vector.h"
35#include "libmesh/parsed_fem_function.h"
36#include "libmesh/parsed_function.h"
37#include "libmesh/point.h"
38#include "libmesh/sparse_matrix.h"
39#include "libmesh/steady_solver.h"
40#include "libmesh/wrapped_functor.h"
41#include "libmesh/elem.h"
42#include "libmesh/parallel_implementation.h"
43#include "libmesh/string_to_enum.h"
44
45// For error integration
46#include "libmesh/error_vector.h"
47#include "libmesh/exact_solution.h"
48#include "libmesh/discontinuity_measure.h"
49#include "libmesh/kelly_error_estimator.h"
50#include "libmesh/fourth_error_estimators.h"
51
52// C++ includes
53#include <memory>
54#include <string>
55
56
57using namespace libMesh;
58
59
60// If there's a missing input argument, then print a help message
61void usage_error(const char * progname)
62{
63 libMesh::out << "Options: " << progname << '\n'
64 << " --dim d mesh dimension [default: autodetect]\n"
65 << " --inmesh filename input mesh file\n"
66 << " --inmat filename input constraint matrix [default: none]\n"
67 << " --mattol filename constraint tolerance when testing mesh connectivity\n"
68 << " [default: 0]\n"
69 << " --insoln filename input solution file\n"
70 << " --calc func function to calculate\n"
71 << " --insys sysnum input system number [default: 0]\n"
72 << " --outsoln filename output solution file [default: out_<insoln>]\n"
73 << " --family famname output FEM family [default: LAGRANGE]\n"
74 << " --order p output FEM order [default: 1]\n"
75 << " --subdomain \"sbd_ids\" each subdomain to check [default: all subdomains]\n"
76 << " --hilbert order Hilbert space to project in [default: 0 => H0]\n"
77 << " --fdm_eps eps Central diff for dfunc/dx [default: " << TOLERANCE << "]\n"
78 << " --error_q extra_q integrate projection error, with adjusted\n"
79 << " (extra) quadrature order [default: off, suggested: 0]\n"
80 << " --jump_error order calculate jump error indicator, for specified\n"
81 << " Hilbert order [default: off]\n"
82 << " --jump_slits calculate jumps across slits [default: off]\n"
83 << " --integral only calculate func integral, not projection\n"
84 << std::endl;
85
86 exit(1);
87}
88
89// Get an input argument, or print a help message if it's missing
90template <typename T>
91T assert_argument (const std::string & argname,
92 const char * progname,
93 const T & defaultarg)
94{
95 if (!libMesh::on_command_line(argname))
96 {
97 libMesh::err << ("No " + argname + " argument found!") << std::endl;
98 usage_error(progname);
99 }
100 return libMesh::command_line_next(argname, defaultarg);
101}
102
103
104struct Integrate {
105 Integrate (const System & sys,
106 const FEMFunctionBase<Number> & f) :
107 _sys(sys), _f(f.clone()), _integral(0) {}
108
110 _sys(other._sys), _f(other._f->clone()), _integral(0) {}
111
112 void operator() (const ConstElemRange & range) {
113 FEMContext context(_sys);
114
115 FEBase * elem_fe = nullptr;
116 context.get_element_fe(0, elem_fe);
117
118 const std::vector<Real> & JxW = elem_fe->get_JxW();
119 const std::vector<Point> & xyz = elem_fe->get_xyz();
120
121 _f->init_context(context);
122
123 // If _f didn't need anything, that wasn't a fluke
124 elem_fe->get_nothing();
125
126 // We only integrate on the highest dimensional elements in the
127 // mesh, lest we be adding apples to oranges
128 const unsigned int mesh_dim = _sys.get_mesh().mesh_dimension();
129
130 for (const auto & elem : range)
131 {
132 if (elem->dim() < mesh_dim)
133 continue;
134
135 context.pre_fe_reinit(_sys, elem);
136 context.elem_fe_reinit();
137
138 for (auto qp : index_range(JxW))
139 {
140 const Number output = (*_f)(context, xyz[qp]);
141
142 _integral += output * JxW[qp];
143 }
144 }
145 }
146
147 void join (const Integrate & other)
148 {
149 _integral += other._integral;
150 }
151
152 Number integral () const { return _integral; }
153
154private:
155 const System & _sys;
156
157 std::unique_ptr<FEMFunctionBase<Number>> _f;
158
160};
161
162
163int main(int argc, char ** argv)
164{
165 LibMeshInit init(argc, argv);
166
167 // In case the mesh file doesn't let us auto-infer dimension, we let
168 // the user specify it on the command line
169 const unsigned char requested_dim =
170 cast_int<unsigned char>(libMesh::command_line_next("--dim", 3));
171
172 // Load the old mesh from --inmesh filename.
173 // Keep it serialized; we don't want elements on the new mesh to be
174 // looking for data on old mesh elements that live off-processor.
175 Mesh old_mesh(init.comm(), requested_dim);
176
177 const std::string meshname =
178 assert_argument("--inmesh", argv[0], std::string(""));
179
180 libMesh::out << "Reading mesh " << meshname << std::endl;
181 old_mesh.read(meshname);
182
183 const std::string matname =
184 libMesh::command_line_next("--inmat", std::string(""));
185
186 if (matname != "")
187 {
188 libMesh::out << "Reading matrix " << matname << std::endl;
189
190 // For extraction matrices Coreform has been experimenting with
191 // PETSc solvers which take the transpose of what we expect, so
192 // we'll un-transpose here.
193 auto matrix = SparseMatrix<Number>::build (old_mesh.comm());
194 matrix->read(matname);
195 matrix->get_transpose(*matrix);
196
197 old_mesh.copy_constraint_rows(*matrix);
198 }
199
200 libMesh::out << "Mesh:" << std::endl;
201 old_mesh.print_info();
202
203 // If we're not using a distributed mesh, this is cheap info to add
204 if (old_mesh.is_serial_on_zero())
205 {
206 const Real mat_tol =
207 libMesh::command_line_next("--mattol", Real(0));
208
209 const dof_id_type n_components =
210 MeshTools::n_connected_components(old_mesh, mat_tol);
211 libMesh::out << "Mesh has " << n_components << " connected components." << std::endl;
212 }
213
214 const std::string solnname =
215 libMesh::command_line_next("--insoln", std::string(""));
216
217 // Load the old solution from --insoln filename, if that's been
218 // specified.
219 EquationSystems old_es(old_mesh);
220 std::string current_sys_name = "new_sys";
221
222 const std::string calcfunc =
223 assert_argument("--calc", argv[0], std::string(""));
224
225 const std::string family =
226 libMesh::command_line_next("--family", std::string("LAGRANGE"));
227
228 const unsigned int order = libMesh::command_line_next("--order", 1u);
229
230 std::unique_ptr<FEMFunctionBase<Number>> goal_function;
231
232 if (solnname != "")
233 {
234 libMesh::out << "Reading solution " << solnname << std::endl;
235
236 old_es.read(solnname,
241
242 old_es.print_info();
243
244 const unsigned int sysnum =
245 libMesh::command_line_next("--insys", 0);
246
247 libmesh_assert_less(sysnum, old_es.n_systems());
248
249 System & old_sys = old_es.get_system(sysnum);
250
251 current_sys_name = old_sys.name();
252
253 goal_function =
254 std::make_unique<ParsedFEMFunction<Number>>(old_sys, calcfunc);
255 }
256 else
257 {
258 current_sys_name = "bare_sys";
259
260 // FEMContext doesn't like seeing systems with no variables
261 System & dummy_sys = old_es.add_system<System>(current_sys_name);
262
263 // And if we're using an IsoGeometric Analysis mesh, we'd better
264 // make sure the user can specify order and family to make it
265 // iso.
266 dummy_sys.add_variable("dummy", static_cast<Order>(order),
267 Utility::string_to_enum<FEFamily>(family));
268
269 old_es.init();
270
271 old_es.print_info();
272
273 goal_function =
274 std::make_unique<WrappedFunctor<Number>>(ParsedFunction<Number>(calcfunc));
275 }
276
277 libMesh::out << "Calculating with system " << current_sys_name << std::endl;
278
279 // Subdomains to integrate on
280 std::vector<libMesh::subdomain_id_type> subdomain_vec;
281 libMesh::command_line_vector("--subdomain", subdomain_vec);
282 std::set<libMesh::subdomain_id_type> subdomains_list(subdomain_vec.begin(),
283 subdomain_vec.end());
284
285 std::string default_outsolnname = "out_soln.xda";
286 if (solnname != "")
287 default_outsolnname = "out_"+solnname;
288 const std::string outsolnname =
289 libMesh::command_line_next("--outsoln", default_outsolnname);
290
291 // Output results in high precision
292 libMesh::out << std::setprecision(std::numeric_limits<Real>::max_digits10);
293
294 if (!libMesh::on_command_line("--integral"))
295 {
296 // Create a new mesh and a new EquationSystems
297 Mesh new_mesh(init.comm(), requested_dim);
298 new_mesh.read(meshname);
299
300 EquationSystems new_es(new_mesh);
301
303
304 new_sys.hilbert_order() = libMesh::command_line_next("--hilbert", 0u);
305
306 new_sys.subdomains_list() = std::move(subdomains_list);
307
308 new_sys.time_solver =
309 std::make_unique<SteadySolver>(new_sys);
310
311 new_sys.fe_family() = family;
312 new_sys.fe_order() = order;
313
314 new_sys.set_goal_func(*goal_function);
315
316 const Real fdm_eps = libMesh::command_line_next("--fdm_eps", Real(TOLERANCE));
317
318 new_sys.set_fdm_eps(fdm_eps);
319
320 if (solnname != "")
321 new_sys.input_system = &old_es.get_system(current_sys_name);
322
323 new_es.init();
324
325 DiffSolver & solver = *(new_sys.time_solver->diff_solver().get());
326 solver.quiet = false;
327 solver.verbose = true;
328 solver.relative_step_tolerance = 1e-10;
329
330 new_sys.solve();
331
332 // Integrate the error if requested
333 if (libMesh::on_command_line("--error_q"))
334 {
335 const unsigned int error_q =
336 libMesh::command_line_next("--error_q", 0u);
337
338 // We just add "u" now but maybe we'll change that
339 for (auto v : make_range(new_sys.n_vars()))
340 {
341 ExactSolution exact_sol(new_es);
342 exact_sol.attach_exact_value(0, goal_function.get());
343 FDMGradient<Gradient> fdm_gradient(*goal_function, fdm_eps);
344 exact_sol.attach_exact_deriv(0, &fdm_gradient);
345 exact_sol.extra_quadrature_order(error_q);
346
347 const std::string var_name = new_sys.variable_name(v);
348 exact_sol.compute_error(current_sys_name, var_name);
349
350 libMesh::out << "L2 norm of " << var_name << ": " <<
351 new_sys.calculate_norm(*new_sys.solution, v, L2) <<
352 std::endl;
353
354 libMesh::out << "L2 error in " << var_name << ": " <<
355 exact_sol.l2_error(current_sys_name, var_name) <<
356 std::endl;
357
358 if (new_sys.hilbert_order() > 0)
359 {
360 libMesh::out << "H1 norm of " << var_name << ": " <<
361 new_sys.calculate_norm(*new_sys.solution, v, H1) <<
362 std::endl;
363
364 libMesh::out << "H1 error in " << var_name << ": " <<
365 exact_sol.h1_error(current_sys_name, var_name) <<
366 std::endl;
367 }
368 }
369 }
370
371 // Calculate the jump error indicator if requested
372 if (libMesh::on_command_line("--jump_error"))
373 {
374 const unsigned int jump_error_hilbert =
375 libMesh::command_line_next("--jump_error", 0u);
376
377 for (auto v : make_range(new_sys.n_vars()))
378 {
379 std::unique_ptr<JumpErrorEstimator> error_estimator;
380 SystemNorm error_norm;
381 error_norm.set_weight(0,0);
382 error_norm.set_weight(v+1,0);
383 error_norm.set_weight(v,1.0);
384
385 if (jump_error_hilbert == 0)
386 {
387 error_estimator = std::make_unique<DiscontinuityMeasure>();
388 error_norm.set_type(v, L2);
389 }
390 else if (jump_error_hilbert == 1)
391 {
392 error_estimator = std::make_unique<KellyErrorEstimator>();
393 error_norm.set_type(v, H1_SEMINORM);
394 }
395 else if (jump_error_hilbert == 2)
396 {
397 error_estimator = std::make_unique<LaplacianErrorEstimator>();
398 error_norm.set_type(v, H2_SEMINORM);
399 }
400 else
401 libmesh_not_implemented();
402
403 if (libMesh::on_command_line("--jump_slits"))
404 error_estimator->integrate_slits = true;
405
406 ErrorVector error_per_cell;
407 error_estimator->error_norm = error_norm;
408 error_estimator->estimate_error(new_sys, error_per_cell);
409
410 const std::string var_name = new_sys.variable_name(v);
411
412 // I really want to just stop supporting libstdc++-8.
413 // const Real total_error = std::reduce(error_per_cell.begin(), error_per_cell.end());
414
415 ErrorVectorReal total_error = 0;
416 for (auto cell_error : error_per_cell)
417 total_error += cell_error;
418
419 if (jump_error_hilbert == 0)
420 libMesh::out << "L2";
421 else
422 libMesh::out << "H" << jump_error_hilbert;
423
424 libMesh::out << " error estimate for " << var_name << ": " <<
425 total_error << std::endl;
426 }
427 }
428
429 // Write out the new solution file
430 new_es.write(outsolnname.c_str(),
433 libMesh::out << "Wrote solution " << outsolnname << std::endl;
434 }
435 else
436 {
437 // If we aren't doing a projection, then we just do an integral
438 System & old_sys = old_es.get_system<System>(current_sys_name);
439
440 ConstElemRange active_local_elem_range
441 (old_mesh.active_local_elements_begin(),
442 old_mesh.active_local_elements_end());
443
444 Integrate integrate(old_sys, *goal_function);
445
446 Threads::parallel_reduce (active_local_elem_range,
447 integrate);
448
449 Number integral = integrate.integral();
450 old_mesh.comm().sum(integral);
451 libMesh::out << "Integral is " << integral << std::endl;
452 }
453
454 return 0;
455}
void usage_error(const char *progname)
Definition calculator.C:61
T assert_argument(const std::string &argname, const char *progname, const T &defaultarg)
Definition calculator.C:91
std::set< libMesh::subdomain_id_type > & subdomains_list()
Definition L2system.h:51
libMesh::System * input_system
Definition L2system.h:71
void set_fdm_eps(libMesh::Real eps)
Definition L2system.h:54
void set_goal_func(libMesh::FEMFunctionBase< libMesh::Number > &goal)
Definition L2system.h:60
unsigned int & fe_order()
Definition L2system.h:50
std::string & fe_family()
Definition L2system.h:49
unsigned int & hilbert_order()
Definition L2system.h:53
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition diff_solver.h:70
bool verbose
The DiffSolver may print a lot more to libMesh::out if verbose is set to true; default is false.
bool quiet
The DiffSolver should not print anything to libMesh::out unless quiet is set to false; default is tru...
std::unique_ptr< TimeSolver > time_solver
A pointer to the solver object we're going to use.
virtual bool is_serial_on_zero() const override final
This is the EquationSystems class.
void print_info(std::ostream &os=libMesh::out) const
Prints information about the equation systems, by default to libMesh::out.
void write(std::string_view name, const XdrMODE, const unsigned int write_flags=(WRITE_DATA), bool partition_agnostic=true) const
Write the systems to disk using the XDR data format.
unsigned int n_systems() const
void read(std::string_view name, const XdrMODE, const unsigned int read_flags=(READ_HEADER|READ_DATA), bool partition_agnostic=true)
Read & initialize the systems from disk using the XDR data format.
virtual void init()
Initialize all the systems.
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
const T_sys & get_system(std::string_view name) const
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
Real l2_error(std::string_view sys_name, std::string_view unknown_name)
Real h1_error(std::string_view sys_name, std::string_view unknown_name)
void attach_exact_deriv(unsigned int sys_num, FunctionBase< Gradient > *g)
Clone and attach an arbitrary functor which computes the exact gradient of the system sys_num solutio...
void attach_exact_value(unsigned int sys_num, FunctionBase< Number > *f)
Clone and attach an arbitrary functor which computes the exact value of the system sys_num solution a...
void compute_error(std::string_view sys_name, std::string_view unknown_name)
Computes and stores the error in the solution value e = u-u_h, the gradient grad(e) = grad(u) - grad(...
void extra_quadrature_order(const int extraorder)
Increases or decreases the order of the quadrature rule used for numerical integration.
void get_nothing() const
virtual_for_inffe const std::vector< Real > & get_JxW() const
virtual_for_inffe const std::vector< Point > & get_xyz() const
This class forms the foundation from which generic finite elements may be derived.
Definition fe_base.h:86
This class provides all data required for a physics package (e.g.
Definition fem_context.h:63
virtual void pre_fe_reinit(const System &, const Elem *e)
Reinitializes local data vectors/matrices on the current geometric element.
virtual void elem_fe_reinit(const std::vector< Point > *const pts=nullptr)
Reinitializes interior FE objects on the current geometric element.
void get_element_fe(unsigned int var, FEGenericBase< OutputShape > *&fe) const
Accessor for interior finite element object for variable var for the largest dimension in the mesh.
FEMFunctionBase is a base class from which users can derive in order to define "function-like" object...
virtual void solve() override
Invokes the solver associated with the system.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
unsigned int mesh_dimension() const
Definition mesh_base.C:430
void copy_constraint_rows(const MeshBase &other_mesh)
Copy the constraints from the other mesh to this mesh.
Definition mesh_base.C:2490
void print_info(std::ostream &os=libMesh::out, const unsigned int verbosity=0, const bool global=true) const
Prints relevant information about the mesh.
Definition mesh_base.C:1755
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
const Parallel::Communicator & comm() const
A Function generated (via FParser) by parsing a mathematical expression.
static std::unique_ptr< SparseMatrix< T > > build(const Parallel::Communicator &comm, const SolverPackage solver_package=libMesh::default_solver_package(), const MatrixBuildType matrix_build_type=MatrixBuildType::AUTOMATIC)
Builds a SparseMatrix<T> using the linear solver package specified by solver_package.
The StoredRange class defines a contiguous, divisible set of objects.
This class defines a norm/seminorm to be applied to a NumericVector which contains coefficients in a ...
Definition system_norm.h:50
void set_type(unsigned int var, const FEMNormType &t)
Sets the type of the norm in variable var, as well as for any unset variables with index less than va...
void set_weight(unsigned int var, Real w)
Sets the weight corresponding to the norm in variable var, as well as for any unset variables with in...
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition system.h:100
const std::string & name() const
Definition system.h:2385
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition system.C:1344
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition system.h:1655
const std::string & variable_name(const unsigned int i) const
Definition system.C:2679
Real calculate_norm(const NumericVector< Number > &v, unsigned int var, FEMNormType norm_type, std::set< unsigned int > *skip_dimensions=nullptr) const
Definition system.C:1511
unsigned int n_vars() const
Definition system.C:2674
const MeshBase & get_mesh() const
Definition system.h:2401
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false, bool skip_detect_interior_parents=false) override
Reads the file specified by name.
dof_id_type n_connected_components(const MeshBase &mesh, Real constraint_tol=0)
Definition mesh_tools.C:864
void parallel_reduce(const Range &range, Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided reduction operation in parallel on the specified range.
The libMesh namespace provides an interface to certain functionality in the library.
OStreamProxy err
DIE A HORRIBLE DEATH HERE typedef float ErrorVectorReal
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
void command_line_vector(const std::string &, std::vector< T > &)
Definition libmesh.C:1044
OStreamProxy out
T command_line_next(std::string name, T default_value)
Use GetPot's search()/next() functions to get following arguments from the command line.
Definition libmesh.C:1025
static constexpr Real TOLERANCE
uint8_t dof_id_type
Definition id_types.h:67
bool on_command_line(std::string arg)
Definition libmesh.C:934
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176
std::string current_sys_name
Definition projection.C:77
Integrate(Integrate &other, Threads::split)
Definition calculator.C:109
std::unique_ptr< FEMFunctionBase< Number > > _f
Definition calculator.C:157
Number integral() const
Definition calculator.C:152
const System & _sys
Definition calculator.C:155
void operator()(const ConstElemRange &range)
Definition calculator.C:112
Number _integral
Definition calculator.C:159
Integrate(const System &sys, const FEMFunctionBase< Number > &f)
Definition calculator.C:105
void join(const Integrate &other)
Definition calculator.C:147
int main()