LCOV - code coverage report
Current view: top level - include/materials - MaterialProperty.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 68 78 87.2 %
Date: 2025-07-17 01:28:37 Functions: 187 487 38.4 %
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      590825 :   PropertyValue(const id_type id) : _id(id) {}
      44             : 
      45      583936 :   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      527492 :   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      590825 :   MaterialPropertyBase(const PropertyValue::id_type id) : PropertyValue(id) {}
     115             : 
     116    49894932 :   bool isAD() const override final { return is_ad; }
     117             : 
     118             :   /**
     119             :    * @returns a read-only reference to the parameter value.
     120             :    */
     121        4239 :   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      563665 :   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   131314911 :   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  1530724946 :   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      796032 : rawValueEqualityHelper(T1 & out, const T2 & in)
     217             : {
     218      796032 :   out = MetaPhysicL::raw_value(in);
     219      796032 : }
     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          16 : MaterialPropertyBase<T, is_ad>::type() const
     243             : {
     244          16 :   static const std::string type_name = MooseUtils::prettyCppType<T>();
     245          16 :   return type_name;
     246             : }
     247             : 
     248             : template <typename T, bool is_ad>
     249             : inline void
     250     1410138 : MaterialPropertyBase<T, is_ad>::resize(const std::size_t size)
     251             : {
     252     1410138 :   _value.template resize</*value_initalize=*/true>(size);
     253     1410138 : }
     254             : 
     255             : template <typename T, bool is_ad>
     256             : inline void
     257    16760981 : 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    16760981 :   if (rhs.isAD() == is_ad)
     263    16760981 :     _value[to_qp] =
     264    16760981 :         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    16760981 : }
     270             : 
     271             : template <typename T, bool is_ad>
     272             : inline void
     273       89829 : MaterialPropertyBase<T, is_ad>::store(std::ostream & stream)
     274             : {
     275      433015 :   for (const auto i : index_range(_value))
     276      343186 :     storeHelper(stream, _value[i], nullptr);
     277       89829 : }
     278             : 
     279             : template <typename T, bool is_ad>
     280             : inline void
     281       58764 : MaterialPropertyBase<T, is_ad>::load(std::istream & stream)
     282             : {
     283      316276 :   for (const auto i : index_range(_value))
     284      257512 :     loadHelper(stream, _value[i], nullptr);
     285       58764 : }
     286             : 
     287             : template <typename T, bool is_ad>
     288             : inline void
     289    33133935 : 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    33133935 :   if (rhs.isAD() == is_ad)
     296             :   {
     297             :     mooseAssert(dynamic_cast<decltype(this)>(&rhs), "Expected same type is not the same");
     298    32934719 :     this->_value.swap(libMesh::cast_ptr<decltype(this)>(&rhs)->_value);
     299    32934719 :     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      199216 :   auto * different_type_prop = dynamic_cast<MaterialPropertyBase<T, !is_ad> *>(&rhs);
     315             :   mooseAssert(different_type_prop,
     316             :               "Wrong material property type T in MaterialPropertyBase<T, is_ad>::swap");
     317             : 
     318      199216 :   this->resize(different_type_prop->size());
     319      995248 :   for (const auto qp : make_range(this->size()))
     320      796032 :     moose::internal::rawValueEqualityHelper(this->_value[qp], (*different_type_prop)[qp]);
     321             : }
     322             : 
     323             : template <typename T, bool is_ad>
     324             : inline const std::type_info &
     325           0 : MaterialPropertyBase<T, is_ad>::typeID() const
     326             : {
     327             :   static const auto & info = typeid(T);
     328           0 :   return info;
     329             : }
     330             : 
     331             : template <typename T, bool is_ad>
     332             : std::unique_ptr<PropertyValue>
     333      522364 : MaterialPropertyBase<T, is_ad>::clone(const std::size_t size) const
     334             : {
     335      522364 :   auto prop = std::make_unique<MaterialProperty<T>>(this->id());
     336      522364 :   if (size)
     337      522364 :     prop->resize(size);
     338     1044728 :   return prop;
     339      522364 : }
     340             : 
     341             : template <typename T>
     342             : class MaterialProperty : public MaterialPropertyBase<T, false>
     343             : {
     344             : public:
     345      575884 :   MaterialProperty(const PropertyValue::id_type id = PropertyValue::invalid_property_id)
     346      575884 :     : MaterialPropertyBase<T, false>(id)
     347             :   {
     348      575884 :   }
     349             : 
     350             : private:
     351             :   /// private copy constructor to avoid shallow copying of material properties
     352             :   MaterialProperty(const MaterialProperty<T> & /*src*/)
     353             :   {
     354             :     mooseError("Material properties must be assigned to references (missing '&')");
     355             :   }
     356             : 
     357             :   /// private assignment operator to avoid shallow copying of material properties
     358             :   MaterialProperty<T> & operator=(const MaterialProperty<T> & /*rhs*/)
     359             :   {
     360             :     mooseError("Material properties must be assigned to references (missing '&')");
     361             :   }
     362             : };
     363             : 
     364             : template <typename T>
     365             : class ADMaterialProperty : public MaterialPropertyBase<T, true>
     366             : {
     367             : public:
     368       14941 :   ADMaterialProperty(const PropertyValue::id_type id = PropertyValue::invalid_property_id)
     369       14941 :     : MaterialPropertyBase<T, true>(id)
     370             :   {
     371       14941 :   }
     372             : 
     373             :   using typename MaterialPropertyBase<T, true>::value_type;
     374             : 
     375             : private:
     376             :   /// private copy constructor to avoid shallow copying of material properties
     377             :   ADMaterialProperty(const ADMaterialProperty<T> & /*src*/)
     378             :   {
     379             :     mooseError("Material properties must be assigned to references (missing '&')");
     380             :   }
     381             : 
     382             :   /// private assignment operator to avoid shallow copying of material properties
     383             :   ADMaterialProperty<T> & operator=(const ADMaterialProperty<T> & /*rhs*/)
     384             :   {
     385             :     mooseError("Material properties must be assigned to references (missing '&')");
     386             :   }
     387             : };
     388             : 
     389             : class MaterialData;
     390             : class MaterialPropertyStorage;
     391             : 
     392             : class MaterialProperties : public UniqueStorage<PropertyValue>
     393             : {
     394             : public:
     395             :   class WriteKey
     396             :   {
     397             :     friend class MaterialData;
     398             :     friend class MaterialPropertyStorage;
     399             :     friend void dataLoad(std::istream &, MaterialPropertyStorage &, void *);
     400             : 
     401     1026743 :     WriteKey() {}
     402             :     WriteKey(const WriteKey &) {}
     403             :   };
     404             : 
     405             :   /**
     406             :    * Resize items in this array, i.e. the number of values needed in PropertyValue array
     407             :    * @param n_qpoints The number of values needed to store (equals the the number of quadrature
     408             :    * points per mesh element)
     409             :    */
     410       65041 :   void resizeItems(const std::size_t n_qpoints, const WriteKey)
     411             :   {
     412      136315 :     for (const auto i : index_range(*this))
     413       71274 :       if (auto value = queryValue(i))
     414       70097 :         value->resize(n_qpoints);
     415       65041 :   }
     416             : 
     417      383223 :   void resize(const std::size_t size, const WriteKey)
     418             :   {
     419      383223 :     UniqueStorage<PropertyValue>::resize(size);
     420      383223 :   }
     421             : 
     422      578479 :   void setPointer(const std::size_t i, std::unique_ptr<PropertyValue> && ptr, const WriteKey)
     423             :   {
     424      578479 :     return UniqueStorage<PropertyValue>::setPointer(i, std::move(ptr));
     425             :   }
     426             : };
     427             : 
     428             : template <typename T, bool is_ad>
     429             : struct GenericMaterialPropertyStruct
     430             : {
     431             :   typedef MaterialProperty<T> type;
     432             : };
     433             : 
     434             : template <typename T>
     435             : struct GenericMaterialPropertyStruct<T, true>
     436             : {
     437             :   typedef ADMaterialProperty<T> type;
     438             : };
     439             : 
     440             : template <typename T, bool is_ad>
     441             : using GenericMaterialProperty = typename GenericMaterialPropertyStruct<T, is_ad>::type;
     442             : 
     443             : /**
     444             :  * Base class to facilitate storage using unique pointers
     445             :  */
     446             : class GenericOptionalMaterialPropertyBase
     447             : {
     448             : public:
     449        1326 :   virtual ~GenericOptionalMaterialPropertyBase() {}
     450             : };
     451             : 
     452             : template <class M, typename T, bool is_ad>
     453             : class OptionalMaterialPropertyProxy;
     454             : 
     455             : /**
     456             :  * Wrapper around a material property pointer. Copying this wrapper is disabled
     457             :  * to enforce capture via reference. Used by the optional material property
     458             :  * API, which requires late binding updates of the stored pointer.
     459             :  */
     460             : template <typename T, bool is_ad>
     461             : class GenericOptionalMaterialProperty : public GenericOptionalMaterialPropertyBase
     462             : {
     463             :   typedef GenericMaterialProperty<T, is_ad> P;
     464             : 
     465             : public:
     466             :   GenericOptionalMaterialProperty(const P * pointer) : _pointer(pointer) {}
     467             : 
     468             :   /// no copy construction is permitted
     469             :   GenericOptionalMaterialProperty(const GenericOptionalMaterialProperty<T, is_ad> &) = delete;
     470             :   /// no copy assignment is permitted
     471             :   GenericOptionalMaterialProperty &
     472             :   operator=(const GenericOptionalMaterialProperty<T, is_ad> &) = delete;
     473             : 
     474             :   /// pass through operator[] to provide a similar API as MaterialProperty
     475       67840 :   const Moose::GenericType<T, is_ad> & operator[](const unsigned int i) const
     476             :   {
     477             :     // check if the optional property is valid in debug mode
     478             :     mooseAssert(
     479             :         _pointer,
     480             :         "Attempting to access an optional material property that was not provided by any material "
     481             :         "class. Make sure to check optional material properties before using them.");
     482       67840 :     return (*_pointer)[i];
     483             :   }
     484             : 
     485             :   /// pass through size calls
     486             :   unsigned int size() const { return (*_pointer).size(); }
     487             : 
     488             :   /// implicit cast to bool to check the if the material property exists
     489      141924 :   operator bool() const { return _pointer; }
     490             : 
     491             :   /// get a pointer to the underlying property (only do this in initialSetup or later)
     492             :   const P * get() const { return _pointer; }
     493             : 
     494             : private:
     495             :   /// the default constructor is only called from the friend class
     496        1530 :   GenericOptionalMaterialProperty() : _pointer(nullptr) {}
     497             : 
     498             :   /// setting the pointer is only permitted through the optional material proxy system
     499         638 :   void set(const P * pointer) { _pointer = pointer; }
     500             :   const P * _pointer;
     501             : 
     502             :   friend class OptionalMaterialPropertyProxy<Material, T, is_ad>;
     503             :   friend class OptionalMaterialPropertyProxy<MaterialPropertyInterface, T, is_ad>;
     504             : };
     505             : 
     506             : void dataStore(std::ostream & stream, PropertyValue & p, void * context);
     507             : void dataLoad(std::istream & stream, PropertyValue & p, void * context);
     508             : 
     509             : void dataStore(std::ostream & stream, MaterialProperties & v, void * context);
     510             : void dataLoad(std::istream & stream, MaterialProperties & v, void * context);
     511             : 
     512             : template <typename T>
     513             : using OptionalMaterialProperty = GenericOptionalMaterialProperty<T, false>;
     514             : template <typename T>
     515             : using OptionalADMaterialProperty = GenericOptionalMaterialProperty<T, true>;

Generated by: LCOV version 1.14