Line data Source code
1 : /********************************************************************/
2 : /* SOFTWARE COPYRIGHT NOTIFICATION */
3 : /* Cardinal */
4 : /* */
5 : /* (c) 2021 UChicago Argonne, LLC */
6 : /* ALL RIGHTS RESERVED */
7 : /* */
8 : /* Prepared by UChicago Argonne, LLC */
9 : /* Under Contract No. DE-AC02-06CH11357 */
10 : /* With the U. S. Department of Energy */
11 : /* */
12 : /* Prepared by Battelle Energy Alliance, LLC */
13 : /* Under Contract No. DE-AC07-05ID14517 */
14 : /* With the U. S. Department of Energy */
15 : /* */
16 : /* See LICENSE for full restrictions */
17 : /********************************************************************/
18 :
19 : #ifdef ENABLE_OPENMC_COUPLING
20 :
21 : #include "CriticalitySearchBase.h"
22 : #include "UserErrorChecking.h"
23 : #include "VariadicTable.h"
24 : #include "BrentsMethod.h"
25 :
26 : // To disable tallies
27 : #include "openmc/tallies/tally.h"
28 :
29 : InputParameters
30 172 : CriticalitySearchBase::validParams()
31 : {
32 172 : auto params = MooseObject::validParams();
33 172 : params += OpenMCBase::validParams();
34 344 : params.addRequiredParam<Real>(
35 : "minimum",
36 : "Minimum for values to search over; the root must occur at a value greater than the minimum");
37 344 : params.addRequiredParam<Real>(
38 : "maximum",
39 : "Maximum for values to search over; the root must occur at a value smaller than the maximum");
40 516 : params.addRangeCheckedParam<Real>(
41 344 : "target", 1.0, "target > 0.0", "Target value of k effective to search for");
42 344 : params.addRequiredRangeCheckedParam<Real>(
43 : "root_tol",
44 : "root_tol > 0",
45 : "Absolute tolerance to converge root that yields target value of the multiplication factor.");
46 516 : params.addRangeCheckedParam<Real>(
47 : "k_tol",
48 344 : 1e-3,
49 : "k_tol > 0",
50 : "Absolute tolerance to converge multiplication factor; be aware that if too few particles "
51 : "are used, statistical noise may require many criticality calculations to converge.");
52 344 : params.addParam<MooseEnum>(
53 344 : "estimator", getEigenvalueEnum(), "Type of eigenvalue estimator to use");
54 344 : params.addParam<bool>(
55 : "run_critical_state",
56 344 : true,
57 : "Whether a final k-eigenvalue calculation should be performed on the critical model state.");
58 344 : params.addParam<bool>(
59 : "tally_during_search",
60 344 : false,
61 : "Whether non-eigenvalue tallies should be disabled during the search process as a "
62 : "performance optimization. If set to 'false', `run_critical_state` must be set to 'true' "
63 : "to ensure tallies are computed on the last iteration.");
64 :
65 172 : params.addClassDescription(
66 : "Base class for defining parameters used in a criticality search in OpenMC.");
67 172 : params.registerBase("CriticalitySearch");
68 172 : params.registerSystemAttributeName("CriticalitySearch");
69 172 : params.addPrivateParam<OpenMCCellAverageProblem *>("_openmc_problem");
70 172 : return params;
71 0 : }
72 :
73 94 : CriticalitySearchBase::CriticalitySearchBase(const InputParameters & parameters)
74 : : MooseObject(parameters),
75 : OpenMCBase(this, parameters),
76 94 : _maximum(getParam<Real>("maximum")),
77 188 : _minimum(getParam<Real>("minimum")),
78 188 : _k_tol(getParam<Real>("k_tol")),
79 188 : _root_tol(getParam<Real>("root_tol")),
80 188 : _estimator(getParam<MooseEnum>("estimator").getEnum<eigenvalue::EigenvalueEnum>()),
81 188 : _run_critical_state(getParam<bool>("run_critical_state")),
82 188 : _tally_during_search(getParam<bool>("tally_during_search")),
83 282 : _target(getParam<Real>("target"))
84 : {
85 94 : if (_minimum >= _maximum)
86 4 : paramError("minimum",
87 2 : "The 'minimum' value (" + std::to_string(_minimum) +
88 2 : ") must be less than the 'maximum' value (" + std::to_string(_maximum) + ").");
89 :
90 92 : if (!_tally_during_search && !_run_critical_state)
91 2 : paramError(
92 : "tally_during_search",
93 : "When disabling tallies during intermediate calculations in the criticality search, "
94 : "you must set 'run_critical_state' to 'true'! This ensures you get tallies on the final "
95 : "iteration.");
96 :
97 90 : auto pp_params = _factory.getValidParams("Receiver");
98 90 : _openmc_problem->addPostprocessor("Receiver", _pp_name, pp_params);
99 90 : }
100 :
101 : void
102 76 : CriticalitySearchBase::searchForCriticality(std::function<void()> step_callback)
103 : {
104 76 : _console << "Running criticality search in OpenMC for " << quantity() << " in range "
105 152 : << std::to_string(_minimum) << " - " << std::to_string(_maximum) << " " << units() << " "
106 76 : << std::endl;
107 :
108 : VariadicTable<int, Real, Real, Real> vt(
109 532 : {"Iteration", quantity() + " " + units(), " k (mean) ", " k (std dev) "});
110 76 : vt.setColumnFormat({VariadicTableColumnFormat::AUTO,
111 : VariadicTableColumnFormat::SCIENTIFIC,
112 : VariadicTableColumnFormat::SCIENTIFIC,
113 : VariadicTableColumnFormat::SCIENTIFIC});
114 :
115 : std::function<Real(Real)> func;
116 964 : func = [&](Real x)
117 : {
118 : // update the OpenMC model with a new parameter
119 812 : updateOpenMCModel(x);
120 812 : _inputs.push_back(x);
121 :
122 : // Execute the callback after updating the model prior to running the OpenMC problem.
123 : // This is used by OpenMCCellAverageProblem to update the MOOSE->OpenMC coupling, where
124 : // we need to ensure the correct temperatures and densities are applied to OpenMC cells
125 : // to maintain a critical state on the final solve. This also ensures that cell tallies
126 : // are extracted using the correct cell->element maps.
127 812 : step_callback();
128 :
129 : // Disable tallies during the search. We need to run this on each step as Cardinal wrapped
130 : // tallies have been reset.
131 812 : if (!_tally_during_search)
132 1124 : for (auto & t : openmc::model::tallies)
133 : t->set_active(false);
134 :
135 : // re-run the model
136 812 : int err = openmc_run();
137 812 : if (err)
138 0 : mooseError(openmc_err_msg);
139 :
140 : // fetch k and print values to console
141 812 : Real k = kMean(_estimator);
142 812 : Real k_std_dev = kStandardDeviation(_estimator);
143 812 : _k_values.push_back(k);
144 812 : _k_std_dev_values.push_back(k_std_dev);
145 :
146 812 : vt.addRow(_k_values.size() - 1, x, k, k_std_dev);
147 812 : vt.print(_console);
148 :
149 812 : if (_k_tol < 3 * k_std_dev)
150 102 : mooseDoOnce(mooseWarning(
151 : "The 'k_tol' for the criticality search (" + std::to_string(_k_tol) +
152 : ") is smaller than 3-sigma standard deviation in k (" + std::to_string(3 * k_std_dev) +
153 : "), which may require many search iterations to converge to this tolerance "
154 : "Consider a looser 'k_tol' or increase the number of particles."));
155 :
156 810 : return k - _target;
157 76 : };
158 :
159 76 : BrentsMethod::root(func, _minimum, _maximum, _root_tol);
160 :
161 : // check if the method converged
162 74 : if (abs(kMean(_estimator) - _target) >= _k_tol)
163 2 : mooseWarning("The eigenvalue produced by the criticality search was not within "
164 : "specified 'k_tol' of the target! This could occur if 'k_tol' is too "
165 : "tight for simulation's statistical error. It can also occur if "
166 : "'root_tol' is too loose and the worth curve is steep near the target");
167 :
168 : // Run the critical state calculation, if requested.
169 72 : if (_run_critical_state)
170 : {
171 72 : _console << "Running the critical state calculation" << std::endl;
172 :
173 : // Re-enable tallies.
174 72 : if (!_tally_during_search)
175 96 : for (auto & t : openmc::model::tallies)
176 : t->set_active(true);
177 :
178 72 : int err = openmc_run();
179 72 : if (err)
180 0 : mooseError(openmc_err_msg);
181 : }
182 :
183 : // fill the converged value into a postprocessor
184 144 : _openmc_problem->setPostprocessorValueByName(_pp_name, _inputs.back());
185 300 : }
186 :
187 : #endif
|