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 79476 : 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 132 : 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 499440 : 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 60295 : 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 4126 : 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 1074 : void broadcast()
304 : {
305 : if constexpr (MooseUtils::canBroadcast<T>::value)
306 1074 : this->comm().broadcast(this->_state.value());
307 : else
308 0 : mooseError("Cannot broadcast Reporter type '", MooseUtils::prettyCppType<T>(), "'");
309 1074 : }
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 5001 : 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 81761 : ReporterContext<T>::ReporterContext(const libMesh::ParallelObject & other,
331 : const MooseObject & producer,
332 1666 : ReporterState<T> & state)
333 80095 : : ReporterContextBase(other, producer), _state(state)
334 : {
335 81761 : _producer_enum.insert(REPORTER_MODE_ROOT, REPORTER_MODE_REPLICATED, REPORTER_MODE_DISTRIBUTED);
336 81761 : }
337 :
338 : template <typename T>
339 3982 : ReporterContext<T>::ReporterContext(const libMesh::ParallelObject & other,
340 : const MooseObject & producer,
341 : ReporterState<T> & state,
342 : const T & default_value)
343 3982 : : ReporterContext(other, producer, state)
344 : {
345 3982 : _state.value() = default_value;
346 3982 : }
347 :
348 : template <typename T>
349 : void
350 567087 : ReporterContext<T>::finalize()
351 : {
352 : // Automatic parallel operation to perform
353 567087 : ReporterContext::AutoOperation auto_operation = ReporterContext::AutoOperation::NONE;
354 :
355 : // Set the default producer mode to ROOT
356 567087 : if (!_producer_enum.isValid())
357 50737 : _producer_enum.assign(REPORTER_MODE_ROOT);
358 :
359 : // Determine auto parallel operation to perform
360 567087 : const auto & producer = _producer_enum; // convenience
361 814037 : for (const auto & pair : _state.getConsumers())
362 : {
363 246956 : const ReporterMode consumer = pair.first;
364 246956 : 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 246956 : if (static_cast<int>(producer) == REPORTER_MODE_ROOT && consumer == REPORTER_MODE_REPLICATED)
379 855 : 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 246101 : else if ((static_cast<int>(producer) == REPORTER_MODE_ROOT &&
387 485572 : consumer == REPORTER_MODE_DISTRIBUTED) ||
388 245824 : (static_cast<int>(producer) == REPORTER_MODE_REPLICATED &&
389 251894 : consumer == REPORTER_MODE_DISTRIBUTED) ||
390 245824 : (static_cast<int>(producer) == REPORTER_MODE_DISTRIBUTED &&
391 491654 : consumer == REPORTER_MODE_ROOT) ||
392 245821 : (static_cast<int>(producer) == REPORTER_MODE_DISTRIBUTED &&
393 3 : consumer == REPORTER_MODE_REPLICATED))
394 6 : mooseError("The Reporter value \"",
395 : name(),
396 : "\" is being produced in ",
397 : producer,
398 : " mode, but the ",
399 : moose_object->typeAndName(),
400 : " is requesting to consume it in ",
401 : consumer,
402 : " mode, which is not supported.");
403 : }
404 :
405 : // Perform desired auto parallel operation
406 567081 : if (auto_operation == ReporterContext::AutoOperation::BROADCAST)
407 825 : this->broadcast();
408 567081 : }
409 :
410 : template <typename T>
411 : void
412 237556 : ReporterContext<T>::copyValuesBack()
413 : {
414 237556 : _state.copyValuesBack();
415 237556 : }
416 :
417 : template <typename T>
418 : void
419 4126 : ReporterContext<T>::storeInfo(nlohmann::json & json) const
420 : {
421 4126 : json["type"] = this->type();
422 4126 : }
423 :
424 : template <typename T>
425 : void
426 6752 : ReporterContext<T>::store(nlohmann::json & json) const
427 : {
428 6752 : nlohmann::to_json(json, this->_state.value());
429 6752 : }
430 :
431 : template <typename T>
432 : class ReporterGeneralContext : public ReporterContext<T>
433 : {
434 : public:
435 75427 : ReporterGeneralContext(const libMesh::ParallelObject & other,
436 : const MooseObject & producer,
437 1135 : ReporterState<T> & state)
438 74292 : : ReporterContext<T>(other, producer, state)
439 : {
440 75427 : }
441 3982 : ReporterGeneralContext(const libMesh::ParallelObject & other,
442 : const MooseObject & producer,
443 : ReporterState<T> & state,
444 : const T & default_value)
445 3982 : : ReporterContext<T>(other, producer, state, default_value)
446 : {
447 3982 : }
448 :
449 : /**
450 : * Declare a reporter value of same type as this context.
451 : *
452 : * NOTE: This is defined in ReporterData.h to avoid cyclic includes that would arise. I don't
453 : * know of a better solution, if you have one please implement it.
454 : */
455 : virtual void declareClone(ReporterData & r_data,
456 : const ReporterName & r_name,
457 : const ReporterMode & mode,
458 : const MooseObject & producer) const override;
459 : /**
460 : * Declare a reporter value that is a vector of the same type as this context.
461 : *
462 : * NOTE: This is defined in ReporterData.h to avoid cyclic includes that would arise. I don't
463 : * know of a better solution, if you have one please implement it.
464 : */
465 : virtual void declareVectorClone(ReporterData & r_data,
466 : const ReporterName & r_name,
467 : const ReporterMode & mode,
468 : const MooseObject & producer) const override;
469 :
470 : virtual void resize(dof_id_type local_size) final;
471 : virtual void clear() final;
472 : virtual void vectorSum() final;
473 :
474 66 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
475 : };
476 :
477 : // Needed for compile-time checking if T is a vector.
478 : template <typename>
479 : struct is_std_vector : std::false_type
480 : {
481 : };
482 :
483 : template <typename T, typename A>
484 : struct is_std_vector<std::vector<T, A>> : std::true_type
485 : {
486 : };
487 :
488 : template <typename T>
489 : void
490 66 : ReporterGeneralContext<T>::resize(dof_id_type size)
491 : {
492 : if constexpr (is_std_vector<T>::value)
493 66 : this->_state.value().resize(size);
494 : else
495 : {
496 0 : libmesh_ignore(size);
497 0 : mooseError("Cannot resize non vector-type reporter values.");
498 : }
499 66 : }
500 : template <typename T>
501 : void
502 66 : ReporterGeneralContext<T>::clear()
503 : {
504 : if constexpr (is_std_vector<T>::value)
505 66 : this->_state.value().clear();
506 : else
507 0 : mooseError("Cannot clear non vector-type reporter values.");
508 66 : }
509 :
510 : template <typename T>
511 : void
512 66 : ReporterGeneralContext<T>::vectorSum()
513 : {
514 : // Case 1: T is a numeric type that we can sum (excluding bool)
515 : if constexpr (std::is_arithmetic<T>::value && !std::is_same<T, bool>::value)
516 : {
517 : // Perform summation of the scalar value across all processors
518 0 : this->comm().sum(this->_state.value());
519 0 : return;
520 : }
521 : // Case 2: T is a vector type
522 : else if constexpr (is_std_vector<T>::value)
523 : {
524 : using VectorValueType = typename T::value_type;
525 :
526 : // Check if the vector elements are of a numeric type
527 : if constexpr (std::is_arithmetic<VectorValueType>::value &&
528 : !std::is_same<VectorValueType, bool>::value)
529 : {
530 : // Perform summation of the vector elements across all processors
531 33 : this->comm().sum(this->_state.value());
532 33 : return;
533 : }
534 : // Check if the vector elements are also vectors
535 : else if constexpr (is_std_vector<VectorValueType>::value)
536 : {
537 : using InnerValueType = typename VectorValueType::value_type;
538 :
539 : // Check if the inner vector elements are of a numeric type
540 : if constexpr (std::is_arithmetic<InnerValueType>::value &&
541 : !std::is_same<InnerValueType, bool>::value)
542 : {
543 : #ifdef DEBUG
544 : auto vec_size = this->_state.value().size();
545 : this->comm().max(vec_size);
546 : // Assert only passes on all ranks if they are all the same size.
547 : mooseAssert(this->_state.value().size() == vec_size,
548 : "Reporter vector have different sizes on different ranks.");
549 : #endif
550 : // Iterate over each inner vector in the outer vector
551 165 : for (auto & innerVector : this->_state.value())
552 : {
553 : // Get the maximum size of the inner vector across all processors
554 132 : dof_id_type maxInnerSize = innerVector.size();
555 132 : this->comm().max(maxInnerSize);
556 :
557 : // Resize the inner vector to the maximum size
558 132 : innerVector.resize(maxInnerSize);
559 :
560 : // Perform summation of the inner vector elements across all processors
561 132 : this->comm().sum(innerVector);
562 : }
563 33 : return;
564 : }
565 : }
566 : }
567 :
568 0 : mooseError("Cannot perform sum operation on non-numeric or unsupported vector types.");
569 : }
570 :
571 : /**
572 : * A context that broadcasts the Reporter value from the root processor
573 : */
574 : template <typename T>
575 : class ReporterBroadcastContext : public ReporterGeneralContext<T>
576 : {
577 : public:
578 : ReporterBroadcastContext(const libMesh::ParallelObject & other,
579 : const MooseObject & producer,
580 : ReporterState<T> & state);
581 : ReporterBroadcastContext(const libMesh::ParallelObject & other,
582 : const MooseObject & producer,
583 : ReporterState<T> & state,
584 : const T & default_value);
585 : virtual void finalize() override;
586 0 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
587 : };
588 :
589 : template <typename T>
590 90 : ReporterBroadcastContext<T>::ReporterBroadcastContext(const libMesh::ParallelObject & other,
591 : const MooseObject & producer,
592 : ReporterState<T> & state)
593 90 : : ReporterGeneralContext<T>(other, producer, state)
594 : {
595 90 : this->_producer_enum.clear();
596 90 : this->_producer_enum.insert(REPORTER_MODE_ROOT);
597 90 : }
598 :
599 : template <typename T>
600 : ReporterBroadcastContext<T>::ReporterBroadcastContext(const libMesh::ParallelObject & other,
601 : const MooseObject & producer,
602 : ReporterState<T> & state,
603 : const T & default_value)
604 : : ReporterGeneralContext<T>(other, producer, state, default_value)
605 : {
606 : this->_producer_enum.clear();
607 : this->_producer_enum.insert(REPORTER_MODE_ROOT);
608 : }
609 :
610 : template <typename T>
611 : void
612 249 : ReporterBroadcastContext<T>::finalize()
613 : {
614 996 : this->requiresConsumerModes(this->_state, {REPORTER_MODE_UNSET, REPORTER_MODE_REPLICATED});
615 249 : this->broadcast();
616 498 : }
617 :
618 : /**
619 : * A context that scatters the Reporter value from the root processor
620 : */
621 : template <typename T>
622 : class ReporterScatterContext : public ReporterGeneralContext<T>
623 : {
624 : public:
625 : ReporterScatterContext(const libMesh::ParallelObject & other,
626 : const MooseObject & producer,
627 : ReporterState<T> & state,
628 : const std::vector<T> & values);
629 : ReporterScatterContext(const libMesh::ParallelObject & other,
630 : const MooseObject & producer,
631 : ReporterState<T> & state,
632 : const T & default_value,
633 : const std::vector<T> & values);
634 :
635 : virtual void finalize() override;
636 0 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
637 :
638 : private:
639 : /// The values to scatter
640 : const std::vector<T> & _values;
641 : };
642 :
643 : template <typename T>
644 90 : ReporterScatterContext<T>::ReporterScatterContext(const libMesh::ParallelObject & other,
645 : const MooseObject & producer,
646 : ReporterState<T> & state,
647 : const std::vector<T> & values)
648 90 : : ReporterGeneralContext<T>(other, producer, state), _values(values)
649 : {
650 90 : this->_producer_enum.clear();
651 90 : this->_producer_enum.insert(REPORTER_MODE_ROOT);
652 90 : }
653 :
654 : template <typename T>
655 : ReporterScatterContext<T>::ReporterScatterContext(const libMesh::ParallelObject & other,
656 : const MooseObject & producer,
657 : ReporterState<T> & state,
658 : const T & default_value,
659 : const std::vector<T> & values)
660 : : ReporterGeneralContext<T>(other, producer, state, default_value), _values(values)
661 : {
662 : this->_producer_enum.clear();
663 : this->_producer_enum.insert(REPORTER_MODE_ROOT);
664 : }
665 :
666 : template <typename T>
667 : void
668 243 : ReporterScatterContext<T>::finalize()
669 : {
670 972 : this->requiresConsumerModes(this->_state, {REPORTER_MODE_UNSET, REPORTER_MODE_REPLICATED});
671 :
672 : mooseAssert(this->processor_id() == 0 ? _values.size() == this->n_processors() : true,
673 : "Vector to be scattered must be sized to match the number of processors");
674 : mooseAssert(
675 : this->processor_id() > 0 ? _values.size() == 0 : true,
676 : "Vector to be scattered must be sized to zero on processors except for the root processor");
677 243 : this->comm().scatter(_values, this->_state.value());
678 486 : }
679 :
680 : /**
681 : * A context that gathers the Reporter value to the root processor
682 : */
683 : template <typename T>
684 : class ReporterGatherContext : public ReporterGeneralContext<T>
685 : {
686 : public:
687 : ReporterGatherContext(const libMesh::ParallelObject & other,
688 : const MooseObject & producer,
689 : ReporterState<T> & state);
690 : ReporterGatherContext(const libMesh::ParallelObject & other,
691 : const MooseObject & producer,
692 : ReporterState<T> & state,
693 : const T & default_value);
694 :
695 : virtual void finalize() override;
696 0 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
697 : };
698 :
699 : template <typename T>
700 120 : ReporterGatherContext<T>::ReporterGatherContext(const libMesh::ParallelObject & other,
701 : const MooseObject & producer,
702 : ReporterState<T> & state)
703 120 : : ReporterGeneralContext<T>(other, producer, state)
704 : {
705 120 : this->_producer_enum.clear();
706 120 : this->_producer_enum.insert(REPORTER_MODE_DISTRIBUTED);
707 120 : }
708 :
709 : template <typename T>
710 : ReporterGatherContext<T>::ReporterGatherContext(const libMesh::ParallelObject & other,
711 : const MooseObject & producer,
712 : ReporterState<T> & state,
713 : const T & default_value)
714 : : ReporterGeneralContext<T>(other, producer, state, default_value)
715 : {
716 : this->_producer_enum.clear();
717 : this->_producer_enum.insert(REPORTER_MODE_DISTRIBUTED);
718 : }
719 :
720 : template <typename T>
721 : void
722 273 : ReporterGatherContext<T>::finalize()
723 : {
724 1092 : this->requiresConsumerModes(this->_state, {REPORTER_MODE_UNSET, REPORTER_MODE_ROOT});
725 273 : this->comm().gather(0, this->_state.value());
726 546 : }
727 :
728 : /**
729 : * This context is specific for vector types of reporters, mainly for declaring a vector
730 : * of the type from another context. As well as resizing the vector of data.
731 : *
732 : * @see ReporterGeneralContext::declareVectorClone and ReporterTransferInterface
733 : */
734 : template <typename T>
735 : class ReporterVectorContext : public ReporterContext<std::vector<T>>
736 : {
737 : public:
738 : ReporterVectorContext(const libMesh::ParallelObject & other,
739 : const MooseObject & producer,
740 : ReporterState<std::vector<T>> & state);
741 : ReporterVectorContext(const libMesh::ParallelObject & other,
742 : const MooseObject & producer,
743 : ReporterState<std::vector<T>> & state,
744 : const std::vector<T> & default_value);
745 :
746 : /**
747 : * This simply throws an error to avoid infinite instantiations.
748 : * It is defined in ReporterData.h to avoid cyclic included.
749 : */
750 : virtual void declareClone(ReporterData & r_data,
751 : const ReporterName & r_name,
752 : const ReporterMode & mode,
753 : const MooseObject & producer) const final;
754 :
755 : /**
756 : * This simply throws an error to avoid infinite instantiations.
757 : * It is defined in ReporterData.h to avoid cyclic included.
758 : */
759 : virtual void declareVectorClone(ReporterData & r_data,
760 : const ReporterName & r_name,
761 : const ReporterMode & mode,
762 : const MooseObject & producer) const final;
763 :
764 : /**
765 : * Since we know that the _state value is a vector type, we can resize it based
766 : * on @param local_size
767 : */
768 377 : virtual void resize(dof_id_type local_size) override { this->_state.value().resize(local_size); }
769 :
770 : /**
771 : * Since we know that the _state value is a vector type, we can clear it.
772 : */
773 0 : virtual void clear() override { this->_state.value().clear(); }
774 :
775 0 : virtual void vectorSum() override
776 : {
777 : // Case 1: T is type that we can sum
778 : if constexpr (std::is_arithmetic<T>::value &&
779 : !std::is_same<T, bool>::value) // We can't sum bools.
780 : {
781 : // Resize vector to max size
782 0 : dof_id_type vec_size = this->_state.value().size();
783 0 : this->comm().max(vec_size);
784 0 : this->_state.value().resize(vec_size);
785 :
786 0 : this->comm().sum(this->_state.value());
787 0 : return;
788 : }
789 : // Case 2: T is a vector
790 : else if constexpr (is_std_vector<T>::value)
791 : {
792 : // Resize vector to max size
793 0 : dof_id_type vec_size = this->_state.value().size();
794 0 : this->comm().max(vec_size);
795 0 : this->_state.value().resize(vec_size);
796 :
797 : using ValueType = typename T::value_type;
798 : // Check if the ValueType is a vector
799 : if constexpr (std::is_arithmetic<ValueType>::value && !std::is_same<ValueType, bool>::value)
800 : {
801 : #ifdef DEBUG
802 : auto vec_size = this->_state.value().size();
803 : this->comm().max(vec_size);
804 : // Assert only passes on all ranks if they are all the same size.
805 : mooseAssert(this->_state.value().size() == vec_size,
806 : "Reporter vector have different sizes on different ranks.");
807 : #endif
808 0 : for (auto & val_vec : this->_state.value())
809 : {
810 : // Resize vector to max size
811 0 : dof_id_type val_vec_size = val_vec.size();
812 0 : this->comm().max(val_vec_size);
813 0 : val_vec.resize(val_vec_size);
814 :
815 0 : this->comm().sum(val_vec);
816 : }
817 0 : return;
818 : }
819 : }
820 : // If we don't perform a summing operation, error out.
821 0 : mooseError("Cannot perform sum operation on non-numeric or unsupported vector types.");
822 : }
823 :
824 0 : virtual std::string contextType() const override { return MooseUtils::prettyCppType(this); }
825 : };
826 :
827 : template <typename T>
828 2352 : ReporterVectorContext<T>::ReporterVectorContext(const libMesh::ParallelObject & other,
829 : const MooseObject & producer,
830 2 : ReporterState<std::vector<T>> & state)
831 2350 : : ReporterContext<std::vector<T>>(other, producer, state)
832 : {
833 2352 : }
834 :
835 : template <typename T>
836 : ReporterVectorContext<T>::ReporterVectorContext(const libMesh::ParallelObject & other,
837 : const MooseObject & producer,
838 : ReporterState<std::vector<T>> & state,
839 : const std::vector<T> & default_value)
840 : : ReporterContext<std::vector<T>>(other, producer, state, default_value)
841 : {
842 : }
|