libMesh
Loading...
Searching...
No Matches
reduced_basis_ex4.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// rbOOmit: An implementation of the Certified Reduced Basis method.
19// Copyright (C) 2009, 2010 David J. Knezevic
20// This file is part of rbOOmit.
21
22
23
24// <h1>Reduced Basis Example 4 - Empirical Interpolation Method</h1>
25// \author David Knezevic
26// \date 2011
27//
28// In this example problem we develop a reduced basis approximation
29// for a parametrized PDE that has "non-affine" parameter
30// dependence. This requires the use of the Empirical Interpolation
31// Method (EIM).
32//
33// We first use EIM to construct an affine approximation to the
34// non-affine term, which is a parametrized function that is a
35// Gaussian with "center" defined by the two parameters (mu_1, mu_2)
36// \in [-1,1]^2. We then employ this EIM approximation in order to
37// generate a reduced basis approximation for the parametrized PDE:
38// -0.05 * Laplacian(u) = f(mu_1, mu_2), with zero Dirichlet boundary
39// conditions.
40
41// Basic include file needed for the mesh functionality.
42#include "libmesh/libmesh.h"
43#include "libmesh/mesh.h"
44#include "libmesh/mesh_generation.h"
45#include "libmesh/equation_systems.h"
46#include "libmesh/exodusII_io.h"
47#include "libmesh/getpot.h"
48#include "libmesh/rb_data_serialization.h"
49#include "libmesh/rb_data_deserialization.h"
50#include "libmesh/enum_solver_package.h"
51
52#include "eim_classes.h"
53#include "rb_classes.h"
54
55using namespace libMesh;
56
57
58int main (int argc, char ** argv)
59{
60 // Initialize libMesh.
61 LibMeshInit init (argc, argv);
62
63 // This example requires a linear solver package.
64 libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE,
65 "--enable-petsc, --enable-trilinos, or --enable-eigen");
66
67#if !defined(LIBMESH_HAVE_XDR)
68 // We need XDR support to write out reduced bases
69 libmesh_example_requires(false, "--enable-xdr");
70#elif defined(LIBMESH_DEFAULT_SINGLE_PRECISION)
71 // XDR binary support requires double precision
72 libmesh_example_requires(false, "double precision");
73#elif defined(LIBMESH_DEFAULT_TRIPLE_PRECISION)
74 // I have no idea why long double isn't working here... [RHS]
75 libmesh_example_requires(false, "double precision");
76#endif
77
78 // Skip this 2D example if libMesh was compiled as 1D-only.
79 libmesh_example_requires(2 <= LIBMESH_DIM, "2D support");
80
81 // This example requires libmesh to be configured with both
82 // DirichletBoundary and Cap'n Proto support.
83#if !defined(LIBMESH_ENABLE_DIRICHLET) || !defined(LIBMESH_HAVE_CAPNPROTO)
84 libmesh_example_requires(false, "--enable-dirichlet --enable-capnp");
85#else
86
87 // Define the names of the input files we will read the problem properties from
88 std::string eim_parameters = "eim.in";
89 std::string rb_parameters = "rb.in";
90 std::string main_parameters = "reduced_basis_ex4.in";
91 GetPot infile(main_parameters);
92
93 unsigned int n_elem = infile("n_elem", 1); // Determines the number of elements in the "truth" mesh
94 const unsigned int dim = 2; // The number of spatial dimensions
95
96 // Read the "online_mode" flag from the command line
97 const int online_mode =
98 libMesh::command_line_next("-online_mode", 0),
99 eim_training_function_to_plot =
100 libMesh::command_line_next("-eim_training_function_to_plot", 0),
101 eim_basis_function_to_plot =
102 libMesh::command_line_next("-eim_basis_function_to_plot", 0);
103
104 ReplicatedMesh mesh (init.comm(), dim);
106 n_elem, n_elem,
107 -1., 1.,
108 -1., 1.,
109 QUAD4);
110
111 // Set to true the write binary (XDR) files with EIM data, false to write ASCII files.
112 bool eim_binary_io = true;
113
114 if (!online_mode)
115 {
116 // First run the Offline stage for the EIM approximation.
117 {
118 libMesh::out << "Perform EIM training" << std::endl << std::endl;
119
120 // Initialize the EquationSystems object for this mesh and attach
121 // the EIM and RB Construction objects
122 EquationSystems equation_systems (mesh);
123
124 SimpleEIMConstruction & eim_construction =
125 equation_systems.add_system<SimpleEIMConstruction> ("EIM");
126
127 // Initialize the data structures for the equation system.
128 equation_systems.init ();
129
130 // Print out some information about the "truth" discretization
132 equation_systems.print_info();
133
134 // Initialize the EIM RBEvaluation object
135 SimpleEIMEvaluation eim_rb_eval(mesh.comm());
136
137 // Set the rb_eval objects for the RBConstructions
138 eim_construction.set_rb_eim_evaluation(eim_rb_eval);
139
140 // Read data from input file and print state
141 eim_construction.process_parameters_file(eim_parameters);
142 eim_construction.print_info();
143
144 // Perform the EIM Greedy and write out the data
145 eim_construction.initialize_eim_construction();
146 eim_construction.train_eim_approximation();
147
148 RBDataSerialization::RBEIMEvaluationSerialization rb_eim_eval_writer(eim_rb_eval);
149 rb_eim_eval_writer.write_to_file("rb_eim_eval.bin");
150
151 // Write out the EIM basis functions
152 eim_rb_eval.write_out_basis_functions("eim_data", eim_binary_io);
153 }
154
155 {
156 libMesh::out << std::endl << "Perform RB training" << std::endl << std::endl;
157
158 // Initialize the EquationSystems object for this mesh and attach
159 // the EIM and RB Construction objects
160 EquationSystems equation_systems (mesh);
161
162 SimpleEIMConstruction & eim_construction =
163 equation_systems.add_system<SimpleEIMConstruction> ("EIM");
164 SimpleRBConstruction & rb_construction =
165 equation_systems.add_system<SimpleRBConstruction> ("RB");
166
167 // Initialize the data structures for the equation system.
168 equation_systems.init ();
169
170 // Print out some information about the "truth" discretization
172 equation_systems.print_info();
173
174 // Initialize the standard RBEvaluation object
175 SimpleRBEvaluation rb_eval(mesh.comm());
176
177 // Initialize the EIM RBEvaluation object
178 SimpleEIMEvaluation eim_rb_eval(mesh.comm());
179
180 // Set the rb_eval objects for the RBConstructions
181 eim_construction.set_rb_eim_evaluation(eim_rb_eval);
182 rb_construction.set_rb_evaluation(rb_eval);
183
184 RBDataDeserialization::RBEIMEvaluationDeserialization rb_eim_eval_reader(eim_rb_eval);
185 rb_eim_eval_reader.read_from_file("rb_eim_eval.bin");
186 eim_rb_eval.read_in_basis_functions(rb_construction, "eim_data", eim_binary_io);
187
188 // Read data from input file and print state
189 rb_construction.process_parameters_file(rb_parameters);
190
191 // attach the EIM theta objects to the RBConstruction and RBEvaluation objects
192 eim_rb_eval.initialize_eim_theta_objects();
193 rb_eval.get_rb_theta_expansion().attach_multiple_F_theta(eim_rb_eval.get_eim_theta_objects());
194
195 // attach the EIM assembly objects to the RBConstruction object
196 eim_construction.initialize_eim_assembly_objects();
197 rb_construction.get_rb_assembly_expansion().attach_multiple_F_assembly(eim_construction.get_eim_assembly_objects());
198
199 // Print out the state of rb_construction now that the EIM objects have been attached
200 rb_construction.print_info();
201
202 // Need to initialize _after_ EIM greedy so that
203 // the system knows how many affine terms there are
204 rb_construction.initialize_rb_construction();
205 rb_construction.train_reduced_basis();
206
207 RBDataSerialization::RBEvaluationSerialization rb_eval_writer(rb_construction.get_rb_evaluation());
208 rb_eval_writer.write_to_file("rb_eval.bin");
209
210 rb_construction.get_rb_evaluation().write_out_basis_functions(rb_construction,
211 "rb_data");
212 }
213 }
214 else // online mode
215 {
216 SimpleEIMEvaluation eim_rb_eval(mesh.comm());
217 SimpleRBEvaluation rb_eval(mesh.comm());
218
219 RBDataDeserialization::RBEIMEvaluationDeserialization rb_eim_eval_reader(eim_rb_eval);
220 rb_eim_eval_reader.read_from_file("rb_eim_eval.bin");
221
222 // attach the EIM theta objects to rb_eval objects
223 eim_rb_eval.initialize_eim_theta_objects();
224 rb_eval.get_rb_theta_expansion().attach_multiple_F_theta(eim_rb_eval.get_eim_theta_objects());
225
226 // Read in the offline data for rb_eval
228 rb_eval_reader.read_from_file("rb_eval.bin", /*read_error_bound_data*/ true);
229
230 // Get the parameters at which we will do a reduced basis solve
231 Real online_center_x = infile("online_center_x", 0.);
232 Real online_center_y = infile("online_center_y", 0.);
233 RBParameters online_mu;
234 online_mu.push_back_value("center_x", online_center_x);
235 online_mu.push_back_value("center_y", online_center_y);
236
237 // Testing: Add secondary center_x and center_y values,
238 // corresponding to e.g. a different time step or load step.
239 online_mu.push_back_value("center_x", 0.5);
240 online_mu.push_back_value("center_y", 0.5);
241
242 // Add 3rd (center_x, center_y) values. For debugging purposes,
243 // we want the number of "samples" (3) to be different from the
244 // number of parameters (2).
245 online_mu.push_back_value("center_x", -0.25);
246 online_mu.push_back_value("center_y", -0.25);
247
248 // Here we are going to pre-evaluate the thetas and pass them in
249 // to rb_solve() in a loop. Note that the rb_solve doesn't
250 // explicitly need the parameters ("mus"), it just needs the
251 // evaluated functions of parameters ("thetas"), but we can
252 // perform an rb_solve() with either.
253 rb_eval.set_parameters(online_mu);
254 rb_eval.print_parameters();
255
256 // When performing an rb_solve() with "mu" values, we only
257 // support single-valued RBParameters objects. In this case,
258 // since the RBParameters object stores multiple "samples", we
259 // take the approach of pre-evaluating the thetas for each
260 // parameter while calling the rb_solve() in a loop.
261 const RBThetaExpansion & rb_theta_expansion = rb_eval.get_rb_theta_expansion();
262
263 // Single-entry vector which makes calling the vector-overrides
264 // of eval_A_theta(), eval_F_theta(), etc. easier.
265 std::vector<RBParameters> mu_vec = {online_mu};
266
267 // 1.) Evaluate and store "A" thetas at all samples:
268 std::vector<std::vector<Number>> all_A(rb_theta_expansion.get_n_A_terms());
269 for (unsigned int q_a=0; q_a<rb_theta_expansion.get_n_A_terms(); q_a++)
270 {
271 // Here we call the version of eval_A_theta() taking a
272 // vector, so we evaluate theta(mu) at all samples
273 // simultaneously.
274 all_A[q_a] = rb_theta_expansion.eval_A_theta(q_a, mu_vec);
275
276 // This size of each A_q vector here is:
277 // sum_i mu_vec[i].n_samples()
278 //
279 // Each A_q vector contains the logically 2D ragged array of
280 // values (theta[i], sample[j(i)]), arranged in "row-major"
281 // format, where the number of samples defined by each mu
282 // object can vary, and they are all concatenated together
283 // to produce one long list of samples.
284 //
285 // Example: suppose that there are 2 mu values containing
286 // the same sets of parameters, with 5 samples defined in the
287 // first and 10 samples defined in the second. Then, the A_q
288 // vector will look like:
289 //
290 // {Theta(mu_vec[0], sample_0), Theta(mu_vec[0], sample_1), ... Theta(mu_vec[0], sample_4),
291 // Theta(mu_vec[1], sample_0), Theta(mu_vec[1], sample_1), ... Theta(mu_vec[1], sample_4), ..., Theta(mu_vec[1], sample_9)}
292 //
293 // Note: this example is unusual in that it would be
294 // conceptually much simpler to have either:
295 // (i) A vector of 15 single-sample RBParameters objects, or
296 // (ii) A single RBParameters object with 15 samples defined in it.
297 // but we can also support a combination of approaches (i)
298 // and (ii) by concatenation, if necessary.
299 }
300
301 // 2.) Evaluate "F" thetas at all samples:
302 std::vector<std::vector<Number>> all_F(rb_theta_expansion.get_n_F_terms());
303 for (unsigned int q_f=0; q_f<rb_theta_expansion.get_n_F_terms(); q_f++)
304 all_F[q_f] = rb_theta_expansion.eval_F_theta(q_f, mu_vec);
305
306 // The eval_F_theta() calls above use "EIM solves" from eim_rb_eval, hence we
307 // can now print out the EIM error indicator values.
308 const auto & eim_error_indicators =
309 eim_rb_eval.get_rb_eim_error_indicators();
310
311 libMesh::out << std::scientific;
312 for (auto idx : index_range(eim_error_indicators))
313 libMesh::out << "EIM (error indicator, normalization factor) for step "
314 << idx << ": "
315 << "(" << eim_error_indicators[idx].first
316 << ", " << eim_error_indicators[idx].second
317 << ")" << std::endl;
318 libMesh::out << std::endl;
319
320 // 3.) Evaluate "output" thetas at all samples: in this case, the
321 // output is particularly simple (does not depend on mu) so this
322 // should just be a vector of all 1s.
323 std::vector<std::vector<Number>> all_outputs(rb_theta_expansion.get_total_n_output_terms());
324 {
325 unsigned int output_counter = 0;
326 for (unsigned int n=0; n<rb_theta_expansion.get_n_outputs(); n++)
327 for (unsigned int q_l=0; q_l<rb_theta_expansion.get_n_output_terms(n); q_l++)
328 all_outputs[output_counter++] =
329 rb_theta_expansion.eval_output_theta(n, q_l, mu_vec);
330 }
331
332 // The total number of thetas is the sum of the "A", "F", and
333 // "output" thetas.
334 unsigned int n_thetas =
335 rb_theta_expansion.get_n_A_terms() +
336 rb_theta_expansion.get_n_F_terms() +
337 rb_theta_expansion.get_total_n_output_terms();
338
339 // Allocate enough space to store all the evaluated theta values for this RBThetaExpansion
340 std::vector<Number> evaluated_thetas(n_thetas);
341
342 // The RBConstruction object is used for plotting reduced-basis solutions (visualization)
343 EquationSystems equation_systems (mesh);
344
345 SimpleRBConstruction & rb_construction =
346 equation_systems.add_system<SimpleRBConstruction> ("RB");
347
348 equation_systems.init ();
349
350 // Tell the RBConstruction object about the RBEvaluation object
351 // and read in the RB basis functions.
352 rb_construction.set_rb_evaluation(rb_eval);
353 rb_eval.read_in_basis_functions(rb_construction, "rb_data");
354
355 // Loop over each sample, fill the evaluated_thetas array, call rb_solve()
356 for (unsigned sample_idx=0; sample_idx<online_mu.n_samples(); ++sample_idx)
357 {
358 unsigned int counter = 0;
359
360 // Set A Theta values for current sample
361 for (unsigned int q_a=0; q_a<rb_theta_expansion.get_n_A_terms(); q_a++)
362 evaluated_thetas[counter++] = all_A[q_a][sample_idx];
363
364 // Set F Theta values for current sample
365 for (unsigned int q_f=0; q_f<rb_theta_expansion.get_n_F_terms(); q_f++)
366 evaluated_thetas[counter++] = all_F[q_f][sample_idx];
367
368 // Set output Theta values for current sample
369 {
370 unsigned int output_counter = 0;
371 for (unsigned int n=0; n<rb_theta_expansion.get_n_outputs(); n++)
372 for (unsigned int q_l=0; q_l<rb_theta_expansion.get_n_output_terms(n); q_l++)
373 evaluated_thetas[counter++] = all_outputs[output_counter++][sample_idx];
374 }
375
376 // Call rb_solve() for the current thetas
377 libMesh::out << "Performing solve for step " << sample_idx << std::endl;
378 rb_eval.rb_solve(rb_eval.get_n_basis_functions(), &evaluated_thetas);
379
380 // Print the output as well as the corresponding output error bound
381 for (auto i : index_range(rb_eval.RB_outputs))
382 libMesh::out << "Output value " << i << " = " << rb_eval.RB_outputs[i]
383 << ", error bound " << i << " = " << rb_eval.RB_output_error_bounds[i]
384 << std::endl;
385
386 // Write an exo file to visualize this solution
387 rb_construction.load_rb_solution();
388#ifdef LIBMESH_HAVE_EXODUS_API
389 ExodusII_IO(mesh).write_equation_systems("RB_sol_" + std::to_string(sample_idx) + ".e", equation_systems);
390#endif
391 } // end for (sample)
392 }
393
394#endif // LIBMESH_ENABLE_DIRICHLET
395}
unsigned int dim
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.
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.
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition exodusII_io.h:53
virtual void write_equation_systems(const std::string &fname, const EquationSystems &es, const std::set< std::string > *system_names=nullptr) override
Writes out the solution for no specific time or timestep.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
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
const Parallel::Communicator & comm() const
void set_rb_evaluation(RBEvaluation &rb_eval_in)
Set the RBEvaluation object.
virtual void load_rb_solution()
Load the RB solution from the most recent solve with rb_eval into this system's solution vector.
This class de-serializes a RBEIMEvaluation object using the Cap'n Proto library.
void read_from_file(const std::string &path, bool use_packing=false)
Read the Cap'n'Proto buffer from disk.
This class de-serializes an RBEvaluation object using the Cap'n Proto library.
void read_from_file(const std::string &path, bool read_error_bound_data, bool use_packing=false)
Read the Cap'n'Proto buffer from disk.
This class serializes an RBEIMEvaluation object using the Cap'n Proto library.
void write_to_file(const std::string &path, bool use_packing=false)
Write the Cap'n'Proto buffer to disk.
This class serializes an RBEvaluation object using the Cap'n Proto library.
void write_to_file(const std::string &path, bool use_packing=false)
Write the Cap'n'Proto buffer to disk.
void initialize_eim_construction()
Perform initialization of this object to prepare for running train_eim_approximation().
std::vector< std::unique_ptr< ElemAssembly > > & get_eim_assembly_objects()
virtual void initialize_eim_assembly_objects()
Build a vector of ElemAssembly objects that accesses the basis functions stored in this RBEIMConstruc...
void set_rb_eim_evaluation(RBEIMEvaluation &rb_eim_eval_in)
Set the RBEIMEvaluation object.
virtual Real train_eim_approximation()
Generate the EIM approximation for the specified parametrized function using either POD or the Greedy...
virtual void print_info()
Print out info that describes the current setup of this RBConstruction.
virtual void process_parameters_file(const std::string &parameters_filename)
Read parameters in from file and set up this system accordingly.
std::vector< Real > RB_output_error_bounds
virtual Real rb_solve(unsigned int N)
Perform online solve with the N RB basis functions, for the set of parameters in current_params,...
virtual unsigned int get_n_basis_functions() const
Get the current number of basis functions.
RBThetaExpansion & get_rb_theta_expansion()
Get a reference to the rb_theta_expansion.
std::vector< Number > RB_outputs
The vectors storing the RB output values and corresponding error bounds.
virtual void read_in_basis_functions(System &sys, const std::string &directory_name="offline_data", const bool read_binary_basis_functions=true)
Read in all the basis functions from file.
This class is part of the rbOOmit framework.
void push_back_value(const std::string &param_name, Real value)
Similar to set_value(name, index, value) but instead of specifying a particular index,...
unsigned int n_samples() const
Returns the number of samples stored for all parameters.
bool set_parameters(const RBParameters &params)
Set the current parameters to params The parameters are checked for validity; an error is thrown if t...
void print_parameters() const
Print the current parameters.
This class stores the set of RBTheta functor objects that define the "parameter-dependent expansion" ...
virtual Number eval_F_theta(unsigned int q, const RBParameters &mu) const
Evaluate theta_q_f at the current parameter.
unsigned int get_total_n_output_terms() const
Returns the total number of affine terms associated with all outputs.
unsigned int get_n_F_terms() const
Get Q_f, the number of terms in the affine expansion for the right-hand side.
unsigned int get_n_A_terms() const
Get Q_a, the number of terms in the affine expansion for the bilinear form.
virtual Number eval_A_theta(unsigned int q, const RBParameters &mu) const
Evaluate theta_q_a at the current parameter.
unsigned int get_n_output_terms(unsigned int output_index) const
Get the number of affine terms associated with the specified output.
unsigned int get_n_outputs() const
Get n_outputs, the number output functionals.
virtual void attach_multiple_F_theta(std::vector< std::unique_ptr< RBTheta > > &theta_q_f)
Attach a vector of pointers to functor objects that each define one of the theta_q_f terms.
virtual Number eval_output_theta(unsigned int output_index, unsigned int q_l, const RBParameters &mu) const
Evaluate theta_q_l at the current parameter.
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
MeshBase & mesh
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
The libMesh namespace provides an interface to certain functionality in the library.
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
SolverPackage default_solver_package()
Definition libmesh.C:1064
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
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
int main()