Loading [MathJax]/extensions/tex2jax.js
libMesh
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
calculator.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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 
57 using namespace libMesh;
58 
59 
60 // If there's a missing input argument, then print a help message
61 void 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
90 template <typename T>
91 T 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 
104 struct 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 
154 private:
155  const System & _sys;
156 
157  std::unique_ptr<FEMFunctionBase<Number>> _f;
158 
160 };
161 
162 
163 int 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 << "L2 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  libMesh::out << "H" << jump_error_hilbert << " error estimate for " << var_name << ": " <<
420  total_error << std::endl;
421  }
422  }
423 
424  // Write out the new solution file
425  new_es.write(outsolnname.c_str(),
428  libMesh::out << "Wrote solution " << outsolnname << std::endl;
429  }
430  else
431  {
432  // If we aren't doing a projection, then we just do an integral
433  System & old_sys = old_es.get_system<System>(current_sys_name);
434 
435  ConstElemRange active_local_elem_range
436  (old_mesh.active_local_elements_begin(),
437  old_mesh.active_local_elements_end());
438 
439  Integrate integrate(old_sys, *goal_function);
440 
441  Threads::parallel_reduce (active_local_elem_range,
442  integrate);
443 
444  Number integral = integrate.integral();
445  old_mesh.comm().sum(integral);
446  libMesh::out << "Integral is " << integral << std::endl;
447  }
448 
449  return 0;
450 }
OStreamProxy err
This class handles the computation of the L2 and/or H1 error for the Systems in the EquationSystems o...
T command_line_next(std::string name, T default_value)
Use GetPot&#39;s search()/next() functions to get following arguments from the command line...
Definition: libmesh.C:1072
std::set< libMesh::subdomain_id_type > & subdomains_list()
Definition: L2system.h:51
This is the EquationSystems class.
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
virtual void pre_fe_reinit(const System &, const Elem *e)
Reinitializes local data vectors/matrices on the current geometric element.
Definition: fem_context.C:1683
A Function generated (via FParser) by parsing a mathematical expression.
bool quiet
The DiffSolver should not print anything to libMesh::out unless quiet is set to false; default is tru...
Definition: diff_solver.h:160
static constexpr Real TOLERANCE
void join(const Integrate &other)
Definition: calculator.C:147
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
Definition: error_vector.h:50
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
Definition: threads_none.h:63
std::unique_ptr< TimeSolver > time_solver
A pointer to the solver object we&#39;re going to use.
Definition: diff_system.h:253
void print_info(std::ostream &os=libMesh::out) const
Prints information about the equation systems, by default to libMesh::out.
void extra_quadrature_order(const int extraorder)
Increases or decreases the order of the quadrature rule used for numerical integration.
This class defines a norm/seminorm to be applied to a NumericVector which contains coefficients in a ...
Definition: system_norm.h:49
The StoredRange class defines a contiguous, divisible set of objects.
Definition: stored_range.h:54
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:90
The libMesh namespace provides an interface to certain functionality in the library.
const T_sys & get_system(std::string_view name) const
DIE A HORRIBLE DEATH HERE typedef float ErrorVectorReal
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.
virtual void elem_fe_reinit(const std::vector< Point > *const pts=nullptr)
Reinitializes interior FE objects on the current geometric element.
Definition: fem_context.C:1477
This is a generic class that defines a solver to handle ImplicitSystem classes, including NonlinearIm...
Definition: diff_solver.h:68
void set_goal_func(libMesh::FEMFunctionBase< libMesh::Number > &goal)
Definition: L2system.h:60
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...
Definition: system_norm.C:142
T assert_argument(const std::string &argname, const char *progname, const T &defaultarg)
Definition: calculator.C:91
Integrate(const System &sys, const FEMFunctionBase< Number > &f)
Definition: calculator.C:105
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:96
Integrate(Integrate &other, Threads::split)
Definition: calculator.C:109
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(...
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
Definition: system.h:1599
Real calculate_norm(const NumericVector< Number > &v, unsigned int var, FEMNormType norm_type, std::set< unsigned int > *skip_dimensions=nullptr) const
Definition: system.C:1702
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
virtual_for_inffe const std::vector< Real > & get_JxW() const
Definition: fe_abstract.h:303
This class provides all data required for a physics package (e.g.
Definition: fem_context.h:62
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.
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:1335
const std::string & variable_name(const unsigned int i) const
Definition: system.h:2474
std::string & fe_family()
Definition: L2system.h:49
virtual_for_inffe const std::vector< Point > & get_xyz() const
Definition: fe_abstract.h:280
Real l2_error(std::string_view sys_name, std::string_view unknown_name)
Number _integral
Definition: calculator.C:159
void get_nothing() const
Definition: fe_abstract.h:269
unsigned int & fe_order()
Definition: L2system.h:50
Number integral() const
Definition: calculator.C:152
dof_id_type n_connected_components(const MeshBase &mesh, Real constraint_tol=0)
Definition: mesh_tools.C:840
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...
bool verbose
The DiffSolver may print a lot more to libMesh::out if verbose is set to true; default is false...
Definition: diff_solver.h:166
const System & _sys
Definition: calculator.C:155
unsigned int & hilbert_order()
Definition: L2system.h:53
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
libMesh::System * input_system
Definition: L2system.h:71
std::string current_sys_name
Definition: projection.C:76
void command_line_vector(const std::string &, std::vector< T > &)
Definition: libmesh.C:1091
OStreamProxy out
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:140
void parallel_reduce(const Range &range, Body &body)
Execute the provided reduction operation in parallel on the specified range.
Definition: threads_none.h:101
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...
Definition: fem_context.h:277
virtual void solve() override
Invokes the solver associated with the system.
Definition: fem_system.C:1076
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...
bool on_command_line(std::string arg)
Definition: libmesh.C:981
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...
Definition: system_norm.C:123
virtual void init()
Initialize all the systems.
unsigned int n_vars() const
Definition: system.h:2426
std::unique_ptr< FEMFunctionBase< Number > > _f
Definition: calculator.C:157
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false) override
Reads the file specified by name.
int main(int argc, char **argv)
Definition: calculator.C:163
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.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
Real h1_error(std::string_view sys_name, std::string_view unknown_name)
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:117
This class forms the foundation from which generic finite elements may be derived.
void set_fdm_eps(libMesh::Real eps)
Definition: L2system.h:54
uint8_t dof_id_type
Definition: id_types.h:67
void usage_error(const char *progname)
Definition: calculator.C:61