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