https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ParameterStudyAction.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
13#include "FEProblemBase.h"
14#include "Control.h"
15#include "Calculators.h"
16
17registerMooseAction("StochasticToolsApp", ParameterStudyAction, "meta_action");
18registerMooseAction("StochasticToolsApp", ParameterStudyAction, "add_distribution");
19registerMooseAction("StochasticToolsApp", ParameterStudyAction, "add_sampler");
20registerMooseAction("StochasticToolsApp", ParameterStudyAction, "add_multi_app");
21registerMooseAction("StochasticToolsApp", ParameterStudyAction, "add_transfer");
22registerMooseAction("StochasticToolsApp", ParameterStudyAction, "add_output");
23registerMooseAction("StochasticToolsApp", ParameterStudyAction, "add_reporter");
24registerMooseAction("StochasticToolsApp", ParameterStudyAction, "add_control");
25
28{
30 params.addClassDescription("Builds objects to set up a basic parameter study.");
31
32 // Parameters to define what we are studying
33 params.addRequiredParam<FileName>(
34 "input", "The input file containing the physics for the parameter study.");
35 params.addRequiredParam<std::vector<std::string>>(
36 "parameters", "List of parameters being perturbed for the study.");
37 params.addParam<std::vector<ReporterName>>(
38 "quantities_of_interest",
39 "List of the reporter names (object_name/value_name) "
40 "that represent the quantities of interest for the study.");
41
42 // Statistics Parameters
43 params.addParam<bool>(
44 "compute_statistics",
45 true,
46 "Whether or not to compute statistics on the 'quantities_of_interest'. "
47 "The default is to compute mean and standard deviation with 0.01, 0.05, 0.1, 0.9, "
48 "0.95, and 0.99 confidence intervals.");
50 stats = "mean stddev";
52 "statistics", stats, "The statistic(s) to compute for the study.");
53 params.addParam<std::vector<Real>>("ci_levels",
54 std::vector<Real>({0.01, 0.05, 0.1, 0.9, 0.95, 0.99}),
55 "A vector of confidence levels to consider for statistics "
56 "confidence intervals, values must be in (0, 1).");
57 params.addParam<unsigned int>(
58 "ci_replicates",
59 1000,
60 "The number of replicates to use when computing confidence level intervals for statistics.");
61
62 // Parameters for the sampling scheme
64 "sampling_type", samplingTypes(), "The type of sampling to use for the parameter study.");
65 params.addParam<unsigned int>("seed", 0, "Random number generator initial seed");
66
67 // Parameters for multi app
68 MooseEnum modes(
69 "normal=0 batch-reset=1 batch-restore=2 batch-keep-solution=3 batch-no-restore=4");
70 params.addParam<MooseEnum>(
71 "multiapp_mode",
72 modes,
73 "The operation mode, 'normal' creates one sub-application for each sample."
74 "'batch' creates one sub-app for each processor and re-executes for each local sample. "
75 "'reset' re-initializes the sub-app for every sample in the batch. "
76 "'restore' does not re-initialize and instead restores to first sample's initialization. "
77 "'keep-solution' re-uses the solution obtained from the first sample in the batch. "
78 "'no-restore' does not restore the sub-app."
79 "The default will be inferred based on the study.");
80 params.addParam<unsigned int>(
81 "min_procs_per_sample",
82 1,
83 "Minimum number of processors to give to each sample. Useful for larger, distributed mesh "
84 "solves where there are memory constraints.");
85 params.addParam<bool>("ignore_solve_not_converge",
86 false,
87 "True to continue main app even if a sub app's solve does not converge.");
88
89 // Samplers ///////////////////////////
90 // Parameters for Monte Carlo and LHS
91 params.addParam<dof_id_type>(
92 "num_samples", "The number of samples to generate for 'monte-carlo' and 'lhs' sampling.");
94 "distributions",
96 "The types of distribution to use for 'monte-carlo' and "
97 "'lhs' sampling. The number of entries defines the number of columns in the matrix.");
98 // Parameters for cartesian product
99 params.addParam<std::vector<Real>>(
100 "linear_space_items",
101 "Parameter for defining the 'cartesian-prodcut' sampling scheme. A list of triplets, each "
102 "item should include the min, step size, and number of steps.");
103 // Parameters for CSV sampler
104 params.addParam<FileName>(
105 "csv_samples_file",
106 "Name of the CSV file that contains the sample matrix for 'csv' sampling.");
107 params.addParam<std::vector<dof_id_type>>(
108 "csv_column_indices",
109 "Column indices in the CSV file to be sampled from for 'csv' sampling. Number of indices "
110 "here "
111 "will be the same as the number of columns per matrix.");
112 params.addParam<std::vector<std::string>>(
113 "csv_column_names",
114 "Column names in the CSV file to be sampled from for 'csv' sampling. Number of columns names "
115 "here will be the same as the number of columns per matrix.");
116 // Parameters for input matrix
117 params.addParam<RealEigenMatrix>("input_matrix", "Sampling matrix for 'input-matrix' sampling.");
118
119 // Distributions ///////////////////////////
120 // Parameters for normal distributions
121 params.addParam<std::vector<Real>>("normal_mean",
122 "Means (or expectations) of the 'normal' distributions.");
123 params.addParam<std::vector<Real>>("normal_standard_deviation",
124 "Standard deviations of the 'normal' distributions.");
125 // Parameters for uniform distributions
126 params.addParam<std::vector<Real>>("uniform_lower_bound",
127 "Lower bounds for 'uniform' distributions.");
128 params.addParam<std::vector<Real>>("uniform_upper_bound",
129 "Upper bounds 'uniform' distributions.");
130 // Parameters for Weibull distributions
131 params.addParam<std::vector<Real>>("weibull_location",
132 "Location parameter (a or low) for 'weibull' distributions.");
133 params.addParam<std::vector<Real>>("weibull_scale",
134 "Scale parameter (b or lambda) for 'weibull' distributions.");
135 params.addParam<std::vector<Real>>("weibull_shape",
136 "Shape parameter (c or k) for 'weibull' distributions.");
137 // Parameters for lognormal distributions
138 params.addParam<std::vector<Real>>(
139 "lognormal_location", "The 'lognormal' distributions' location parameter (m or mu).");
140 params.addParam<std::vector<Real>>(
141 "lognormal_scale", "The 'lognormal' distributions' scale parameter (s or sigma).");
142 // Parameters for truncated normal distributions
143 params.addParam<std::vector<Real>>("tnormal_mean",
144 "Means (or expectations) of the 'tnormal' distributions.");
145 params.addParam<std::vector<Real>>("tnormal_standard_deviation",
146 "Standard deviations of the 'tnormal' distributions.");
147 params.addParam<std::vector<Real>>("tnormal_lower_bound", "'tnormal' distributions' lower bound");
148 params.addParam<std::vector<Real>>("tnormal_upper_bound", "'tnormal' distributions' upper bound");
149
150 // Outputting parameters
151 MultiMooseEnum out_type("none=0 csv=1 json=2", "json");
152 params.addParam<MultiMooseEnum>(
153 "output_type",
154 out_type,
155 "Method in which to output sampler matrix and quantities of interest. Warning: "
156 "'csv' output will not include vector-type quantities.");
157 params.addParam<std::vector<ReporterValueName>>(
158 "sampler_column_names",
159 "Names of the sampler columns for outputting the sampling matrix. If 'parameters' are not "
160 "bracketed, the default is based on these values. Otherwise, the default is based on the "
161 "sampler name.");
162
163 // Debug parameters
164 params.addParam<bool>("show_study_objects",
165 false,
166 "Set to true to show all the objects being built by this action.");
167 return params;
168}
169
171 : Action(parameters),
172 _parameters(getParam<std::vector<std::string>>("parameters")),
173 _sampling_type(getParam<MooseEnum>("sampling_type")),
174 _distributions(isParamValid("distributions") ? getParam<MultiMooseEnum>("distributions")
175 : MultiMooseEnum("")),
176 _multiapp_mode(inferMultiAppMode()),
177 _compute_stats(isParamValid("quantities_of_interest") && getParam<bool>("compute_statistics")),
178 _show_objects(getParam<bool>("show_study_objects"))
179{
180 // Check sampler parameters
181 const auto sampler_params = samplerParameters();
182 const auto this_sampler_params = sampler_params[_sampling_type];
183 // Check required sampler parameters
184 for (const auto & param : this_sampler_params)
185 if (param.second && !isParamValid(param.first))
186 paramError("sampling_type",
187 "The ",
188 param.first,
189 " parameter is required to build the requested sampling type.");
190 // Check unused parameters
191 std::string msg = "";
192 for (unsigned int i = 0; i < sampler_params.size(); ++i)
193 for (const auto & param : sampler_params[i])
194 if (this_sampler_params.find(param.first) == this_sampler_params.end() &&
195 parameters.isParamSetByUser(param.first))
196 msg += (msg.empty() ? "" : ", ") + param.first;
197 if (!msg.empty())
198 paramError("sampling_type",
199 "The following parameters are unused for the selected sampling type: ",
200 msg);
201
202 // Check distribution parameters
203 const auto distribution_params = distributionParameters();
204 std::vector<unsigned int> dist_count(distribution_params.size(), 0);
205 for (const auto & dist : _distributions)
206 dist_count[(unsigned int)dist]++;
207 msg = "";
208 for (unsigned int i = 0; i < distribution_params.size(); ++i)
209 for (const auto & param : distribution_params[i])
210 {
211 // Check if parameter was set
212 if (dist_count[i] > 0 && !isParamValid(param))
213 paramError("distributions",
214 "The ",
215 param,
216 " parameter is required to build the listed distributions.");
217 // Check if parameter has correct size
218 else if (dist_count[i] > 0 && getParam<std::vector<Real>>(param).size() != dist_count[i])
219 paramError("distributions",
220 "The number of entries in ",
221 param,
222 " does not match the number of required entries (",
223 dist_count[i],
224 ") to build the listed distributions.");
225 // Check if parameter was set and unused
226 else if (dist_count[i] == 0 && parameters.isParamSetByUser(param))
227 msg += (msg.empty() ? "" : ", ") + param;
228 }
229 if (!msg.empty())
231 "distributions", "The following parameters are unused for the listed distributions: ", msg);
232
233 // Check statistics parameters
234 if (!_compute_stats)
235 {
236 msg = "";
237 for (const auto & param : statisticsParameters())
238 if (parameters.isParamSetByUser(param))
239 msg += (msg.empty() ? "" : ", ") + param;
240 if (!msg.empty())
241 paramError("compute_statistics",
242 "The following parameters are unused since statistics are not being computed: ",
243 msg);
244 }
245}
246
249{
250 return MooseEnum("monte-carlo=0 lhs=1 cartesian-product=2 csv=3 input-matrix=4");
251}
252
255{
256 return MultiMooseEnum("normal=0 uniform=1 weibull=2 lognormal=3 tnormal=4");
257}
258
259void
261{
262 if (_current_task == "meta_action")
263 {
264 const auto stm_actions = _awh.getActions<StochasticToolsAction>();
265 if (stm_actions.empty())
266 {
267 auto params = _action_factory.getValidParams("StochasticToolsAction");
268 params.set<bool>("_built_by_moose") = true;
269 params.set<std::string>("registered_identifier") = "(AutoBuilt)";
270
271 std::shared_ptr<Action> action = _action_factory.create(
272 "StochasticToolsAction", _name + "_stochastic_tools_action", params);
273 _awh.addActionBlock(action);
274
275 if (_show_objects)
276 showObject("StochasticToolsAction", _name + "_stochastic_tools_action", params);
277 }
278 }
279 else if (_current_task == "add_distribution")
280 {
281 // This map is used to keep track of how many of a certain
282 // distribution is being created.
283 std::unordered_map<std::string, unsigned int> dist_count;
284 for (const auto & dt : distributionTypes().getNames())
285 dist_count[dt] = 0;
286
287 // We will have a single call to addDistribution for each entry
288 // So declare these quantities and set in the if statements
289 std::string distribution_type;
291
292 // Loop through the inputted distributions
293 unsigned int full_count = 0;
294 for (const auto & dist : _distributions)
295 {
296 // Convenient reference to the current count
297 unsigned int & count = dist_count[dist.name()];
298
299 // Set the distribution type and parameters
300 if (dist == "normal")
301 {
302 distribution_type = "Normal";
303 params = _factory.getValidParams(distribution_type);
304 params.set<Real>("mean") = getDistributionParam<Real>("normal_mean", count);
305 params.set<Real>("standard_deviation") =
306 getDistributionParam<Real>("normal_standard_deviation", count);
307 }
308 else if (dist == "uniform")
309 {
310 distribution_type = "Uniform";
311 params = _factory.getValidParams(distribution_type);
312 params.set<Real>("lower_bound") = getDistributionParam<Real>("uniform_lower_bound", count);
313 params.set<Real>("upper_bound") = getDistributionParam<Real>("uniform_upper_bound", count);
314 }
315 else if (dist == "weibull")
316 {
317 distribution_type = "Weibull";
318 params = _factory.getValidParams(distribution_type);
319 params.set<Real>("location") = getDistributionParam<Real>("weibull_location", count);
320 params.set<Real>("scale") = getDistributionParam<Real>("weibull_scale", count);
321 params.set<Real>("shape") = getDistributionParam<Real>("weibull_shape", count);
322 }
323 else if (dist == "lognormal")
324 {
325 distribution_type = "Lognormal";
326 params = _factory.getValidParams(distribution_type);
327 params.set<Real>("location") = getDistributionParam<Real>("lognormal_location", count);
328 params.set<Real>("scale") = getDistributionParam<Real>("lognormal_scale", count);
329 }
330 else if (dist == "tnormal")
331 {
332 distribution_type = "TruncatedNormal";
333 params = _factory.getValidParams(distribution_type);
334 params.set<Real>("mean") = getDistributionParam<Real>("tnormal_mean", count);
335 params.set<Real>("standard_deviation") =
336 getDistributionParam<Real>("tnormal_standard_deviation", count);
337 params.set<Real>("lower_bound") = getDistributionParam<Real>("tnormal_lower_bound", count);
338 params.set<Real>("upper_bound") = getDistributionParam<Real>("tnormal_upper_bound", count);
339 }
340 else
341 paramError("distributions", "Unknown distribution type.");
342
343 // Add the distribution
344 _problem->addDistribution(distribution_type, distributionName(full_count), params);
345 if (_show_objects)
346 showObject(distribution_type, distributionName(full_count), params);
347
348 // Increment the counts
349 count++;
350 full_count++;
351 }
352 }
353 else if (_current_task == "add_sampler")
354 {
355 // We will have a single call to addSampler
356 // So declare these quantities and set in the if statements
357 std::string sampler_type;
359
360 // Set the distribution type and parameters
361 // monte-carlo or lhs
362 if (_sampling_type == 0 || _sampling_type == 1)
363 {
364 sampler_type = _sampling_type == 0 ? "MonteCarlo" : "LatinHypercube";
365 params = _factory.getValidParams(sampler_type);
366 params.set<dof_id_type>("num_rows") = getParam<dof_id_type>("num_samples");
367 params.set<std::vector<DistributionName>>("distributions") =
369 }
370 // cartesian-product
371 else if (_sampling_type == 2)
372 {
373 sampler_type = "CartesianProduct";
374 params = _factory.getValidParams(sampler_type);
375 params.set<std::vector<Real>>("linear_space_items") =
376 getParam<std::vector<Real>>("linear_space_items");
377 }
378 // csv
379 else if (_sampling_type == 3)
380 {
381 sampler_type = "CSVSampler";
382 params = _factory.getValidParams(sampler_type);
383 params.set<FileName>("samples_file") = getParam<FileName>("csv_samples_file");
384 if (isParamValid("csv_column_indices") && isParamValid("csv_column_names"))
385 paramError("csv_column_indices",
386 "'csv_column_indices' and 'csv_column_names' cannot both be set.");
387 else if (isParamValid("csv_column_indices"))
388 params.set<std::vector<dof_id_type>>("column_indices") =
389 getParam<std::vector<dof_id_type>>("csv_column_indices");
390 else if (isParamValid("csv_column_names"))
391 params.set<std::vector<std::string>>("column_names") =
392 getParam<std::vector<std::string>>("csv_column_names");
393 }
394 // input-matrix
395 else if (_sampling_type == 4)
396 {
397 sampler_type = "InputMatrix";
398 params = _factory.getValidParams(sampler_type);
399 params.set<RealEigenMatrix>("matrix") = getParam<RealEigenMatrix>("input_matrix");
400 }
401 else
402 paramError("sampling_type", "Unknown sampling type.");
403
404 // Need to set the right execute_on for command-line control
405 if (_multiapp_mode <= 1)
406 params.set<ExecFlagEnum>("execute_on") = {EXEC_PRE_MULTIAPP_SETUP};
407 else
408 params.set<ExecFlagEnum>("execute_on") = {EXEC_INITIAL};
409
410 // Set the minimum number of procs
411 params.set<unsigned int>("min_procs_per_row") = getParam<unsigned int>("min_procs_per_sample");
412
413 // Add the sampler
414 _problem->addSampler(sampler_type, samplerName(), params);
415 if (_show_objects)
416 showObject(sampler_type, samplerName(), params);
417 }
418 else if (_current_task == "add_multi_app")
419 {
420 auto params = _factory.getValidParams("SamplerFullSolveMultiApp");
421
422 // Dealing with failed solves
423 params.set<bool>("ignore_solve_not_converge") = getParam<bool>("ignore_solve_not_converge");
424
425 // Set input file
426 params.set<std::vector<FileName>>("input_files") = {getParam<FileName>("input")};
427
428 // Set the Sampler
429 params.set<SamplerName>("sampler") = samplerName();
430
431 // Set parameters based on the sampling mode
432 // normal
433 if (_multiapp_mode == 0)
434 params.set<MooseEnum>("mode") = "normal";
435 // batch-reset
436 else if (_multiapp_mode == 1)
437 params.set<MooseEnum>("mode") = "batch-reset";
438 // batch-restore variants
439 else
440 {
441 // Set the mode to 'batch-restore'
442 params.set<MooseEnum>("mode") = "batch-restore";
443
444 // If we are doing batch-restore, the parameters must be controllable.
445 // So we will add the necessary control to the sub-app using command-line
446 std::string clia = "Controls/" + samplerReceiverName() + "/type=SamplerReceiver";
447 params.set<std::vector<CLIArgString>>("cli_args").push_back(clia);
448
449 // batch-keep-solution
450 if (_multiapp_mode == 3)
451 {
452 params.set<bool>("keep_solution_during_restore") = true;
453 // Conceptually all these runs are not 'sequential in time' (moving along a transient)
454 // but rather simply restarted from the same solution
455 params.set<bool>("update_old_solution_when_keeping_solution_during_restore") = false;
456 }
457 // batch-no-restore
458 else if (_multiapp_mode == 4)
459 params.set<bool>("no_restore") = true;
460 }
461
462 // Set the minimum number of procs
463 params.set<unsigned int>("min_procs_per_app") = getParam<unsigned int>("min_procs_per_sample");
464
465 // Setting execute_on to make sure things happen in the correct order
466 params.set<ExecFlagEnum>("execute_on") = {EXEC_TIMESTEP_BEGIN};
467
468 // Add the multiapp
469 _problem->addMultiApp("SamplerFullSolveMultiApp", multiappName(), params);
470 if (_show_objects)
471 showObject("SamplerFullSolveMultiApp", multiappName(), params);
472 }
473 else if (_current_task == "add_transfer")
474 {
475 // Add the parameter transfer if we are doing 'batch-restore'
476 if (_multiapp_mode >= 2)
477 {
478 auto params = _factory.getValidParams("SamplerParameterTransfer");
479 params.set<MultiAppName>("to_multi_app") = multiappName();
480 params.set<SamplerName>("sampler") = samplerName();
481 params.set<std::vector<std::string>>("parameters") = _parameters;
482 _problem->addTransfer("SamplerParameterTransfer", parameterTransferName(), params);
483 if (_show_objects)
484 showObject("SamplerParameterTransfer", parameterTransferName(), params);
485 }
486
487 // Add reporter transfer if QoIs have been specified
488 if (isParamValid("quantities_of_interest"))
489 {
490 auto params = _factory.getValidParams("SamplerReporterTransfer");
491 params.set<MultiAppName>("from_multi_app") = multiappName();
492 params.set<SamplerName>("sampler") = samplerName();
493 params.set<std::string>("stochastic_reporter") = stochasticReporterName();
494 params.set<std::vector<ReporterName>>("from_reporter") =
495 getParam<std::vector<ReporterName>>("quantities_of_interest");
496 params.set<std::string>("prefix") = "";
497 _problem->addTransfer("SamplerReporterTransfer", reporterTransferName(), params);
498 if (_show_objects)
499 showObject("SamplerReporterTransfer", reporterTransferName(), params);
500 }
501 }
502 else if (_current_task == "add_output")
503 {
504 const auto & output = getParam<MultiMooseEnum>("output_type");
505
506 // Add csv output
507 if (output.isValueSet("csv"))
508 {
509 auto params = _factory.getValidParams("CSV");
510 params.set<ExecFlagEnum>("execute_on") = {EXEC_TIMESTEP_END};
511 _problem->addOutput("CSV", outputName("csv"), params);
512 if (_show_objects)
513 showObject("CSV", outputName("csv"), params);
514 }
515
516 // Add json output
517 if (output.isValueSet("json") || _compute_stats)
518 {
519 auto params = _factory.getValidParams("JSON");
520 params.set<ExecFlagEnum>("execute_on") = {EXEC_TIMESTEP_END};
521 _problem->addOutput("JSON", outputName("json"), params);
522 if (_show_objects)
523 showObject("JSON", outputName("json"), params);
524 }
525 }
526 else if (_current_task == "add_reporter")
527 {
528 // Add stochastic reporter object
529 auto params = _factory.getValidParams("StochasticMatrix");
530
531 // Ideally this would be based on the number of samples since gathering
532 // data onto a single processor can be memory and run-time expensive,
533 // but most people want everything in one output file
534 params.set<MooseEnum>("parallel_type") = "ROOT";
535
536 // Supply the sampler for output
537 params.set<SamplerName>("sampler") = samplerName();
538
539 // Set the column names if supplied or identifiable with "parameters"
540 auto & names = params.set<std::vector<ReporterValueName>>("sampler_column_names");
541 if (isParamValid("sampler_column_names"))
542 names = getParam<std::vector<ReporterValueName>>("sampler_column_names");
543 else
544 {
545 // There isn't a guaranteed mapping if using brackets
546 bool has_bracket = false;
547 for (const auto & param : _parameters)
548 if (param.find("[") != std::string::npos)
549 has_bracket = true;
550
551 // If no brackets, then there is mapping, so use parameter names
552 if (!has_bracket)
553 for (auto param : _parameters)
554 {
555 // Reporters don't like '/' in the name, so replace those with '_'
556 std::replace(param.begin(), param.end(), '/', '_');
557 names.push_back(param);
558 }
559 }
560
561 // Specify output objects
562 const auto & output_type = getParam<MultiMooseEnum>("output_type");
563 auto & outputs = params.set<std::vector<OutputName>>("outputs");
564 if (output_type.isValueSet("csv"))
565 outputs.push_back(outputName("csv"));
566 if (output_type.isValueSet("json"))
567 outputs.push_back(outputName("json"));
568 if (output_type.isValueSet("none"))
569 outputs = {"none"};
570
571 params.set<ExecFlagEnum>("execute_on") = {EXEC_TIMESTEP_END};
572 _problem->addReporter("StochasticMatrix", stochasticReporterName(), params);
573 if (_show_objects)
574 showObject("StochasticReporter", stochasticReporterName(), params);
575
576 // Add statistics object
577 if (_compute_stats)
578 {
579 auto params = _factory.getValidParams("StatisticsReporter");
580 auto & reps = params.set<std::vector<ReporterName>>("reporters");
581 for (const auto & qoi : getParam<std::vector<ReporterName>>("quantities_of_interest"))
582 reps.push_back(quantityOfInterestName(qoi));
583 params.set<MultiMooseEnum>("compute") = getParam<MultiMooseEnum>("statistics");
584 params.set<MooseEnum>("ci_method") = "percentile";
585 params.set<std::vector<Real>>("ci_levels") = getParam<std::vector<Real>>("ci_levels");
586 params.set<unsigned int>("ci_replicates") = getParam<unsigned int>("ci_replicates");
587 params.set<ExecFlagEnum>("execute_on") = {EXEC_TIMESTEP_END};
588 params.set<std::vector<OutputName>>("outputs") = {outputName("json")};
589 _problem->addReporter("StatisticsReporter", statisticsName(), params);
590 if (_show_objects)
591 showObject("StatisticsReporter", statisticsName(), params);
592 }
593 }
594 else if (_current_task == "add_control")
595 {
596 // Add command-line control if the multiapp mode warrants it
597 if (_multiapp_mode <= 1)
598 {
599 auto params = _factory.getValidParams("MultiAppSamplerControl");
600 params.set<MultiAppName>("multi_app") = multiappName();
601 params.set<SamplerName>("sampler") = samplerName();
602 params.set<std::vector<std::string>>("param_names") = _parameters;
603 auto control =
604 _factory.create<Control>("MultiAppSamplerControl", multiappControlName(), params);
605 _problem->getControlWarehouse().addObject(control);
606 if (_show_objects)
607 showObject("MultiAppSamplerControl", multiappControlName(), params);
608 }
609 }
610}
611
612DistributionName
614{
615 return "study_distribution_" + std::to_string(count);
616}
617
618std::vector<DistributionName>
619ParameterStudyAction::distributionNames(unsigned int full_count) const
620{
621 std::vector<DistributionName> dist_names;
622 for (const auto & i : make_range(full_count))
623 dist_names.push_back(distributionName(i));
624 return dist_names;
625}
626
632
633void
635 std::string name,
636 const InputParameters & params) const
637{
638 // Output basic information
639 std::string base_type = params.hasBase() ? params.getBase() : "Unknown";
640 _console << "[ParameterStudy] "
641 << "Base Type: " << COLOR_YELLOW << base_type << COLOR_DEFAULT << "\n"
642 << " Type: " << COLOR_YELLOW << type << COLOR_DEFAULT << "\n"
643 << " Name: " << COLOR_YELLOW << name << COLOR_DEFAULT;
644
645 // Gather parameters and their values if:
646 // - It is not a private parameter
647 // - Doesn't start with '_' (which usually indicates private)
648 // - Parameter is set by this action
649 // - Is not the "type" parameter
650 std::map<std::string, std::string> param_map;
651 for (const auto & it : params)
652 if (!params.isPrivate(it.first) && it.first[0] != '_' && params.isParamSetByUser(it.first) &&
653 it.first != "type")
654 {
655 std::stringstream ss;
656 it.second->print(ss);
657 param_map[it.first] = ss.str();
658 }
659
660 // Print the gathered parameters
661 if (!param_map.empty())
662 _console << "\n Parameters: ";
663 bool first = true;
664 for (const auto & it : param_map)
665 {
666 if (!first)
667 _console << "\n" << std::string(29, ' ');
668 _console << COLOR_YELLOW << std::setw(24) << it.first << COLOR_DEFAULT << " : " << COLOR_MAGENTA
669 << it.second << COLOR_DEFAULT;
670 first = false;
671 }
672
673 _console << std::endl;
674}
675
676std::vector<std::map<std::string, bool>>
678{
679 // monte-carlo, lhs, cartesian-product, csv, input-matrix
680 return {{{"num_samples", true}, {"distributions", true}},
681 {{"num_samples", true}, {"distributions", true}},
682 {{"linear_space_items", true}},
683 {{"csv_samples_file", true}, {"csv_column_indices", false}, {"csv_column_names", false}},
684 {{"input_matrix", true}}};
685}
686
687std::vector<std::vector<std::string>>
689{
690 // normal, uniform, weibull, lognormal, tnormal
691 return {
692 {"normal_mean", "normal_standard_deviation"},
693 {"uniform_lower_bound", "uniform_upper_bound"},
694 {"weibull_location", "weibull_scale", "weibull_shape"},
695 {"lognormal_location", "lognormal_scale"},
696 {"tnormal_mean", "tnormal_standard_deviation", "tnormal_lower_bound", "tnormal_upper_bound"}};
697}
698
699std::set<std::string>
701{
702 return {"statistics", "ci_levels", "ci_replicates"};
703}
704
705unsigned int
707{
708 if (isParamValid("multiapp_mode"))
709 return getParam<MooseEnum>("multiapp_mode");
710
711 const unsigned int default_mode = 1;
712
713 // First obvious thing is if it is a parsed parameter, indicated by the lack of '/'
714 for (const auto & param : _parameters)
715 if (param.find("/") == std::string::npos)
716 return default_mode;
717 // Next we'll see if there is a GlobalParam
718 for (const auto & param : _parameters)
719 if (param.find("GlobalParams") != std::string::npos)
720 return default_mode;
721
722 // Now for the difficult check
723 // Parse input file and create root hit node
724 const auto input_filename = MooseUtils::realpath(getParam<FileName>("input"));
725 std::ifstream f(input_filename);
726 std::string input((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
727 std::unique_ptr<hit::Node> root(hit::parse(input_filename, input));
728
729 // Walk through the input and see if every param is controllable
731 root->walk(&control_walker, hit::NodeType::Section);
732 if (!control_walker.areControllable())
733 return default_mode;
734
735 // Walk through the input and determine how the problem is being executed
736 ExecutionTypeWalker exec_walker;
737 root->walk(&exec_walker, hit::NodeType::Section);
738 // If it is steady-state, then we don't need to restore
739 if (exec_walker.getExecutionType() == 1)
740 return 4;
741 // If it is pseudo-transeint, then we can keep the solution
742 else if (exec_walker.getExecutionType() == 2)
743 return 3;
744 // If it's transient or unknown, don't keep the solution and restore
745 else
746 return 2;
747}
748
750 const std::vector<std::string> & parameters, MooseApp & app)
751 : _app(app), _is_controllable(parameters.size(), false)
752{
753 // Seperate the object from the parameter into a list of pairs
754 for (const auto & param : parameters)
755 {
756 const auto pos = param.rfind("/");
757 _pars.emplace_back(param.substr(0, pos), param.substr(pos + 1));
758 }
759}
760
761void
762AreParametersControllableWalker::walk(const std::string & fullpath,
763 const std::string & /*nodename*/,
764 hit::Node * n)
765{
766 for (const auto & i : index_range(_pars))
767 {
768 const std::string obj = _pars[i].first;
769 const std::string par = _pars[i].second;
770 if (obj == fullpath)
771 {
772 const auto typeit = n->find("type");
773 if (typeit && typeit != n && typeit->type() == hit::NodeType::Field)
774 {
775 const std::string obj_type = n->param<std::string>("type");
776 const auto params = _app.getFactory().getValidParams(obj_type);
777 _is_controllable[i] = params.isControllable(par);
778 }
779 }
780 }
781}
782
783bool
785{
786 for (const auto & ic : _is_controllable)
787 if (!ic)
788 return false;
789 return true;
790}
791
792void
793ExecutionTypeWalker::walk(const std::string & fullpath,
794 const std::string & /*nodename*/,
795 hit::Node * n)
796{
797 if (fullpath == "Executioner")
798 {
799 // This should not be hit since there shouldn't be two Executioner blocks
800 // But if it does happen, then go back to not knowing
801 if (_found_exec)
802 _exec_type = 0;
803 else
804 {
805 // Get the type of executioner
806 std::string executioner_type = "Unknown";
807 const auto typeit = n->find("type");
808 if (typeit && typeit != n && typeit->type() == hit::NodeType::Field)
809 executioner_type = n->param<std::string>("type");
810
811 // If it's Steady or Eigenvalue, then it's a steady-state problem
812 if (executioner_type == "Steady" || executioner_type == "Eigenvalue")
813 _exec_type = 1;
814 // If it's Transient
815 else if (executioner_type == "Transient")
816 {
817 // Now we'll see if it's a pseudo transient
818 const auto it = n->find("steady_state_detection");
819 if (it && it != n && it->type() == hit::NodeType::Field &&
820 n->param<bool>("steady_state_detection"))
821 _exec_type = 2;
822 else
823 _exec_type = 3;
824 }
825 }
826
827 _found_exec = true;
828 }
829}
Real f(Real x)
Test function for Brents method.
InputParameters emptyInputParameters()
const ExecFlagType EXEC_PRE_MULTIAPP_SETUP
const ExecFlagType EXEC_TIMESTEP_END
const ExecFlagType EXEC_TIMESTEP_BEGIN
const ExecFlagType EXEC_INITIAL
unsigned int count
registerMooseAction("StochasticToolsApp", ParameterStudyAction, "meta_action")
const std::string name
Definition Setup.h:21
std::shared_ptr< Action > create(const std::string &action, const std::string &action_name, InputParameters &parameters)
InputParameters getValidParams(const std::string &name)
std::vector< const T * > getActions()
void addActionBlock(std::shared_ptr< Action > blk)
static InputParameters validParams()
MooseApp & _app
std::shared_ptr< FEProblemBase > & _problem
const std::string & _current_task
ActionWarehouse & _awh
This class is a hit walker used to see if a list of parameters are all controllable.
std::vector< std::pair< std::string, std::string > > _pars
AreParametersControllableWalker(const std::vector< std::string > &parameters, MooseApp &app)
void walk(const std::string &fullpath, const std::string &nodename, hit::Node *n) override
const ConsoleStream _console
This class is a hit walker used to see what type of execution the input is doing.
unsigned int getExecutionType() const
void walk(const std::string &fullpath, const std::string &nodename, hit::Node *n) override
std::shared_ptr< MooseObject > create(const std::string &obj_name, const std::string &name, const InputParameters &parameters, THREAD_ID tid=0, bool print_deprecated=true)
InputParameters getValidParams(const std::string &name) const
bool isPrivate(const std::string &name) const
bool isParamSetByUser(const std::string &name) const
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)
T & set(const std::string &name, bool quiet_mode=false)
bool isControllable(const std::string &name) const
const std::string & getBase() const
bool hasBase() const
Factory & getFactory()
const InputParameters & parameters() const
const std::string & type() const
const std::string & name() const
void paramError(const std::string &param, Args... args) const
const std::string & _name
const T & getParam(const std::string &name) const
bool isParamValid(const std::string &name) const
std::vector< std::string > getNames() const
unsigned int size() const
ActionFactory & _action_factory
Factory & _factory
OutputName outputName(std::string type) const
The perscribed name of the output objects created in this action.
DistributionName distributionName(unsigned int count) const
The perscribed name of the distribution.
static InputParameters validParams()
std::string stochasticReporterName() const
The perscribed name of the QoI storage object created in this action.
std::vector< DistributionName > distributionNames(unsigned int full_count) const
static MultiMooseEnum distributionTypes()
Return an enum of available distributions for the study.
ReporterName quantityOfInterestName(const ReporterName &qoi) const
The name of the reporter values in the StochasticReporter representing the QoIs.
const unsigned int _multiapp_mode
The multiapp mode.
ParameterStudyAction(const InputParameters &params)
SamplerName samplerName() const
The perscribed name of the sampler created in this action.
std::string statisticsName() const
The perscribed name of the statistics object created in this action.
unsigned int inferMultiAppMode()
This function will infer the best way to run the multiapps.
std::string multiappControlName() const
The perscribed name of the command-line control created in this action.
const std::vector< std::string > & _parameters
The inputted parameter vector.
virtual void act() override
const unsigned int _sampling_type
The sampling type.
MultiAppName multiappName() const
The perscribed name of the multiapp created in this action.
std::string samplerReceiverName() const
The perscribed name of the control given to the sub-app for parameter transfer.
void showObject(std::string type, std::string name, const InputParameters &params) const
Helper function to show the object being built.
static std::set< std::string > statisticsParameters()
List of parameters that are only associated with computing statistics.
static std::vector< std::vector< std::string > > distributionParameters()
This is a vector associating the distribution type and a list of parameters that are needed.
const MultiMooseEnum _distributions
The distributions.
static std::vector< std::map< std::string, bool > > samplerParameters()
This is a vector associating the sampling type with a list of associated parameters The list includes...
std::string parameterTransferName() const
The perscribed name of the parameter transfer created in this action.
std::string reporterTransferName() const
The perscribed name of the reporter transfer created in this action.
const bool _compute_stats
Whether or not we are computing statistics.
static MooseEnum samplingTypes()
Return an enum of available sampling types for the study.
const bool _show_objects
Switch to show the objects being built on console.
const std::string & getObjectName() const
const std::string & getValueName() const
Helper for performing common tasks for stochastic simulations.
std::string realpath(const std::string &path)
MultiMooseEnum makeCalculatorEnum()
Definition Calculators.C:16