LCOV - code coverage report
Current view: top level - src/materials - PorousFlowMaterial.C (source / functions) Hit Total Coverage
Test: idaholab/moose porous_flow: #31405 (292dce) with base fef103 Lines: 58 59 98.3 %
Date: 2025-09-04 07:55:56 Functions: 8 8 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             : #include "PorousFlowMaterial.h"
      11             : 
      12             : #include "MaterialPropertyStorage.h"
      13             : 
      14             : #include "libmesh/quadrature.h"
      15             : 
      16             : #include <limits>
      17             : 
      18             : InputParameters
      19      571434 : PorousFlowMaterial::validParams()
      20             : {
      21      571434 :   InputParameters params = Material::validParams();
      22     1142868 :   params.addRequiredParam<UserObjectName>(
      23             :       "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names");
      24     1142868 :   params.addParam<bool>(
      25     1142868 :       "at_nodes", false, "Evaluate Material properties at nodes instead of quadpoints");
      26     1142868 :   params.addPrivateParam<std::string>("pf_material_type", "pf_material");
      27      571434 :   params.addClassDescription("This generalises MOOSE's Material class to allow for Materials that "
      28             :                              "hold information related to the nodes in the finite element");
      29             : 
      30             :   // Needed due to the custom tomfoolery going on with nodal material sizing in
      31             :   // initStatefulProperties()
      32      571434 :   params.set<bool>("_force_stateful_init") = true;
      33             : 
      34      571434 :   return params;
      35           0 : }
      36             : 
      37      447095 : PorousFlowMaterial::PorousFlowMaterial(const InputParameters & parameters)
      38             :   : Material(parameters),
      39      447095 :     _nodal_material(getParam<bool>("at_nodes")),
      40      447095 :     _dictator(getUserObject<PorousFlowDictator>("PorousFlowDictator")),
      41             :     _pressure_variable_name("pressure_variable"),
      42             :     _saturation_variable_name("saturation_variable"),
      43             :     _temperature_variable_name("temperature_variable"),
      44      447095 :     _mass_fraction_variable_name("mass_fraction_variable")
      45             : {
      46      447095 : }
      47             : 
      48             : void
      49      433821 : PorousFlowMaterial::initialSetup()
      50             : {
      51      433821 :   if (!_nodal_material)
      52             :     return;
      53             : 
      54      197829 :   _material_data.onlyResizeIfSmaller(true);
      55             :   auto & storage = _material_data.getMaterialPropertyStorage();
      56      197829 :   if (!storage.hasStatefulProperties())
      57             :     return;
      58             : 
      59             :   auto & stateful_prop_id_to_prop_id = storage.statefulProps();
      60      533607 :   for (const auto i : index_range(stateful_prop_id_to_prop_id))
      61             :   {
      62      438591 :     const auto prop_id = stateful_prop_id_to_prop_id[i];
      63             :     if (_supplied_prop_ids.count(prop_id))
      64       29692 :       _supplied_old_prop_ids.push_back(i);
      65             :   }
      66             : }
      67             : 
      68             : void
      69     7093661 : PorousFlowMaterial::initStatefulProperties(unsigned int n_points)
      70             : {
      71     7093661 :   if (_nodal_material)
      72             :   {
      73             :     // size the properties to max(number_of_nodes, number_of_quadpoints)
      74     3131368 :     sizeNodalProperties();
      75             : 
      76             :     // compute the values for number_of_nodes
      77     3131368 :     Material::initStatefulProperties(_current_elem->n_nodes());
      78             :   }
      79             :   else
      80     3962293 :     Material::initStatefulProperties(n_points);
      81     7093661 : }
      82             : 
      83             : void
      84   106171382 : PorousFlowMaterial::computeNodalProperties()
      85             : {
      86   106171382 :   const unsigned int numnodes = _current_elem->n_nodes();
      87             : 
      88             :   // compute the values for all nodes
      89   534270630 :   for (_qp = 0; _qp < numnodes; ++_qp)
      90   428099330 :     computeQpProperties();
      91             : 
      92             :   // If number_of_nodes < number_of_quadpoints, the remaining values in the
      93             :   // material data array are zero (for scalars) and empty (for vectors).
      94             :   // Unfortunately, this can cause issues with adaptivity, where the empty
      95             :   // value can be transferred to a node in a child element. This can lead
      96             :   // to a segfault when accessing stateful properties, see #14428.
      97             :   // To prevent this, we copy the last node value to the empty array positions.
      98   106171300 :   if (numnodes < _qrule->n_points())
      99             :   {
     100    11766624 :     MaterialProperties & props = _material_data.props();
     101             : 
     102             :     // Copy from qp = _current_elem->n_nodes() - 1 to qp = _qrule->n_points() -1
     103    46478988 :     for (const auto & prop_id : _supplied_prop_ids)
     104   136574912 :       for (unsigned int qp = numnodes; qp < _qrule->n_points(); ++qp)
     105   101862548 :         props[prop_id].qpCopy(qp, props[prop_id], numnodes - 1);
     106             :   }
     107   106171300 : }
     108             : 
     109             : void
     110   218912318 : PorousFlowMaterial::computeProperties()
     111             : {
     112   218912318 :   if (_nodal_material)
     113             :   {
     114             :     // size the properties to max(number_of_nodes, number_of_quadpoints)
     115   106171382 :     sizeNodalProperties();
     116             : 
     117   106171382 :     computeNodalProperties();
     118             :   }
     119             :   else
     120   112740936 :     Material::computeProperties();
     121   218912182 : }
     122             : 
     123             : void
     124   109302750 : PorousFlowMaterial::sizeNodalProperties()
     125             : {
     126             :   /*
     127             :    * For nodal materials, the Properties should be sized as the maximum of
     128             :    * the number of nodes and the number of quadpoints.
     129             :    * We only actually need "number of nodes" pieces of information, which are
     130             :    * computed by computeProperties(), so the n_points - _current_elem->n_nodes()
     131             :    * elements at the end of the std::vector will always be zero, but they
     132             :    * are needed because MOOSE does copy operations (etc) that assumes that
     133             :    * the std::vector is sized to number of quadpoints.
     134             :    *
     135             :    * On boundary materials, the number of nodes may be larger than the number of
     136             :    * qps on the face of the element, in which case the remaining entries in the
     137             :    * material properties storage will be zero.
     138             :    *
     139             :    * \author lindsayad: MooseArray currently has the unfortunate side effect that if your new size
     140             :    * is greater than the current size, then we clear the whole data structure. Consequently this
     141             :    * call has the potential to clear material property evaluations done earlier in the material
     142             :    * dependency chain. So instead we selectively resize just our own properties and not everyone's
     143             :    */
     144             :   // _material_data.resize(std::max(_current_elem->n_nodes(), _qrule->n_points()));
     145             : 
     146   109302750 :   const auto new_size = std::max(_current_elem->n_nodes(), _qrule->n_points());
     147   109302750 :   auto & storage = _material_data.getMaterialPropertyStorage();
     148             : 
     149             :   auto & props = _material_data.props();
     150   454690225 :   for (const auto prop_id : _supplied_prop_ids)
     151   345387475 :     props[prop_id].resize(new_size);
     152             : 
     153   211444706 :   for (const auto state : storage.statefulIndexRange())
     154   146193752 :     for (const auto prop_id : _supplied_old_prop_ids)
     155    44051796 :       if (_material_data.props(state).hasValue(prop_id))
     156     2157085 :         _material_data.props(state)[prop_id].resize(new_size);
     157   109302750 : }
     158             : 
     159             : unsigned
     160      341062 : PorousFlowMaterial::nearestQP(unsigned nodenum) const
     161             : {
     162             :   unsigned nearest_qp = 0;
     163             :   Real smallest_dist = std::numeric_limits<Real>::max();
     164     1875994 :   for (const auto qp : make_range(_qrule->n_points()))
     165             :   {
     166     1534932 :     const Real this_dist = (_current_elem->point(nodenum) - _q_point[qp]).norm();
     167     1534932 :     if (this_dist < smallest_dist)
     168             :     {
     169             :       nearest_qp = qp;
     170             :       smallest_dist = this_dist;
     171             :     }
     172             :   }
     173      341062 :   return nearest_qp;
     174             : }

Generated by: LCOV version 1.14