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 :
13 : #include "libmesh/parallel.h"
14 : #include "libmesh/parallel_object.h"
15 : #include "libmesh/simple_range.h"
16 :
17 : #include "ReporterName.h"
18 : #include "RestartableData.h"
19 : #include "ReporterMode.h"
20 :
21 : // Forward declarations
22 : class MooseObject;
23 : class ReporterContextBase;
24 :
25 : /**
26 : * The base class for storing a Reporter's state
27 : *
28 : * The base class is needed in order to store the states without a template
29 : * parameter so that they can be iterated through to observe the producers
30 : * and consumers.
31 : */
32 : class ReporterStateBase
33 : {
34 : public:
35 : ReporterStateBase(const ReporterName & name);
36 1243875 : virtual ~ReporterStateBase() = default;
37 :
38 : /**
39 : * Return the ReporterName that this state is associated with
40 : */
41 686204 : const ReporterName & getReporterName() const { return _reporter_name; }
42 :
43 : /**
44 : * Add a consumer for this ReporterState
45 : * @param mode The mode that the object will consume the Reporter value
46 : * @param moose_object The MooseObject doing the consuming (for error reporting)
47 : * @see ReporterData
48 : */
49 : void addConsumer(ReporterMode mode, const MooseObject & moose_object);
50 :
51 : /**
52 : * Returns the consumers for this state; a pair that consists of the mode
53 : * that the state is being consumed by, and the object consuming it
54 : * @see ReporterContext
55 : */
56 574955 : const std::set<std::pair<ReporterMode, const MooseObject *>> & getConsumers() const
57 : {
58 574955 : return _consumers;
59 : }
60 :
61 : /**
62 : * @returns The type associated with this state
63 : */
64 : virtual std::string valueType() const = 0;
65 :
66 : /**
67 : * Sets the special Reporter type to a Postprocessor.
68 : *
69 : * See ReporterData::declareReporterValue.
70 : */
71 12 : void setIsPostprocessor() { _reporter_name.setIsPostprocessor(); }
72 : /**
73 : * Sets the special Reporter type to a VectorPostprocessor.
74 : *
75 : * See ReporterData::declareReporterValue.
76 : */
77 12 : void setIsVectorPostprocessor() { _reporter_name.setIsVectorPostprocessor(); }
78 :
79 : private:
80 : /// Name of data that state is associated
81 : ReporterName _reporter_name;
82 :
83 : /// The consumers for this state; we store the MooseObject for detailed error reporting
84 : std::set<std::pair<ReporterMode, const MooseObject *>> _consumers;
85 : };
86 :
87 : /**
88 : * Custom sort for ReporterState::_consumers so that they are sorted by
89 : * object type, object name, and then mode, which makes for pretty output.
90 : */
91 : bool operator<(const std::pair<ReporterMode, const MooseObject *> & a,
92 : const std::pair<ReporterMode, const MooseObject *> & b);
93 :
94 : /**
95 : * A special version of RestartableData to aid in storing Reporter values. This object is
96 : * used by the ReporterData object. The objects provides a convenient method to define
97 : * Reporter data that has a value as well as some number of old data values. Please refer to
98 : * ReporterData.h for more information regarding the use of this class.
99 : *
100 : * @param name The name of the Reporter value
101 : *
102 : * This class stores the current/old/older/... data using a std::list to allow values to be inserted
103 : * into the data structure without corrupting references to the other values. This allows for
104 : * arbitrary time data to be stored.
105 : *
106 : * NOTE:
107 : * Access to the data should be through the value() method to ensure the data is allocated correctly
108 : */
109 : template <typename T>
110 : class ReporterState : public ReporterStateBase, public RestartableData<std::list<T>>
111 : {
112 : public:
113 : ReporterState(const ReporterName & name);
114 :
115 : ///@{
116 : /**
117 : * Return a reference to the current value or one of the old values.
118 : *
119 : * The time_index of 0 returns the current value, 1 returns old, 2 returns older, etc.
120 : */
121 : T & value(const std::size_t time_index = 0);
122 : const T & value(const std::size_t time_index = 0) const;
123 : ///@}
124 :
125 : /**
126 : * Copy stored values back in time to old/older etc.
127 : */
128 : void copyValuesBack();
129 :
130 : /**
131 : * Restore values to their old values, i.e. value(0) = value(1). This only occurs if old values
132 : * have been declared, which happens automatically for postprocessors.
133 : *
134 : * @return true State was restored
135 : * @return false State was NOT restored
136 : */
137 : bool restoreState();
138 :
139 62 : std::string valueType() const override final { return MooseUtils::prettyCppType<T>(); }
140 :
141 : /**
142 : * Loads and stores the data from/to a stream for restart
143 : *
144 : * This is a special version that handles the fact that the calls declare/getReporterValue
145 : * occur within the constructor of objects. As such, the storage list already contains data
146 : * and the references to this data must remain valid.
147 : *
148 : * The default dataLoad assumes the list being populated is empty and simply uses push_back.
149 : * Therefore, this function loads the data directly into the container to avoid this problem
150 : * and unnecessary copies.
151 : *
152 : * The default dataStore is very similar, but to ensure consistency (because we're re-defining
153 : * the load), we implement it again here.
154 : */
155 : ///@{
156 : void storeInternal(std::ostream & stream) override final;
157 : void loadInternal(std::istream & stream) override final;
158 : ///@}
159 : };
160 :
161 : template <typename T>
162 1247515 : ReporterState<T>::ReporterState(const ReporterName & name)
163 1247515 : : ReporterStateBase(name), RestartableData<std::list<T>>(name.getRestartableName(), nullptr)
164 : {
165 1247515 : }
166 :
167 : template <typename T>
168 : T &
169 148539 : ReporterState<T>::value(const std::size_t time_index)
170 : {
171 : // Initialize the data; the first entry is the "current" data
172 148539 : if (this->get().empty())
173 77633 : this->set().resize(1);
174 :
175 : // If we are a postprocessor, we want to always store an old value so that we can restore the data
176 : // if needed. See restoreState.
177 : // Note: This can easily be extended to other states like vector-postprocessors or any other
178 : // reporter value. However, these states have indeterminate sizes and could create significant,
179 : // unecessary memory overhead. In the future, we can extend this to other reporter types if
180 : // the need justifies the overhead.
181 148539 : if (this->getReporterName().isPostprocessor() && time_index == 0 && this->get().size() <= 1)
182 50342 : this->set().push_back(this->get().back());
183 :
184 : // Initialize old, older, ... data
185 148539 : if (this->get().size() <= time_index)
186 5222 : this->set().resize(time_index + 1, this->get().back());
187 :
188 148539 : return *(std::next(this->set().begin(), time_index));
189 : }
190 :
191 : template <typename T>
192 : const T &
193 1114238 : ReporterState<T>::value(const std::size_t time_index) const
194 : {
195 1114238 : if (this->get().size() <= time_index)
196 0 : mooseError("The desired time index ",
197 : time_index,
198 : " does not exists for the '",
199 : getReporterName(),
200 : "' Reporter value, which contains ",
201 0 : this->get().size(),
202 : " old value(s). The getReporterValue method must be called with the desired time "
203 : "index to be able to access data.");
204 1114238 : return *(std::next(this->get().begin(), time_index));
205 : }
206 :
207 : template <typename T>
208 : void
209 229607 : ReporterState<T>::copyValuesBack()
210 : {
211 229607 : std::list<T> & values = this->set();
212 229607 : for (typename std::list<T>::reverse_iterator iter = values.rbegin();
213 431264 : std::next(iter) != values.rend();
214 201657 : ++iter)
215 201657 : (*iter) = (*std::next(iter));
216 229607 : }
217 :
218 : template <typename T>
219 : bool
220 9618 : ReporterState<T>::restoreState()
221 : {
222 9618 : if (this->get().size() <= 1)
223 530 : return false;
224 :
225 9088 : this->set().front() = *std::next(this->get().begin());
226 9088 : return true;
227 : }
228 :
229 : template <typename T>
230 : void
231 41400 : ReporterState<T>::storeInternal(std::ostream & stream)
232 : {
233 : // Store the container size
234 41400 : std::size_t size = this->get().size();
235 41400 : dataStore(stream, size, nullptr);
236 :
237 : // Store each entry of the list directly into the storage
238 128662 : for (auto & val : this->set())
239 87262 : storeHelper(stream, val, nullptr);
240 41400 : }
241 :
242 : template <typename T>
243 : void
244 10814 : ReporterState<T>::loadInternal(std::istream & stream)
245 : {
246 : // Read the container size
247 10814 : std::size_t size = 0;
248 10814 : dataLoad(stream, size, nullptr);
249 :
250 10814 : auto & values = this->set();
251 :
252 : // If the current container is undersized, expand it to fit the loaded data
253 10814 : if (values.size() < size)
254 0 : values.resize(size);
255 :
256 : // Load each entry of the list directly into the storage
257 : // Because we don't shrink the container if the stored size is smaller than
258 : // our declared size, we have the odd iterator combo you see below
259 32819 : for (auto & val : as_range(values.begin(), std::next(values.begin(), size)))
260 22005 : loadHelper(stream, val, nullptr);
261 10814 : }
|