https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ParameterMeshOptimization.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
11
12#include "AddVariableAction.h"
13#include "ParameterMesh.h"
14#include "OptUtils.h"
15#include "libmesh/string_to_enum.h"
16
17#include "ReadExodusMeshVars.h"
18
19using namespace libMesh;
20
22
25{
27
29 "Computes objective function, gradient and contains reporters for communicating between "
30 "optimizeSolve and subapps using mesh-based parameter definition.");
31
32 params.addRequiredParam<std::vector<FileName>>(
33 "parameter_meshes", "Exodus file containing meshes describing parameters.");
34
36 MultiMooseEnum families(family.getRawNames(), "LAGRANGE");
38 "parameter_families",
39 families,
40 "Specifies the family of FE shape functions for each group of parameters. If a single value "
41 "is "
42 "specified, then that value is used for all groups of parameters.");
44 MultiMooseEnum orders(order.getRawNames(), "FIRST");
46 "parameter_orders",
47 orders,
48 "Specifies the order of FE shape functions for each group of parameters. If a single value "
49 "is "
50 "specified, then that value is used for all groups of parameters.");
51
52 params.addParam<unsigned int>(
53 "num_parameter_times", 1, "The number of time points the parameters represent.");
54
55 params.addParam<std::vector<std::string>>(
56 "initial_condition_mesh_variable",
57 "Name of variable on parameter mesh to use as initial condition.");
58 params.addParam<std::vector<std::string>>(
59 "lower_bound_mesh_variable", "Name of variable on parameter mesh to use as lower bound.");
60 params.addParam<std::vector<std::string>>(
61 "upper_bound_mesh_variable", "Name of variable on parameter mesh to use as upper bound.");
62 params.addParam<std::vector<unsigned int>>(
63 "exodus_timesteps_for_parameter_mesh_variable",
64 "Timesteps to read all parameter group bounds and initial conditions from Exodus mesh. The "
65 "options are to give no timestep, a single timestep or \"num_parameter_times\" timesteps. "
66 "No timestep results in the final timestep from the mesh being used. A single timestep "
67 "results in values at that timestep being used for all timesteps. \"num_parameter_times\" "
68 "timesteps results in values from the mesh at those steps being used. The same timesteps "
69 "are used for all parameter groups and all meshes, the capability to define different "
70 "timesteps for different meshes is not supported.");
71
72 // New parameters for multiple regularization types
73 MultiMooseEnum reg_types("L2_GRADIENT");
75 "regularization_types",
76 reg_types,
77 "Types of regularization to apply. Multiple types can be specified.");
78
79 params.addParam<std::vector<Real>>("regularization_coeffs",
80 {},
81 "Coefficients for each regularization type. Must match the "
82 "number of regularization_types specified.");
83
84 params.addParamNamesToGroup("tikhonov_coeff regularization_types regularization_coeffs",
85 "Regularization");
86
87 return params;
88}
89
91 : GeneralOptimization(parameters),
92 _regularization_coeffs(getParam<std::vector<Real>>("regularization_coeffs")),
93 _regularization_types(getParam<MultiMooseEnum>("regularization_types")
94 .getSetValueIDs<ParameterMesh::RegularizationType>())
95{
96 // Validate that regularization coefficients match types
98 paramError("regularization_coeffs",
99 "Number of regularization coefficients (",
101 ") must match number of regularization types (",
103 ")");
104}
105
106std::vector<Real>
108 const FileName mesh_file_name,
109 const std::vector<unsigned int> & exodus_timestep,
110 const std::string & mesh_var_name) const
111{
112 // read data off Exodus mesh
113 ReadExodusMeshVars data_mesh(fetype, mesh_file_name, mesh_var_name);
114 std::vector<Real> parsed_data;
115 // read from mesh
116 for (auto const & step : exodus_timestep)
117 {
118 std::vector<Real> data = data_mesh.getParameterValues(step);
119 parsed_data.insert(parsed_data.end(), data.begin(), data.end());
120 }
121
122 return parsed_data;
123}
124
125void
127{
128 if ((isParamValid("num_values_name") || isParamValid("num_values")))
129 paramError("num_values_name or num_values should not be used with ParameterMeshOptimization. "
130 "Instead the number of dofs is set by the parameter meshes.");
131
132 _nvalues.resize(_nparams, 0);
133 // Fill the mesh information
134 const auto & meshes = getParam<std::vector<FileName>>("parameter_meshes");
135 const auto & families = getParam<MultiMooseEnum>("parameter_families");
136 const auto & orders = getParam<MultiMooseEnum>("parameter_orders");
137 const auto & ntimes = getParam<unsigned int>("num_parameter_times");
138
139 // Fill exodus parameter bounds and IC information
140 std::vector<std::string> initial_condition_mesh_variable;
141 std::vector<std::string> lower_bound_mesh_variable;
142 std::vector<std::string> upper_bound_mesh_variable;
143 if (isParamValid("initial_condition_mesh_variable"))
144 initial_condition_mesh_variable =
145 getParam<std::vector<std::string>>("initial_condition_mesh_variable");
146 if (isParamValid("lower_bound_mesh_variable"))
147 lower_bound_mesh_variable = getParam<std::vector<std::string>>("lower_bound_mesh_variable");
148 if (isParamValid("upper_bound_mesh_variable"))
149 upper_bound_mesh_variable = getParam<std::vector<std::string>>("upper_bound_mesh_variable");
150
151 std::vector<unsigned int> exodus_timestep;
152 if (isParamValid("exodus_timesteps_for_parameter_mesh_variable"))
153 exodus_timestep =
154 getParam<std::vector<unsigned int>>("exodus_timesteps_for_parameter_mesh_variable");
155 else // get last timestep in file
156 exodus_timestep = {std::numeric_limits<unsigned int>::max()};
157
158 // now do a bunch of error checking
159 // Size checks for data
160 if (meshes.size() != _nparams)
161 paramError("parameter_meshes",
162 "There must be a mesh associated with each group of parameters.");
163 if (families.size() > 1 && families.size() != _nparams)
164 paramError("parameter_families",
165 "There must be a family associated with each group of parameters.");
166 if (orders.size() > 1 && orders.size() != _nparams)
167 paramError("parameter_orders",
168 "There must be an order associated with each group of parameters.");
169
170 // error checking that initial conditions and bounds are only read from a single location
171 if (isParamValid("initial_condition_mesh_variable") && isParamValid("initial_condition"))
172 paramError("initial_condition_mesh_variable",
173 "Initial conditions for all parameter groups can only be defined by "
174 "initial_condition_mesh_variable or "
175 "initial_condition but not both.");
176 else if (isParamValid("lower_bound_mesh_variable") && isParamValid("lower_bounds"))
178 "lower_bound_mesh_variable",
179 "Lower bounds for all parameter groups can only be defined by lower_bound_mesh_variable or "
180 "lower_bounds but not both.");
181 else if (isParamValid("upper_bound_mesh_variable") && isParamValid("upper_bounds"))
183 "upper_bound_mesh_variable",
184 "Upper bounds for all parameter groups can only be defined by upper_bound_mesh_variable or "
185 "upper_bounds but not both.");
186
187 // Make sure they did not specify too many timesteps
188 if (isParamValid("exodus_timesteps_for_parameter_mesh_variable") &&
189 (!isParamValid("lower_bound_mesh_variable") + !isParamValid("upper_bound_mesh_variable") +
190 !isParamValid("initial_condition_mesh_variable") ==
191 3))
192 paramError("\"exodus_timesteps_for_parameter_mesh_variable\" should only be specified if "
193 "reading values from a mesh.");
194 else if (exodus_timestep.size() != ntimes && exodus_timestep.size() != 1)
195 paramError("exodus_timesteps_for_parameter_mesh_variable",
196 "Number of timesteps to read mesh data specified by "
197 "\"exodus_timesteps_for_parameter_mesh_variable\" incorrect. "
198 "\"exodus_timesteps_for_parameter_mesh_variable\" can specify a single timestep or "
199 "\"num_parameter_times\" timesteps.");
200
201 _ndof = 0;
203 for (const auto & param_id : make_range(_nparams))
204 {
205 const std::string family = families.size() > 1 ? families[param_id] : families[0];
206 const std::string order = orders.size() > 1 ? orders[param_id] : orders[0];
207 const FEType fetype(Utility::string_to_enum<Order>(order),
208 Utility::string_to_enum<FEFamily>(family));
209
210 _parameter_meshes[param_id] = std::make_unique<ParameterMesh>(fetype, meshes[param_id]);
211 _nvalues[param_id] = _parameter_meshes[param_id]->size() * ntimes;
212 _ndof += _nvalues[param_id];
213
214 // read and assign initial conditions
215 {
216 std::vector<Real> initial_condition;
217 if (isParamValid("initial_condition_mesh_variable"))
219 fetype, meshes[param_id], exodus_timestep, initial_condition_mesh_variable[param_id]);
220 else
221 initial_condition = parseInputData("initial_condition", 0, param_id);
222
223 _parameters[param_id]->assign(initial_condition.begin(), initial_condition.end());
224 }
225
226 // read and assign lower bound
227 {
228 std::vector<Real> lower_bound;
229 if (isParamValid("lower_bound_mesh_variable"))
230 lower_bound = parseExodusData(
231 fetype, meshes[param_id], exodus_timestep, lower_bound_mesh_variable[param_id]);
232 else
233 lower_bound = parseInputData("lower_bounds", std::numeric_limits<Real>::lowest(), param_id);
234
235 _lower_bounds.insert(_lower_bounds.end(), lower_bound.begin(), lower_bound.end());
236 }
237
238 // read and assign upper bound
239 {
240 std::vector<Real> upper_bound;
241 if (isParamValid("upper_bound_mesh_variable"))
242 upper_bound = parseExodusData(
243 fetype, meshes[param_id], exodus_timestep, upper_bound_mesh_variable[param_id]);
244 else
245 upper_bound = parseInputData("upper_bounds", std::numeric_limits<Real>::max(), param_id);
246
247 _upper_bounds.insert(_upper_bounds.end(), upper_bound.begin(), upper_bound.end());
248 }
249
250 // resize gradient vector to be filled later
251 _gradients[param_id]->resize(_nvalues[param_id]);
252 }
253}
254
255Real
257{
259
260 // Apply each regularization type with its coefficient
261 for (const auto reg_idx : index_range(_regularization_types))
262 {
263 if (_regularization_coeffs[reg_idx] > 0.0)
264 {
265 Real regularization_value = 0.0;
266
267 // Convert MultiMooseEnum to RegularizationType using get() method
269
270 for (const auto & param_id : make_range(_nparams))
271 {
272 // Get current parameter values for this group
273 const auto & param_values = *_parameters[param_id];
274
275 // Compute regularization objective for this type
276 regularization_value +=
277 _parameter_meshes[param_id]->computeRegularizationObjective(param_values, reg_type);
278 }
279
280 val += _regularization_coeffs[reg_idx] * regularization_value;
281 }
282 }
283
284 return val;
285}
286
287void
289{
290 // Add regularization gradient contributions to the reporter gradients before base computation
291 for (const auto reg_idx : index_range(_regularization_types))
292 {
293 if (_regularization_coeffs[reg_idx] > 0.0)
294 {
295 // Convert MultiMooseEnum to RegularizationType using get() method
297
298 for (const auto & param_id : make_range(_nparams))
299 {
300 // Get current parameter values for this group
301 const auto & param_values = *_parameters[param_id];
302 auto grad_values = _gradients[param_id];
303
304 // Compute regularization gradient for this type
305 std::vector<Real> reg_grad =
306 _parameter_meshes[param_id]->computeRegularizationGradient(param_values, reg_type);
307
308 // Add to gradient with coefficient
309 for (unsigned int i = 0; i < param_values.size(); ++i)
310 (*grad_values)[i] += _regularization_coeffs[reg_idx] * reg_grad[i];
311 }
312 }
313 }
314
315 // Now call base class method which includes Tikhonov and copies to PETSc vector
317}
registerMooseObject("OptimizationApp", ParameterMeshOptimization)
static MooseEnum getNonlinearVariableFamilies()
static MooseEnum getNonlinearVariableOrders()
Optimization reporter that interfaces with TAO.
virtual Real computeObjective() override
Function to compute objective.
static InputParameters validParams()
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void paramError(const std::string &param, Args... args) const
const T & getParam(const std::string &name) const
bool isParamValid(const std::string &name) const
std::string getRawNames() const
std::vector< Real > parseInputData(std::string type, Real default_value, unsigned int param_id) const
Function to to parse bounds and initial conditions from input file.
const unsigned int _nparams
Number of parameter vectors.
std::vector< std::vector< Real > * > _gradients
Gradient values declared as reporter data.
virtual void computeGradient(libMesh::PetscVector< Number > &gradient) const
Function to compute gradient.
std::vector< Real > _lower_bounds
Bounds of the parameters.
dof_id_type _ndof
Total number of parameters.
std::vector< std::vector< Real > * > _parameters
Parameter values declared as reporter data.
std::vector< dof_id_type > _nvalues
Number of values for each parameter.
Mesh-based parameter optimization.
const std::vector< Real > _regularization_coeffs
Vector of regularization coefficients corresponding to each type.
ParameterMeshOptimization(const InputParameters &parameters)
const std::vector< ParameterMesh::RegularizationType > _regularization_types
Regularization types to apply.
std::vector< Real > parseExodusData(const FEType fetype, const FileName mesh_file_name, const std::vector< unsigned int > &exodus_timestep, const std::string &mesh_var_name) const
Read initialization data off of parameter mesh and error check.
virtual void setICsandBounds() override
Sets the initial conditions and bounds right before it is needed.
std::vector< std::unique_ptr< ParameterMesh > > _parameter_meshes
Store parameter meshes for regularization computation.
virtual Real computeObjective() override
Function to compute objective.
static InputParameters validParams()
virtual void computeGradient(libMesh::PetscVector< Number > &gradient) const override
Function to compute gradient.
Utility class to use an Exodus mesh to define controllable parameters for optimization problems This ...
RegularizationType
Enumerations for regularization computations.
Utility function to read a single variable off an Exodus mesh for optimization problem This class wil...
std::vector< Real > getParameterValues(const unsigned int timestep) const
Initializes parameter data and sets bounds in the main optmiization application getParameterValues is...
The following methods are specializations for using the Parallel::packed_range_* routines for a vecto...
auto index_range(const T &sizable)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
Number initial_condition(const Point &p, const Parameters &parameters, const std::string &, const std::string &)