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 "Moose.h"
13 : #include "MooseHashing.h"
14 : #include "HashMap.h"
15 : #include "MaterialProperty.h"
16 : #include "MaterialPropertyRegistry.h"
17 : #include "MaterialData.h"
18 :
19 : #include <variant>
20 :
21 : // Forward declarations
22 : class MaterialBase;
23 : class QpMap;
24 :
25 : // libMesh forward declarations
26 : namespace libMesh
27 : {
28 : class QBase;
29 : class Elem;
30 : }
31 :
32 : class MaterialPropertyStorage;
33 :
34 : void dataStore(std::ostream & stream, MaterialPropertyStorage & storage, void * context);
35 : void dataLoad(std::istream & stream, MaterialPropertyStorage & storage, void * context);
36 :
37 : /**
38 : * Stores the stateful material properties computed by materials.
39 : *
40 : * Thread-safe
41 : */
42 : class MaterialPropertyStorage
43 : {
44 : public:
45 : MaterialPropertyStorage(MaterialPropertyRegistry & registry);
46 :
47 : /**
48 : * Basic structure for storing information about a property
49 : */
50 : struct PropRecord
51 : {
52 : /// Whether or not this property is stateful
53 2170707 : bool stateful() const { return state > 0; }
54 : /// The material (type,name) that have declared this property
55 : std::set<std::string> declarers;
56 : /// The type of this property
57 : std::string type;
58 : /// The stateful id in _storage used for this property, if any
59 : unsigned int stateful_id = invalid_uint;
60 : /// The max state requrested for this property (0 = current, 1 = old, ...)
61 : unsigned int state = 0;
62 : /// Whether or not this property was restored (stateful only)
63 : bool restored = false;
64 : };
65 :
66 : /**
67 : * Creates storage for newly created elements from mesh Adaptivity. Also, copies values from the
68 : * parent qps to the new children.
69 : *
70 : * Note - call this on the MaterialPropertyStorage object for the _children_ that you want to
71 : * project to. ie, if you are trying
72 : * to project to the sides of the children, then call this on the boundary
73 : * MaterialPropertyStorage. Pass in the parent
74 : * MaterialPropertyStorage you are projecting _from_. ie the volume one if you are projecting to
75 : * "internal" child element faces.
76 : *
77 : * There are 3 cases here:
78 : *
79 : * 1. Volume to volume (parent_side = -1, child = -1, child_side = -1)
80 : * Call on volume MaterialPropertyStorage and pass volume MaterialPropertyStorage for
81 : * parent_material_props
82 : *
83 : * 2. Parent side to child side (parent_side = 0+, child = -1, child_side = 0+) where parent_side
84 : * == child_side
85 : * Call on boundary MaterialPropertyStorage and pass boundary MaterialPropertyStorage for
86 : * parent_material_props
87 : *
88 : * 3. Child side to parent volume (parent_side = -1, child = 0+, child_side = 0+)
89 : * Call on boundary MaterialPropertyStorage and pass volume MaterialPropertyStorage for
90 : * parent_material_props
91 : *
92 : * @param pid - processor id of children to prolong to
93 : * @param refinement_map - 2D array of QpMap objects
94 : * @param qrule The current quadrature rule
95 : * @param qrule_face The current face qrule
96 : * @param parent_material_props The place to pull parent material property values from
97 : * @param tid The thread ID
98 : * @param elem The parent element that was just refined
99 : * @param input_parent_side - the side of the parent for which material properties are prolonged
100 : * @param input_child - the number of the child
101 : * @param input_child_side - the side on the child where material properties will be prolonged
102 : */
103 : void prolongStatefulProps(processor_id_type pid,
104 : const std::vector<std::vector<QpMap>> & refinement_map,
105 : const libMesh::QBase & qrule,
106 : const libMesh::QBase & qrule_face,
107 : MaterialPropertyStorage & parent_material_props,
108 : const THREAD_ID tid,
109 : const Elem & elem,
110 : const int input_parent_side,
111 : const int input_child,
112 : const int input_child_side);
113 :
114 : /**
115 : * Based on the p-refinement flag of \p elem, either prolong (for refinement) or restrict (for
116 : * coarsening) the stateful material property data.
117 : * @param pid The rank returned by the mesh. This is used to assert that we are only
118 : * prolonging/restricting for elements that our process owns
119 : * @param p_refinement_map A map that describes, for each quadrature point on the current level
120 : * which quadrature point on the previous level it is closest to
121 : * @param qrule The volumetric quadrature rule
122 : * @param qrule_face The face quadrature rule
123 : * @param tid The thread ID
124 : * @param elem The element that was just p-refined or coarsened that we are performing material
125 : * property prolongation/restriction for
126 : * @param input_side Which element side we are performing material property
127 : * prolongation/restriction for. Pass in -1 for doing volumetric prolongation/restriction
128 : */
129 : void updateStatefulPropsForPRefinement(const processor_id_type pid,
130 : const std::vector<QpMap> & p_refinement_map,
131 : const libMesh::QBase & qrule,
132 : const libMesh::QBase & qrule_face,
133 : const THREAD_ID tid,
134 : const Elem & elem,
135 : const int input_side);
136 :
137 : /**
138 : * Creates storage for newly created elements from mesh Adaptivity. Also, copies values from the
139 : * children to the parent.
140 : *
141 : * @param coarsening_map - map from unsigned ints to QpMap's
142 : * @param coarsened_element_children - a pointer to a vector of coarsened element children
143 : * @param qrule The current quadrature rule
144 : * @param qrule_face The current face qrule
145 : * @param tid The thread ID
146 : * @param elem The parent element that was just refined
147 : * @param input_side Side of the element 'elem' (0 for volumetric material properties)
148 : */
149 : void restrictStatefulProps(const std::vector<std::pair<unsigned int, QpMap>> & coarsening_map,
150 : const std::vector<const Elem *> & coarsened_element_children,
151 : const libMesh::QBase & qrule,
152 : const libMesh::QBase & qrule_face,
153 : const THREAD_ID tid,
154 : const Elem & elem,
155 : int input_side = -1);
156 :
157 : /**
158 : * Initialize stateful material properties
159 : * @param tid The thread ID
160 : * @param mats Materials that will compute the initial values
161 : * @param n_qpoints Number of quadrature points
162 : * @param elem Element we are on
163 : * @param side Side of the element 'elem' (0 for volumetric material properties)
164 : *
165 : * If restartable stateful information is available, this will load from restart
166 : * instead of calling initStatefulProperties()
167 : */
168 : void initStatefulProps(const THREAD_ID tid,
169 : const std::vector<std::shared_ptr<MaterialBase>> & mats,
170 : const unsigned int n_qpoints,
171 : const Elem & elem,
172 : const unsigned int side = 0);
173 :
174 : /**
175 : * Shift the material properties in time.
176 : *
177 : * Old material properties become older, current material properties become old. Older material
178 : * properties are
179 : * reused for computing current properties. This is called when solve succeeded.
180 : */
181 : void shift();
182 :
183 : /**
184 : * Copy material properties from elem_from to elem_to. Thread safe.
185 : *
186 : * WARNING: This is not capable of copying material data to/from elements on other processors.
187 : * It only works if both elem_to and elem_from are both on the local processor.
188 : * We can't currently check to ensure that they're on processor here because this isn't a
189 : * ParallelObject.
190 : *
191 : * @param tid The thread ID
192 : * @param elem_to Element to copy data to
193 : * @param elem_from Element to copy data from
194 : * @param side Side number (elemental material properties have this equal to zero)
195 : * @param n_qpoints number of quadrature points to work with
196 : */
197 : void copy(const THREAD_ID tid,
198 : const Elem & elem_to,
199 : const Elem & elem_from,
200 : unsigned int side,
201 : unsigned int n_qpoints);
202 :
203 : /**
204 : * Copy material properties from elem_from to elem_to.
205 : * Similar to the other method but using pointers to elements instead of references.
206 : *
207 : * @param tid The thread ID
208 : * @param elem_to Pointer to the element to copy data to
209 : * @param elem_from Pointer to the element to copy data from
210 : * @param side Side number (elemental material properties have this equal to zero)
211 : * @param n_qpoints number of quadrature points to work with
212 : */
213 : void copy(const THREAD_ID tid,
214 : const Elem * elem_to,
215 : const Elem * elem_from,
216 : unsigned int side,
217 : unsigned int n_qpoints);
218 :
219 : /**
220 : * Swap (shallow copy) material properties in MaterialData and MaterialPropertyStorage
221 : * Thread safe
222 : * @param tid The thread id
223 : * @param elem Element id
224 : * @param side Side number (elemental material properties have this equal to zero)
225 : */
226 : void swap(const THREAD_ID tid, const Elem & elem, unsigned int side);
227 :
228 : /**
229 : * Swap (shallow copy) material properties in MaterialPropertyStorage and MaterialDat
230 : * Thread safe
231 : * @param tid The thread id
232 : * @param elem Element id
233 : * @param side Side number (elemental material properties have this equal to zero)
234 : */
235 : void swapBack(const THREAD_ID tid, const Elem & elem, unsigned int side);
236 :
237 : /**
238 : * @return a Boolean indicating whether stateful properties exist on this material
239 : */
240 26760987 : bool hasStatefulProperties() const { return maxState() > 0; }
241 :
242 : /**
243 : * @return a Boolean indicating whether or not this material has older properties declared
244 : */
245 : bool hasOlderProperties() const { return maxState() > 1; }
246 :
247 : /**
248 : * Accessible type of the stored material property data.
249 : *
250 : * This probably should have been returned as a proxy class; only
251 : * access it via foo[elem][side] and maybe we'll be able to refactor
252 : * it in the future without breaking your code.
253 : */
254 : typedef HashMap<const Elem *, HashMap<unsigned int, MaterialProperties>> PropsType;
255 :
256 : ///@{
257 : /**
258 : * Access methods to the stored material property data with the given state \p state.
259 : */
260 : const PropsType & props(const unsigned int state = 0) const;
261 : const MaterialProperties &
262 : props(const Elem * elem, unsigned int side, const unsigned int state = 0) const;
263 : MaterialProperties & setProps(const Elem * elem, unsigned int side, const unsigned int state = 0);
264 : ///@}
265 :
266 66670 : bool hasProperty(const std::string & prop_name) const { return _registry.hasProperty(prop_name); }
267 :
268 : /**
269 : * Adds a property with the name \p prop_name, type \p type, and state \p state (0 = current, 1 =
270 : * old, etc)
271 : *
272 : * This is idempotent - calling multiple times with the same name will provide the same id and
273 : * works fine.
274 : *
275 : * \p declarer should be specified by the object declaring the property if it is being declared.
276 : */
277 : unsigned int addProperty(const std::string & prop_name,
278 : const std::type_info & type,
279 : const unsigned int state,
280 : const MaterialBase * const declarer);
281 :
282 : const std::vector<unsigned int> & statefulProps() const { return _stateful_prop_id_to_prop_id; }
283 :
284 334922 : const MaterialPropertyRegistry & getMaterialPropertyRegistry() const { return _registry; }
285 :
286 : /**
287 : * @return The name of the stateful property with id \p id, if any.
288 : */
289 : std::optional<std::string> queryStatefulPropName(const unsigned int id) const;
290 :
291 : /**
292 : * Remove the property storage and element pointer from internal data structures
293 : * Use this when elements are deleted so we don't end up with invalid elem pointers (for e.g.
294 : * stateful properties) hanging around in our data structures
295 : */
296 : void eraseProperty(const Elem * elem);
297 :
298 : /**
299 : * @returns The current maximum stored state (0 = none, 1 = old, 2 = older)
300 : */
301 43147112 : unsigned int maxState() const
302 : {
303 : mooseAssert(_max_state < _storage.size(), "Too big");
304 43147112 : return _max_state;
305 : }
306 : /**
307 : * @returns The number of stored states (2 = up to old, 3 = up to older)
308 : */
309 16262316 : unsigned int numStates() const { return maxState() + 1; }
310 : /**
311 : * @returns A range over states to be used in range-based for loops
312 : */
313 15478271 : libMesh::IntRange<unsigned int> stateIndexRange() const
314 : {
315 15478271 : return libMesh::IntRange<unsigned int>(0, numStates());
316 : }
317 : /**
318 : * @returns A range over stateful states to be used in range-based for loops
319 : *
320 : * Will be an empty range if there are no stateful states
321 : */
322 397276 : libMesh::IntRange<unsigned int> statefulIndexRange() const
323 : {
324 397276 : return libMesh::IntRange<unsigned int>(1, numStates());
325 : }
326 :
327 : /**
328 : * @return The MaterialData for thread \p tid
329 : */
330 : const MaterialData & getMaterialData(const THREAD_ID tid) const { return _material_data[tid]; }
331 455887460 : MaterialData & getMaterialData(const THREAD_ID tid) { return _material_data[tid]; }
332 :
333 : /**
334 : * Sets the loading of stateful material properties to recover
335 : *
336 : * This enforces the requirement of one-to-one stateful material properties,
337 : * disabling advanced restart of stateful properties
338 : */
339 177171 : void setRecovering() { _recovering = true; }
340 :
341 : /**
342 : * Sets the loading of stateful material properties in place
343 : *
344 : * On init, this cannot be set because we must first call initProps()
345 : * to properly initialize the dynamic types within _storage. After
346 : * the first sweep through with initProps(), we can then load the stateful
347 : * props directly in place into _storage
348 : *
349 : * Also clears _restartable_map, as it should no longer be needed
350 : */
351 : void setRestartInPlace();
352 :
353 : /**
354 : * Get the property record associated with the material with id \p id
355 : */
356 : const PropRecord & getPropRecord(const unsigned int id) const;
357 :
358 : /**
359 : * @return Whether or not the material property with name \p name was restored
360 : */
361 : bool isRestoredProperty(const std::string & name) const;
362 :
363 : protected:
364 : /// The actual storage
365 : std::array<PropsType, MaterialData::max_state + 1> _storage;
366 :
367 : /// Property records indexed by property id (may be null)
368 : std::vector<std::optional<PropRecord>> _prop_records;
369 :
370 : /// the vector of stateful property ids (the vector index is the map to stateful prop_id)
371 : std::vector<unsigned int> _stateful_prop_id_to_prop_id;
372 :
373 : void sizeProps(MaterialProperties & mp, unsigned int size);
374 :
375 : private:
376 : /// Initializes hashmap entries for element and side to proper qpoint and
377 : /// property count sizes.
378 : std::vector<MaterialProperties *>
379 : initProps(const THREAD_ID tid, const Elem * elem, unsigned int side, unsigned int n_qpoints);
380 :
381 : /// Initializes just one hashmap's entries
382 : MaterialProperties & initProps(const THREAD_ID tid,
383 : const unsigned int state,
384 : const Elem * elem,
385 : unsigned int side,
386 : unsigned int n_qpoints);
387 :
388 : ///@{
389 : /**
390 : * Shallow copies of material properties
391 : *
392 : */
393 : static void shallowSwapData(const std::vector<unsigned int> & stateful_prop_ids,
394 : MaterialProperties & data,
395 : MaterialProperties & data_from);
396 : static void shallowSwapDataBack(const std::vector<unsigned int> & stateful_prop_ids,
397 : MaterialProperties & data,
398 : MaterialProperties & data_from);
399 : ///@}
400 :
401 : /**
402 : * @returns A writeable reference to the properties at state \p state.
403 : */
404 : PropsType & setProps(const unsigned int state);
405 :
406 : /**
407 : * @returns A writeable reference to the properties for elem \p elem,
408 : * side \p side, and state \p state.
409 : *
410 : * Similar to setProps, but will initialize (default construct) the
411 : * entry if it does not exist.
412 : */
413 : MaterialProperties &
414 : initAndSetProps(const Elem * elem, const unsigned int side, const unsigned int state);
415 :
416 : /// The maximum state (0 = current, 1 = old, 2 = older)
417 : unsigned int _max_state;
418 :
419 : // You'd think a private mutex would work here, so I'll leave this
420 : // in the namespace for when that happens, but CI thinks that can
421 : // make us crash, so I'll just initialize this to Threads::spin_mtx
422 : libMesh::Threads::spin_mutex & _spin_mtx;
423 :
424 : /// Shared registry (across storage objects) for property names and IDs
425 : MaterialPropertyRegistry & _registry;
426 :
427 : /// The threaded material data
428 : std::vector<MaterialData> _material_data;
429 :
430 : typedef std::unordered_map<std::pair<const Elem *, unsigned int>,
431 : std::map<unsigned int, std::vector<std::stringstream>>>
432 : RestartableMapType;
433 :
434 : /// The restartable data to be loaded in initStatefulProps() later
435 : RestartableMapType _restartable_map;
436 :
437 : /// Whether or not we want to restart stateful properties in place
438 : bool _restart_in_place;
439 : /// Whether or not we're recovering; enforces a one-to-one mapping of stateful properties
440 : bool _recovering;
441 :
442 : // Need to be able to eraseProperty from here
443 : friend class ProjectMaterialProperties;
444 :
445 : // Need to be able to initProps from here
446 : friend class RedistributeProperties;
447 :
448 : // Need non-const props from here
449 : friend void dataLoad(std::istream &, MaterialPropertyStorage &, void *);
450 : friend void dataStore(std::ostream &, MaterialPropertyStorage &, void *);
451 : };
452 :
453 : inline const MaterialPropertyStorage::PropsType &
454 35492936 : MaterialPropertyStorage::props(const unsigned int state) const
455 : {
456 : mooseAssert(state < _storage.size(), "Invalid material property state " + std::to_string(state));
457 35492936 : return _storage[state];
458 : }
459 :
460 : inline const MaterialProperties &
461 23070364 : MaterialPropertyStorage::props(const Elem * elem, unsigned int side, const unsigned int state) const
462 : {
463 23070364 : const auto find_elem = props(state).find(elem);
464 : mooseAssert(find_elem != props(state).end(), "Material property does not have elem entry");
465 23070364 : const auto find_side = find_elem->second.find(side);
466 : mooseAssert(find_side != find_elem->second.end(), "Material property does not have side entry");
467 23070364 : return find_side->second;
468 : }
469 :
470 : inline MaterialProperties &
471 11505054 : MaterialPropertyStorage::setProps(const Elem * elem, unsigned int side, const unsigned int state)
472 : {
473 11505054 : return const_cast<MaterialProperties &>(std::as_const(*this).props(elem, side, state));
474 : }
475 :
476 : inline MaterialProperties &
477 12075445 : MaterialPropertyStorage::initAndSetProps(const Elem * elem,
478 : unsigned int side,
479 : const unsigned int state)
480 : {
481 12075445 : return setProps(state)[elem][side];
482 : }
483 :
484 : inline MaterialPropertyStorage::PropsType &
485 12422572 : MaterialPropertyStorage::setProps(const unsigned int state)
486 : {
487 12422572 : return const_cast<MaterialPropertyStorage::PropsType &>(std::as_const(*this).props(state));
488 : }
489 :
490 : void dataStore(std::ostream & stream, MaterialPropertyStorage::PropRecord & record, void * context);
491 : void dataLoad(std::istream & stream, MaterialPropertyStorage::PropRecord & record, void * context);
|