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 : #pragma once
10 :
11 : #include <iostream>
12 : #include <typeinfo>
13 :
14 : #include "MooseError.h"
15 : #include "libmesh/id_types.h"
16 : #include "libmesh/parallel.h"
17 : #include "libmesh/parallel_object.h"
18 :
19 : #include "ReporterName.h"
20 : #include "ReporterMode.h"
21 : #include "ReporterState.h"
22 : #include "JsonIO.h"
23 : #include "JsonSyntaxTree.h"
24 : #include "MooseObject.h"
25 : #include <type_traits>
26 :
27 : class ReporterData;
28 :
29 : /**
30 : * This is a helper class to aid with parallel communication of compute Reporter values as well
31 : * as provides a link to the stored Reporter value state object.
32 : *
33 : * @see Reporter, ReporterData, ReporterState
34 : *
35 : * This file contains several reporter context types with specific polymorphism:
36 : *
37 : * ReporterContextBase--->ReporterContext<T>
38 : * | |
39 : * | ReporterGeneralContext<T>
40 : * | | | |
41 : * | | | ReporterGatherContext<T>
42 : * | | ReporterScatterContext<T>
43 : * | ReporterBroadcastContext<T>
44 : * |
45 : * ReporterVectorContext<std::vector<T>>
46 : *
47 : * When creating a new context, it is generally advisable to derive from ReporterGeneralContext
48 : * (@see VectorPostprocessorContext). The reason for the split between ReporterGeneralContext
49 : * and ReporterVectorContext is due to the declareVectorClone and resize functionality. If we
50 : * were to declare a vector clone in ReporterContext there would be a infinite instantiation of
51 : * of vector contexts, which is why this declare is defined in ReporterGeneralContext and an
52 : * error is thrown in ReporterVectorContext. There is also no easy way to partially instantiate
53 : * a member function (you have to due it for the entire class), which is why the resize is
54 : * defined in ReporterVectorContext. That being said, we are always open for improvements,
55 : * especially for simplifying the polymorphism of these contexts.
56 : */
57 : class ReporterContextBase : public libMesh::ParallelObject
58 : {
59 : public:
60 : ReporterContextBase(const libMesh::ParallelObject & other, const MooseObject & producer);
61 73993 : virtual ~ReporterContextBase() = default;
62 :
63 : /// Return the ReporterName that the context is associated
64 : virtual const ReporterName & name() const = 0;
65 :
66 : /// Return the type of the data stored
67 : // This is a helper for ReporterContext::storeInfo
68 : virtual std::string type() const = 0;
69 :
70 : /**
71 : * @returns The derived context type for this context.
72 : *
73 : * This must be overridden in every class.
74 : */
75 : virtual std::string contextType() const = 0;
76 :
77 : /// Called by FEProblemBase::advanceState via ReporterData
78 : virtual void copyValuesBack() = 0;
79 :
80 : /// Called by FEProblemBase::restoreSolutions via ReporterData
81 : virtual bool restoreState() = 0;
82 :
83 : /// Called by JSONOutput::outputReporters to output meta data independent of calculated
84 : /// values
85 : virtual void storeInfo(nlohmann::json & json) const = 0;
86 :
87 : /// Called by JSONOutput::outputReporters to invoke storage of values for output
88 : ///
89 : /// This method exists and is distinct from the RestartableData::store method for JSON output
90 : /// via the JSONOutput object. The RestartableData::store/load methods are designed for restart
91 : /// and include all the data including the old values.
92 : ///
93 : /// This method only outputs the current value within the JSONOutput object.
94 : /// NOTE: nlohmann qualification is needed for argument json because the std::vector overload is
95 : /// not in the std namespace, it's in the nlohmann namespace, and will come up in argument
96 : /// dependent lookup (ADL) only because of this qualification.
97 : ///
98 : /// @see JsonIO.h
99 : /// @see JSONOutput.h
100 : virtual void store(nlohmann::json & json) const = 0;
101 :
102 : /// Called by FEProblemBase::joinAndFinalize via ReporterData
103 : virtual void finalize() = 0; // new ReporterContext objects should override
104 :
105 : /**
106 : * Initialize the producer mode.
107 : *
108 : * This done after construction to allow the constructor to define the available values in the
109 : * ReporterProducerEnum.
110 : *
111 : * @see ReporterData::declareReporterValue
112 : */
113 : void init(const ReporterMode & mode);
114 :
115 : /**
116 : * Return the MooseObject that produces this Reporter.
117 : */
118 148 : const MooseObject & getProducer() const { return _producer; }
119 :
120 : /**
121 : * Return the Reporter value produced mode
122 : */
123 : const ReporterProducerEnum & getProducerModeEnum() const;
124 :
125 : /**
126 : * Helper for enabling generic transfer of Reporter values
127 : * @param r_data The ReporterData on the app that this data is being transferred to
128 : * @param r_name The name of the Report being transferred to
129 : *
130 : * @see MultiAppReporterTransfer
131 : */
132 : virtual void transfer(ReporterData & r_data,
133 : const ReporterName & r_name,
134 : unsigned int time_index = 0) const = 0;
135 :
136 : /**
137 : * Helper for enabling generic transfer of Reporter values to a vector
138 : * @param r_data The ReporterData on the app that this data is being transferred to
139 : * @param r_name The name of the Report being transfered to
140 : *
141 : * @see ReporterTransferInterface
142 : */
143 : virtual void transferToVector(ReporterData & r_data,
144 : const ReporterName & r_name,
145 : dof_id_type index,
146 : unsigned int time_index = 0) const = 0;
147 :
148 : /**
149 : * Helper for enabling generic transfer of a vector Reporter of values to a
150 : * single value
151 : * @param r_data The ReporterData on the app that this data is being transferred to
152 : * @param r_name The name of the Reporter being transferred to
153 : *
154 : * @see ReporterTransferInterface
155 : */
156 : virtual void transferFromVector(ReporterData & r_data,
157 : const ReporterName & r_name,
158 : dof_id_type index,
159 : unsigned int time_index = 0) const = 0;
160 :
161 : /**
162 : * Helper for declaring new reporter values based on this context
163 : *
164 : * @param r_data The ReporterData on the app that this value is being declared
165 : * @param r_name The name of the Reporter value being declared
166 : * @param mode Reporter mode to declare with
167 : *
168 : * @see ReporterTransferInterface
169 : */
170 : virtual void declareClone(ReporterData & r_data,
171 : const ReporterName & r_name,
172 : const ReporterMode & mode,
173 : const MooseObject & producer) const = 0;
174 :
175 : /**
176 : * Helper for declaring new vector reporter values based on this context
177 : *
178 : * @param r_data The ReporterData on the app that this value is being declared
179 : * @param r_name The name of the Reporter value being declared
180 : * @param mode Reporter mode to declare with
181 : *
182 : * @see ReporterTransferInterface
183 : */
184 : virtual void declareVectorClone(ReporterData & r_data,
185 : const ReporterName & r_name,
186 : const ReporterMode & mode,
187 : const MooseObject & producer) const = 0;
188 :
189 : /**
190 : * Helper for resizing vector data
191 : *
192 : * @param local_size Number of elements to resize vector to
193 : */
194 : virtual void resize(dof_id_type local_size) = 0;
195 :
196 : /**
197 : * Helper for clearing vector data
198 : */
199 : virtual void clear() = 0;
200 :
201 : /**
202 : * Helper for summing reporter value.
203 : */
204 : virtual void vectorSum() = 0;
205 :
206 : protected:
207 : /**
208 : * Helper for checking whether or not the state \p state has only the modes \p modes.
209 : */
210 : void requiresConsumerModes(const ReporterStateBase & state,
211 : const std::set<ReporterMode> & modes) const;
212 :
213 : /// The MooseObject that is producing this Reporter
214 : const MooseObject & _producer;
215 :
216 : /// Defines how the Reporter value can be produced and how it is being produced
217 : ReporterProducerEnum _producer_enum;
218 : };
219 :
220 : /**
221 : * General context that is called by all Reporter values to manage the old values.
222 : *
223 : * This is the default context object, the communication aspect includes inspecting the produced
224 : * mode against the consumed mode to be sure that the data is compatible or if automatic
225 : * communication can be done to make them compatible.
226 : */
227 : template <typename T>
228 : class ReporterContext : public ReporterContextBase
229 : {
230 : public:
231 : /**
232 : * Options for automatic parallel operations to perform by the default context
233 : */
234 : enum class AutoOperation
235 : {
236 : NONE,
237 : BROADCAST
238 : };
239 :
240 : ReporterContext(const libMesh::ParallelObject & other,
241 : const MooseObject & producer,
242 : ReporterState<T> & state);
243 : ReporterContext(const libMesh::ParallelObject & other,
244 : const MooseObject & producer,
245 : ReporterState<T> & state,
246 : const T & default_value);
247 :
248 : /**
249 : * Return the name of the Reporter value
250 : */
251 468564 : const ReporterName & name() const override final { return _state.getReporterName(); }
252 :
253 : /**
254 : * Return a reference to the ReporterState object that is storing the Reporter value
255 : */
256 56185 : const ReporterState<T> & state() const { return _state; }
257 :
258 : /**
259 : * Return the type being stored by the associated ReporterState object.
260 : *
261 : * @see ReporterContext::storeInfo
262 : */
263 3490 : virtual std::string type() const override { return MooseUtils::prettyCppType<T>(); }
264 :
265 : /**
266 : * Perform automatic parallel communication based on the producer/consumer modes
267 : */
268 : virtual void finalize() override;
269 :
270 : /**
271 : * Perform type specific transfer
272 : *
273 : * NOTE: This is defined in ReporterData.h to avoid cyclic includes that would arise. I don't
274 : * know of a better solution, if you have one please implement it.
275 : */
276 : virtual void transfer(ReporterData & r_data,
277 : const ReporterName & r_name,
278 : unsigned int time_index = 0) const override;
279 :
280 : /**
281 : * Perform type specific transfer to a vector
282 : *
283 : * NOTE: This is defined in ReporterData.h to avoid cyclic includes that would arise. I don't
284 : * know of a better solution, if you have one please implement it.
285 : */
286 : virtual void transferToVector(ReporterData & r_data,
287 : const ReporterName & r_name,
288 : dof_id_type index,
289 : unsigned int time_index = 0) const override;
290 :
291 : /**
292 : * Perform type specific transfer from a vector
293 : *
294 : * NOTE: This is defined in ReporterData.h to avoid cyclic includes that would arise. I don't
295 : * know of a better solution, if you have one please implement it.
296 : */
297 : virtual void transferFromVector(ReporterData & r_data,
298 : const ReporterName & r_name,
299 : dof_id_type index,
300 : unsigned int time_index = 0) const override;
301 :
302 : protected:
303 993 : void broadcast()
304 : {
305 : if constexpr (MooseUtils::canBroadcast<T>::value)
306 993 : this->comm().broadcast(this->_state.value());
307 : else
308 0 : mooseError("Cannot broadcast Reporter type '", MooseUtils::prettyCppType<T>(), "'");
309 993 : }
310 :
311 : /// Output meta data to JSON, see JSONOutput
312 : virtual void storeInfo(nlohmann::json & json) const override;
313 :
314 : /// Output data to JSON, see JSONOutput
315 : virtual void store(nlohmann::json & json) const override;
316 :
317 : virtual std::string contextType() const override = 0;
318 :
319 : // The following are called by the ReporterData and are not indented for external use
320 : virtual void copyValuesBack() override;
321 :
322 : /// Restore state to its old values. @see ReporterState::restoreState
323 9618 : virtual bool restoreState() override { return _state.restoreState(); }
324 :
325 : /// The state on which this context object operates
326 : ReporterState<T> & _state;
327 : };
328 :
329 : template <typename T>
330 77625 : ReporterContext<T>::ReporterContext(const libMesh::ParallelObject & other,
331 : const MooseObject & producer,
332 : ReporterState<T> & state)
333 77625 : : ReporterContextBase(other, producer), _state(state)
334 : {
335 77625 : _producer_enum.insert(REPORTER_MODE_ROOT, REPORTER_MODE_REPLICATED, REPORTER_MODE_DISTRIBUTED);
336 77625 : }
337 :
338 : template <typename T>
339 3590 : ReporterContext<T>::ReporterContext(const libMesh::ParallelObject & other,
340 : const MooseObject & producer,
341 : ReporterState<T> & state,
342 : const T & default_value)
343 3590 : : ReporterContext(other, producer, state)
344 : {
345 3590 : _state.value() = default_value;
346 3590 : }
347 :
348 : template <typename T>
349 : void
350 517956 : ReporterContext<T>::finalize()
351 : {
352 : // Automatic parallel operation to perform
353 517956 : ReporterContext::AutoOperation auto_operation = ReporterContext::AutoOperation::NONE;
354 :
355 : // Set the default producer mode to ROOT
356 517956 : if (!_producer_enum.isValid())
357 49314 : _producer_enum.assign(REPORTER_MODE_ROOT);
358 :
359 : // Determine auto parallel operation to perform
360 517956 : const auto & producer = _producer_enum; // convenience
361 751001 : for (const auto & pair : _state.getConsumers())
362 : {
363 233053 : const ReporterMode consumer = pair.first;
364 233053 : const MooseObject * moose_object = pair.second;
365 :
366 : // The following sets up the automatic operations and performs error checking for the various
367 : // modes for the producer and consumer
368 : //
369 : // The data is correct and requires no operation for the following conditions (PRODUCER ->
370 : // CONSUMER)
371 : // ROOT -> ROOT
372 : // REPLICATED -> REPLICATED
373 : // DISTRIBUTED -> DISTRIBUTED
374 : // REPLICATED -> ROOT
375 :
376 : // Perform broadcast in the case
377 : // ROOT -> REPLICATED
378 233053 : if (producer == REPORTER_MODE_ROOT && consumer == REPORTER_MODE_REPLICATED)
379 765 : auto_operation = ReporterContext::AutoOperation::BROADCAST;
380 :
381 : // The following are not support and create an error
382 : // ROOT -> DISTRIBUTED
383 : // REPLICATED -> DISTRIBUTED
384 : // DISTRIBUTED -> ROOT
385 : // DISTRIBUTED -> REPLICATED
386 458722 : else if ((producer == REPORTER_MODE_ROOT && consumer == REPORTER_MODE_DISTRIBUTED) ||
387 232288 : (producer == REPORTER_MODE_REPLICATED && consumer == REPORTER_MODE_DISTRIBUTED) ||
388 696860 : (producer == REPORTER_MODE_DISTRIBUTED && consumer == REPORTER_MODE_ROOT) ||
389 232284 : (producer == REPORTER_MODE_DISTRIBUTED && consumer == REPORTER_MODE_REPLICATED))
390 8 : mooseError("The Reporter value \"",
391 : name(),
392 : "\" is being produced in ",
393 : producer,
394 : " mode, but the ",
395 : moose_object->typeAndName(),
396 : " is requesting to consume it in ",
397 : consumer,
398 : " mode, which is not supported.");
399 : }
400 :
401 : // Perform desired auto parallel operation
402 517948 : if (auto_operation == ReporterContext::AutoOperation::BROADCAST)
403 735 : this->broadcast();
404 517948 : }
405 :
406 : template <typename T>
407 : void
408 229607 : ReporterContext<T>::copyValuesBack()
409 : {
410 229607 : _state.copyValuesBack();
411 229607 : }
412 :
413 : template <typename T>
414 : void
415 3490 : ReporterContext<T>::storeInfo(nlohmann::json & json) const
416 : {
417 3490 : json["type"] = this->type();
418 3490 : }
419 :
420 : template <typename T>
421 : void
422 5730 : ReporterContext<T>::store(nlohmann::json & json) const
423 : {
424 5730 : nlohmann::to_json(json, this->_state.value());
425 5730 : }
426 :
427 : template <typename T>
428 : class ReporterGeneralContext : public ReporterContext<T>
429 : {
430 : public:
431 71946 : ReporterGeneralContext(const libMesh::ParallelObject & other,
432 : const MooseObject & producer,
433 : ReporterState<T> & state)
434 71946 : : ReporterContext<T>(other, producer, state)
435 : {
436 71946 : }
437 3590 : ReporterGeneralContext(const libMesh::ParallelObject & other,
438 : const MooseObject & producer,
439 : ReporterState<T> & state,
440 : const T & default_value)
441 3590 : : ReporterContext<T>(other, producer, state, default_value)
442 : {
443 3590 : }
444 :
445 : /**
446 : * Declare a reporter value of same type as this context.
447 : *
448 : * NOTE: This is defined in ReporterData.h to avoid cyclic includes that would arise. I don't
449 : * know of a better solution, if you have one please implement it.
450 : */
451 : virtual void declareClone(ReporterData & r_data,
452 : const ReporterName & r_name,
453 : const ReporterMode & mode,
454 : const MooseObject & producer) const override;
455 : /**
456 : * Declare a reporter value that is a vector of the same type as this context.
457 : *
458 : * NOTE: This is defined in ReporterData.h to avoid cyclic includes that would arise. I don't
459 : * know of a better solution, if you have one please implement it.
460 : */
461 : virtual void declareVectorClone(ReporterData & r_data,
462 : const ReporterName & r_name,
463 : const ReporterMode & mode,
464 : const MooseObject & producer) const override;
465 :
466 : virtual void resize(dof_id_type local_size) final;
467 : virtual void clear() final;
468 : virtual void vectorSum() final;
469 :
470 74 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
471 : };
472 :
473 : // Needed for compile-time checking if T is a vector.
474 : template <typename>
475 : struct is_std_vector : std::false_type
476 : {
477 : };
478 :
479 : template <typename T, typename A>
480 : struct is_std_vector<std::vector<T, A>> : std::true_type
481 : {
482 : };
483 :
484 : template <typename T>
485 : void
486 66 : ReporterGeneralContext<T>::resize(dof_id_type size)
487 : {
488 : if constexpr (is_std_vector<T>::value)
489 66 : this->_state.value().resize(size);
490 : else
491 : {
492 0 : libmesh_ignore(size);
493 0 : mooseError("Cannot resize non vector-type reporter values.");
494 : }
495 66 : }
496 : template <typename T>
497 : void
498 66 : ReporterGeneralContext<T>::clear()
499 : {
500 : if constexpr (is_std_vector<T>::value)
501 66 : this->_state.value().clear();
502 : else
503 0 : mooseError("Cannot clear non vector-type reporter values.");
504 66 : }
505 :
506 : template <typename T>
507 : void
508 66 : ReporterGeneralContext<T>::vectorSum()
509 : {
510 : // Case 1: T is a numeric type that we can sum (excluding bool)
511 : if constexpr (std::is_arithmetic<T>::value && !std::is_same<T, bool>::value)
512 : {
513 : // Perform summation of the scalar value across all processors
514 0 : this->comm().sum(this->_state.value());
515 0 : return;
516 : }
517 : // Case 2: T is a vector type
518 : else if constexpr (is_std_vector<T>::value)
519 : {
520 : using VectorValueType = typename T::value_type;
521 :
522 : // Check if the vector elements are of a numeric type
523 : if constexpr (std::is_arithmetic<VectorValueType>::value &&
524 : !std::is_same<VectorValueType, bool>::value)
525 : {
526 : // Perform summation of the vector elements across all processors
527 33 : this->comm().sum(this->_state.value());
528 33 : return;
529 : }
530 : // Check if the vector elements are also vectors
531 : else if constexpr (is_std_vector<VectorValueType>::value)
532 : {
533 : using InnerValueType = typename VectorValueType::value_type;
534 :
535 : // Check if the inner vector elements are of a numeric type
536 : if constexpr (std::is_arithmetic<InnerValueType>::value &&
537 : !std::is_same<InnerValueType, bool>::value)
538 : {
539 : #ifdef DEBUG
540 : auto vec_size = this->_state.value().size();
541 : this->comm().max(vec_size);
542 : // Assert only passes on all ranks if they are all the same size.
543 : mooseAssert(this->_state.value().size() == vec_size,
544 : "Reporter vector have different sizes on different ranks.");
545 : #endif
546 : // Iterate over each inner vector in the outer vector
547 165 : for (auto & innerVector : this->_state.value())
548 : {
549 : // Get the maximum size of the inner vector across all processors
550 132 : dof_id_type maxInnerSize = innerVector.size();
551 132 : this->comm().max(maxInnerSize);
552 :
553 : // Resize the inner vector to the maximum size
554 132 : innerVector.resize(maxInnerSize);
555 :
556 : // Perform summation of the inner vector elements across all processors
557 132 : this->comm().sum(innerVector);
558 : }
559 33 : return;
560 : }
561 : }
562 : }
563 :
564 0 : mooseError("Cannot perform sum operation on non-numeric or unsupported vector types.");
565 : }
566 :
567 : /**
568 : * A context that broadcasts the Reporter value from the root processor
569 : */
570 : template <typename T>
571 : class ReporterBroadcastContext : public ReporterGeneralContext<T>
572 : {
573 : public:
574 : ReporterBroadcastContext(const libMesh::ParallelObject & other,
575 : const MooseObject & producer,
576 : ReporterState<T> & state);
577 : ReporterBroadcastContext(const libMesh::ParallelObject & other,
578 : const MooseObject & producer,
579 : ReporterState<T> & state,
580 : const T & default_value);
581 : virtual void finalize() override;
582 0 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
583 : };
584 :
585 : template <typename T>
586 95 : ReporterBroadcastContext<T>::ReporterBroadcastContext(const libMesh::ParallelObject & other,
587 : const MooseObject & producer,
588 : ReporterState<T> & state)
589 95 : : ReporterGeneralContext<T>(other, producer, state)
590 : {
591 95 : this->_producer_enum.clear();
592 95 : this->_producer_enum.insert(REPORTER_MODE_ROOT);
593 95 : }
594 :
595 : template <typename T>
596 : ReporterBroadcastContext<T>::ReporterBroadcastContext(const libMesh::ParallelObject & other,
597 : const MooseObject & producer,
598 : ReporterState<T> & state,
599 : const T & default_value)
600 : : ReporterGeneralContext<T>(other, producer, state, default_value)
601 : {
602 : this->_producer_enum.clear();
603 : this->_producer_enum.insert(REPORTER_MODE_ROOT);
604 : }
605 :
606 : template <typename T>
607 : void
608 258 : ReporterBroadcastContext<T>::finalize()
609 : {
610 774 : this->requiresConsumerModes(this->_state, {REPORTER_MODE_UNSET, REPORTER_MODE_REPLICATED});
611 258 : this->broadcast();
612 516 : }
613 :
614 : /**
615 : * A context that scatters the Reporter value from the root processor
616 : */
617 : template <typename T>
618 : class ReporterScatterContext : public ReporterGeneralContext<T>
619 : {
620 : public:
621 : ReporterScatterContext(const libMesh::ParallelObject & other,
622 : const MooseObject & producer,
623 : ReporterState<T> & state,
624 : const std::vector<T> & values);
625 : ReporterScatterContext(const libMesh::ParallelObject & other,
626 : const MooseObject & producer,
627 : ReporterState<T> & state,
628 : const T & default_value,
629 : const std::vector<T> & values);
630 :
631 : virtual void finalize() override;
632 0 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
633 :
634 : private:
635 : /// The values to scatter
636 : const std::vector<T> & _values;
637 : };
638 :
639 : template <typename T>
640 95 : ReporterScatterContext<T>::ReporterScatterContext(const libMesh::ParallelObject & other,
641 : const MooseObject & producer,
642 : ReporterState<T> & state,
643 : const std::vector<T> & values)
644 95 : : ReporterGeneralContext<T>(other, producer, state), _values(values)
645 : {
646 95 : this->_producer_enum.clear();
647 95 : this->_producer_enum.insert(REPORTER_MODE_ROOT);
648 95 : }
649 :
650 : template <typename T>
651 : ReporterScatterContext<T>::ReporterScatterContext(const libMesh::ParallelObject & other,
652 : const MooseObject & producer,
653 : ReporterState<T> & state,
654 : const T & default_value,
655 : const std::vector<T> & values)
656 : : ReporterGeneralContext<T>(other, producer, state, default_value), _values(values)
657 : {
658 : this->_producer_enum.clear();
659 : this->_producer_enum.insert(REPORTER_MODE_ROOT);
660 : }
661 :
662 : template <typename T>
663 : void
664 250 : ReporterScatterContext<T>::finalize()
665 : {
666 750 : this->requiresConsumerModes(this->_state, {REPORTER_MODE_UNSET, REPORTER_MODE_REPLICATED});
667 :
668 : mooseAssert(this->processor_id() == 0 ? _values.size() == this->n_processors() : true,
669 : "Vector to be scattered must be sized to match the number of processors");
670 : mooseAssert(
671 : this->processor_id() > 0 ? _values.size() == 0 : true,
672 : "Vector to be scattered must be sized to zero on processors except for the root processor");
673 250 : this->comm().scatter(_values, this->_state.value());
674 500 : }
675 :
676 : /**
677 : * A context that gathers the Reporter value to the root processor
678 : */
679 : template <typename T>
680 : class ReporterGatherContext : public ReporterGeneralContext<T>
681 : {
682 : public:
683 : ReporterGatherContext(const libMesh::ParallelObject & other,
684 : const MooseObject & producer,
685 : ReporterState<T> & state);
686 : ReporterGatherContext(const libMesh::ParallelObject & other,
687 : const MooseObject & producer,
688 : ReporterState<T> & state,
689 : const T & default_value);
690 :
691 : virtual void finalize() override;
692 0 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
693 : };
694 :
695 : template <typename T>
696 125 : ReporterGatherContext<T>::ReporterGatherContext(const libMesh::ParallelObject & other,
697 : const MooseObject & producer,
698 : ReporterState<T> & state)
699 125 : : ReporterGeneralContext<T>(other, producer, state)
700 : {
701 125 : this->_producer_enum.clear();
702 125 : this->_producer_enum.insert(REPORTER_MODE_DISTRIBUTED);
703 125 : }
704 :
705 : template <typename T>
706 : ReporterGatherContext<T>::ReporterGatherContext(const libMesh::ParallelObject & other,
707 : const MooseObject & producer,
708 : ReporterState<T> & state,
709 : const T & default_value)
710 : : ReporterGeneralContext<T>(other, producer, state, default_value)
711 : {
712 : this->_producer_enum.clear();
713 : this->_producer_enum.insert(REPORTER_MODE_DISTRIBUTED);
714 : }
715 :
716 : template <typename T>
717 : void
718 280 : ReporterGatherContext<T>::finalize()
719 : {
720 840 : this->requiresConsumerModes(this->_state, {REPORTER_MODE_UNSET, REPORTER_MODE_ROOT});
721 280 : this->comm().gather(0, this->_state.value());
722 560 : }
723 :
724 : /**
725 : * This context is specific for vector types of reporters, mainly for declaring a vector
726 : * of the type from another context. As well as resizing the vector of data.
727 : *
728 : * @see ReporterGeneralContext::declareVectorClone and ReporterTransferInterface
729 : */
730 : template <typename T>
731 : class ReporterVectorContext : public ReporterContext<std::vector<T>>
732 : {
733 : public:
734 : ReporterVectorContext(const libMesh::ParallelObject & other,
735 : const MooseObject & producer,
736 : ReporterState<std::vector<T>> & state);
737 : ReporterVectorContext(const libMesh::ParallelObject & other,
738 : const MooseObject & producer,
739 : ReporterState<std::vector<T>> & state,
740 : const std::vector<T> & default_value);
741 :
742 : /**
743 : * This simply throws an error to avoid infinite instantiations.
744 : * It is defined in ReporterData.h to avoid cyclic included.
745 : */
746 : virtual void declareClone(ReporterData & r_data,
747 : const ReporterName & r_name,
748 : const ReporterMode & mode,
749 : const MooseObject & producer) const final;
750 :
751 : /**
752 : * This simply throws an error to avoid infinite instantiations.
753 : * It is defined in ReporterData.h to avoid cyclic included.
754 : */
755 : virtual void declareVectorClone(ReporterData & r_data,
756 : const ReporterName & r_name,
757 : const ReporterMode & mode,
758 : const MooseObject & producer) const final;
759 :
760 : /**
761 : * Since we know that the _state value is a vector type, we can resize it based
762 : * on @param local_size
763 : */
764 387 : virtual void resize(dof_id_type local_size) override { this->_state.value().resize(local_size); }
765 :
766 : /**
767 : * Since we know that the _state value is a vector type, we can clear it.
768 : */
769 0 : virtual void clear() override { this->_state.value().clear(); }
770 :
771 0 : virtual void vectorSum() override
772 : {
773 : // Case 1: T is type that we can sum
774 : if constexpr (std::is_arithmetic<T>::value &&
775 : !std::is_same<T, bool>::value) // We can't sum bools.
776 : {
777 : // Resize vector to max size
778 0 : dof_id_type vec_size = this->_state.value().size();
779 0 : this->comm().max(vec_size);
780 0 : this->_state.value().resize(vec_size);
781 :
782 0 : this->comm().sum(this->_state.value());
783 0 : return;
784 : }
785 : // Case 2: T is a vector
786 : else if constexpr (is_std_vector<T>::value)
787 : {
788 : // Resize vector to max size
789 0 : dof_id_type vec_size = this->_state.value().size();
790 0 : this->comm().max(vec_size);
791 0 : this->_state.value().resize(vec_size);
792 :
793 : using ValueType = typename T::value_type;
794 : // Check if the ValueType is a vector
795 : if constexpr (std::is_arithmetic<ValueType>::value && !std::is_same<ValueType, bool>::value)
796 : {
797 : #ifdef DEBUG
798 : auto vec_size = this->_state.value().size();
799 : this->comm().max(vec_size);
800 : // Assert only passes on all ranks if they are all the same size.
801 : mooseAssert(this->_state.value().size() == vec_size,
802 : "Reporter vector have different sizes on different ranks.");
803 : #endif
804 0 : for (auto & val_vec : this->_state.value())
805 : {
806 : // Resize vector to max size
807 0 : dof_id_type val_vec_size = val_vec.size();
808 0 : this->comm().max(val_vec_size);
809 0 : val_vec.resize(val_vec_size);
810 :
811 0 : this->comm().sum(val_vec);
812 : }
813 0 : return;
814 : }
815 : }
816 : // If we don't perform a summing operation, error out.
817 0 : mooseError("Cannot perform sum operation on non-numeric or unsupported vector types.");
818 : }
819 :
820 0 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
821 : };
822 :
823 : template <typename T>
824 2089 : ReporterVectorContext<T>::ReporterVectorContext(const libMesh::ParallelObject & other,
825 : const MooseObject & producer,
826 : ReporterState<std::vector<T>> & state)
827 2089 : : ReporterContext<std::vector<T>>(other, producer, state)
828 : {
829 2089 : }
830 :
831 : template <typename T>
832 : ReporterVectorContext<T>::ReporterVectorContext(const libMesh::ParallelObject & other,
833 : const MooseObject & producer,
834 : ReporterState<std::vector<T>> & state,
835 : const std::vector<T> & default_value)
836 : : ReporterContext<std::vector<T>>(other, producer, state, default_value)
837 : {
838 : }
|