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
20
23{
25
27 "Computes objective function, gradient and contains reporters for communicating between "
28 "optimizeSolve and subapps using mesh-based parameter definition.");
29
30 params.addRequiredParam<std::vector<FileName>>(
31 "parameter_meshes", "Exodus file containing meshes describing parameters.");
32
34 MultiMooseEnum families(family.getRawNames(), "LAGRANGE");
36 "parameter_families",
37 families,
38 "Specifies the family of FE shape functions for each group of parameters. If a single value "
39 "is "
40 "specified, then that value is used for all groups of parameters.");
42 MultiMooseEnum orders(order.getRawNames(), "FIRST");
44 "parameter_orders",
45 orders,
46 "Specifies the order of FE shape functions for each group of parameters. If a single value "
47 "is "
48 "specified, then that value is used for all groups of parameters.");
49
50 params.addParam<unsigned int>(
51 "num_parameter_times", 1, "The number of time points the parameters represent.");
52
53 params.addParam<std::vector<std::string>>(
54 "initial_condition_mesh_variable",
55 "Name of variable on parameter mesh to use as initial condition.");
56 params.addParam<std::vector<std::string>>(
57 "lower_bound_mesh_variable", "Name of variable on parameter mesh to use as lower bound.");
58 params.addParam<std::vector<std::string>>(
59 "upper_bound_mesh_variable", "Name of variable on parameter mesh to use as upper bound.");
60 params.addParam<std::vector<unsigned int>>(
61 "exodus_timesteps_for_parameter_mesh_variable",
62 "Timesteps to read all parameter group bounds and initial conditions from Exodus mesh. The "
63 "options are to give no timestep, a single timestep or \"num_parameter_times\" timesteps. "
64 "No timestep results in the final timestep from the mesh being used. A single timestep "
65 "results in values at that timestep being used for all timesteps. \"num_parameter_times\" "
66 "timesteps results in values from the mesh at those steps being used. The same timesteps "
67 "are used for all parameter groups and all meshes, the capability to define different "
68 "timesteps for different meshes is not supported.");
69
70 // New parameters for multiple regularization types
71 MultiMooseEnum reg_types("L2_GRADIENT");
73 "regularization_types",
74 reg_types,
75 "Types of regularization to apply. Multiple types can be specified.");
76
77 params.addParam<std::vector<Real>>("regularization_coeffs",
78 {},
79 "Coefficients for each regularization type. Must match the "
80 "number of regularization_types specified.");
81
82 params.addParamNamesToGroup("tikhonov_coeff regularization_types regularization_coeffs",
83 "Regularization");
84
85 return params;
86}
87
89 : GeneralOptimization(parameters),
90 _regularization_coeffs(getParam<std::vector<Real>>("regularization_coeffs")),
91 _regularization_types(getParam<MultiMooseEnum>("regularization_types")
92 .getSetValueIDs<ParameterMesh::RegularizationType>())
93{
94 // Validate that regularization coefficients match types
96 paramError("regularization_coeffs",
97 "Number of regularization coefficients (",
99 ") must match number of regularization types (",
101 ")");
102}
103
104std::vector<Real>
106 const FileName mesh_file_name,
107 const std::vector<unsigned int> & exodus_timestep,
108 const std::string & mesh_var_name) const
109{
110 // read data off Exodus mesh
111 ReadExodusMeshVars data_mesh(fetype, mesh_file_name, mesh_var_name);
112 std::vector<Real> parsed_data;
113 // read from mesh
114 for (auto const & step : exodus_timestep)
115 {
116 std::vector<Real> data = data_mesh.getParameterValues(step);
117 parsed_data.insert(parsed_data.end(), data.begin(), data.end());
118 }
119
120 return parsed_data;
121}
122
123void
125{
126 if ((isParamValid("num_values_name") || isParamValid("num_values")))
127 paramError("num_values_name or num_values should not be used with ParameterMeshOptimization. "
128 "Instead the number of dofs is set by the parameter meshes.");
129
130 _nvalues.resize(_nparams, 0);
131 // Fill the mesh information
132 const auto & meshes = getParam<std::vector<FileName>>("parameter_meshes");
133 const auto & families = getParam<MultiMooseEnum>("parameter_families");
134 const auto & orders = getParam<MultiMooseEnum>("parameter_orders");
135 const auto & ntimes = getParam<unsigned int>("num_parameter_times");
136
137 // Fill exodus parameter bounds and IC information
138 std::vector<std::string> initial_condition_mesh_variable;
139 std::vector<std::string> lower_bound_mesh_variable;
140 std::vector<std::string> upper_bound_mesh_variable;
141 if (isParamValid("initial_condition_mesh_variable"))
142 initial_condition_mesh_variable =
143 getParam<std::vector<std::string>>("initial_condition_mesh_variable");
144 if (isParamValid("lower_bound_mesh_variable"))
145 lower_bound_mesh_variable = getParam<std::vector<std::string>>("lower_bound_mesh_variable");
146 if (isParamValid("upper_bound_mesh_variable"))
147 upper_bound_mesh_variable = getParam<std::vector<std::string>>("upper_bound_mesh_variable");
148
149 std::vector<unsigned int> exodus_timestep;
150 if (isParamValid("exodus_timesteps_for_parameter_mesh_variable"))
151 exodus_timestep =
152 getParam<std::vector<unsigned int>>("exodus_timesteps_for_parameter_mesh_variable");
153 else // get last timestep in file
154 exodus_timestep = {std::numeric_limits<unsigned int>::max()};
155
156 // now do a bunch of error checking
157 // Size checks for data
158 if (meshes.size() != _nparams)
159 paramError("parameter_meshes",
160 "There must be a mesh associated with each group of parameters.");
161 if (families.size() > 1 && families.size() != _nparams)
162 paramError("parameter_families",
163 "There must be a family associated with each group of parameters.");
164 if (orders.size() > 1 && orders.size() != _nparams)
165 paramError("parameter_orders",
166 "There must be an order associated with each group of parameters.");
167
168 // error checking that initial conditions and bounds are only read from a single location
169 if (isParamValid("initial_condition_mesh_variable") && isParamValid("initial_condition"))
170 paramError("initial_condition_mesh_variable",
171 "Initial conditions for all parameter groups can only be defined by "
172 "initial_condition_mesh_variable or "
173 "initial_condition but not both.");
174 else if (isParamValid("lower_bound_mesh_variable") && isParamValid("lower_bounds"))
176 "lower_bound_mesh_variable",
177 "Lower bounds for all parameter groups can only be defined by lower_bound_mesh_variable or "
178 "lower_bounds but not both.");
179 else if (isParamValid("upper_bound_mesh_variable") && isParamValid("upper_bounds"))
181 "upper_bound_mesh_variable",
182 "Upper bounds for all parameter groups can only be defined by upper_bound_mesh_variable or "
183 "upper_bounds but not both.");
184
185 // Make sure they did not specify too many timesteps
186 if (isParamValid("exodus_timesteps_for_parameter_mesh_variable") &&
187 (!isParamValid("lower_bound_mesh_variable") + !isParamValid("upper_bound_mesh_variable") +
188 !isParamValid("initial_condition_mesh_variable") ==
189 3))
190 paramError("\"exodus_timesteps_for_parameter_mesh_variable\" should only be specified if "
191 "reading values from a mesh.");
192 else if (exodus_timestep.size() != ntimes && exodus_timestep.size() != 1)
193 paramError("exodus_timesteps_for_parameter_mesh_variable",
194 "Number of timesteps to read mesh data specified by "
195 "\"exodus_timesteps_for_parameter_mesh_variable\" incorrect. "
196 "\"exodus_timesteps_for_parameter_mesh_variable\" can specify a single timestep or "
197 "\"num_parameter_times\" timesteps.");
198
199 _ndof = 0;
201 for (const auto & param_id : make_range(_nparams))
202 {
203 const std::string family = families.size() > 1 ? families[param_id] : families[0];
204 const std::string order = orders.size() > 1 ? orders[param_id] : orders[0];
205 const FEType fetype(Utility::string_to_enum<Order>(order),
206 Utility::string_to_enum<FEFamily>(family));
207
208 _parameter_meshes[param_id] = std::make_unique<ParameterMesh>(fetype, meshes[param_id]);
209 _nvalues[param_id] = _parameter_meshes[param_id]->size() * ntimes;
210 _ndof += _nvalues[param_id];
211
212 // read and assign initial conditions
213 {
214 std::vector<Real> initial_condition;
215 if (isParamValid("initial_condition_mesh_variable"))
217 fetype, meshes[param_id], exodus_timestep, initial_condition_mesh_variable[param_id]);
218 else
219 initial_condition = parseInputData("initial_condition", 0, param_id);
220
221 _parameters[param_id]->assign(initial_condition.begin(), initial_condition.end());
222 }
223
224 // read and assign lower bound
225 {
226 std::vector<Real> lower_bound;
227 if (isParamValid("lower_bound_mesh_variable"))
228 lower_bound = parseExodusData(
229 fetype, meshes[param_id], exodus_timestep, lower_bound_mesh_variable[param_id]);
230 else
231 lower_bound = parseInputData("lower_bounds", std::numeric_limits<Real>::lowest(), param_id);
232
233 _lower_bounds.insert(_lower_bounds.end(), lower_bound.begin(), lower_bound.end());
234 }
235
236 // read and assign upper bound
237 {
238 std::vector<Real> upper_bound;
239 if (isParamValid("upper_bound_mesh_variable"))
240 upper_bound = parseExodusData(
241 fetype, meshes[param_id], exodus_timestep, upper_bound_mesh_variable[param_id]);
242 else
243 upper_bound = parseInputData("upper_bounds", std::numeric_limits<Real>::max(), param_id);
244
245 _upper_bounds.insert(_upper_bounds.end(), upper_bound.begin(), upper_bound.end());
246 }
247
248 // resize gradient vector to be filled later
249 _gradients[param_id]->resize(_nvalues[param_id]);
250 }
251}
252
253Real
255{
257
258 // Apply each regularization type with its coefficient
259 for (const auto reg_idx : index_range(_regularization_types))
260 {
261 if (_regularization_coeffs[reg_idx] > 0.0)
262 {
263 Real regularization_value = 0.0;
264
265 // Convert MultiMooseEnum to RegularizationType using get() method
267
268 for (const auto & param_id : make_range(_nparams))
269 {
270 // Get current parameter values for this group
271 const auto & param_values = *_parameters[param_id];
272
273 // Compute regularization objective for this type
274 regularization_value +=
275 _parameter_meshes[param_id]->computeRegularizationObjective(param_values, reg_type);
276 }
277
278 val += _regularization_coeffs[reg_idx] * regularization_value;
279 }
280 }
281
282 return val;
283}
284
285void
287{
288 // Add regularization gradient contributions to the reporter gradients before base computation
289 for (const auto reg_idx : index_range(_regularization_types))
290 {
291 if (_regularization_coeffs[reg_idx] > 0.0)
292 {
293 // Convert MultiMooseEnum to RegularizationType using get() method
295
296 for (const auto & param_id : make_range(_nparams))
297 {
298 // Get current parameter values for this group
299 const auto & param_values = *_parameters[param_id];
300 auto grad_values = _gradients[param_id];
301
302 // Compute regularization gradient for this type
303 std::vector<Real> reg_grad =
304 _parameter_meshes[param_id]->computeRegularizationGradient(param_values, reg_type);
305
306 // Add to gradient with coefficient
307 for (unsigned int i = 0; i < param_values.size(); ++i)
308 (*grad_values)[i] += _regularization_coeffs[reg_idx] * reg_grad[i];
309 }
310 }
311 }
312
313 // Now call base class method which includes Tikhonov and copies to PETSc vector
315}
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...
Number initial_condition(const Point &p, const Parameters &parameters, const std::string &, const std::string &)