https://mooseframework.inl.gov
PorousFlowMaterial.C
Go to the documentation of this file.
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 
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 (const auto qp : make_range(_qrule->n_points()))
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
virtual void initStatefulProperties(const unsigned int n_points)
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
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...
IntRange< T > make_range(T beg, T end)
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...