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