LCOV - code coverage report
Current view: top level - include/materials - MaterialProperty.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33187 (5aa0b2) with base d7c4bd Lines: 68 78 87.2 %
Date: 2026-06-30 12:18:20 Functions: 197 514 38.3 %
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 <vector>
      13             : #include <memory>
      14             : #include <typeinfo>
      15             : 
      16             : #include "MooseArray.h"
      17             : #include "MooseTypes.h"
      18             : #include "DataIO.h"
      19             : #include "MooseError.h"
      20             : #include "UniqueStorage.h"
      21             : #include "MooseUtils.h"
      22             : 
      23             : #include "libmesh/libmesh_common.h"
      24             : #include "libmesh/tensor_value.h"
      25             : #include "libmesh/vector_value.h"
      26             : #include "libmesh/int_range.h"
      27             : 
      28             : #include "metaphysicl/raw_type.h"
      29             : 
      30             : class PropertyValue;
      31             : class Material;
      32             : class MaterialPropertyInterface;
      33             : 
      34             : /**
      35             :  * Abstract definition of a property value.
      36             :  */
      37             : class PropertyValue
      38             : {
      39             : public:
      40             :   /// The type for a material property ID
      41             :   typedef unsigned int id_type;
      42             : 
      43      233594 :   PropertyValue(const id_type id) : _id(id) {}
      44             : 
      45      227348 :   virtual ~PropertyValue(){};
      46             : 
      47             :   /// The material property ID for an invalid property
      48             :   /// We only have this because there are a few cases where folks want to instantiate their
      49             :   /// own fake materials, and we should at least force them to be consistent
      50             :   static constexpr id_type invalid_property_id = std::numeric_limits<id_type>::max() - 1;
      51             : 
      52             :   /**
      53             :    * @return The ID of the underlying material property
      54             :    */
      55      170080 :   id_type id() const { return _id; }
      56             : 
      57             :   /**
      58             :    * String identifying the type of parameter stored.
      59             :    */
      60             :   virtual const std::string & type() const = 0;
      61             : 
      62             :   /**
      63             :    * Clone this value.  Useful in copy-construction.
      64             :    */
      65             :   virtual std::unique_ptr<PropertyValue> clone(const std::size_t) const = 0;
      66             : 
      67             :   virtual unsigned int size() const = 0;
      68             : 
      69             :   /**
      70             :    * Resizes the property to the size n
      71             :    */
      72             :   virtual void resize(const std::size_t size) = 0;
      73             : 
      74             :   virtual void swap(PropertyValue & rhs) = 0;
      75             : 
      76             :   virtual bool isAD() const = 0;
      77             : 
      78             :   /**
      79             :    * Copy the value of a Property from one specific to a specific qp in this Property.
      80             :    * Important note: this copy operation loses AD derivative information if either this
      81             :    * or the rhs is not an AD material property
      82             :    *
      83             :    * @param to_qp The quadrature point in _this_ Property that you want to copy to.
      84             :    * @param rhs The Property you want to copy _from_.
      85             :    * @param from_qp The quadrature point in rhs you want to copy _from_.
      86             :    */
      87             :   virtual void
      88             :   qpCopy(const unsigned int to_qp, const PropertyValue & rhs, const unsigned int from_qp) = 0;
      89             : 
      90             :   // save/restore in a file
      91             :   virtual void store(std::ostream & stream) = 0;
      92             :   virtual void load(std::istream & stream) = 0;
      93             : 
      94             :   /**
      95             :    * @return The type_info for the underlying stored type T
      96             :    */
      97             :   virtual const std::type_info & typeID() const = 0;
      98             : 
      99             : protected:
     100             :   /// The material property ID
     101             :   const id_type _id;
     102             : };
     103             : 
     104             : /**
     105             :  * Concrete definition of a parameter value
     106             :  * for a specified type.
     107             :  */
     108             : template <typename T, bool is_ad>
     109             : class MaterialPropertyBase : public PropertyValue
     110             : {
     111             : public:
     112             :   typedef Moose::GenericType<T, is_ad> value_type;
     113             : 
     114      233594 :   MaterialPropertyBase(const PropertyValue::id_type id) : PropertyValue(id) {}
     115             : 
     116    26595018 :   bool isAD() const override final { return is_ad; }
     117             : 
     118             :   /**
     119             :    * @returns a read-only reference to the parameter value.
     120             :    */
     121          62 :   const MooseArray<Moose::GenericType<T, is_ad>> & get() const { return _value; }
     122             : 
     123             :   /**
     124             :    * @returns a writable reference to the parameter value.
     125             :    */
     126           0 :   MooseArray<Moose::GenericType<T, is_ad>> & set() { return _value; }
     127             : 
     128             :   /**
     129             :    * String identifying the type of parameter stored.
     130             :    */
     131             :   virtual const std::string & type() const override final;
     132             : 
     133             :   /**
     134             :    * Resizes the property to the size n
     135             :    */
     136             :   virtual void resize(const std::size_t size) override final;
     137             : 
     138      446808 :   virtual unsigned int size() const override final { return _value.size(); }
     139             : 
     140             :   /**
     141             :    * Get element i out of the array as a writeable reference.
     142             :    */
     143   109511729 :   Moose::GenericType<T, is_ad> & operator[](const unsigned int i) { return _value[i]; }
     144             : 
     145             :   /**
     146             :    * Get element i out of the array as a ready-only reference.
     147             :    */
     148  1166130424 :   const Moose::GenericType<T, is_ad> & operator[](const unsigned int i) const { return _value[i]; }
     149             : 
     150             :   /**
     151             :    * Copy the value of a Property from one specific to a specific qp in this Property.
     152             :    *
     153             :    * @param to_qp The quadrature point in _this_ Property that you want to copy to.
     154             :    * @param rhs The Property you want to copy _from_.
     155             :    * @param from_qp The quadrature point in rhs you want to copy _from_.
     156             :    */
     157             :   virtual void qpCopy(const unsigned int to_qp,
     158             :                       const PropertyValue & rhs,
     159             :                       const unsigned int from_qp) override final;
     160             : 
     161             :   /**
     162             :    * Store the property into a binary stream
     163             :    */
     164             :   virtual void store(std::ostream & stream) override final;
     165             : 
     166             :   /**
     167             :    * Load the property from a binary stream
     168             :    */
     169             :   virtual void load(std::istream & stream) override final;
     170             : 
     171             :   virtual void swap(PropertyValue & rhs) override final;
     172             : 
     173             :   const std::type_info & typeID() const override final;
     174             : 
     175             :   /**
     176             :    * @return A clone of this property.
     177             :    *
     178             :    * Note that this will only ever return a non-AD clone, even if this property
     179             :    * is an AD property. This is on purpose; whenever we need clones, it's for
     180             :    * older states in which we don't store derivatives beacuse it's too expensive.
     181             :    */
     182             :   virtual std::unique_ptr<PropertyValue> clone(const std::size_t size) const override final;
     183             : 
     184             : private:
     185             :   /// private copy constructor to avoid shallow copying of material properties
     186             :   MaterialPropertyBase(const MaterialPropertyBase<T, is_ad> & /*src*/)
     187             :   {
     188             :     mooseError("Material properties must be assigned to references (missing '&')");
     189             :   }
     190             : 
     191             :   /// private assignment operator to avoid shallow copying of material properties
     192             :   MaterialPropertyBase<T, is_ad> & operator=(const MaterialPropertyBase<T, is_ad> & /*rhs*/)
     193             :   {
     194             :     mooseError("Material properties must be assigned to references (missing '&')");
     195             :   }
     196             : 
     197             : protected:
     198             :   /// Stored parameter value.
     199             :   MooseArray<Moose::GenericType<T, is_ad>> _value;
     200             : };
     201             : 
     202             : template <typename T>
     203             : class MaterialProperty;
     204             : template <typename T>
     205             : class ADMaterialProperty;
     206             : 
     207             : // ------------------------------------------------------------
     208             : // Material::Property<> class inline methods
     209             : 
     210             : namespace moose
     211             : {
     212             : namespace internal
     213             : {
     214             : template <typename T1, typename T2>
     215             : void
     216      682440 : rawValueEqualityHelper(T1 & out, const T2 & in)
     217             : {
     218      682440 :   out = MetaPhysicL::raw_value(in);
     219      682440 : }
     220             : 
     221             : template <typename T1, typename T2>
     222             : void
     223           0 : rawValueEqualityHelper(std::vector<T1> & out, const std::vector<T2> & in)
     224             : {
     225           0 :   out.resize(in.size());
     226           0 :   for (MooseIndex(in) i = 0; i < in.size(); ++i)
     227           0 :     rawValueEqualityHelper(out[i], in[i]);
     228           0 : }
     229             : 
     230             : template <typename T1, typename T2, std::size_t N>
     231             : void
     232             : rawValueEqualityHelper(std::array<T1, N> & out, const std::array<T2, N> & in)
     233             : {
     234             :   for (MooseIndex(in) i = 0; i < in.size(); ++i)
     235             :     rawValueEqualityHelper(out[i], in[i]);
     236             : }
     237             : }
     238             : }
     239             : 
     240             : template <typename T, bool is_ad>
     241             : inline const std::string &
     242          12 : MaterialPropertyBase<T, is_ad>::type() const
     243             : {
     244          12 :   static const std::string type_name = MooseUtils::prettyCppType<T>();
     245          12 :   return type_name;
     246             : }
     247             : 
     248             : template <typename T, bool is_ad>
     249             : inline void
     250     1068660 : MaterialPropertyBase<T, is_ad>::resize(const std::size_t size)
     251             : {
     252     1068660 :   _value.template resize</*value_initalize=*/true>(size);
     253     1068660 : }
     254             : 
     255             : template <typename T, bool is_ad>
     256             : inline void
     257    11488243 : MaterialPropertyBase<T, is_ad>::qpCopy(const unsigned int to_qp,
     258             :                                        const PropertyValue & rhs,
     259             :                                        const unsigned int from_qp)
     260             : {
     261             :   // If we're the same
     262    11488243 :   if (rhs.isAD() == is_ad)
     263    11488243 :     _value[to_qp] =
     264    11488243 :         libMesh::cast_ptr<const MaterialPropertyBase<T, is_ad> *>(&rhs)->_value[from_qp];
     265             :   else
     266           0 :     moose::internal::rawValueEqualityHelper(
     267             :         _value[to_qp],
     268           0 :         (*libMesh::cast_ptr<const MaterialPropertyBase<T, !is_ad> *>(&rhs))[from_qp]);
     269    11488243 : }
     270             : 
     271             : template <typename T, bool is_ad>
     272             : inline void
     273       50311 : MaterialPropertyBase<T, is_ad>::store(std::ostream & stream)
     274             : {
     275      235087 :   for (const auto i : index_range(_value))
     276      184776 :     storeHelper(stream, _value[i], nullptr);
     277       50311 : }
     278             : 
     279             : template <typename T, bool is_ad>
     280             : inline void
     281       20858 : MaterialPropertyBase<T, is_ad>::load(std::istream & stream)
     282             : {
     283      126360 :   for (const auto i : index_range(_value))
     284      105502 :     loadHelper(stream, _value[i], nullptr);
     285       20858 : }
     286             : 
     287             : template <typename T, bool is_ad>
     288             : inline void
     289    15106763 : MaterialPropertyBase<T, is_ad>::swap(PropertyValue & rhs)
     290             : {
     291             :   mooseAssert(this->id() == rhs.id(), "Inconsistent properties");
     292             :   mooseAssert(this->typeID() == rhs.typeID(), "Inconsistent types");
     293             : 
     294             :   // If we're the same
     295    15106763 :   if (rhs.isAD() == is_ad)
     296             :   {
     297             :     mooseAssert(dynamic_cast<decltype(this)>(&rhs), "Expected same type is not the same");
     298    14935943 :     this->_value.swap(libMesh::cast_ptr<decltype(this)>(&rhs)->_value);
     299    14935943 :     return;
     300             :   }
     301             : 
     302             :   // We may call this function when doing swap between MaterialData material properties (you can
     303             :   // think of these as the current element properties) and MaterialPropertyStorage material
     304             :   // properties (these are the stateful material properties that we store for *every* element). We
     305             :   // never store ADMaterialProperty in stateful storage (e.g. MaterialPropertyStorage) for memory
     306             :   // resource reasons; instead we keep a regular MaterialProperty version of it. Hence we do have a
     307             :   // need to exchange data between the AD and regular copies which we implement below. The below
     308             :   // is obviously not a swap, for which you cannot identify a giver and receiver. Instead the below
     309             :   // has a clear giver and receiver. The giver is the object passed in as the rhs. The receiver is
     310             :   // *this* object. This directionality, although not conceptually appropriate given the method
     311             :   // name, *is* appropriate to how this method is used in practice. See shallowCopyData and
     312             :   // shallowCopyDataBack in MaterialPropertyStorage.C
     313             : 
     314      170820 :   auto * different_type_prop = libMesh::cast_ptr<MaterialPropertyBase<T, !is_ad> *>(&rhs);
     315             : 
     316      170820 :   this->resize(different_type_prop->size());
     317      853260 :   for (const auto qp : make_range(this->size()))
     318      682440 :     moose::internal::rawValueEqualityHelper(this->_value[qp], (*different_type_prop)[qp]);
     319             : }
     320             : 
     321             : template <typename T, bool is_ad>
     322             : inline const std::type_info &
     323           0 : MaterialPropertyBase<T, is_ad>::typeID() const
     324             : {
     325             :   static const auto & info = typeid(T);
     326           0 :   return info;
     327             : }
     328             : 
     329             : template <typename T, bool is_ad>
     330             : std::unique_ptr<PropertyValue>
     331      164952 : MaterialPropertyBase<T, is_ad>::clone(const std::size_t size) const
     332             : {
     333      164952 :   auto prop = std::make_unique<MaterialProperty<T>>(this->id());
     334      164952 :   if (size)
     335      164952 :     prop->resize(size);
     336      329904 :   return prop;
     337      164952 : }
     338             : 
     339             : template <typename T>
     340             : class MaterialProperty : public MaterialPropertyBase<T, false>
     341             : {
     342             : public:
     343      218624 :   MaterialProperty(const PropertyValue::id_type id = PropertyValue::invalid_property_id)
     344      218624 :     : MaterialPropertyBase<T, false>(id)
     345             :   {
     346      218624 :   }
     347             : 
     348             : private:
     349             :   /// private copy constructor to avoid shallow copying of material properties
     350             :   MaterialProperty(const MaterialProperty<T> & /*src*/)
     351             :   {
     352             :     mooseError("Material properties must be assigned to references (missing '&')");
     353             :   }
     354             : 
     355             :   /// private assignment operator to avoid shallow copying of material properties
     356             :   MaterialProperty<T> & operator=(const MaterialProperty<T> & /*rhs*/)
     357             :   {
     358             :     mooseError("Material properties must be assigned to references (missing '&')");
     359             :   }
     360             : };
     361             : 
     362             : template <typename T>
     363             : class ADMaterialProperty : public MaterialPropertyBase<T, true>
     364             : {
     365             : public:
     366       14970 :   ADMaterialProperty(const PropertyValue::id_type id = PropertyValue::invalid_property_id)
     367       14970 :     : MaterialPropertyBase<T, true>(id)
     368             :   {
     369       14970 :   }
     370             : 
     371             :   using typename MaterialPropertyBase<T, true>::value_type;
     372             : 
     373             : private:
     374             :   /// private copy constructor to avoid shallow copying of material properties
     375             :   ADMaterialProperty(const ADMaterialProperty<T> & /*src*/)
     376             :   {
     377             :     mooseError("Material properties must be assigned to references (missing '&')");
     378             :   }
     379             : 
     380             :   /// private assignment operator to avoid shallow copying of material properties
     381             :   ADMaterialProperty<T> & operator=(const ADMaterialProperty<T> & /*rhs*/)
     382             :   {
     383             :     mooseError("Material properties must be assigned to references (missing '&')");
     384             :   }
     385             : };
     386             : 
     387             : class MaterialData;
     388             : class MaterialPropertyStorage;
     389             : 
     390             : class MaterialProperties : public UniqueStorage<PropertyValue>
     391             : {
     392             : public:
     393             :   class WriteKey
     394             :   {
     395             :     friend class MaterialData;
     396             :     friend class MaterialPropertyStorage;
     397             :     friend void dataLoad(std::istream &, MaterialPropertyStorage &, void *);
     398             : 
     399      492881 :     WriteKey() {}
     400             :     WriteKey(const WriteKey &) {}
     401             :   };
     402             : 
     403             :   /**
     404             :    * Resize items in this array, i.e. the number of values needed in PropertyValue array
     405             :    * @param n_qpoints The number of values needed to store (equals the the number of quadrature
     406             :    * points per mesh element)
     407             :    */
     408       62714 :   void resizeItems(const std::size_t n_qpoints, const WriteKey)
     409             :   {
     410      132838 :     for (const auto i : index_range(*this))
     411       70124 :       if (auto value = queryValue(i))
     412       69063 :         value->resize(n_qpoints);
     413       62714 :   }
     414             : 
     415      207403 :   void resize(const std::size_t size, const WriteKey)
     416             :   {
     417      207403 :     UniqueStorage<PropertyValue>::resize(size);
     418      207403 :   }
     419             : 
     420      222764 :   void setPointer(const std::size_t i, std::unique_ptr<PropertyValue> && ptr, const WriteKey)
     421             :   {
     422      222764 :     return UniqueStorage<PropertyValue>::setPointer(i, std::move(ptr));
     423             :   }
     424             : };
     425             : 
     426             : template <typename T, bool is_ad>
     427             : struct GenericMaterialPropertyStruct
     428             : {
     429             :   typedef MaterialProperty<T> type;
     430             : };
     431             : 
     432             : template <typename T>
     433             : struct GenericMaterialPropertyStruct<T, true>
     434             : {
     435             :   typedef ADMaterialProperty<T> type;
     436             : };
     437             : 
     438             : template <typename T, bool is_ad>
     439             : using GenericMaterialProperty = typename GenericMaterialPropertyStruct<T, is_ad>::type;
     440             : 
     441             : /**
     442             :  * Base class to facilitate storage using unique pointers
     443             :  */
     444             : class GenericOptionalMaterialPropertyBase
     445             : {
     446             : public:
     447        1326 :   virtual ~GenericOptionalMaterialPropertyBase() {}
     448             : };
     449             : 
     450             : template <class M, typename T, bool is_ad>
     451             : class OptionalMaterialPropertyProxy;
     452             : 
     453             : /**
     454             :  * Wrapper around a material property pointer. Copying this wrapper is disabled
     455             :  * to enforce capture via reference. Used by the optional material property
     456             :  * API, which requires late binding updates of the stored pointer.
     457             :  */
     458             : template <typename T, bool is_ad>
     459             : class GenericOptionalMaterialProperty : public GenericOptionalMaterialPropertyBase
     460             : {
     461             :   typedef GenericMaterialProperty<T, is_ad> P;
     462             : 
     463             : public:
     464             :   GenericOptionalMaterialProperty(const P * pointer) : _pointer(pointer) {}
     465             : 
     466             :   /// no copy construction is permitted
     467             :   GenericOptionalMaterialProperty(const GenericOptionalMaterialProperty<T, is_ad> &) = delete;
     468             :   /// no copy assignment is permitted
     469             :   GenericOptionalMaterialProperty &
     470             :   operator=(const GenericOptionalMaterialProperty<T, is_ad> &) = delete;
     471             : 
     472             :   /// pass through operator[] to provide a similar API as MaterialProperty
     473       68420 :   const Moose::GenericType<T, is_ad> & operator[](const unsigned int i) const
     474             :   {
     475             :     // check if the optional property is valid in debug mode
     476             :     mooseAssert(
     477             :         _pointer,
     478             :         "Attempting to access an optional material property that was not provided by any material "
     479             :         "class. Make sure to check optional material properties before using them.");
     480       68420 :     return (*_pointer)[i];
     481             :   }
     482             : 
     483             :   /// pass through size calls
     484             :   unsigned int size() const { return (*_pointer).size(); }
     485             : 
     486             :   /// implicit cast to bool to check the if the material property exists
     487      142898 :   operator bool() const { return _pointer; }
     488             : 
     489             :   /// get a pointer to the underlying property (only do this in initialSetup or later)
     490             :   const P * get() const { return _pointer; }
     491             : 
     492             : private:
     493             :   /// the default constructor is only called from the friend class
     494        1566 :   GenericOptionalMaterialProperty() : _pointer(nullptr) {}
     495             : 
     496             :   /// setting the pointer is only permitted through the optional material proxy system
     497         672 :   void set(const P * pointer) { _pointer = pointer; }
     498             :   const P * _pointer;
     499             : 
     500             :   friend class OptionalMaterialPropertyProxy<Material, T, is_ad>;
     501             :   friend class OptionalMaterialPropertyProxy<MaterialPropertyInterface, T, is_ad>;
     502             : };
     503             : 
     504             : void dataStore(std::ostream & stream, PropertyValue & p, void * context);
     505             : void dataLoad(std::istream & stream, PropertyValue & p, void * context);
     506             : 
     507             : void dataStore(std::ostream & stream, MaterialProperties & v, void * context);
     508             : void dataLoad(std::istream & stream, MaterialProperties & v, void * context);
     509             : 
     510             : template <typename T>
     511             : using OptionalMaterialProperty = GenericOptionalMaterialProperty<T, false>;
     512             : template <typename T>
     513             : using OptionalADMaterialProperty = GenericOptionalMaterialProperty<T, true>;

Generated by: LCOV version 1.14