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 : #pragma once
11 :
12 : #include "ElementUserObject.h"
13 :
14 : #include "libmesh/int_range.h"
15 :
16 : #include <tuple>
17 : #include <string>
18 : #include <vector>
19 : #include <utility>
20 :
21 : namespace BatchMaterialUtils
22 : {
23 :
24 : // type wrappers
25 : template <typename T, unsigned int state>
26 : struct GatherMatPropTempl
27 : {
28 : typedef T type;
29 : typedef const MaterialProperty<T> gather_type;
30 :
31 : template <typename M>
32 52 : static gather_type * getPointer(M & mpi, const MaterialPropertyName & name)
33 : {
34 52 : return &mpi.template getGenericMaterialProperty<T, false>(name, state);
35 : }
36 : };
37 :
38 : template <typename T>
39 : using GatherMatProp = GatherMatPropTempl<T, 0>;
40 : template <typename T>
41 : using GatherMatPropOld = GatherMatPropTempl<T, 1>;
42 :
43 : struct GatherVariable
44 : {
45 : typedef Real type;
46 : typedef const VariableValue gather_type;
47 :
48 : template <typename C>
49 13 : static gather_type * getPointer(const C & coupleable, const VariableName & name)
50 : {
51 13 : return &coupleable.coupledValue(name);
52 : }
53 : };
54 :
55 : struct GatherVariableOld
56 : {
57 : typedef Real type;
58 : typedef const VariableValue gather_type;
59 :
60 : template <typename C>
61 13 : static gather_type * getPointer(const C & coupleable, const VariableName & name)
62 : {
63 13 : return &coupleable.coupledValueOld(name);
64 : }
65 : };
66 :
67 : // tuple wrappers
68 : struct TupleStd
69 : {
70 : // the tuple type
71 : template <typename... Args>
72 : using type = std::tuple<Args...>;
73 :
74 : // the element access function
75 : template <int N, typename T>
76 17280000 : static auto & get(T && t)
77 : {
78 17280000 : return std::get<N>(t);
79 : }
80 :
81 : // tuple size (number of elements)
82 : template <typename T>
83 : using size = std::tuple_size<T>;
84 :
85 : // element type access
86 : template <int I, typename T>
87 : using element = typename std::tuple_element<I, T>::type;
88 : };
89 : }
90 :
91 : template <typename Tuple, typename Output, typename... Input>
92 : class BatchMaterial : public ElementUserObject
93 : {
94 : /// shorthand for the instantiated template type
95 : typedef BatchMaterial<Tuple, Output, Input...> BatchMaterialType;
96 :
97 : /// Helper template for obtainig all variable and material property references
98 : template <int I, typename T, typename... Names>
99 : void construct(T && name, Names &&... names);
100 :
101 : /// Helper template for gathering all items into the input data tuples
102 : template <int I>
103 : void copy(const unsigned int nqp);
104 :
105 : public:
106 14288 : static InputParameters validParams() { return ElementUserObject::validParams(); }
107 :
108 : template <typename... Names>
109 13 : BatchMaterial(const InputParameters & params, Names &&... names)
110 13 : : ElementUserObject(params), _output_ready(false)
111 : {
112 13 : construct<0, Names...>(std::forward<Names>(names)...);
113 13 : }
114 :
115 : /// override this method to implement the computation on the batch data
116 : virtual void batchCompute() = 0;
117 :
118 : /// The output type is directly specified as a template parameter
119 : typedef Output OutputType;
120 : /// The serialized batch data is stored in a vector
121 : typedef std::vector<OutputType> OutputVector;
122 :
123 : /// input data needs to use a flexible tuple type (std::tuple or cuda::std::tuple)
124 : typedef typename Tuple::template type<typename Input::type...> InputType;
125 : /// The serialized batch data is stored in a vector
126 : typedef std::vector<InputType> InputVector;
127 :
128 : /// Get a read-only reference to the output data
129 39 : const OutputVector & getOutputData() const { return _output_data; }
130 :
131 : /// Get a writable reference to the output data
132 : OutputVector & setOutputData() { return _output_data; }
133 :
134 : /// get a reference to the input data
135 : const InputVector & getInputData() const { return _input_data; }
136 :
137 : /// check if the output is fully computed and ready to be fetched
138 2160000 : bool outputReady() const { return _output_ready; }
139 :
140 : /// get the index for the first qp of a specified element (other qps are at the following indices)
141 : std::size_t getIndex(dof_id_type elem_id) const;
142 :
143 : /// data structures are initialized here
144 : void initialize() override final;
145 :
146 : /// All data is automatically gathered here
147 : void execute() override final;
148 :
149 : /// Assemble data from all threads
150 : void threadJoin(const UserObject & uo) override final;
151 :
152 : /// we call batchCompute() from here
153 : void finalize() override final;
154 :
155 : /// Input data, utilized in batchCompute()
156 : InputVector _input_data;
157 :
158 : /// Output data, written to in batchCompute()
159 : OutputVector _output_data;
160 :
161 : // use regular tuple for the Moose pointers
162 : std::tuple<typename Input::gather_type *...> _input_ptr;
163 :
164 : /// current element index
165 : std::size_t _index;
166 :
167 : /// map from element ID to index
168 : std::map<dof_id_type, std::size_t> _index_map;
169 :
170 : friend struct BatchMaterialUtils::GatherVariable;
171 :
172 : friend struct BatchMaterialUtils::GatherVariableOld;
173 :
174 : protected:
175 : /// Whether we should perform a batch compute
176 720216 : virtual bool shouldCompute() { return true; }
177 :
178 : private:
179 : /// flag that indicates if _output_data has been fully computed
180 : bool _output_ready;
181 : };
182 :
183 : template <typename Tuple, typename Output, typename... Input>
184 : template <int I, typename T, typename... Names>
185 : void
186 78 : BatchMaterial<Tuple, Output, Input...>::construct(T && name, Names &&... names)
187 : {
188 : // couple the variable or material property
189 : typedef typename std::tuple_element<I, std::tuple<Input...>>::type CurrentElement;
190 78 : std::get<I>(_input_ptr) = CurrentElement::getPointer(*this, name);
191 :
192 : // recursively couple the next variable or material property
193 : if constexpr (sizeof...(Names) > 0)
194 65 : construct<I + 1, Names...>(std::forward<Names>(names)...);
195 78 : }
196 :
197 : template <typename Tuple, typename Output, typename... Input>
198 : template <int I>
199 : void
200 4320000 : BatchMaterial<Tuple, Output, Input...>::copy(const unsigned int nqp)
201 : {
202 : // copy all qp values for the current item
203 21600000 : for (const auto qp : make_range(nqp))
204 17280000 : Tuple::template get<I>(_input_data[_index + qp]) = (*std::get<I>(_input_ptr))[qp];
205 :
206 : // proceed to next item
207 : if constexpr (I + 1 < sizeof...(Input))
208 3600000 : copy<I + 1>(nqp);
209 4320000 : }
210 :
211 : template <typename Tuple, typename Output, typename... Input>
212 : std::size_t
213 1440000 : BatchMaterial<Tuple, Output, Input...>::getIndex(dof_id_type elem_id) const
214 : {
215 1440000 : const auto it = _index_map.find(elem_id);
216 1440000 : if (it == _index_map.end())
217 0 : mooseError("Element ", elem_id, " was not found in the index map for ", name(), ".");
218 1440000 : return it->second;
219 : }
220 :
221 : template <typename Tuple, typename Output, typename... Input>
222 : void
223 108 : BatchMaterial<Tuple, Output, Input...>::initialize()
224 : {
225 108 : _index = 0;
226 :
227 108 : if (shouldCompute())
228 108 : _output_ready = false;
229 108 : }
230 :
231 : template <typename Tuple, typename Output, typename... Input>
232 : void
233 720000 : BatchMaterial<Tuple, Output, Input...>::execute()
234 : {
235 720000 : if (!shouldCompute())
236 0 : return;
237 :
238 : // update index map
239 720000 : _index_map[_current_elem->id()] = _index;
240 :
241 : // make sure the input data is sized sufficiently big
242 720000 : const auto nqp = _qrule->n_points();
243 720000 : if (_input_data.size() < _index + nqp)
244 90000 : _input_data.resize(_index + nqp);
245 :
246 : // copy data
247 720000 : copy<0>(nqp);
248 720000 : _index += nqp;
249 : }
250 :
251 : template <typename Tuple, typename Output, typename... Input>
252 : void
253 9 : BatchMaterial<Tuple, Output, Input...>::threadJoin(const UserObject & uo)
254 : {
255 9 : if (!shouldCompute())
256 0 : return;
257 :
258 : // join maps (with index shift)
259 9 : const auto & bm = static_cast<const BatchMaterialType &>(uo);
260 45009 : for (const auto & [id, index] : bm._index_map)
261 45000 : _index_map[id] = index + _index;
262 :
263 : // make sure we have enough space
264 9 : const auto capacity = _input_data.capacity();
265 9 : if (capacity < _index + bm._index)
266 1 : _input_data.reserve(_index + bm._index);
267 :
268 : // concatenate input data
269 18 : _input_data.insert(std::begin(_input_data) + _index,
270 9 : std::begin(bm._input_data),
271 9 : std::begin(bm._input_data) + bm._index);
272 9 : _index += bm._index;
273 : }
274 :
275 : template <typename Tuple, typename Output, typename... Input>
276 : void
277 99 : BatchMaterial<Tuple, Output, Input...>::finalize()
278 : {
279 99 : if (!shouldCompute())
280 0 : return;
281 :
282 : // resize the input and output data blocks to contain just the gathered items
283 : // (should be a no-op mostly)
284 99 : _input_data.resize(_index);
285 99 : _output_data.resize(_index);
286 99 : batchCompute();
287 :
288 99 : _output_ready = true;
289 : }
|