Loading [MathJax]/extensions/tex2jax.js
https://mooseframework.inl.gov
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
MaterialPropertyStorage.C
Go to the documentation of this file.
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 
11 #include "MaterialProperty.h"
12 #include "Material.h"
13 #include "MaterialData.h"
14 #include "MooseMesh.h"
15 #include "MaterialBase.h"
16 #include "DataIO.h"
17 
18 #include "libmesh/fe_interface.h"
19 #include "libmesh/quadrature.h"
20 
21 #include <optional>
22 
24  : _max_state(0),
25  _spin_mtx(libMesh::Threads::spin_mtx),
26  _registry(registry),
27  _restart_in_place(false),
28  _recovering(false)
29 {
31  for (const auto tid : make_range(libMesh::n_threads()))
32  _material_data.emplace_back(*this, tid);
33 }
34 
35 void
36 MaterialPropertyStorage::shallowSwapData(const std::vector<unsigned int> & stateful_prop_ids,
37  MaterialProperties & data,
38  MaterialProperties & data_from)
39 {
40  for (const auto i : make_range(std::min(stateful_prop_ids.size(), data_from.size())))
41  if (stateful_prop_ids[i] < data.size() && data.hasValue(stateful_prop_ids[i]) &&
42  data_from.hasValue(i))
43  {
44  auto & prop = data[stateful_prop_ids[i]];
45  auto & prop_from = data_from[i];
46  prop.swap(prop_from);
47  }
48 }
49 
50 void
51 MaterialPropertyStorage::shallowSwapDataBack(const std::vector<unsigned int> & stateful_prop_ids,
52  MaterialProperties & data,
53  MaterialProperties & data_from)
54 {
55  for (const auto i : make_range(std::min(stateful_prop_ids.size(), data.size())))
56  if (stateful_prop_ids[i] < data_from.size() && data.hasValue(i) &&
57  data_from.hasValue(stateful_prop_ids[i]))
58  {
59  auto & prop = data[i];
60  auto & prop_from = data_from[stateful_prop_ids[i]];
61  prop.swap(prop_from);
62  }
63 }
64 
65 std::optional<std::string>
67 {
68  if (_prop_records.size() > id && _prop_records[id] && _prop_records[id]->stateful())
69  return _registry.getName(id);
70  return {};
71 }
72 
73 void
75 {
76  for (const auto state : stateIndexRange())
77  setProps(state).erase(elem);
78 }
79 
80 void
82 {
83  _restart_in_place = true;
84  _restartable_map.clear();
85 }
86 
88 MaterialPropertyStorage::getPropRecord(const unsigned int id) const
89 {
90  mooseAssert(_prop_records.size() > id, "Invalid ID");
91  auto & prop_record_ptr = _prop_records[id];
92  mooseAssert(prop_record_ptr, "Not initialized");
93  return *prop_record_ptr;
94 }
95 
96 bool
97 MaterialPropertyStorage::isRestoredProperty(const std::string & name) const
98 {
99  const auto & record = getPropRecord(_registry.getID(name));
100  if (!record.stateful())
101  mooseAssert(!record.restored, "Stateful properties should not be restored");
102  return record.restored;
103 }
104 
105 void
107  const processor_id_type libmesh_dbg_var(pid),
108  const std::vector<QpMap> & p_refinement_map,
109  const QBase & qrule,
110  const QBase & qrule_face,
111  const THREAD_ID tid,
112  const Elem & elem,
113  const int input_side)
114 {
115  unsigned int n_qpoints = 0;
116 
117  // If we passed in -1 for these then we really need to store properties at 0
118  unsigned int side = input_side == -1 ? 0 : input_side;
119 
120  if (input_side == -1) // Not doing side projection (ie, doing volume projection)
121  n_qpoints = qrule.n_points();
122  else
123  n_qpoints = qrule_face.n_points();
124 
125  getMaterialData(tid).resize(n_qpoints);
126 
127  mooseAssert(elem.active(), "We should be doing p-refinement on active elements only");
128  mooseAssert(elem.processor_id() == pid, "Prolongation should be occurring locally");
129  mooseAssert(p_refinement_map.size() == n_qpoints, "Refinement map not proper size");
130 
131  auto current_p_level_props = initProps(tid, &elem, side, n_qpoints);
132 
133  for (const auto state : stateIndexRange())
134  for (const auto i : index_range(_stateful_prop_id_to_prop_id))
135  {
136  auto & current_p_level_prop = (*current_p_level_props[state])[i];
137  // We need to clone this property in order to not overwrite the values we're going to be
138  // reading from
139  auto previous_p_level_prop = current_p_level_prop.clone(current_p_level_prop.size());
140  // Cloning, despite its name, does not copy the data. Luckily since we are about to overwrite
141  // all of the current_p_level_prop data, we can just swap its data over to our
142  // previous_p_level_prop
143  previous_p_level_prop->swap(current_p_level_prop);
144  current_p_level_prop.resize(n_qpoints);
145  for (const auto qp : index_range(p_refinement_map))
146  current_p_level_prop.qpCopy(qp, *previous_p_level_prop, p_refinement_map[qp]._to);
147  }
148 }
149 
150 void
152  processor_id_type pid,
153  const std::vector<std::vector<QpMap>> & refinement_map,
154  const QBase & qrule,
155  const QBase & qrule_face,
156  MaterialPropertyStorage & parent_material_props,
157  const THREAD_ID tid,
158  const Elem & elem,
159  const int input_parent_side,
160  const int input_child,
161  const int input_child_side)
162 {
163  mooseAssert(input_child != -1 || input_parent_side == input_child_side, "Invalid inputs!");
164 
165  unsigned int n_qpoints = 0;
166 
167  // If we passed in -1 for these then we really need to store properties at 0
168  unsigned int parent_side = input_parent_side == -1 ? 0 : input_parent_side;
169  unsigned int child_side = input_child_side == -1 ? 0 : input_child_side;
170 
171  if (input_child_side == -1) // Not doing side projection (ie, doing volume projection)
172  n_qpoints = qrule.n_points();
173  else
174  n_qpoints = qrule_face.n_points();
175 
176  getMaterialData(tid).resize(n_qpoints);
177 
178  unsigned int n_children = elem.n_children();
179 
180  std::vector<unsigned int> children;
181 
182  if (input_child != -1) // Passed in a child explicitly
183  children.push_back(input_child);
184  else
185  {
186  children.resize(n_children);
187  for (unsigned int child = 0; child < n_children; child++)
188  children[child] = child;
189  }
190 
191  for (const auto & child : children)
192  {
193  // If we're not projecting an internal child side, but we are projecting sides, see if this
194  // child is on that side
195  if (input_child == -1 && input_child_side != -1 && !elem.is_child_on_side(child, parent_side))
196  continue;
197 
198  const Elem * child_elem = elem.child_ptr(child);
199 
200  // If it's not a local child then it'll be prolonged where it is
201  // local
202  if (child_elem->processor_id() != pid)
203  continue;
204 
205  mooseAssert(child < refinement_map.size(), "Refinement_map vector not initialized");
206  const std::vector<QpMap> & child_map = refinement_map[child];
207 
208  auto child_props = initProps(tid, child_elem, child_side, n_qpoints);
209 
210  for (const auto state : stateIndexRange())
211  {
212  const auto & parent_props = parent_material_props.props(&elem, parent_side, state);
213  for (const auto i : index_range(_stateful_prop_id_to_prop_id))
214  for (const auto qp : index_range(refinement_map[child]))
215  (*child_props[state])[i].qpCopy(qp, parent_props[i], child_map[qp]._to);
216  }
217  }
218 }
219 
220 void
222  const std::vector<std::pair<unsigned int, QpMap>> & coarsening_map,
223  const std::vector<const Elem *> & coarsened_element_children,
224  const QBase & qrule,
225  const QBase & qrule_face,
226  const THREAD_ID tid,
227  const Elem & elem,
228  int input_side)
229 {
230  unsigned int side;
231 
232  bool doing_a_side = input_side != -1;
233 
234  unsigned int n_qpoints = 0;
235 
236  if (!doing_a_side)
237  {
238  side = 0; // Use 0 for the elem
239  n_qpoints = qrule.n_points();
240  }
241  else
242  {
243  side = input_side;
244  n_qpoints = qrule_face.n_points();
245  }
246 
247  auto parent_props = initProps(tid, &elem, side, n_qpoints);
248 
249  // Copy from the child stateful properties
250  for (const auto qp : index_range(coarsening_map))
251  {
252  const std::pair<unsigned int, QpMap> & qp_pair = coarsening_map[qp];
253  unsigned int child = qp_pair.first;
254 
255  mooseAssert(child < coarsened_element_children.size(),
256  "Coarsened element children vector not initialized");
257  const Elem * child_elem = coarsened_element_children[child];
258  const QpMap & qp_map = qp_pair.second;
259 
260  for (const auto state : stateIndexRange())
261  {
262  const auto & child_props = props(child_elem, side, state);
263  for (const auto i : index_range(_stateful_prop_id_to_prop_id))
264  (*parent_props[state])[i].qpCopy(qp, child_props[i], qp_map._to);
265  }
266  }
267 }
268 
269 void
271  const std::vector<std::shared_ptr<MaterialBase>> & mats,
272  const unsigned int n_qpoints,
273  const Elem & elem,
274  const unsigned int side /* = 0*/)
275 {
276  // Material -> stateful properties that need to be restarted for said material
277  // We need this because we need to initialize everything in dependency the dependency ordering
278  // as given in mats, which means that we can't just do these all up front
279  std::unordered_map<const MaterialBase *,
280  std::vector<std::pair<unsigned int, std::vector<std::stringstream> *>>>
281  materials_to_restart;
282  // Find the entry in the restartable data (binary data waiting to be restarted)
283  // for this [elem, side], if any
284  RestartableMapType::mapped_type * restartable_entry = nullptr;
285  if (_restartable_map.size())
286  if (auto it = _restartable_map.find(std::make_pair(&elem, side)); it != _restartable_map.end())
287  restartable_entry = &it->second;
288 
289  // The stateful objects that we're going to initialize. This is needed for materials that are
290  // passed in as mat that are not stateful, who we don't want to call initStatefulProperties() on.
291  // We unfortunately can only determine this here due to block/boundary restriction, which is
292  // not known without mapping property -> material
293  std::vector<MaterialBase *> stateful_mats;
294  // The stateful IDs that we need to copy back
295  std::vector<unsigned int> stateful_ids_to_copy;
296 
297 #ifndef NDEBUG
298  // All of the stateful IDs; used to make sure that we're not supplying one property
299  // across multiple materials
300  std::set<unsigned int> stateful_ids;
301 #endif
302 
303  // Work through all of the materials that we were passed to figure out which ones are stateful
304  // that we need to initialize, and also to figure out which ones we need to restart
305  for (const auto & mat : mats)
306  {
307  // For keeping track of this material in stateful_mats
308  bool stateful = false;
309 
310  // Check each material that was declared
311  for (const auto id : mat->getSuppliedPropIDs())
312  {
313  const auto & record = getPropRecord(id);
314  if (record.stateful())
315  {
316  const auto stateful_id = record.stateful_id;
317  stateful = true;
318 
319 #ifndef NDEBUG
320  const auto it_inserted_pair = stateful_ids.insert(stateful_id);
321  mooseAssert(it_inserted_pair.second,
322  "Material property '" + _registry.getName(id) +
323  "' supplied by multiple materials at the same point");
324 #endif
325 
326  bool restarting = false;
327  // We have restartable data for this [elem, side]; see if we have it for this prop
328  if (restartable_entry)
329  {
330  if (auto id_datum_pair_it = restartable_entry->find(stateful_id);
331  id_datum_pair_it != restartable_entry->end())
332  {
333  restarting = true;
334  materials_to_restart[mat.get()].emplace_back(stateful_id, &id_datum_pair_it->second);
335  }
336  }
337 
338  if (!restarting)
339  stateful_ids_to_copy.push_back(record.stateful_id);
340  }
341  }
342 
343  if (stateful || mat->forceStatefulInit())
344  stateful_mats.push_back(mat.get());
345  }
346 
347  // This currently initializes all of the stateful properties for this [elem, side],
348  // even though we didn't necessarily need to init all of them. Future work?
349  auto props = initProps(tid, &elem, side, n_qpoints);
350 
351  // Whether or not we have swapped material data from _storage to _material_data
352  // When we're initializing from initStatefulProperties, the MaterialBase objects
353  // need to be able to access the data in _material_data. When we're initalizing
354  // from restart, we need to be able to access from _storage.
355  bool swapped = false;
356 
357  // Initialize properties
358  for (auto mat : stateful_mats)
359  {
360  const auto materials_to_restart_find = materials_to_restart.find(mat);
361  const bool restart = materials_to_restart_find != materials_to_restart.end();
362 
363  if (!restart || mat->forceStatefulInit())
364  {
365  // Need stateful _material_data in the material to store
366  if (!swapped)
367  {
368  swap(tid, elem, side);
369  swapped = true;
370  }
371 
372  mat->initStatefulProperties(n_qpoints);
373  }
374 
375  if (restart)
376  {
377  // Need data in _storage
378  if (swapped)
379  {
380  swapBack(tid, elem, side);
381  swapped = false;
382  }
383 
384  // Load from the cached binary backup into place
385  for (auto & [stateful_id, datum_ptr] : materials_to_restart_find->second)
386  for (const auto state : index_range(*datum_ptr))
387  {
388  (*datum_ptr)[state].seekg(0, std::ios::beg);
389  dataLoad((*datum_ptr)[state], (*props[state])[stateful_id], nullptr);
390  }
391  }
392  }
393 
394  // Done with accessing from _material_data
395  if (swapped)
396  swapBack(tid, elem, side);
397 
398  // Copy to older states as needed, only for non-restarted data
399  for (const auto stateful_id : stateful_ids_to_copy)
400  for (const auto state : statefulIndexRange())
401  for (const auto qp : make_range(n_qpoints))
402  (*props[state])[stateful_id].qpCopy(qp, (*props[0])[stateful_id], qp);
403 }
404 
405 void
407 {
408  mooseAssert(hasStatefulProperties(), "Doesn't have stateful props");
409 
416  for (unsigned int state = maxState(); state != 0; state--)
417  std::swap(setProps(state), setProps(state - 1));
418 }
419 
420 void
422  const Elem & elem_to,
423  const Elem & elem_from,
424  unsigned int side,
425  unsigned int n_qpoints)
426 {
427  copy(tid, &elem_to, &elem_from, side, n_qpoints);
428 }
429 
430 void
432  const Elem * elem_to,
433  const Elem * elem_from,
434  unsigned int side,
435  unsigned int n_qpoints)
436 {
437  auto to_props = initProps(tid, elem_to, side, n_qpoints);
438 
439  for (const auto state : stateIndexRange())
440  {
441  const auto & from_props = props(elem_from, side, state);
442  for (const auto i : index_range(_stateful_prop_id_to_prop_id))
443  for (const auto qp : make_range(n_qpoints))
444  (*to_props[state])[i].qpCopy(qp, from_props[i], qp);
445  }
446 }
447 
448 void
449 MaterialPropertyStorage::swap(const THREAD_ID tid, const Elem & elem, unsigned int side)
450 {
451  Threads::spin_mutex::scoped_lock lock(this->_spin_mtx);
452 
453  for (const auto state : stateIndexRange())
455  getMaterialData(tid).props(state),
456  // Would be nice to make this setProps()
457  initAndSetProps(&elem, side, state));
458 }
459 
460 void
461 MaterialPropertyStorage::swapBack(const THREAD_ID tid, const Elem & elem, unsigned int side)
462 {
463  Threads::spin_mutex::scoped_lock lock(this->_spin_mtx);
464 
465  for (const auto state : stateIndexRange())
467  setProps(&elem, side, state),
468  getMaterialData(tid).props(state));
469 
470  // Workaround for MOOSE difficulties in keeping materialless
471  // elements (e.g. Lower D elements in Mortar code) materials
472  for (const auto state : stateIndexRange())
473  if (props(&elem, side, state).empty())
474  setProps(state)[&elem].erase(side);
475 }
476 
477 unsigned int
478 MaterialPropertyStorage::addProperty(const std::string & prop_name,
479  const std::type_info & type,
480  const unsigned int state,
481  const MaterialBase * const declarer)
482 {
483  if (state > MaterialData::max_state)
484  mooseError("Material property state of ",
485  state,
486  " is not supported. Max state supported: ",
488 
489  // Increment state as needed
490  if (maxState() < state)
491  _max_state = state;
492 
493  // Register the property
494  const auto prop_id = _registry.addOrGetID(prop_name, {});
495 
496  // Instantiate the record if needed
497  if (_prop_records.size() < _registry.size())
498  _prop_records.resize(_registry.size());
499  if (!_prop_records[prop_id])
500  _prop_records[prop_id] = PropRecord();
501 
502  // Fill the record
503  auto & record = *_prop_records[prop_id];
504  record.type = type.name();
505  if (declarer)
506  record.declarers.emplace(declarer->typeAndName());
507  record.state = std::max(state, record.state);
508 
509  // Keep track of stateful props by quick access
510  if (state > 0 && std::find(_stateful_prop_id_to_prop_id.begin(),
512  prop_id) == _stateful_prop_id_to_prop_id.end())
513  {
514  _stateful_prop_id_to_prop_id.push_back(prop_id);
515  record.stateful_id = _stateful_prop_id_to_prop_id.size() - 1;
516  }
517 
518  return prop_id;
519 }
520 
521 std::vector<MaterialProperties *>
523  const Elem * elem,
524  unsigned int side,
525  unsigned int n_qpoints)
526 {
527  std::vector<MaterialProperties *> props(numStates());
528  for (const auto state : stateIndexRange())
529  props[state] = &this->initProps(tid, state, elem, side, n_qpoints);
530  return props;
531 }
532 
535  const unsigned int state,
536  const Elem * elem,
537  unsigned int side,
538  unsigned int n_qpoints)
539 {
540  auto & material_data = getMaterialData(tid);
541  material_data.resize(n_qpoints);
542 
543  auto & mat_props = initAndSetProps(elem, side, state);
544 
545  // In some special cases, material_data might be larger than n_qpoints
546  if (material_data.isOnlyResizeIfSmaller())
547  n_qpoints = material_data.nQPoints();
548 
549  const auto n_props = _stateful_prop_id_to_prop_id.size();
550  if (mat_props.size() < n_props)
551  mat_props.resize(n_props, {});
552 
553  // init properties (allocate memory. etc)
554  for (const auto i : index_range(_stateful_prop_id_to_prop_id))
555  if (!mat_props.hasValue(i))
556  {
557  const auto prop_id = _stateful_prop_id_to_prop_id[i];
558  mat_props.setPointer(i, material_data.props(0)[prop_id].clone(n_qpoints), {});
559  mooseAssert(mat_props[i].id() == prop_id, "Inconsistent id");
560  }
561 
562  return mat_props;
563 }
564 
565 void
566 dataStore(std::ostream & stream, MaterialPropertyStorage & storage, void * context)
567 {
568  // Store the material property ID -> name map for mapping back
569  const auto & registry = storage.getMaterialPropertyRegistry();
570  std::vector<std::string> ids_to_names(registry.idsToNamesBegin(), registry.idsToNamesEnd());
571  dataStore(stream, ids_to_names, nullptr);
572 
573  // Store the stateful ID -> property ID map for mapping back
574  dataStore(stream, storage._stateful_prop_id_to_prop_id, nullptr);
575 
576  // Store the prop -> record map
577  dataStore(stream, storage._prop_records, nullptr);
578 
579  // Store the number of states
580  auto num_states = storage.numStates();
581  dataStore(stream, num_states, nullptr);
582 
583  // Store every property
584  for (const auto state : storage.stateIndexRange())
585  {
586  std::size_t num_elems = storage.setProps(state).size();
587  dataStore(stream, num_elems, nullptr);
588 
589  for (auto & elem_side_map_pair : storage.setProps(state))
590  {
591  const Elem * elem = elem_side_map_pair.first;
592  mooseAssert(elem, "Null element");
593  dataStore(stream, elem, context);
594 
595  auto & side_map = elem_side_map_pair.second;
596  std::size_t num_sides = side_map.size();
597  dataStore(stream, num_sides, nullptr);
598 
599  for (auto & [side, props] : side_map)
600  {
601  dataStore(stream, side, nullptr);
602 
603  std::size_t num_props = props.size();
604  dataStore(stream, num_props, nullptr);
605  mooseAssert(num_props > 0, "No properties");
606 
607  std::size_t n_q_points = 0;
608  for (const auto & entry : props)
609  if (entry.size() > n_q_points)
610  n_q_points = entry.size();
611  dataStore(stream, n_q_points, nullptr);
612 
613  // Here we actually store a stringstream of the data instead of the data directly, because
614  // upon load we don't know if we can load it immediately into place or if we need to cache
615  // it to load later. We also store it as skippable so that we can support not loading a
616  // property if it no longer exists in restart
617  for (auto & entry : props)
618  {
619  std::stringstream out;
620  dataStore(out, entry, nullptr);
621  dataStore(stream, out, nullptr);
622  }
623  }
624  }
625  }
626 }
627 
628 void
629 dataLoad(std::istream & stream, MaterialPropertyStorage & storage, void * context)
630 {
631  storage._restartable_map.clear();
632 
633  const auto & registry = storage.getMaterialPropertyRegistry();
634 
635  std::vector<std::string> from_prop_ids_to_names;
636  dataLoad(stream, from_prop_ids_to_names, nullptr);
637 
638  decltype(storage._stateful_prop_id_to_prop_id) from_stateful_prop_id_to_prop_id;
639  dataLoad(stream, from_stateful_prop_id_to_prop_id, nullptr);
640 
641  decltype(storage._prop_records) from_prop_records;
642  dataLoad(stream, from_prop_records, nullptr);
643 
644  decltype(storage.numStates()) num_states;
645  dataLoad(stream, num_states, nullptr);
646 
647  {
648  // Build maps of material object -> properties and property -> material objects
649  const auto build_maps = [](const auto & prop_records, const auto & ids_to_names)
650  {
651  std::map<std::string, std::set<std::string>> object_to_props, prop_to_objects;
652  for (const auto i : index_range(prop_records))
653  if (prop_records[i] && prop_records[i]->stateful())
654  {
655  const auto & prop = ids_to_names[i];
656  for (const auto & declarer : (*prop_records[i]).declarers)
657  {
658  object_to_props[declarer].insert(prop);
659  prop_to_objects[prop].insert(declarer);
660  }
661  }
662 
663  return std::make_pair(std::move(object_to_props), std::move(prop_to_objects));
664  };
665  // Maps for the current stateful properties
666  const std::vector<std::string> prop_ids_to_names(registry.idsToNamesBegin(),
667  registry.idsToNamesEnd());
668  const auto [object_to_props, prop_to_objects] =
669  build_maps(storage._prop_records, prop_ids_to_names);
670  // Maps for the stored stateful properties
671  const auto [from_object_to_props, from_prop_to_objects] =
672  build_maps(from_prop_records, from_prop_ids_to_names);
673 
674  // Enforce our stateful requirements
675  for (const auto & [object, props] : object_to_props)
676  {
677  const auto find_from_object = from_object_to_props.find(object);
678 
679  // We have a material object that was stored with the same name that
680  // had stateful material properties. Here, we enforce that the stateful
681  // properties stored match exactly the ones that we have declared in
682  // the new run
683  if (find_from_object != from_object_to_props.end())
684  {
685  const auto & from_props = find_from_object->second;
686  if (props != from_props)
687  {
688  std::stringstream error;
689  error << "The stateful material properties in " << object
690  << " that are being restarted do not match the stored properties in the same "
691  "material object from the checkpoint.\n\n";
692  error << "Checkpointed stateful properties:\n";
693  for (const auto & prop : from_props)
694  error << " - " << prop << "\n";
695  error << "\nCurrent stateful properties:\n";
696  for (const auto & prop : props)
697  error << " - " << prop << "\n";
698  mooseError(error.str());
699  }
700  }
701  // We're recovering and we haven't found a stateful material object. We require a
702  // one-to-one stateful mapping when recovering
703  else if (storage._recovering)
704  {
705  mooseError("The ",
706  object,
707  " was stored in restart but no longer exists. This is not supported when "
708  "recovering stateful material properties.");
709  }
710  }
711 
712  // We can easily support this, but have chosen not to due to ambiguity and we
713  // don't yet know how to express this ambiguity. Just removing this error
714  // _should_ make it work without issue because to_stateful_ids below for this
715  // property will be an empty optional, which means simply don't load it. Or,
716  // we could load it into the new property.
717  for (const auto & [from_prop, from_objects] : from_prop_to_objects)
718  if (const auto find_objects = prop_to_objects.find(from_prop);
719  find_objects != prop_to_objects.end())
720  for (const auto & object : find_objects->second)
721  if (!from_objects.count(object))
722  mooseError(
723  "The stateful material property '",
724  from_prop,
725  "' was declared in ",
726  object,
727  " but was not declared in that object on checkpoint.\n\nThis is not currently "
728  "supported due to ambiguity.\n\nPlease contact the development team on "
729  "GitHub if you desire this capability.");
730  }
731 
732  std::vector<std::optional<unsigned int>> to_stateful_ids(from_stateful_prop_id_to_prop_id.size());
733 
734  auto & to_prop_records = storage._prop_records;
735 
736  // Mark everything as not restored in the event that we call this again
737  for (auto & record_ptr : to_prop_records)
738  if (record_ptr)
739  record_ptr->restored = false;
740 
741  // Fill the mapping from previous ID to current stateful ID
742  for (const auto from_stateful_id : index_range(from_stateful_prop_id_to_prop_id))
743  {
744  const auto from_prop_id = from_stateful_prop_id_to_prop_id[from_stateful_id];
745 
746  mooseAssert(from_prop_id < from_prop_records.size(), "Invalid record map");
747  mooseAssert(from_prop_records[from_prop_id], "Not set");
748  const auto & from_record = *from_prop_records[from_prop_id];
749  mooseAssert(from_record.stateful(), "Not stateful");
750 
751  mooseAssert(from_prop_id < from_prop_ids_to_names.size(), "Invalid ID map");
752  const auto & name = from_prop_ids_to_names[from_prop_id];
753 
754  if (const auto query_to_prop_id = registry.queryID(name))
755  {
756  const auto to_prop_id = *query_to_prop_id;
757 
758  mooseAssert(to_prop_id < to_prop_records.size(), "Invalid record map");
759  mooseAssert(to_prop_records[to_prop_id], "Not set");
760  auto & to_record = *to_prop_records[to_prop_id];
761 
762  if (to_record.stateful())
763  {
764  if (from_record.type != to_record.type)
765  mooseError(
766  "The type for the restarted stateful material property '", name, "' does not match");
767 
768  // I'm not sure if we need to enforce this one, but I don't want to think
769  // about it deeply so we'll just make it an error until someone complains
770  // we have time to think
771  if (from_record.state != to_record.state)
772  mooseError("The number of states for the restarted stateful material property '",
773  name,
774  "' do not match.\n\n",
775  "Checkpointed states: ",
776  from_record.state,
777  "\nCurrent states: ",
778  to_record.state);
779 
780  const auto to_stateful_id = storage.getPropRecord(to_prop_id).stateful_id;
781  mooseAssert(to_stateful_id != invalid_uint, "Not stateful");
782 
783  to_stateful_ids[from_stateful_id] = to_stateful_id;
784 
785  // Mark that we're going to restore this property
786  to_record.restored = true;
787  mooseAssert(storage.isRestoredProperty(name), "Restored mismatch");
788 
789  if (storage._recovering)
790  mooseAssert(from_stateful_id == to_stateful_id, "Does not have direct mapping");
791  }
792  }
793  }
794 
795  // Load the properties
796  for (const auto state : make_range(num_states))
797  {
798  std::size_t num_elems;
799  dataLoad(stream, num_elems, nullptr);
800 
801  for (std::size_t i_elem = 0; i_elem < num_elems; ++i_elem)
802  {
803  const Elem * elem;
804  dataLoad(stream, elem, context);
805  mooseAssert(elem, "Null element");
806 
807  std::size_t num_sides;
808  dataLoad(stream, num_sides, nullptr);
809 
810  for (std::size_t i_side = 0; i_side < num_sides; ++i_side)
811  {
812  unsigned int side;
813  dataLoad(stream, side, nullptr);
814 
815  std::size_t num_props;
816  dataLoad(stream, num_props, nullptr);
817  mooseAssert(num_props <= to_stateful_ids.size(), "Missized map");
818 
819  std::size_t num_q_points;
820  dataLoad(stream, num_q_points, nullptr);
821 
822  // Avoid multiple map lookups for entries pertaining to [elem, side]
823  MaterialPropertyStorage::RestartableMapType::mapped_type * restart_entry = nullptr;
824  MaterialProperties * in_place_entry = nullptr;
825 
826  // Load each stateful property
827  for (const auto from_stateful_id : make_range(num_props))
828  {
829  // Load the binary data, which lets us choose in a moment whether
830  // or not to load it in place or to cache it to load later
831  std::stringstream data;
832  dataLoad(stream, data, nullptr);
833  data.seekg(0, std::ios::beg);
834 
835  // We have a property to load into
836  if (const auto to_stateful_id_ptr = to_stateful_ids[from_stateful_id])
837  {
838  const auto to_stateful_id = *to_stateful_id_ptr;
839 
840  // Load the data directly into _storage
841  if (storage._restart_in_place)
842  {
843  if (!in_place_entry)
844  in_place_entry = &storage.setProps(elem, side, state);
845 
846  dataLoad(data, (*in_place_entry)[to_stateful_id], nullptr);
847  }
848  // Properties aren't initialized, so load the data into
849  // _restartable_map to be loaded later in initStatefulProps()
850  else
851  {
852  if (!restart_entry)
853  restart_entry = &storage._restartable_map[std::make_pair(elem, side)];
854 
855  auto & mat_entry = (*restart_entry)[to_stateful_id];
856  if (state >= mat_entry.size())
857  mat_entry.resize(state + 1);
858 
859  mat_entry[state] = std::move(data);
860  }
861  }
862  }
863  }
864  }
865  }
866 }
867 
868 void
869 dataStore(std::ostream & stream, MaterialPropertyStorage::PropRecord & record, void *)
870 {
871  dataStore(stream, record.declarers, nullptr);
872  dataStore(stream, record.type, nullptr);
873  dataStore(stream, record.stateful_id, nullptr);
874  dataStore(stream, record.state, nullptr);
875 }
876 
877 void
878 dataLoad(std::istream & stream, MaterialPropertyStorage::PropRecord & record, void *)
879 {
880  dataLoad(stream, record.declarers, nullptr);
881  dataLoad(stream, record.type, nullptr);
882  dataLoad(stream, record.stateful_id, nullptr);
883  dataLoad(stream, record.state, nullptr);
884 }
std::string name(const ElemQuality q)
MaterialProperties & setProps(const Elem *elem, unsigned int side, const unsigned int state=0)
void shift()
Shift the material properties in time.
unsigned int n_threads()
std::vector< MaterialData > _material_data
The threaded material data.
const unsigned int invalid_uint
Registry class for material property IDs and names.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:302
void eraseProperty(const Elem *elem)
Remove the property storage and element pointer from internal data structures Use this when elements ...
void swap(std::vector< T > &data, const std::size_t idx0, const std::size_t idx1, const libMesh::Parallel::Communicator &comm)
Swap function for serial or distributed vector of data.
Definition: Shuffle.h:494
Stores the stateful material properties computed by materials.
std::vector< unsigned int > _stateful_prop_id_to_prop_id
the vector of stateful property ids (the vector index is the map to stateful prop_id) ...
const MaterialPropertyRegistry & getMaterialPropertyRegistry() const
Helper object for holding qp mapping info.
Definition: MooseMesh.h:69
libMesh::Threads::spin_mutex & _spin_mtx
std::vector< std::optional< PropRecord > > _prop_records
Property records indexed by property id (may be null)
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
bool restored
Whether or not this property was restored (stateful only)
static void shallowSwapData(const std::vector< unsigned int > &stateful_prop_ids, MaterialProperties &data, MaterialProperties &data_from)
Shallow copies of material properties.
static void shallowSwapDataBack(const std::vector< unsigned int > &stateful_prop_ids, MaterialProperties &data, MaterialProperties &data_from)
unsigned int _to
The qp to map to.
Definition: MooseMesh.h:78
MaterialPropertyStorage(MaterialPropertyRegistry &registry)
std::size_t size() const
auto max(const L &left, const R &right)
uint8_t processor_id_type
void setRestartInPlace()
Sets the loading of stateful material properties in place.
void prolongStatefulProps(processor_id_type pid, const std::vector< std::vector< QpMap >> &refinement_map, const libMesh::QBase &qrule, const libMesh::QBase &qrule_face, MaterialPropertyStorage &parent_material_props, const THREAD_ID tid, const Elem &elem, const int input_parent_side, const int input_child, const int input_child_side)
Creates storage for newly created elements from mesh Adaptivity.
libMesh::IntRange< unsigned int > stateIndexRange() const
void swapBack(const THREAD_ID tid, const Elem &elem, unsigned int side)
Swap (shallow copy) material properties in MaterialPropertyStorage and MaterialDat Thread safe...
std::optional< std::string > queryStatefulPropName(const unsigned int id) const
bool isRestoredProperty(const std::string &name) const
bool _recovering
Whether or not we&#39;re recovering; enforces a one-to-one mapping of stateful properties.
unsigned int numStates() const
unsigned int addProperty(const std::string &prop_name, const std::type_info &type, const unsigned int state, const MaterialBase *const declarer)
Adds a property with the name prop_name, type type, and state state (0 = current, 1 = old...
unsigned int addOrGetID(const std::string &name, const WriteKey)
unsigned int state
The max state requrested for this property (0 = current, 1 = old, ...)
std::string typeAndName() const
Get the class&#39;s combined type and name; useful in error handling.
Definition: MooseBase.C:27
static constexpr unsigned int max_state
The max time state supported (2 = older)
Definition: MaterialData.h:39
std::vector< MaterialProperties * > initProps(const THREAD_ID tid, const Elem *elem, unsigned int side, unsigned int n_qpoints)
Initializes hashmap entries for element and side to proper qpoint and property count sizes...
RestartableMapType _restartable_map
The restartable data to be loaded in initStatefulProps() later.
void updateStatefulPropsForPRefinement(const processor_id_type pid, const std::vector< QpMap > &p_refinement_map, const libMesh::QBase &qrule, const libMesh::QBase &qrule_face, const THREAD_ID tid, const Elem &elem, const int input_side)
Based on the p-refinement flag of elem, either prolong (for refinement) or restrict (for coarsening) ...
Basic structure for storing information about a property.
const PropsType & props(const unsigned int state=0) const
Access methods to the stored material property data with the given state state.
const std::string & getName(const unsigned int id) const
OStreamProxy out
unsigned int getID(const std::string &name) const
IntRange< T > make_range(T beg, T end)
void dataStore(std::ostream &stream, MaterialPropertyStorage &storage, void *context)
MaterialData & getMaterialData(const THREAD_ID tid)
MaterialPropertyRegistry & _registry
Shared registry (across storage objects) for property names and IDs.
friend void dataLoad(std::istream &, MaterialPropertyStorage &, void *)
void restrictStatefulProps(const std::vector< std::pair< unsigned int, QpMap >> &coarsening_map, const std::vector< const Elem *> &coarsened_element_children, const libMesh::QBase &qrule, const libMesh::QBase &qrule_face, const THREAD_ID tid, const Elem &elem, int input_side=-1)
Creates storage for newly created elements from mesh Adaptivity.
void swap(const THREAD_ID tid, const Elem &elem, unsigned int side)
Swap (shallow copy) material properties in MaterialData and MaterialPropertyStorage Thread safe...
void dataLoad(std::istream &stream, MaterialPropertyStorage &storage, void *context)
void initStatefulProps(const THREAD_ID tid, const std::vector< std::shared_ptr< MaterialBase >> &mats, const unsigned int n_qpoints, const Elem &elem, const unsigned int side=0)
Initialize stateful material properties.
bool _restart_in_place
Whether or not we want to restart stateful properties in place.
void copy(const THREAD_ID tid, const Elem &elem_to, const Elem &elem_from, unsigned int side, unsigned int n_qpoints)
Copy material properties from elem_from to elem_to.
auto min(const L &left, const R &right)
const PropRecord & getPropRecord(const unsigned int id) const
Get the property record associated with the material with id id.
MaterialBases compute MaterialProperties.
Definition: MaterialBase.h:62
bool hasValue(const std::size_t i) const
auto index_range(const T &sizable)
unsigned int _max_state
The maximum state (0 = current, 1 = old, 2 = older)
unsigned int stateful_id
The stateful id in _storage used for this property, if any.
void resize(unsigned int n_qpoints)
Resize the data to hold properties for n_qpoints quadrature points.
Definition: MaterialData.C:21
unsigned int THREAD_ID
Definition: MooseTypes.h:205
std::set< std::string > declarers
The material (type,name) that have declared this property.
MaterialProperties & initAndSetProps(const Elem *elem, const unsigned int side, const unsigned int state)
libMesh::IntRange< unsigned int > statefulIndexRange() const
spin_mutex spin_mtx
std::string type
The type of this property.