LCOV - code coverage report
Current view: top level - include/materials - MaterialPropertyStorage.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 25 25 100.0 %
Date: 2025-07-17 01:28:37 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

          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);

Generated by: LCOV version 1.14