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 : // STL includes
11 : #include <iterator>
12 :
13 : // MOOSE includes
14 : #include "Sampler.h"
15 :
16 : InputParameters
17 3635 : Sampler::validParams()
18 : {
19 3635 : InputParameters params = MooseObject::validParams();
20 3635 : params += SetupInterface::validParams();
21 3635 : params += DistributionInterface::validParams();
22 7270 : params.addClassDescription("A base class for distribution sampling.");
23 :
24 3635 : ExecFlagEnum & exec_enum = params.set<ExecFlagEnum>("execute_on", true);
25 3635 : exec_enum.addAvailableFlags(EXEC_PRE_MULTIAPP_SETUP);
26 7270 : exec_enum = {EXEC_INITIAL};
27 :
28 14540 : params.addParam<unsigned int>("seed", 0, "Random number generator initial seed");
29 7270 : params.registerBase("Sampler");
30 7270 : params.registerSystemAttributeName("Sampler");
31 :
32 : // Define the allowable limits for data returned by getSamples/getLocalSamples/getNextLocalRow
33 : // to prevent system for going over allowable limits. The DenseMatrix object uses unsigned int
34 : // for size definition, so as start the limits will be based the max of unsigned int. Note,
35 : // the values here are the limits of the number of items in the complete container. dof_id_type
36 : // is used just in case in the future we need more.
37 10905 : params.addParam<dof_id_type>("limit_get_global_samples",
38 7270 : 0.1 * std::numeric_limits<unsigned int>::max(),
39 : "The maximum allowed number of items in the DenseMatrix returned by "
40 : "getGlobalSamples method.");
41 10905 : params.addParam<dof_id_type>(
42 : "limit_get_local_samples",
43 7270 : 0.1 * std::numeric_limits<unsigned int>::max(),
44 : "The maximum allowed number of items in the DenseMatrix returned by getLocalSamples method.");
45 10905 : params.addParam<dof_id_type>(
46 : "limit_get_next_local_row",
47 7270 : 0.1 * std::numeric_limits<unsigned int>::max(),
48 : "The maximum allowed number of items in the std::vector returned by getNextLocalRow method.");
49 :
50 10905 : params.addParam<unsigned int>(
51 : "min_procs_per_row",
52 7270 : 1,
53 : "This will ensure that the sampler is partitioned properly when "
54 : "'MultiApp/*/min_procs_per_app' is specified. It is not recommended to use otherwise.");
55 7270 : params.addParam<unsigned int>(
56 : "max_procs_per_row",
57 7270 : std::numeric_limits<unsigned int>::max(),
58 : "This will ensure that the sampler is partitioned properly when "
59 : "'MultiApp/*/max_procs_per_app' is specified. It is not recommended to use otherwise.");
60 3635 : return params;
61 3635 : }
62 :
63 312 : Sampler::Sampler(const InputParameters & parameters)
64 : : MooseObject(parameters),
65 : SetupInterface(this),
66 : DistributionInterface(this),
67 : PerfGraphInterface(this),
68 : SamplerInterface(this),
69 : VectorPostprocessorInterface(this),
70 : ReporterInterface(this),
71 312 : _min_procs_per_row(getParam<unsigned int>("min_procs_per_row") > n_processors()
72 312 : ? n_processors()
73 936 : : getParam<unsigned int>("min_procs_per_row")),
74 624 : _max_procs_per_row(getParam<unsigned int>("max_procs_per_row")),
75 312 : _n_rows(0),
76 312 : _n_cols(0),
77 312 : _n_seeds(1),
78 312 : _next_local_row_requires_state_restore(true),
79 312 : _initialized(false),
80 312 : _needs_reinit(true),
81 312 : _has_executed(false),
82 624 : _limit_get_global_samples(getParam<dof_id_type>("limit_get_global_samples")),
83 624 : _limit_get_local_samples(getParam<dof_id_type>("limit_get_local_samples")),
84 624 : _limit_get_next_local_row(getParam<dof_id_type>("limit_get_next_local_row")),
85 936 : _auto_advance_generators(true)
86 : {
87 312 : }
88 :
89 : void
90 303 : Sampler::init()
91 : {
92 : // The init() method is private so it is un-likely to be called, but just in case the following
93 : // was added to help avoid future mistakes.
94 303 : if (_initialized)
95 0 : mooseError("The Sampler::init() method is called automatically and should not be called.");
96 :
97 : // Initialize the parallel partition of sample to return
98 303 : reinit();
99 :
100 : // Seed the "master" seed generator
101 606 : const unsigned int seed = getParam<unsigned int>("seed");
102 303 : MooseRandom seed_generator;
103 303 : seed_generator.seed(0, seed);
104 :
105 : // See the "secondary" generator that will be used for the random number generation
106 303 : _generators.resize(_n_seeds);
107 606 : for (std::size_t i = 0; i < _n_seeds; ++i)
108 : {
109 303 : const auto gseed = seed_generator.randl(0);
110 303 : _generators[i] = std::make_unique<MooseRandomStateless>(gseed);
111 : }
112 :
113 : // Mark class as initialized, which locks out certain methods
114 303 : _initialized = true;
115 303 : }
116 :
117 : void
118 307 : Sampler::reinit()
119 : {
120 307 : _rank_config.first = constructRankConfig(false);
121 307 : _rank_config.second = constructRankConfig(true);
122 307 : if (_rank_config.first.num_local_sims != _rank_config.second.num_local_sims ||
123 307 : _rank_config.first.first_local_sim_index != _rank_config.second.first_local_sim_index ||
124 307 : _rank_config.first.is_first_local_rank != _rank_config.second.is_first_local_rank)
125 0 : mooseError("Sampler has inconsistent partitionings for normal and batch mode.");
126 :
127 307 : _n_local_rows = _rank_config.first.is_first_local_rank ? _rank_config.first.num_local_sims : 0;
128 307 : _local_row_begin = _rank_config.first.first_local_sim_index;
129 307 : _local_row_end = _local_row_begin + _n_local_rows;
130 :
131 : // Set the next row iterator index
132 307 : _next_local_row = _local_row_begin;
133 :
134 : // Create communicator that only has processors with rows
135 307 : _communicator.split(_n_local_rows > 0 ? 1 : MPI_UNDEFINED, processor_id(), _local_comm);
136 :
137 : // Update reinit() flag (see execute method)
138 307 : _needs_reinit = false;
139 307 : }
140 :
141 : LocalRankConfig
142 614 : Sampler::constructRankConfig(bool batch_mode) const
143 : {
144 614 : return rankConfig(
145 1228 : processor_id(), n_processors(), _n_rows, _min_procs_per_row, _max_procs_per_row, batch_mode);
146 : }
147 :
148 : void
149 340 : Sampler::setNumberOfRows(dof_id_type n_rows)
150 : {
151 340 : if (n_rows == 0)
152 3 : mooseError("The number of rows cannot be zero.");
153 :
154 337 : _needs_reinit = true;
155 337 : _n_rows = n_rows;
156 337 : }
157 :
158 : void
159 309 : Sampler::setNumberOfCols(dof_id_type n_cols)
160 : {
161 309 : if (n_cols == 0)
162 3 : mooseError("The number of columns cannot be zero.");
163 :
164 306 : _needs_reinit = true;
165 306 : _n_cols = n_cols;
166 306 : }
167 :
168 : void
169 6 : Sampler::setNumberOfRandomSeeds(std::size_t n_seeds)
170 : {
171 6 : if (_initialized)
172 3 : mooseError("The 'setNumberOfRandomSeeds()' method can not be called after the Sampler has been "
173 : "initialized; "
174 : "this method should be called in the constructor of the Sampler object.");
175 :
176 3 : if (n_seeds == 0)
177 3 : mooseError("The number of seeds must be larger than zero.");
178 :
179 0 : _n_seeds = n_seeds;
180 0 : }
181 :
182 : void
183 295 : Sampler::execute()
184 : {
185 295 : executeSetUp();
186 271 : if (_needs_reinit)
187 4 : reinit();
188 :
189 271 : if (_has_executed)
190 0 : advanceGeneratorsInternal(_n_rows * _n_cols);
191 :
192 271 : executeTearDown();
193 271 : _has_executed = true;
194 271 : }
195 :
196 : DenseMatrix<Real>
197 175 : Sampler::getGlobalSamples()
198 : {
199 875 : TIME_SECTION("getGlobalSamples", 1, "Retrieving Global Samples");
200 :
201 175 : checkReinitStatus();
202 :
203 172 : if (_n_rows * _n_cols > _limit_get_global_samples)
204 3 : paramError("limit_get_global_samples",
205 : "The number of entries in the DenseMatrix (",
206 3 : _n_rows * _n_cols,
207 : ") exceeds the allowed limit of ",
208 3 : _limit_get_global_samples,
209 : ".");
210 :
211 169 : _next_local_row_requires_state_restore = true;
212 169 : DenseMatrix<Real> output(_n_rows, _n_cols);
213 169 : computeSampleMatrix(output);
214 332 : return output;
215 166 : }
216 :
217 : DenseMatrix<Real>
218 122 : Sampler::getLocalSamples()
219 : {
220 610 : TIME_SECTION("getLocalSamples", 1, "Retrieving Local Samples");
221 :
222 122 : checkReinitStatus();
223 :
224 119 : if (_n_local_rows * _n_cols > _limit_get_local_samples)
225 4 : paramError("limit_get_local_samples",
226 : "The number of entries in the DenseMatrix (",
227 4 : _n_local_rows * _n_cols,
228 : ") exceeds the allowed limit of ",
229 4 : _limit_get_local_samples,
230 : ".");
231 :
232 115 : DenseMatrix<Real> output(_n_local_rows, _n_cols);
233 115 : if (_n_local_rows == 0)
234 0 : return output;
235 :
236 115 : _next_local_row_requires_state_restore = true;
237 115 : computeLocalSampleMatrix(output);
238 115 : return output;
239 115 : }
240 :
241 : std::vector<Real>
242 1200342 : Sampler::getNextLocalRow()
243 : {
244 1200342 : checkReinitStatus();
245 :
246 1200339 : if (_next_local_row_requires_state_restore)
247 : {
248 83 : _next_local_row_requires_state_restore = false;
249 :
250 83 : if (_n_cols > _limit_get_next_local_row)
251 3 : paramError("limit_get_next_local_row",
252 : "The number of entries in the std::vector (",
253 : _n_cols,
254 : ") exceeds the allowed limit of ",
255 3 : _limit_get_next_local_row,
256 : ".");
257 : }
258 :
259 1200336 : std::vector<Real> output(_n_cols);
260 1200336 : computeSampleRow(_next_local_row, output);
261 : mooseAssert(output.size() == _n_cols, "The row of sample data is not sized correctly.");
262 1200336 : _next_local_row++;
263 :
264 1200336 : if (_next_local_row == _local_row_end)
265 : {
266 75 : _next_local_row = _local_row_begin;
267 75 : _next_local_row_requires_state_restore = true;
268 : }
269 :
270 1200336 : return output;
271 0 : }
272 :
273 : void
274 169 : Sampler::computeSampleMatrix(DenseMatrix<Real> & matrix)
275 : {
276 845 : TIME_SECTION("computeSampleMatrix", 2, "Computing Sample Matrix");
277 :
278 3001683 : for (dof_id_type i = 0; i < _n_rows; ++i)
279 : {
280 3001517 : std::vector<Real> row(_n_cols, 0);
281 3001517 : computeSampleRow(i, row);
282 : mooseAssert(row.size() == _n_cols, "The row of sample data is not sized correctly.");
283 : mooseAssert(!_needs_reinit,
284 : "Changing the size of the sample must not occur during matrix access.");
285 3001514 : std::copy(row.begin(), row.end(), matrix.get_values().begin() + i * _n_cols);
286 3001514 : }
287 166 : }
288 :
289 : void
290 115 : Sampler::computeLocalSampleMatrix(DenseMatrix<Real> & matrix)
291 : {
292 575 : TIME_SECTION("computeLocalSampleMatrix", 2, "Computing Local Sample Matrix");
293 :
294 1200717 : for (dof_id_type i = _local_row_begin; i < _local_row_end; ++i)
295 : {
296 1200602 : std::vector<Real> row(_n_cols, 0);
297 1200602 : computeSampleRow(i, row);
298 : mooseAssert(row.size() == _n_cols, "The row of sample data is not sized correctly.");
299 : mooseAssert(!_needs_reinit,
300 : "Changing the size of the sample must not occur during matrix access.");
301 1200602 : std::copy(
302 1200602 : row.begin(), row.end(), matrix.get_values().begin() + ((i - _local_row_begin) * _n_cols));
303 1200602 : }
304 115 : }
305 :
306 : void
307 5402455 : Sampler::computeSampleRow(dof_id_type i, std::vector<Real> & data)
308 : {
309 10821861 : for (dof_id_type j = 0; j < _n_cols; ++j)
310 : {
311 5419409 : data[j] = computeSample(i, j);
312 : mooseAssert(!_needs_reinit,
313 : "Changing the size of the sample must not occur during matrix access.");
314 : }
315 5402452 : }
316 :
317 : void
318 0 : Sampler::advanceGenerators(const dof_id_type count)
319 : {
320 0 : TIME_SECTION("advanceGenerators", 2, "Advancing Generators");
321 :
322 0 : for (std::size_t j = 0; j < _generators.size(); ++j)
323 0 : advanceGenerator(j, count);
324 0 : }
325 : void
326 0 : Sampler::advanceGenerator(const unsigned int seed_index, const dof_id_type count)
327 : {
328 : mooseAssert(seed_index < _generators.size(), "The seed number index does not exists.");
329 0 : _generators[seed_index]->advance(count);
330 0 : }
331 :
332 : void
333 0 : Sampler::advanceGeneratorsInternal(const dof_id_type count)
334 : {
335 0 : if (_auto_advance_generators)
336 0 : advanceGenerators(count);
337 0 : }
338 :
339 : void
340 0 : Sampler::setAutoAdvanceGenerators(const bool state)
341 : {
342 0 : _auto_advance_generators = state;
343 0 : }
344 :
345 : Real
346 10416 : Sampler::getRand(std::size_t n, unsigned int index) const
347 : {
348 : mooseAssert(index < _generators.size(), "The seed number index does not exists.");
349 10416 : return _generators[index]->rand(n);
350 : }
351 :
352 : unsigned int
353 0 : Sampler::getRandl(std::size_t n, unsigned int lower, unsigned int upper, unsigned int index) const
354 : {
355 : mooseAssert(index < _generators.size(), "The seed number index does not exists.");
356 0 : return _generators[index]->randl(n, lower, upper);
357 : }
358 :
359 : dof_id_type
360 31 : Sampler::getNumberOfRows() const
361 : {
362 31 : checkReinitStatus();
363 28 : return _n_rows;
364 : }
365 :
366 : dof_id_type
367 10419 : Sampler::getNumberOfCols() const
368 : {
369 10419 : checkReinitStatus();
370 10416 : return _n_cols;
371 : }
372 :
373 : dof_id_type
374 3 : Sampler::getNumberOfLocalRows() const
375 : {
376 3 : checkReinitStatus();
377 0 : return _n_local_rows;
378 : }
379 :
380 : dof_id_type
381 81 : Sampler::getLocalRowBegin() const
382 : {
383 81 : checkReinitStatus();
384 78 : return _local_row_begin;
385 : }
386 :
387 : dof_id_type
388 1200382 : Sampler::getLocalRowEnd() const
389 : {
390 1200382 : checkReinitStatus();
391 1200379 : return _local_row_end;
392 : }
393 :
394 : void
395 2411555 : Sampler::checkReinitStatus() const
396 : {
397 2411555 : if (_needs_reinit)
398 24 : mooseError("A call to 'setNumberOfRows()/Columns()' was made after initialization, as such the "
399 : "expected Sampler output has changed and a new sample must be created. However, a "
400 : "call to Sampler::reinit() was not performed. The renit() method is automatically "
401 : "called during Sampler execution, which occurs according to the 'execute_on' "
402 : "settings of the Sampler object. An adjustment to this parameter may be required. "
403 : "It is recommended that calls to 'setNumberOfRows()/Columns() occur within the "
404 : "Sampler::executeSetUp() method; this will ensure that the reinitialize is handled "
405 : "correctly. Have a nice day.");
406 2411531 : }
|