LCOV - code coverage report
Current view: top level - include/materials - MaterialBase.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 88 95 92.6 %
Date: 2025-07-17 01:28:37 Functions: 83 95 87.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             : // MOOOSE includes
      13             : #include "MooseObject.h"
      14             : #include "BlockRestrictable.h"
      15             : #include "BoundaryRestrictable.h"
      16             : #include "SetupInterface.h"
      17             : #include "MooseVariableDependencyInterface.h"
      18             : #include "ScalarCoupleable.h"
      19             : #include "FunctionInterface.h"
      20             : #include "DistributionInterface.h"
      21             : #include "UserObjectInterface.h"
      22             : #include "TransientInterface.h"
      23             : #include "PostprocessorInterface.h"
      24             : #include "VectorPostprocessorInterface.h"
      25             : #include "DependencyResolverInterface.h"
      26             : #include "Restartable.h"
      27             : #include "MeshChangedInterface.h"
      28             : #include "OutputInterface.h"
      29             : #include "RandomInterface.h"
      30             : #include "ElementIDInterface.h"
      31             : #include "MaterialProperty.h"
      32             : #include "MaterialData.h"
      33             : #include "MathUtils.h"
      34             : #include "Assembly.h"
      35             : #include "GeometricSearchInterface.h"
      36             : #include "ADFunctorInterface.h"
      37             : #include "SolutionInvalidInterface.h"
      38             : #include "MaterialPropertyInterface.h"
      39             : 
      40             : #define usingMaterialBaseMembers                                                                   \
      41             :   usingMooseObjectMembers;                                                                         \
      42             :   usingTransientInterfaceMembers;                                                                  \
      43             :   using MaterialBase::_subproblem;                                                                 \
      44             :   using MaterialBase::_fe_problem;                                                                 \
      45             :   using MaterialBase::_tid;                                                                        \
      46             :   using MaterialBase::_assembly;                                                                   \
      47             :   using MaterialBase::_qp;                                                                         \
      48             :   using MaterialBase::_coord;                                                                      \
      49             :   using MaterialBase::_normals;                                                                    \
      50             :   using MaterialBase::_mesh
      51             : 
      52             : // forward declarations
      53             : class MaterialBase;
      54             : class MooseMesh;
      55             : class SubProblem;
      56             : class FaceInfo;
      57             : class FEProblemBase;
      58             : 
      59             : /**
      60             :  * MaterialBases compute MaterialProperties.
      61             :  */
      62             : class MaterialBase : public MooseObject,
      63             :                      public BlockRestrictable,
      64             :                      public BoundaryRestrictable,
      65             :                      public SetupInterface,
      66             :                      public MooseVariableDependencyInterface,
      67             :                      public ScalarCoupleable,
      68             :                      public FunctionInterface,
      69             :                      public DistributionInterface,
      70             :                      public UserObjectInterface,
      71             :                      public TransientInterface,
      72             :                      public PostprocessorInterface,
      73             :                      public VectorPostprocessorInterface,
      74             :                      public DependencyResolverInterface,
      75             :                      public Restartable,
      76             :                      public MeshChangedInterface,
      77             :                      public OutputInterface,
      78             :                      public RandomInterface,
      79             :                      public ElementIDInterface,
      80             :                      protected GeometricSearchInterface,
      81             :                      protected ADFunctorInterface,
      82             :                      protected SolutionInvalidInterface
      83             : {
      84             : public:
      85             :   static InputParameters validParams();
      86             : 
      87             :   MaterialBase(const InputParameters & parameters);
      88             : 
      89             :   /**
      90             :    * Initialize stateful properties (if material has some)
      91             :    *
      92             :    * This is _only_ called if this material has properties that are
      93             :    * requested as stateful
      94             :    */
      95             :   virtual void initStatefulProperties(unsigned int n_points);
      96             : 
      97           0 :   virtual bool isInterfaceMaterial() { return false; };
      98             : 
      99             :   /**
     100             :    * Performs the quadrature point loop, calling computeQpProperties
     101             :    */
     102             :   virtual void computeProperties() = 0;
     103             : 
     104             :   /**
     105             :    * Resets the properties at each quadrature point (see resetQpProperties), only called if 'compute
     106             :    * = false'.
     107             :    *
     108             :    * This method is called internally by MOOSE, you probably don't want to mess with this.
     109             :    */
     110             :   virtual void resetProperties();
     111             : 
     112             :   /**
     113             :    * A method for (re)computing the properties of a MaterialBase.
     114             :    *
     115             :    * This is intended to be called from other objects, by first calling
     116             :    * MaterialPropertyInterface::getMaterial and then calling this method on the MaterialBase object
     117             :    * returned.
     118             :    */
     119             :   virtual void computePropertiesAtQp(unsigned int qp);
     120             : 
     121             :   ///@{
     122             :   /**
     123             :    * Declare the property named "name"
     124             :    */
     125             :   template <typename T>
     126       38356 :   MaterialProperty<T> & declarePropertyByName(const std::string & prop_name)
     127             :   {
     128       38356 :     return declareGenericPropertyByName<T, false>(prop_name);
     129             :   }
     130             :   template <typename T>
     131             :   MaterialProperty<T> & declareProperty(const std::string & name);
     132             :   template <typename T>
     133       10670 :   ADMaterialProperty<T> & declareADPropertyByName(const std::string & prop_name)
     134             :   {
     135       10670 :     return declareGenericPropertyByName<T, true>(prop_name);
     136             :   }
     137             :   template <typename T>
     138             :   ADMaterialProperty<T> & declareADProperty(const std::string & name);
     139             : 
     140             :   template <typename T, bool is_ad>
     141       31466 :   auto & declareGenericProperty(const std::string & prop_name)
     142             :   {
     143             :     if constexpr (is_ad)
     144        9103 :       return declareADProperty<T>(prop_name);
     145             :     else
     146       22363 :       return declareProperty<T>(prop_name);
     147             :   }
     148             :   template <typename T, bool is_ad>
     149             :   GenericMaterialProperty<T, is_ad> & declareGenericPropertyByName(const std::string & prop_name);
     150             :   ///@}
     151             : 
     152             :   /**
     153             :    * Return a material property that is initialized to zero by default and does
     154             :    * not need to (but can) be declared by another material.
     155             :    */
     156             :   template <typename T, bool is_ad>
     157             :   const GenericMaterialProperty<T, is_ad> &
     158             :   getGenericZeroMaterialProperty(const std::string & name);
     159             :   template <typename T, bool is_ad>
     160             :   const GenericMaterialProperty<T, is_ad> &
     161             :   getGenericZeroMaterialPropertyByName(const std::string & prop_name);
     162             : 
     163             :   /**
     164             :    * Return a constant zero anonymous material property
     165             :    */
     166             :   template <typename T, bool is_ad>
     167             :   const GenericMaterialProperty<T, is_ad> & getGenericZeroMaterialProperty();
     168             : 
     169             :   /// for backwards compatibility
     170             :   template <typename T, typename... Ts>
     171             :   const MaterialProperty<T> & getZeroMaterialProperty(Ts... args)
     172             :   {
     173             :     return getGenericZeroMaterialProperty<T, false>(args...);
     174             :   }
     175             : 
     176             :   /// for backwards compatibility
     177             :   template <typename T, typename... Ts>
     178             :   const MaterialProperty<T> & getZeroMaterialPropertyByName(Ts... args)
     179             :   {
     180             :     return getGenericZeroMaterialPropertyByName<T, false>(args...);
     181             :   }
     182             : 
     183             :   /**
     184             :    * Return a set of properties accessed with getMaterialProperty
     185             :    * @return A reference to the set of properties with calls to getMaterialProperty
     186             :    */
     187       37403 :   virtual const std::set<std::string> & getRequestedItems() override { return _requested_props; }
     188             : 
     189             :   /**
     190             :    * Return a set of properties accessed with declareProperty
     191             :    * @return A reference to the set of properties with calls to declareProperty
     192             :    */
     193      216488 :   virtual const std::set<std::string> & getSuppliedItems() override { return _supplied_props; }
     194             : 
     195             :   /**
     196             :    * Get the prop ids corresponding to \p declareProperty
     197             :    * @return A reference to the set of properties with calls to \p declareProperty
     198             :    */
     199      630802 :   const std::set<unsigned int> & getSuppliedPropIDs() { return _supplied_prop_ids; }
     200             : 
     201             :   void checkStatefulSanity() const;
     202             : 
     203             :   /**
     204             :    * Get the list of output objects that this class is restricted
     205             :    * @return A vector of OutputNames
     206             :    */
     207             :   std::set<OutputName> getOutputs();
     208             : 
     209             :   /**
     210             :    * Returns true of the MaterialData type is not associated with volume data
     211             :    */
     212             :   virtual bool isBoundaryMaterial() const = 0;
     213             : 
     214             :   /**
     215             :    * Subdomain setup evaluating material properties when required
     216             :    */
     217             :   virtual void subdomainSetup() override;
     218             : 
     219             :   /**
     220             :    * Retrieve the set of material properties that _this_ object depends on.
     221             :    *
     222             :    * @return The IDs corresponding to the material properties that
     223             :    * MUST be reinited before evaluating this object
     224             :    */
     225             :   virtual const std::unordered_set<unsigned int> & getMatPropDependencies() const = 0;
     226             : 
     227             :   /**
     228             :    * @return Whether this material has stateful properties
     229             :    */
     230         636 :   bool hasStatefulProperties() const { return _has_stateful_property; }
     231             : 
     232             :   /**
     233             :    * Whether this material supports ghosted computations. This is important for finite volume
     234             :    * calculations in which variables have defined values on ghost cells/elements and for which these
     235             :    * ghost values may need to flow through material calculations to be eventually consumed by FV
     236             :    * flux kernels or boundary conditions
     237             :    */
     238           0 :   virtual bool ghostable() const { return false; }
     239             : 
     240       19392 :   void setFaceInfo(const FaceInfo & fi) { _face_info = &fi; }
     241             : 
     242             :   /**
     243             :    * Build the materials required by a set of consumer objects
     244             :    */
     245             :   template <typename Consumers>
     246             :   static std::deque<MaterialBase *>
     247             :   buildRequiredMaterials(const Consumers & mat_consumers,
     248             :                          const std::vector<std::shared_ptr<MaterialBase>> & mats,
     249             :                          const bool allow_stateful);
     250             : 
     251             :   /**
     252             :    * Set active properties of this material
     253             :    * Note: This function is called by FEProblemBase::setActiveMaterialProperties in an element loop
     254             :    *       typically when switching subdomains.
     255             :    */
     256             :   void setActiveProperties(const std::unordered_set<unsigned int> & needed_props);
     257             : 
     258             :   /**
     259             :    * @return Whether or not this material should forcefully call
     260             :    * initStatefulProperties() even if it doesn't produce properties
     261             :    * that needs state.
     262             :    *
     263             :    * Please don't set this to true :(
     264             :    */
     265      221062 :   bool forceStatefulInit() const { return _force_stateful_init; }
     266             : 
     267             : protected:
     268             :   /**
     269             :    * Users must override this method.
     270             :    */
     271             :   virtual void computeQpProperties();
     272             : 
     273             :   /**
     274             :    * Resets the properties prior to calculation of traditional materials (only if 'compute =
     275             :    * false').
     276             :    *
     277             :    * This method must be overridden in your class. This is called just prior to the re-calculation
     278             :    * of
     279             :    * traditional material properties to ensure that the properties are in a proper state for
     280             :    * calculation.
     281             :    */
     282             :   virtual void resetQpProperties();
     283             : 
     284             :   /**
     285             :    * Initialize stateful properties at quadrature points.  Note when using this function you only
     286             :    * need to address
     287             :    * the "current" material properties not the old ones directly, i.e. if you have a property named
     288             :    * "_diffusivity"
     289             :    * and an older property named "_diffusivity_old".  You only need to initialize diffusivity.
     290             :    * MOOSE will use
     291             :    * copy that initial value to the old and older values as necessary.
     292             :    *
     293             :    * This is _only_ called if this material has properties that are
     294             :    * requested as stateful
     295             :    */
     296             :   virtual void initQpStatefulProperties();
     297             : 
     298             :   virtual const MaterialData & materialData() const = 0;
     299             :   virtual MaterialData & materialData() = 0;
     300             : 
     301           0 :   virtual const FEProblemBase & miProblem() const { return _fe_problem; }
     302           0 :   virtual FEProblemBase & miProblem() { return _fe_problem; }
     303             : 
     304             :   virtual const QBase & qRule() const = 0;
     305             : 
     306             :   /**
     307             :    * Check whether a material property is active
     308             :    */
     309        5128 :   bool isPropertyActive(const unsigned int prop_id) const
     310             :   {
     311        5128 :     return _active_prop_ids.count(prop_id) > 0;
     312             :   }
     313             : 
     314             :   SubProblem & _subproblem;
     315             : 
     316             :   FEProblemBase & _fe_problem;
     317             :   THREAD_ID _tid;
     318             :   Assembly & _assembly;
     319             : 
     320             :   unsigned int _qp;
     321             : 
     322             :   const MooseArray<Real> & _coord;
     323             :   /// normals at quadrature points (valid only in boundary materials)
     324             :   const MooseArray<Point> & _normals;
     325             : 
     326             :   MooseMesh & _mesh;
     327             : 
     328             :   /// Coordinate system
     329             :   const Moose::CoordinateSystemType & _coord_sys;
     330             : 
     331             :   /// Set of properties accessed via get method
     332             :   std::set<std::string> _requested_props;
     333             : 
     334             :   /// Set of properties declared
     335             :   std::set<std::string> _supplied_props;
     336             : 
     337             :   /// The ids of the supplied properties, i.e. the indices where they
     338             :   /// are stored in the _material_data->props().  Note: these ids ARE
     339             :   /// NOT IN THE SAME ORDER AS THE _supplied_props set, which is
     340             :   /// ordered alphabetically by name.  The intention of this container
     341             :   /// is to allow rapid copying of MaterialProperty values in
     342             :   /// MaterialBase::computeProperties() without looking up the ids from
     343             :   /// the name strings each time.
     344             :   std::set<unsigned int> _supplied_prop_ids;
     345             : 
     346             :   /// The ids of the current active supplied properties
     347             :   std::unordered_set<unsigned int> _active_prop_ids;
     348             : 
     349             :   /// If False MOOSE does not compute this property
     350             :   const bool _compute;
     351             : 
     352             :   enum QP_Data_Type
     353             :   {
     354             :     CURR,
     355             :     PREV
     356             :   };
     357             : 
     358             :   /// The minimum states requested (0 = current, 1 = old, 2 = older)
     359             :   /// This is sparse and is used to keep track of whether or not stateful
     360             :   /// properties are requested without state 0 being requested
     361             :   std::unordered_map<unsigned int, unsigned int> _props_to_min_states;
     362             : 
     363             :   /// Small helper function to call store{Subdomain,Boundary}MatPropName
     364             :   void registerPropName(const std::string & prop_name, bool is_get, const unsigned int state);
     365             : 
     366             :   /// Check and throw an error if the execution has progressed past the construction stage
     367             :   void checkExecutionStage();
     368             : 
     369             :   std::vector<unsigned int> _displacements;
     370             : 
     371             :   bool _has_stateful_property;
     372             : 
     373             :   bool _overrides_init_stateful_props = true;
     374             : 
     375             :   const FaceInfo * _face_info = nullptr;
     376             : 
     377             : private:
     378             :   /**
     379             :    * Helper method for adding a material property name to the material property requested set
     380             :    */
     381             :   void markMatPropRequested(const std::string & name);
     382             : 
     383             :   /**
     384             :    * Adds to a map based on block ids of material properties for which a zero
     385             :    * value can be returned. These properties are optional and will not trigger a
     386             :    * missing material property error.
     387             :    *
     388             :    * @param block_id The block id for the MaterialProperty
     389             :    * @param name The name of the property
     390             :    */
     391             :   void storeSubdomainZeroMatProp(SubdomainID block_id, const MaterialPropertyName & name);
     392             : 
     393             :   /**
     394             :    * Adds to a map based on boundary ids of material properties for which a zero
     395             :    * value can be returned. These properties are optional and will not trigger a
     396             :    * missing material property error.
     397             :    *
     398             :    * @param boundary_id The block id for the MaterialProperty
     399             :    * @param name The name of the property
     400             :    */
     401             :   void storeBoundaryZeroMatProp(BoundaryID boundary_id, const MaterialPropertyName & name);
     402             : 
     403             :   /**
     404             :    * @return The maximum number of quadrature points in use on any element in this problem.
     405             :    */
     406             :   unsigned int getMaxQps() const;
     407             : 
     408             :   /// Suffix to append to the name of the material property/ies when declaring it/them
     409             :   const MaterialPropertyName _declare_suffix;
     410             : 
     411             :   /// Whether or not to force stateful init; see forceStatefulInit()
     412             :   const bool _force_stateful_init;
     413             : 
     414             :   /// To let it access the declaration suffix
     415             :   friend class FunctorMaterial;
     416             : };
     417             : 
     418             : template <typename T>
     419             : MaterialProperty<T> &
     420       38356 : MaterialBase::declareProperty(const std::string & name)
     421             : {
     422             :   // Check if the supplied parameter is a valid input parameter key
     423       38356 :   std::string prop_name = name;
     424       38356 :   if (_pars.have_parameter<MaterialPropertyName>(name))
     425         594 :     prop_name = _pars.get<MaterialPropertyName>(name);
     426             : 
     427       76712 :   return declarePropertyByName<T>(prop_name);
     428       38356 : }
     429             : 
     430             : template <typename T, bool is_ad>
     431             : GenericMaterialProperty<T, is_ad> &
     432       58673 : MaterialBase::declareGenericPropertyByName(const std::string & prop_name)
     433             : {
     434      117541 :   const auto prop_name_modified =
     435       58673 :       _declare_suffix.empty()
     436       58673 :           ? prop_name
     437       59258 :           : MooseUtils::join(std::vector<std::string>({prop_name, _declare_suffix}), "_");
     438             : 
     439             :   // Call this before so that the ID is valid
     440       58673 :   auto & prop = materialData().declareProperty<T, is_ad>(prop_name_modified, *this);
     441             : 
     442       58673 :   registerPropName(prop_name_modified, false, 0);
     443       58673 :   return prop;
     444       58868 : }
     445             : 
     446             : template <typename T, bool is_ad>
     447             : const GenericMaterialProperty<T, is_ad> &
     448        4023 : MaterialBase::getGenericZeroMaterialProperty(const std::string & name)
     449             : {
     450             :   // Check if the supplied parameter is a valid input parameter key
     451        4023 :   std::string prop_name = name;
     452        4023 :   if (_pars.have_parameter<MaterialPropertyName>(name))
     453           0 :     prop_name = _pars.get<MaterialPropertyName>(name);
     454             : 
     455        8046 :   return getGenericZeroMaterialPropertyByName<T, is_ad>(prop_name);
     456        4023 : }
     457             : 
     458             : template <typename T, bool is_ad>
     459             : const GenericMaterialProperty<T, is_ad> &
     460        8799 : MaterialBase::getGenericZeroMaterialPropertyByName(const std::string & prop_name)
     461             : {
     462        8799 :   checkExecutionStage();
     463        8799 :   auto & preload_with_zero = materialData().getProperty<T, is_ad>(prop_name, 0, *this);
     464             : 
     465        8799 :   _requested_props.insert(prop_name);
     466        8799 :   registerPropName(prop_name, true, 0);
     467        8799 :   markMatPropRequested(prop_name);
     468             : 
     469             :   // Register this material on these blocks and boundaries as a zero property with relaxed
     470             :   // consistency checking
     471       17598 :   for (std::set<SubdomainID>::const_iterator it = blockIDs().begin(); it != blockIDs().end(); ++it)
     472        8799 :     storeSubdomainZeroMatProp(*it, prop_name);
     473       17598 :   for (std::set<BoundaryID>::const_iterator it = boundaryIDs().begin(); it != boundaryIDs().end();
     474        8799 :        ++it)
     475        8799 :     storeBoundaryZeroMatProp(*it, prop_name);
     476             : 
     477             :   // set values for all qpoints to zero
     478             :   // (in multiapp scenarios getMaxQps can return different values in each app; we need the max)
     479        8799 :   unsigned int nqp = getMaxQps();
     480        8799 :   if (nqp > preload_with_zero.size())
     481        6933 :     preload_with_zero.resize(nqp);
     482       48753 :   for (unsigned int qp = 0; qp < nqp; ++qp)
     483       39954 :     MathUtils::mooseSetToZero(preload_with_zero[qp]);
     484             : 
     485        8799 :   return preload_with_zero;
     486             : }
     487             : 
     488             : template <typename T, bool is_ad>
     489             : const GenericMaterialProperty<T, is_ad> &
     490         576 : MaterialBase::getGenericZeroMaterialProperty()
     491             : {
     492             :   // static zero property storage
     493         576 :   static GenericMaterialProperty<T, is_ad> zero(MaterialPropertyInterface::zero_property_id);
     494             : 
     495             :   // resize to accomodate maximum number of qpoints
     496             :   // (in multiapp scenarios getMaxQps can return different values in each app; we need the max)
     497         576 :   unsigned int nqp = getMaxQps();
     498         576 :   if (nqp > zero.size())
     499          28 :     zero.resize(nqp);
     500             : 
     501             :   // set values for all qpoints to zero
     502        2880 :   for (unsigned int qp = 0; qp < nqp; ++qp)
     503        2304 :     MathUtils::mooseSetToZero(zero[qp]);
     504             : 
     505         576 :   return zero;
     506             : }
     507             : 
     508             : template <typename T>
     509             : ADMaterialProperty<T> &
     510       10670 : MaterialBase::declareADProperty(const std::string & name)
     511             : {
     512             :   // Check if the supplied parameter is a valid input parameter key
     513       10670 :   std::string prop_name = name;
     514       10670 :   if (_pars.have_parameter<MaterialPropertyName>(name))
     515         403 :     prop_name = _pars.get<MaterialPropertyName>(name);
     516             : 
     517       21340 :   return declareADPropertyByName<T>(prop_name);
     518       10670 : }
     519             : 
     520             : template <typename Consumers>
     521             : std::deque<MaterialBase *>
     522        3164 : MaterialBase::buildRequiredMaterials(const Consumers & mat_consumers,
     523             :                                      const std::vector<std::shared_ptr<MaterialBase>> & mats,
     524             :                                      const bool allow_stateful)
     525             : {
     526        3164 :   std::deque<MaterialBase *> required_mats;
     527             : 
     528        3164 :   std::unordered_set<unsigned int> needed_mat_props;
     529        6808 :   for (const auto & consumer : mat_consumers)
     530             :   {
     531        3644 :     const auto & mp_deps = consumer->getMatPropDependencies();
     532        3644 :     needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
     533             :   }
     534             : 
     535             :   // A predicate of calling this function is that these materials come in already sorted by
     536             :   // dependency with the front of the container having no other material dependencies and following
     537             :   // materials potentially depending on the ones in front of them. So we can start at the back and
     538             :   // iterate forward checking whether the current material supplies anything that is needed, and if
     539             :   // not we discard it
     540       16380 :   for (auto it = mats.rbegin(); it != mats.rend(); ++it)
     541             :   {
     542       13216 :     auto * const mat = it->get();
     543       13216 :     bool supplies_needed = false;
     544             : 
     545       13216 :     const auto & supplied_props = mat->getSuppliedPropIDs();
     546             : 
     547             :     // Do O(N) with the small container
     548       40598 :     for (const auto supplied_prop : supplied_props)
     549             :     {
     550       30142 :       if (needed_mat_props.count(supplied_prop))
     551             :       {
     552        2760 :         supplies_needed = true;
     553        2760 :         break;
     554             :       }
     555             :     }
     556             : 
     557       13216 :     if (!supplies_needed)
     558       10456 :       continue;
     559             : 
     560        2760 :     if (!allow_stateful && mat->hasStatefulProperties())
     561           0 :       ::mooseError(
     562             :           "Someone called buildRequiredMaterials with allow_stateful = false but a material "
     563             :           "dependency ",
     564           0 :           mat->name(),
     565             :           " computes stateful properties.");
     566             : 
     567        2760 :     const auto & mp_deps = mat->getMatPropDependencies();
     568        2760 :     needed_mat_props.insert(mp_deps.begin(), mp_deps.end());
     569        2760 :     required_mats.push_front(mat);
     570             :   }
     571             : 
     572        6328 :   return required_mats;
     573        3164 : }

Generated by: LCOV version 1.14