www.mooseframework.org
PorousFlowMaterial.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
13 
14 #include "libmesh/quadrature.h"
15 
16 #include <limits>
17 
20 {
22  params.addRequiredParam<UserObjectName>(
23  "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names");
24  params.addParam<bool>(
25  "at_nodes", false, "Evaluate Material properties at nodes instead of quadpoints");
26  params.addPrivateParam<std::string>("pf_material_type", "pf_material");
27  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  params.set<bool>("_force_stateful_init") = true;
33 
34  return params;
35 }
36 
38  : Material(parameters),
39  _nodal_material(getParam<bool>("at_nodes")),
40  _dictator(getUserObject<PorousFlowDictator>("PorousFlowDictator")),
41  _pressure_variable_name("pressure_variable"),
42  _saturation_variable_name("saturation_variable"),
43  _temperature_variable_name("temperature_variable"),
44  _mass_fraction_variable_name("mass_fraction_variable")
45 {
46 }
47 
48 void
50 {
51  if (!_nodal_material)
52  return;
53 
55  auto & storage = _material_data.getMaterialPropertyStorage();
56  if (!storage.hasStatefulProperties())
57  return;
58 
59  auto & stateful_prop_id_to_prop_id = storage.statefulProps();
60  for (const auto i : index_range(stateful_prop_id_to_prop_id))
61  {
62  const auto prop_id = stateful_prop_id_to_prop_id[i];
63  if (_supplied_prop_ids.count(prop_id))
64  _supplied_old_prop_ids.push_back(i);
65  }
66 }
67 
68 void
70 {
71  if (_nodal_material)
72  {
73  // size the properties to max(number_of_nodes, number_of_quadpoints)
75 
76  // compute the values for number_of_nodes
78  }
79  else
81 }
82 
83 void
85 {
86  const unsigned int numnodes = _current_elem->n_nodes();
87 
88  // compute the values for all nodes
89  for (_qp = 0; _qp < numnodes; ++_qp)
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  if (numnodes < _qrule->n_points())
99  {
101 
102  // Copy from qp = _current_elem->n_nodes() - 1 to qp = _qrule->n_points() -1
103  for (const auto & prop_id : _supplied_prop_ids)
104  for (unsigned int qp = numnodes; qp < _qrule->n_points(); ++qp)
105  props[prop_id].qpCopy(qp, props[prop_id], numnodes - 1);
106  }
107 }
108 
109 void
111 {
112  if (_nodal_material)
113  {
114  // size the properties to max(number_of_nodes, number_of_quadpoints)
116 
118  }
119  else
121 }
122 
123 void
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  const auto new_size = std::max(_current_elem->n_nodes(), _qrule->n_points());
147  auto & storage = _material_data.getMaterialPropertyStorage();
148 
149  auto & props = _material_data.props();
150  for (const auto prop_id : _supplied_prop_ids)
151  props[prop_id].resize(new_size);
152 
153  for (const auto state : storage.statefulIndexRange())
154  for (const auto prop_id : _supplied_old_prop_ids)
155  if (_material_data.props(state).hasValue(prop_id))
156  _material_data.props(state)[prop_id].resize(new_size);
157 }
158 
159 unsigned
160 PorousFlowMaterial::nearestQP(unsigned nodenum) const
161 {
162  unsigned nearest_qp = 0;
163  Real smallest_dist = std::numeric_limits<Real>::max();
164  for (unsigned qp = 1; qp < _qrule->n_points(); ++qp)
165  {
166  const Real this_dist = (_current_elem->point(nodenum) - _q_point[qp]).norm();
167  if (this_dist < smallest_dist)
168  {
169  nearest_qp = qp;
170  smallest_dist = this_dist;
171  }
172  }
173  return nearest_qp;
174 }
const MooseArray< Point > & _q_point
const MaterialPropertyStorage & getMaterialPropertyStorage() const
void sizeNodalProperties()
Resizes properties to be equal to max(number of nodes, number of quadpoints) in the current element...
virtual void computeProperties() override
Correctly sizes nodal materials, then computes using Material::computeProperties. ...
const QBase *const & _qrule
virtual void computeQpProperties()
void onlyResizeIfSmaller(bool flag)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
std::vector< unsigned int > _supplied_old_prop_ids
stateful material property ids that this material supplies
void addPrivateParam(const std::string &name, const T &value)
virtual void initialSetup() override
T & set(const std::string &name, bool quiet_mode=false)
virtual void initStatefulProperties(unsigned int n_points) override
Correctly sizes nodal materials, then initialises using Material::initStatefulProperties.
virtual void computeProperties() override
const bool _nodal_material
Whether the derived class holds nodal values.
void resize(const std::size_t size, const WriteKey)
void addRequiredParam(const std::string &name, const std::string &doc_string)
const std::vector< unsigned int > & statefulProps() const
MaterialData & _material_data
unsigned int _qp
static InputParameters validParams()
const MaterialProperties & props(const unsigned int state=0) const
std::set< unsigned int > _supplied_prop_ids
virtual void initStatefulProperties(unsigned int n_points)
auto norm(const T &a) -> decltype(std::abs(a))
PorousFlowMaterial(const InputParameters &parameters)
static InputParameters validParams()
unsigned nearestQP(unsigned nodenum) const
Find the nearest quadpoint to the node labelled by nodenum in the current element.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This holds maps between the nonlinear variables used in a PorousFlow simulation and the variable numb...
void addClassDescription(const std::string &doc_string)
bool hasValue(const std::size_t i) const
auto index_range(const T &sizable)
const Elem *const & _current_elem
void computeNodalProperties()
Compute the material properties at each node, and if the number of nodes is less than the number of q...