LCOV - code coverage report
Current view: top level - include/materials - MaterialPropertyStorage.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 6f668f Lines: 28 28 100.0 %
Date: 2025-09-22 20:01:15 Functions: 16 16 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 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);

Generated by: LCOV version 1.14