Line data Source code
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 :
10 : #include "ParameterMeshOptimization.h"
11 :
12 : #include "AddVariableAction.h"
13 : #include "ParameterMesh.h"
14 : #include "libmesh/string_to_enum.h"
15 :
16 : using namespace libMesh;
17 :
18 : registerMooseObject("OptimizationApp", ParameterMeshOptimization);
19 :
20 : InputParameters
21 300 : ParameterMeshOptimization::validParams()
22 : {
23 300 : InputParameters params = GeneralOptimization::validParams();
24 :
25 300 : params.addClassDescription(
26 : "Computes objective function, gradient and contains reporters for communicating between "
27 : "optimizeSolve and subapps using mesh-based parameter definition.");
28 :
29 600 : params.addRequiredParam<std::vector<FileName>>(
30 : "parameter_meshes", "Exodus file containing meshes describing parameters.");
31 :
32 300 : const auto family = AddVariableAction::getNonlinearVariableFamilies();
33 300 : MultiMooseEnum families(family.getRawNames(), "LAGRANGE");
34 600 : params.addParam<MultiMooseEnum>(
35 : "parameter_families",
36 : families,
37 : "Specifies the family of FE shape functions for each group of parameters. If a single value "
38 : "is "
39 : "specified, then that value is used for all groups of parameters.");
40 300 : const auto order = AddVariableAction::getNonlinearVariableOrders();
41 300 : MultiMooseEnum orders(order.getRawNames(), "FIRST");
42 600 : params.addParam<MultiMooseEnum>(
43 : "parameter_orders",
44 : orders,
45 : "Specifies the order of FE shape functions for each group of parameters. If a single value "
46 : "is "
47 : "specified, then that value is used for all groups of parameters.");
48 :
49 600 : params.addParam<unsigned int>(
50 600 : "num_parameter_times", 1, "The number of time points the parameters represent.");
51 :
52 600 : params.addParam<std::vector<std::string>>(
53 : "initial_condition_mesh_variable",
54 : "Name of variable on parameter mesh to use as initial condition.");
55 600 : params.addParam<std::vector<std::string>>(
56 : "lower_bound_mesh_variable", "Name of variable on parameter mesh to use as lower bound.");
57 600 : params.addParam<std::vector<std::string>>(
58 : "upper_bound_mesh_variable", "Name of variable on parameter mesh to use as upper bound.");
59 600 : params.addParam<std::vector<unsigned int>>(
60 : "exodus_timesteps_for_parameter_mesh_variable",
61 : "Timesteps to read all parameter group bounds and initial conditions from Exodus mesh. The "
62 : "options are to give no timestep, a single timestep or \"num_parameter_times\" timesteps. "
63 : "No timestep results in the final timestep from the mesh being used. A single timestep "
64 : "results in values at that timestep being used for all timesteps. \"num_parameter_times\" "
65 : "timesteps results in values from the mesh at those steps being used. The same timesteps "
66 : "are used for all parameter groups and all meshes, the capability to define different "
67 : "timesteps for different meshes is not supported.");
68 :
69 300 : return params;
70 300 : }
71 :
72 150 : ParameterMeshOptimization::ParameterMeshOptimization(const InputParameters & parameters)
73 150 : : GeneralOptimization(parameters)
74 : {
75 150 : }
76 :
77 : std::vector<Real>
78 200 : ParameterMeshOptimization::parseExodusData(const std::vector<unsigned int> & exodus_timestep,
79 : const ParameterMesh & pmesh,
80 : const std::string & mesh_var_name,
81 : unsigned int ntimes) const
82 : {
83 200 : unsigned int num_cont_params = pmesh.size() * ntimes;
84 : std::vector<Real> parsed_data;
85 : // read from mesh
86 :
87 564 : for (auto const & step : exodus_timestep)
88 : {
89 730 : std::vector<Real> data = pmesh.getParameterValues(mesh_var_name, step);
90 364 : parsed_data.insert(parsed_data.end(), data.begin(), data.end());
91 364 : }
92 198 : if (parsed_data.size() != num_cont_params)
93 0 : mooseError("Number of parameters assigned by ",
94 : mesh_var_name,
95 : " is not equal to the number of parameters on the mesh. Mesh contains ",
96 : num_cont_params,
97 : " parameters and ",
98 : mesh_var_name,
99 : " assigned ",
100 0 : parsed_data.size(),
101 : " parameters.");
102 :
103 198 : return parsed_data;
104 0 : }
105 :
106 : void
107 150 : ParameterMeshOptimization::setICsandBounds()
108 : {
109 600 : if ((isParamValid("num_values_name") || isParamValid("num_values")))
110 0 : paramError("num_values_name or num_values should not be used with ParameterMeshOptimization. "
111 : "Instead the number of dofs is set by the parameter meshes.");
112 :
113 150 : _nvalues.resize(_nparams, 0);
114 : // Fill the mesh information
115 150 : const auto & meshes = getParam<std::vector<FileName>>("parameter_meshes");
116 150 : const auto & families = getParam<MultiMooseEnum>("parameter_families");
117 150 : const auto & orders = getParam<MultiMooseEnum>("parameter_orders");
118 300 : const auto & ntimes = getParam<unsigned int>("num_parameter_times");
119 :
120 : // Fill exodus parameter bounds and IC information
121 : std::vector<std::string> initial_condition_mesh_variable;
122 : std::vector<std::string> lower_bound_mesh_variable;
123 : std::vector<std::string> upper_bound_mesh_variable;
124 300 : if (isParamValid("initial_condition_mesh_variable"))
125 : initial_condition_mesh_variable =
126 168 : getParam<std::vector<std::string>>("initial_condition_mesh_variable");
127 300 : if (isParamValid("lower_bound_mesh_variable"))
128 111 : lower_bound_mesh_variable = getParam<std::vector<std::string>>("lower_bound_mesh_variable");
129 300 : if (isParamValid("upper_bound_mesh_variable"))
130 153 : upper_bound_mesh_variable = getParam<std::vector<std::string>>("upper_bound_mesh_variable");
131 :
132 : std::vector<unsigned int> exodus_timestep;
133 300 : if (isParamValid("exodus_timesteps_for_parameter_mesh_variable"))
134 : exodus_timestep =
135 99 : getParam<std::vector<unsigned int>>("exodus_timesteps_for_parameter_mesh_variable");
136 : else // get last timestep in file
137 117 : exodus_timestep = {std::numeric_limits<unsigned int>::max()};
138 :
139 : // now do a bunch of error checking
140 : // Size checks for data
141 150 : if (meshes.size() != _nparams)
142 2 : paramError("parameter_meshes",
143 : "There must be a mesh associated with each group of parameters.");
144 148 : if (families.size() > 1 && families.size() != _nparams)
145 2 : paramError("parameter_families",
146 : "There must be a family associated with each group of parameters.");
147 146 : if (orders.size() > 1 && orders.size() != _nparams)
148 2 : paramError("parameter_orders",
149 : "There must be an order associated with each group of parameters.");
150 :
151 : // error checking that initial conditions and bounds are only read from a single location
152 400 : if (isParamValid("initial_condition_mesh_variable") && isParamValid("initial_condition"))
153 0 : paramError("initial_condition_mesh_variable",
154 : "Initial conditions for all parameter groups can only be defined by "
155 : "initial_condition_mesh_variable or "
156 : "initial_condition but not both.");
157 362 : else if (isParamValid("lower_bound_mesh_variable") && isParamValid("lower_bounds"))
158 2 : paramError(
159 : "lower_bound_mesh_variable",
160 : "Lower bounds for all parameter groups can only be defined by lower_bound_mesh_variable or "
161 : "lower_bounds but not both.");
162 382 : else if (isParamValid("upper_bound_mesh_variable") && isParamValid("upper_bounds"))
163 0 : paramError(
164 : "upper_bound_mesh_variable",
165 : "Upper bounds for all parameter groups can only be defined by upper_bound_mesh_variable or "
166 : "upper_bounds but not both.");
167 :
168 : // Make sure they did not specify too many timesteps
169 426 : if (isParamValid("exodus_timesteps_for_parameter_mesh_variable") &&
170 241 : (!isParamValid("lower_bound_mesh_variable") + !isParamValid("upper_bound_mesh_variable") +
171 239 : !isParamValid("initial_condition_mesh_variable") ==
172 : 3))
173 2 : paramError("\"exodus_timesteps_for_parameter_mesh_variable\" should only be specified if "
174 : "reading values from a mesh.");
175 140 : else if (exodus_timestep.size() != ntimes && exodus_timestep.size() != 1)
176 2 : paramError("exodus_timesteps_for_parameter_mesh_variable",
177 : "Number of timesteps to read mesh data specified by "
178 : "\"exodus_timesteps_for_parameter_mesh_variable\" incorrect. "
179 : "\"exodus_timesteps_for_parameter_mesh_variable\" can specify a single timestep or "
180 : "\"num_parameter_times\" timesteps.");
181 :
182 138 : _ndof = 0;
183 304 : for (const auto & param_id : make_range(_nparams))
184 : {
185 : // store off all the variable names that you might want to read from the mesh
186 : std::vector<std::string> var_names;
187 348 : if (isParamValid("initial_condition_mesh_variable"))
188 83 : var_names.push_back(initial_condition_mesh_variable[param_id]);
189 348 : if (isParamValid("lower_bound_mesh_variable"))
190 51 : var_names.push_back(lower_bound_mesh_variable[param_id]);
191 348 : if (isParamValid("upper_bound_mesh_variable"))
192 76 : var_names.push_back(upper_bound_mesh_variable[param_id]);
193 :
194 174 : const std::string family = families.size() > 1 ? families[param_id] : families[0];
195 174 : const std::string order = orders.size() > 1 ? orders[param_id] : orders[0];
196 174 : const FEType fetype(Utility::string_to_enum<Order>(order),
197 174 : Utility::string_to_enum<FEFamily>(family));
198 :
199 174 : ParameterMesh pmesh(fetype, meshes[param_id], var_names);
200 170 : _nvalues[param_id] = pmesh.size() * ntimes;
201 170 : _ndof += _nvalues[param_id];
202 :
203 : // read and assign initial conditions
204 : std::vector<Real> initial_condition;
205 340 : if (isParamValid("initial_condition_mesh_variable"))
206 162 : initial_condition = parseExodusData(
207 : exodus_timestep, pmesh, initial_condition_mesh_variable[param_id], ntimes);
208 : else
209 263 : initial_condition = parseInputData("initial_condition", 0, param_id);
210 :
211 168 : _parameters[param_id]->assign(initial_condition.begin(), initial_condition.end());
212 :
213 : // read and assign lower bound
214 : std::vector<Real> lower_bound;
215 336 : if (isParamValid("lower_bound_mesh_variable"))
216 : lower_bound =
217 92 : parseExodusData(exodus_timestep, pmesh, lower_bound_mesh_variable[param_id], ntimes);
218 : else
219 363 : lower_bound = parseInputData("lower_bounds", std::numeric_limits<Real>::lowest(), param_id);
220 :
221 166 : _lower_bounds.insert(_lower_bounds.end(), lower_bound.begin(), lower_bound.end());
222 :
223 : // read and assign upper bound
224 : std::vector<Real> upper_bound;
225 332 : if (isParamValid("upper_bound_mesh_variable"))
226 : upper_bound =
227 144 : parseExodusData(exodus_timestep, pmesh, upper_bound_mesh_variable[param_id], ntimes);
228 : else
229 282 : upper_bound = parseInputData("upper_bounds", std::numeric_limits<Real>::max(), param_id);
230 :
231 166 : _upper_bounds.insert(_upper_bounds.end(), upper_bound.begin(), upper_bound.end());
232 :
233 : // resize gradient vector to be filled later
234 166 : _gradients[param_id]->resize(_nvalues[param_id]);
235 332 : }
236 130 : }
|