www.mooseframework.org
RichardsMaterial.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 "RichardsMaterial.h"
11 #include "Assembly.h"
12 #include "MooseMesh.h"
13 
14 #include <cmath> // std::sinh and std::cosh
15 
16 #include "libmesh/quadrature.h"
17 
19 
22 {
24 
25  params.addRequiredParam<Real>(
26  "mat_porosity", "The porosity of the material. Should be between 0 and 1. Eg, 0.1");
27  params.addCoupledVar("por_change",
28  0,
29  "An auxillary variable describing porosity changes. "
30  "Porosity = mat_porosity + por_change. If this is not "
31  "provided, zero is used.");
32  params.addRequiredParam<RealTensorValue>("mat_permeability", "The permeability tensor (m^2).");
33  params.addCoupledVar("perm_change",
34  "A list of auxillary variable describing permeability "
35  "changes. There must be 9 of these, corresponding to the "
36  "xx, xy, xz, yx, yy, yz, zx, zy, zz components respectively. "
37  " Permeability = mat_permeability*10^(perm_change).");
38  params.addRequiredParam<UserObjectName>(
39  "richardsVarNames_UO", "The UserObject that holds the list of Richards variable names.");
40  params.addRequiredParam<std::vector<UserObjectName>>(
41  "relperm_UO", "List of names of user objects that define relative permeability");
42  params.addRequiredParam<std::vector<UserObjectName>>(
43  "seff_UO",
44  "List of name of user objects that define effective saturation as a function of "
45  "pressure list");
46  params.addRequiredParam<std::vector<UserObjectName>>(
47  "sat_UO",
48  "List of names of user objects that define saturation as a function of effective saturation");
49  params.addRequiredParam<std::vector<UserObjectName>>(
50  "density_UO", "List of names of user objects that define the fluid density");
51  params.addRequiredParam<std::vector<UserObjectName>>(
52  "SUPG_UO", "List of names of user objects that define the SUPG");
53  params.addRequiredParam<std::vector<Real>>(
54  "viscosity", "List of viscosity of fluids (Pa.s). Typical value for water is=1E-3");
56  "gravity",
57  "Gravitational acceleration (m/s^2) as a vector pointing downwards. Eg (0,0,-10)");
58  // params.addRequiredCoupledVar("pressure_vars", "List of variables that represent the pressure");
59  params.addParam<bool>(
60  "linear_shape_fcns",
61  true,
62  "If you are using second-order Lagrange shape functions you need to set this to false.");
63  return params;
64 }
65 
67  : Material(parameters),
68 
69  _material_por(getParam<Real>("mat_porosity")),
70  _por_change(coupledValue("por_change")),
71  _por_change_old(coupledValueOld("por_change")),
72 
73  _material_perm(getParam<RealTensorValue>("mat_permeability")),
74 
75  _material_gravity(getParam<RealVectorValue>("gravity")),
76 
77  _porosity_old(declareProperty<Real>("porosity_old")),
78  _porosity(declareProperty<Real>("porosity")),
79  _permeability(declareProperty<RealTensorValue>("permeability")),
80  _gravity(declareProperty<RealVectorValue>("gravity")),
81 
82  _richards_name_UO(getUserObject<RichardsVarNames>("richardsVarNames_UO")),
83  _num_p(_richards_name_UO.num_v()),
84 
85  _perm_change(isCoupled("perm_change")
86  ? coupledValues("perm_change")
87  : std::vector<const VariableValue *>(LIBMESH_DIM * LIBMESH_DIM, &_zero)),
88 
89  _trace_perm(_material_perm.tr()),
90 
91  _material_viscosity(getParam<std::vector<Real>>("viscosity")),
92 
93  _pp_old(declareProperty<std::vector<Real>>("porepressure_old")),
94  _pp(declareProperty<std::vector<Real>>("porepressure")),
95  _dpp_dv(declareProperty<std::vector<std::vector<Real>>>("dporepressure_dv")),
96  _d2pp_dv(declareProperty<std::vector<std::vector<std::vector<Real>>>>("d2porepressure_dvdv")),
97 
98  _viscosity(declareProperty<std::vector<Real>>("viscosity")),
99 
100  _density_old(declareProperty<std::vector<Real>>("density_old")),
101  _density(declareProperty<std::vector<Real>>("density")),
102  _ddensity_dv(declareProperty<std::vector<std::vector<Real>>>("ddensity_dv")),
103 
104  _seff_old(declareProperty<std::vector<Real>>("s_eff_old")),
105  _seff(declareProperty<std::vector<Real>>("s_eff")),
106  _dseff_dv(declareProperty<std::vector<std::vector<Real>>>("ds_eff_dv")),
107  _d2seff_dv(declareProperty<std::vector<std::vector<std::vector<Real>>>>("d2s_eff_dvdv")),
108 
109  _sat_old(declareProperty<std::vector<Real>>("sat_old")),
110  _sat(declareProperty<std::vector<Real>>("sat")),
111  _dsat_dv(declareProperty<std::vector<std::vector<Real>>>("dsat_dv")),
112 
113  _rel_perm(declareProperty<std::vector<Real>>("rel_perm")),
114  _drel_perm_dv(declareProperty<std::vector<std::vector<Real>>>("drel_perm_dv")),
115 
116  _mass_old(declareProperty<std::vector<Real>>("mass_old")),
117  _mass(declareProperty<std::vector<Real>>("mass")),
118  _dmass(declareProperty<std::vector<std::vector<Real>>>("dmass")),
119 
120  _flux_no_mob(declareProperty<std::vector<RealVectorValue>>("flux_no_mob")),
121  _dflux_no_mob_dv(declareProperty<std::vector<std::vector<RealVectorValue>>>("dflux_no_mob_dv")),
122  _dflux_no_mob_dgradv(
123  declareProperty<std::vector<std::vector<RealTensorValue>>>("dflux_no_mob_dgradv")),
124 
125  _flux(declareProperty<std::vector<RealVectorValue>>("flux")),
126  _dflux_dv(declareProperty<std::vector<std::vector<RealVectorValue>>>("dflux_dv")),
127  _dflux_dgradv(declareProperty<std::vector<std::vector<RealTensorValue>>>("dflux_dgradv")),
128  _d2flux_dvdv(
129  declareProperty<std::vector<std::vector<std::vector<RealVectorValue>>>>("d2flux_dvdv")),
130  _d2flux_dgradvdv(
131  declareProperty<std::vector<std::vector<std::vector<RealTensorValue>>>>("d2flux_dgradvdv")),
132  _d2flux_dvdgradv(
133  declareProperty<std::vector<std::vector<std::vector<RealTensorValue>>>>("d2flux_dvdgradv")),
134 
135  _tauvel_SUPG(declareProperty<std::vector<RealVectorValue>>("tauvel_SUPG")),
136  _dtauvel_SUPG_dgradp(
137  declareProperty<std::vector<std::vector<RealTensorValue>>>("dtauvel_SUPG_dgradv")),
138  _dtauvel_SUPG_dp(declareProperty<std::vector<std::vector<RealVectorValue>>>("dtauvel_SUPG_dv"))
139 
140 {
141 
142  // Need to add the variables that the user object is coupled to as dependencies so MOOSE will
143  // compute them
144  {
145  const std::vector<MooseVariableFEBase *> & coupled_vars =
147  for (unsigned int i = 0; i < coupled_vars.size(); i++)
148  addMooseVariableDependency(coupled_vars[i]);
149  }
150 
151  if (_material_por <= 0 || _material_por >= 1)
152  mooseError("Porosity set to ", _material_por, " but it must be between 0 and 1");
153 
154  if (isCoupled("perm_change") && (coupledComponents("perm_change") != LIBMESH_DIM * LIBMESH_DIM))
155  mooseError(LIBMESH_DIM * LIBMESH_DIM,
156  " components of perm_change must be given to a RichardsMaterial. You supplied ",
157  coupledComponents("perm_change"),
158  "\n");
159 
160  if (!(_material_viscosity.size() == _num_p &&
161  getParam<std::vector<UserObjectName>>("relperm_UO").size() == _num_p &&
162  getParam<std::vector<UserObjectName>>("seff_UO").size() == _num_p &&
163  getParam<std::vector<UserObjectName>>("sat_UO").size() == _num_p &&
164  getParam<std::vector<UserObjectName>>("density_UO").size() == _num_p &&
165  getParam<std::vector<UserObjectName>>("SUPG_UO").size() == _num_p))
166  mooseError("There are ",
167  _num_p,
168  " Richards fluid variables, so you need to specify this "
169  "number of viscosities, relperm_UO, seff_UO, sat_UO, "
170  "density_UO, SUPG_UO");
171 
172  _d2density.resize(_num_p);
173  _d2rel_perm_dv.resize(_num_p);
174  _pressure_vals.resize(_num_p);
175  _pressure_old_vals.resize(_num_p);
177  _material_seff_UO.resize(_num_p);
178  _material_sat_UO.resize(_num_p);
180  _material_SUPG_UO.resize(_num_p);
181  _grad_p.resize(_num_p);
182 
183  for (unsigned int i = 0; i < _num_p; ++i)
184  {
185  // DON'T WANT "pressure_vars" at all since pp_name_UO contains the same info
186  //_pressure_vals[i] = &coupledValue("pressure_vars", i); // coupled value returns a reference
187  //_pressure_old_vals[i] = (_is_transient ? &coupledValueOld("pressure_vars", i) : &_zero);
188  //_grad_p[i] = &coupledGradient("pressure_vars", i);
189 
190  // in the following. first get the userobject names that were inputted, then get the i_th one
191  // of these, then get the actual userobject that this corresponds to, then finally & gives
192  // pointer to RichardsRelPerm object.
193  _material_relperm_UO[i] = &getUserObjectByName<RichardsRelPerm>(
194  getParam<std::vector<UserObjectName>>("relperm_UO")[i]);
195  _material_seff_UO[i] =
196  &getUserObjectByName<RichardsSeff>(getParam<std::vector<UserObjectName>>("seff_UO")[i]);
197  _material_sat_UO[i] =
198  &getUserObjectByName<RichardsSat>(getParam<std::vector<UserObjectName>>("sat_UO")[i]);
199  _material_density_UO[i] = &getUserObjectByName<RichardsDensity>(
200  getParam<std::vector<UserObjectName>>("density_UO")[i]);
201  _material_SUPG_UO[i] =
202  &getUserObjectByName<RichardsSUPG>(getParam<std::vector<UserObjectName>>("SUPG_UO")[i]);
203  }
204 }
205 
206 void
208 {
209  // Get the pressure and effective saturation at each quadpoint
210  // From these we will build the relative permeability, density, flux, etc
211  if (_richards_name_UO.var_types() == "pppp")
212  {
213  for (unsigned int i = 0; i < _num_p; ++i)
214  {
218  }
219  }
220 
221  for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
222  {
223  _pp_old[qp].resize(_num_p);
224  _pp[qp].resize(_num_p);
225  _dpp_dv[qp].resize(_num_p);
226  _d2pp_dv[qp].resize(_num_p);
227 
228  _seff_old[qp].resize(_num_p);
229  _seff[qp].resize(_num_p);
230  _dseff_dv[qp].resize(_num_p);
231  _d2seff_dv[qp].resize(_num_p);
232 
233  if (_richards_name_UO.var_types() == "pppp")
234  {
235  for (unsigned int i = 0; i < _num_p; ++i)
236  {
237  _pp_old[qp][i] = (*_pressure_old_vals[i])[qp];
238  _pp[qp][i] = (*_pressure_vals[i])[qp];
239 
240  _dpp_dv[qp][i].assign(_num_p, 0);
241  _dpp_dv[qp][i][i] = 1;
242 
243  _d2pp_dv[qp][i].resize(_num_p);
244  for (unsigned int j = 0; j < _num_p; ++j)
245  _d2pp_dv[qp][i][j].assign(_num_p, 0);
246 
247  _seff_old[qp][i] = (*_material_seff_UO[i]).seff(_pressure_old_vals, qp);
248  _seff[qp][i] = (*_material_seff_UO[i]).seff(_pressure_vals, qp);
249 
250  _dseff_dv[qp][i].resize(_num_p);
251  (*_material_seff_UO[i]).dseff(_pressure_vals, qp, _dseff_dv[qp][i]);
252 
253  _d2seff_dv[qp][i].resize(_num_p);
254  for (unsigned int j = 0; j < _num_p; ++j)
255  _d2seff_dv[qp][i][j].resize(_num_p);
256  (*_material_seff_UO[i]).d2seff(_pressure_vals, qp, _d2seff_dv[qp][i]);
257  }
258  }
259  // the above lines of code are only valid for "pppp"
260  // if you decide to code other RichardsVariables (eg "psss")
261  // you will need to add some lines here
262  }
263 }
264 
265 void
267 {
268  // fluid viscosity
269  _viscosity[qp].resize(_num_p);
270  for (unsigned int i = 0; i < _num_p; ++i)
271  _viscosity[qp][i] = _material_viscosity[i];
272 
273  // fluid saturation
274  _sat_old[qp].resize(_num_p);
275  _sat[qp].resize(_num_p);
276  _dsat_dv[qp].resize(_num_p);
277  for (unsigned int i = 0; i < _num_p; ++i)
278  {
279  _sat_old[qp][i] = (*_material_sat_UO[i]).sat(_seff_old[qp][i]);
280  _sat[qp][i] = (*_material_sat_UO[i]).sat(_seff[qp][i]);
281  _dsat_dv[qp][i].assign(_num_p, (*_material_sat_UO[i]).dsat(_seff[qp][i]));
282  for (unsigned int j = 0; j < _num_p; ++j)
283  _dsat_dv[qp][i][j] *= _dseff_dv[qp][i][j];
284  }
285 
286  // fluid density
288  _density[qp].resize(_num_p);
290  for (unsigned int i = 0; i < _num_p; ++i)
291  {
292  _density_old[qp][i] = (*_material_density_UO[i]).density(_pp_old[qp][i]);
293  _density[qp][i] = (*_material_density_UO[i]).density(_pp[qp][i]);
294  _ddensity_dv[qp][i].assign(_num_p, (*_material_density_UO[i]).ddensity(_pp[qp][i]));
295  for (unsigned int j = 0; j < _num_p; ++j)
296  _ddensity_dv[qp][i][j] *= _dpp_dv[qp][i][j];
297  }
298 
299  // relative permeability
300  _rel_perm[qp].resize(_num_p);
302  for (unsigned int i = 0; i < _num_p; ++i)
303  {
304  _rel_perm[qp][i] = (*_material_relperm_UO[i]).relperm(_seff[qp][i]);
305  _drel_perm_dv[qp][i].assign(_num_p, (*_material_relperm_UO[i]).drelperm(_seff[qp][i]));
306  for (unsigned int j = 0; j < _num_p; ++j)
307  _drel_perm_dv[qp][i][j] *= _dseff_dv[qp][i][j];
308  }
309 
310  // fluid mass
311  _mass_old[qp].resize(_num_p);
312  _mass[qp].resize(_num_p);
313  _dmass[qp].resize(_num_p);
314  for (unsigned int i = 0; i < _num_p; ++i)
315  {
316  _mass_old[qp][i] = _porosity_old[qp] * _density_old[qp][i] * _sat_old[qp][i];
317  _mass[qp][i] = _porosity[qp] * _density[qp][i] * _sat[qp][i];
318  _dmass[qp][i].resize(_num_p);
319  for (unsigned int j = 0; j < _num_p; ++j)
320  _dmass[qp][i][j] = _porosity[qp] * (_ddensity_dv[qp][i][j] * _sat[qp][i] +
321  _density[qp][i] * _dsat_dv[qp][i][j]);
322  }
323 
324  // flux without the mobility part
325  _flux_no_mob[qp].resize(_num_p);
326  _dflux_no_mob_dv[qp].resize(_num_p);
328  for (unsigned int i = 0; i < _num_p; ++i)
329  {
330  _flux_no_mob[qp][i] = _permeability[qp] * ((*_grad_p[i])[qp] - _density[qp][i] * _gravity[qp]);
331 
332  _dflux_no_mob_dv[qp][i].resize(_num_p);
333  for (unsigned int j = 0; j < _num_p; ++j)
334  _dflux_no_mob_dv[qp][i][j] = _permeability[qp] * (-_ddensity_dv[qp][i][j] * _gravity[qp]);
335 
337  for (unsigned int j = 0; j < _num_p; ++j)
338  _dflux_no_mob_dgradv[qp][i][j] = _permeability[qp] * _dpp_dv[qp][i][j];
339  }
340 
341  // flux
342  _flux[qp].resize(_num_p);
343  _dflux_dv[qp].resize(_num_p);
345  for (unsigned int i = 0; i < _num_p; ++i)
346  {
347  _flux[qp][i] = _density[qp][i] * _rel_perm[qp][i] * _flux_no_mob[qp][i] / _viscosity[qp][i];
348 
349  _dflux_dv[qp][i].resize(_num_p);
350  for (unsigned int j = 0; j < _num_p; ++j)
351  {
352  _dflux_dv[qp][i][j] =
353  _density[qp][i] * _rel_perm[qp][i] * _dflux_no_mob_dv[qp][i][j] / _viscosity[qp][i];
354  _dflux_dv[qp][i][j] +=
355  (_ddensity_dv[qp][i][j] * _rel_perm[qp][i] + _density[qp][i] * _drel_perm_dv[qp][i][j]) *
356  _flux_no_mob[qp][i] / _viscosity[qp][i];
357  }
358 
359  _dflux_dgradv[qp][i].resize(_num_p);
360  for (unsigned int j = 0; j < _num_p; ++j)
361  _dflux_dgradv[qp][i][j] =
362  _density[qp][i] * _rel_perm[qp][i] * _dflux_no_mob_dgradv[qp][i][j] / _viscosity[qp][i];
363  }
364 }
365 
366 void
368 {
369  _d2flux_dvdv[qp].resize(_num_p);
372 
373  for (unsigned int i = 0; i < _num_p; ++i)
374  {
375  _d2flux_dvdv[qp][i].resize(_num_p);
378  for (unsigned int j = 0; j < _num_p; ++j)
379  {
380  _d2flux_dvdv[qp][i][j].assign(_num_p, RealVectorValue());
381  _d2flux_dgradvdv[qp][i][j].assign(_num_p, RealTensorValue());
382  _d2flux_dvdgradv[qp][i][j].assign(_num_p, RealTensorValue());
383  }
384  }
385 }
386 
387 void
389 {
391 
392  for (unsigned int i = 0; i < _num_p; ++i)
393  {
394  if ((*_material_SUPG_UO[i]).SUPG_trivial())
395  continue; // as the derivatives won't be needed
396 
397  // second derivative of density
398  _d2density[i].resize(_num_p);
399  Real ddens = (*_material_density_UO[i]).ddensity(_pp[qp][i]);
400  Real d2dens = (*_material_density_UO[i]).d2density(_pp[qp][i]);
401  for (unsigned int j = 0; j < _num_p; ++j)
402  {
403  _d2density[i][j].resize(_num_p);
404  for (unsigned int k = 0; k < _num_p; ++k)
405  _d2density[i][j][k] =
406  d2dens * _dpp_dv[qp][i][j] * _dpp_dv[qp][i][k] + ddens * _d2pp_dv[qp][i][j][k];
407  }
408 
409  // second derivative of relative permeability
410  _d2rel_perm_dv[i].resize(_num_p);
411  Real drel = (*_material_relperm_UO[i]).drelperm(_seff[qp][i]);
412  Real d2rel = (*_material_relperm_UO[i]).d2relperm(_seff[qp][i]);
413  for (unsigned int j = 0; j < _num_p; ++j)
414  {
415  _d2rel_perm_dv[i][j].resize(_num_p);
416  for (unsigned int k = 0; k < _num_p; ++k)
417  _d2rel_perm_dv[i][j][k] =
418  d2rel * _dseff_dv[qp][i][j] * _dseff_dv[qp][i][k] + drel * _d2seff_dv[qp][i][j][k];
419  }
420 
421  // now compute the second derivs of the fluxes
422  for (unsigned int j = 0; j < _num_p; ++j)
423  {
424  for (unsigned int k = 0; k < _num_p; ++k)
425  {
426  _d2flux_dvdv[qp][i][j][k] =
427  _d2density[i][j][k] * _rel_perm[qp][i] *
428  (_permeability[qp] * ((*_grad_p[i])[qp] - _density[qp][i] * _gravity[qp]));
429  _d2flux_dvdv[qp][i][j][k] +=
430  (_ddensity_dv[qp][i][j] * _drel_perm_dv[qp][i][k] +
431  _ddensity_dv[qp][i][k] * _drel_perm_dv[qp][i][j]) *
432  (_permeability[qp] * ((*_grad_p[i])[qp] - _density[qp][i] * _gravity[qp]));
433  _d2flux_dvdv[qp][i][j][k] +=
434  _density[qp][i] * _d2rel_perm_dv[i][j][k] *
435  (_permeability[qp] * ((*_grad_p[i])[qp] - _density[qp][i] * _gravity[qp]));
436  _d2flux_dvdv[qp][i][j][k] += (_ddensity_dv[qp][i][j] * _rel_perm[qp][i] +
437  _density[qp][i] * _drel_perm_dv[qp][i][j]) *
438  (_permeability[qp] * (-_ddensity_dv[qp][i][k] * _gravity[qp]));
439  _d2flux_dvdv[qp][i][j][k] += (_ddensity_dv[qp][i][k] * _rel_perm[qp][i] +
440  _density[qp][i] * _drel_perm_dv[qp][i][k]) *
441  (_permeability[qp] * (-_ddensity_dv[qp][i][j] * _gravity[qp]));
442  _d2flux_dvdv[qp][i][j][k] += _density[qp][i] * _rel_perm[qp][i] *
443  (_permeability[qp] * (-_d2density[i][j][k] * _gravity[qp]));
444  }
445  }
446  for (unsigned int j = 0; j < _num_p; ++j)
447  for (unsigned int k = 0; k < _num_p; ++k)
448  _d2flux_dvdv[qp][i][j][k] /= _viscosity[qp][i];
449 
450  for (unsigned int j = 0; j < _num_p; ++j)
451  {
452  for (unsigned int k = 0; k < _num_p; ++k)
453  {
454  _d2flux_dgradvdv[qp][i][j][k] = (_ddensity_dv[qp][i][k] * _rel_perm[qp][i] +
455  _density[qp][i] * _drel_perm_dv[qp][i][k]) *
456  _permeability[qp] * _dpp_dv[qp][i][j] / _viscosity[qp][i];
457  _d2flux_dvdgradv[qp][i][k][j] = _d2flux_dgradvdv[qp][i][j][k];
458  }
459  }
460  }
461 }
462 
463 void
465 {
466  _tauvel_SUPG[qp].assign(_num_p, RealVectorValue());
468  _dtauvel_SUPG_dp[qp].resize(_num_p);
469  for (unsigned int i = 0; i < _num_p; ++i)
470  {
471  _dtauvel_SUPG_dp[qp][i].assign(_num_p, RealVectorValue());
472  _dtauvel_SUPG_dgradp[qp][i].assign(_num_p, RealTensorValue());
473  }
474 }
475 
476 void
478 {
479  // Grab reference to linear Lagrange finite element object pointer,
480  // currently this is always a linear Lagrange element, so this might need to
481  // be generalized if we start working with higher-order elements...
482  auto && fe = _assembly.getFE(getParam<bool>("linear_shape_fcns") ? FEType(FIRST, LAGRANGE)
483  : FEType(SECOND, LAGRANGE),
484  _current_elem->dim());
485 
486  // Grab references to FE object's mapping data from the _subproblem's FE object
487  const std::vector<Real> & dxidx(fe->get_dxidx());
488  const std::vector<Real> & dxidy(fe->get_dxidy());
489  const std::vector<Real> & dxidz(fe->get_dxidz());
490  const std::vector<Real> & detadx(fe->get_detadx());
491  const std::vector<Real> & detady(fe->get_detady());
492  const std::vector<Real> & detadz(fe->get_detadz());
493  const std::vector<Real> & dzetadx(fe->get_dzetadx());
494  const std::vector<Real> & dzetady(fe->get_dzetady());
495  const std::vector<Real> & dzetadz(fe->get_dzetadz());
496 
497  for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
498  {
499 
500  // Bounds checking on element data and putting into vector form
501  mooseAssert(qp < dxidx.size(), "Insufficient data in dxidx array!");
502  mooseAssert(qp < dxidy.size(), "Insufficient data in dxidy array!");
503  mooseAssert(qp < dxidz.size(), "Insufficient data in dxidz array!");
504  if (_mesh.dimension() >= 2)
505  {
506  mooseAssert(qp < detadx.size(), "Insufficient data in detadx array!");
507  mooseAssert(qp < detady.size(), "Insufficient data in detady array!");
508  mooseAssert(qp < detadz.size(), "Insufficient data in detadz array!");
509  }
510  if (_mesh.dimension() >= 3)
511  {
512  mooseAssert(qp < dzetadx.size(), "Insufficient data in dzetadx array!");
513  mooseAssert(qp < dzetady.size(), "Insufficient data in dzetady array!");
514  mooseAssert(qp < dzetadz.size(), "Insufficient data in dzetadz array!");
515  }
516 
517  // CHECK : Does this work spherical, cylindrical, etc?
518  RealVectorValue xi_prime(dxidx[qp], dxidy[qp], dxidz[qp]);
519  RealVectorValue eta_prime, zeta_prime;
520  if (_mesh.dimension() >= 2)
521  {
522  eta_prime(0) = detadx[qp];
523  eta_prime(1) = detady[qp];
524  }
525  if (_mesh.dimension() == 3)
526  {
527  eta_prime(2) = detadz[qp];
528  zeta_prime(0) = dzetadx[qp];
529  zeta_prime(1) = dzetady[qp];
530  zeta_prime(2) = dzetadz[qp];
531  }
532 
533  _trace_perm = _permeability[qp].tr();
534  for (unsigned int i = 0; i < _num_p; ++i)
535  {
536  RealVectorValue vel =
537  (*_material_SUPG_UO[i])
538  .velSUPG(_permeability[qp], (*_grad_p[i])[qp], _density[qp][i], _gravity[qp]);
539  RealTensorValue dvel_dgradp = (*_material_SUPG_UO[i]).dvelSUPG_dgradp(_permeability[qp]);
540  RealVectorValue dvel_dp =
541  (*_material_SUPG_UO[i])
542  .dvelSUPG_dp(_permeability[qp], _ddensity_dv[qp][i][i], _gravity[qp]);
543  RealVectorValue bb =
544  (*_material_SUPG_UO[i]).bb(vel, _mesh.dimension(), xi_prime, eta_prime, zeta_prime);
545  RealVectorValue dbb2_dgradp =
546  (*_material_SUPG_UO[i]).dbb2_dgradp(vel, dvel_dgradp, xi_prime, eta_prime, zeta_prime);
547  Real dbb2_dp = (*_material_SUPG_UO[i]).dbb2_dp(vel, dvel_dp, xi_prime, eta_prime, zeta_prime);
548  Real tau = (*_material_SUPG_UO[i]).tauSUPG(vel, _trace_perm, bb);
549  RealVectorValue dtau_dgradp =
550  (*_material_SUPG_UO[i]).dtauSUPG_dgradp(vel, dvel_dgradp, _trace_perm, bb, dbb2_dgradp);
551  Real dtau_dp = (*_material_SUPG_UO[i]).dtauSUPG_dp(vel, dvel_dp, _trace_perm, bb, dbb2_dp);
552 
553  _tauvel_SUPG[qp][i] = tau * vel;
554 
555  RealTensorValue dtauvel_dgradp = tau * dvel_dgradp;
556  for (const auto j : make_range(Moose::dim))
557  for (const auto k : make_range(Moose::dim))
558  dtauvel_dgradp(j, k) +=
559  dtau_dgradp(j) * vel(k); // this is outerproduct - maybe libmesh can do it better?
560  for (unsigned int j = 0; j < _num_p; ++j)
561  _dtauvel_SUPG_dgradp[qp][i][j] = dtauvel_dgradp * _dpp_dv[qp][i][j];
562 
563  RealVectorValue dtauvel_dp = dtau_dp * vel + tau * dvel_dp;
564  for (unsigned int j = 0; j < _num_p; ++j)
565  _dtauvel_SUPG_dp[qp][i][j] = dtauvel_dp * _dpp_dv[qp][i][j];
566  }
567  }
568 }
569 
570 void
572 {
573  // compute porepressures and effective saturations
574  // with algorithms depending on the _richards_name_UO.var_types()
575  computePandSeff();
576 
577  // porosity, permeability, and gravity
578  for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
579  {
580  _porosity[qp] = _material_por + _por_change[qp];
582 
584  for (const auto i : make_range(Moose::dim))
585  for (const auto j : make_range(Moose::dim))
586  _permeability[qp](i, j) *= std::pow(10, (*_perm_change[LIBMESH_DIM * i + j])[qp]);
587 
589  }
590 
591  // compute "derived" quantities -- those that depend on P and Seff --- such as density, relperm
592  for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
594 
595  // compute certain second derivatives of the derived quantities
596  // These are needed in Jacobian calculations if doing SUPG
597  for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
599 
600  // Now for SUPG itself
601  for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
602  zeroSUPG(qp);
603 
604  // the following saves computational effort if all SUPG is trivial
605  bool trivial_supg = true;
606  for (unsigned int i = 0; i < _num_p; ++i)
607  trivial_supg = trivial_supg && (*_material_SUPG_UO[i]).SUPG_trivial();
608  if (trivial_supg)
609  return;
610  else
611  computeSUPG();
612 }
MaterialProperty< std::vector< std::vector< RealTensorValue > > > & _dflux_no_mob_dgradv
d(_flux_no_mob_i)/d(grad(variable_j))
LAGRANGE
MaterialProperty< std::vector< std::vector< std::vector< Real > > > > & _d2pp_dv
d^2(porepressure_i)/d(variable_j)/d(variable_k)
MaterialProperty< std::vector< Real > > & _pp
porepressure(s)
virtual bool isCoupled(const std::string &var_name, unsigned int i=0) const
const QBase *const & _qrule
MaterialProperty< RealVectorValue > & _gravity
MaterialProperty< std::vector< std::vector< std::vector< RealTensorValue > > > > & _d2flux_dvdgradv
d^2(Richards flux_i)/d(variable_j)/d(grad(variable_k)), here flux_i is the i_th flux, which is itself a RealVectorValue. We should have _d2flux_dvdgradv[i][j][k] = _d2flux_dgradvdv[i][k][j], but i think it is more clear having both, and hopefully not a blowout on memory/CPU.
std::vector< std::vector< std::vector< Real > > > _d2rel_perm_dv
d^2(relperm_i)/dP_j/dP_k - used in various derivative calculations
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
RichardsMaterial(const InputParameters &parameters)
MaterialProperty< std::vector< std::vector< std::vector< RealTensorValue > > > > & _d2flux_dgradvdv
d^2(Richards flux_i)/d(grad(variable_j))/d(variable_k), here flux_i is the i_th flux, which is itself a RealVectorValue
std::vector< const RichardsRelPerm * > _material_relperm_UO
const VariableValue * richards_vals_old(unsigned int richards_var_num) const
a vector of pointers to old VariableValues
MaterialProperty< std::vector< Real > > & _pp_old
old values of porepressure(s)
const RichardsVarNames & _richards_name_UO
The variable names userobject for the Richards variables.
MaterialProperty< std::vector< RealVectorValue > > & _flux
fluid flux (a vector of fluxes for multicomponent)
std::vector< Real > _material_viscosity
FIRST
const std::vector< const VariableValue * > _perm_change
static const std::string density
Definition: NS.h:33
static constexpr std::size_t dim
unsigned int _num_p
This holds maps between pressure_var or pressure_var, sat_var used in RichardsMaterial and kernels...
MaterialProperty< std::vector< Real > > & _sat
saturation (vector of saturations in case of multiphase)
SECOND
std::vector< const RichardsSUPG * > _material_SUPG_UO
void addRequiredParam(const std::string &name, const std::string &doc_string)
MaterialProperty< std::vector< std::vector< Real > > > & _drel_perm_dv
d(relperm_i)/d(variable_j)
virtual void resize(const std::size_t size) override final
Real _material_por
porosity as entered by the user
const VariableValue & _por_change
porosity changes. if not entered they default to zero
void zero2ndDerivedQuantities(unsigned int qp)
Zeroes 2nd derivatives of the flux.
TensorValue< Real > RealTensorValue
MaterialProperty< std::vector< Real > > & _seff_old
old effective saturation
registerMooseObject("RichardsApp", RichardsMaterial)
MaterialProperty< std::vector< std::vector< Real > > > & _dpp_dv
d(porepressure_i)/d(variable_j)
void computePandSeff()
computes the quadpoint values of the porepressure(s) and effective saturation(s), and their derivativ...
MaterialProperty< std::vector< std::vector< std::vector< RealVectorValue > > > > & _d2flux_dvdv
d^2(Richards flux_i)/d(variable_j)/d(variable_k), here flux_i is the i_th flux, which is itself a Rea...
MaterialProperty< RealTensorValue > & _permeability
MaterialProperty< std::vector< std::vector< RealVectorValue > > > & _dflux_no_mob_dv
d(_flux_no_mob_i)/d(variable_j)
MooseMesh & _mesh
std::string var_types() const
return the _var_types string
static InputParameters validParams()
const VariableGradient * grad_var(unsigned int richards_var_num) const
a vector of pointers to grad(Variable)
virtual unsigned int dimension() const
MaterialProperty< std::vector< std::vector< RealTensorValue > > > & _dtauvel_SUPG_dgradp
Assembly & _assembly
std::vector< const VariableGradient * > _grad_p
MaterialProperty< std::vector< std::vector< RealVectorValue > > > & _dflux_dv
d(Richards flux_i)/d(variable_j), here flux_i is the i_th flux, which is itself a RealVectorValue ...
std::vector< const VariableValue * > _pressure_vals
MaterialProperty< std::vector< Real > > & _rel_perm
relative permeability (vector of relative permeabilities in case of multiphase)
MaterialProperty< std::vector< Real > > & _mass
fluid mass (a vector of masses for multicomponent)
RealVectorValue _material_gravity
gravity as entered by user
MaterialProperty< std::vector< RealVectorValue > > & _flux_no_mob
permeability*(grad(P) - density*gravity) (a vector of these for multicomponent)
std::vector< const RichardsDensity * > _material_density_UO
void computeDerivedQuantities(unsigned int qp)
Computes the "derived" quantities — those that depend on porepressure(s) and effective saturation(s)...
MaterialProperty< std::vector< Real > > & _density
fluid density (or densities for multiphase problems)
std::vector< const VariableValue * > _pressure_old_vals
MaterialProperty< std::vector< Real > > & _sat_old
old saturation
void addCoupledVar(const std::string &name, const std::string &doc_string)
const std::vector< MooseVariableFieldBase *> & getCoupledMooseVars() const
OutputTools< Real >::VariableValue VariableValue
std::vector< const RichardsSeff * > _material_seff_UO
const VariableValue * richards_vals(unsigned int richards_var_num) const
a vector of pointers to VariableValues
unsigned int coupledComponents(const std::string &var_name) const
MaterialProperty< std::vector< Real > > & _mass_old
old value of fluid mass (a vector of masses for multicomponent)
void addMooseVariableDependency(MooseVariableFieldBase *var)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
MaterialProperty< Real > & _porosity
void computeSUPG()
Computes the tauvel_SUPG and its derivatives.
MaterialProperty< std::vector< RealVectorValue > > & _tauvel_SUPG
MaterialProperty< std::vector< std::vector< std::vector< Real > > > > & _d2seff_dv
d^2(Seff_i)/d(variable_j)/d(variable_k)
void compute2ndDerivedQuantities(unsigned int qp)
Computes 2nd derivatives of the flux.
std::vector< const RichardsSat * > _material_sat_UO
void zeroSUPG(unsigned int qp)
Assigns and zeroes the MaterialProperties associated with SUPG.
MaterialProperty< std::vector< Real > > & _density_old
old fluid density (or densities for multiphase problems)
IntRange< T > make_range(T beg, T end)
MaterialProperty< Real > & _porosity_old
material properties
const VariableValue & _por_change_old
void mooseError(Args &&... args) const
MaterialProperty< std::vector< Real > > & _seff
effective saturation (vector of effective saturations in case of multiphase)
RealTensorValue _material_perm
permeability as entered by the user
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
MaterialProperty< std::vector< std::vector< RealTensorValue > > > & _dflux_dgradv
d(Richards flux_i)/d(grad(variable_j)), here flux_i is the i_th flux, which is itself a RealVectorVal...
Real _trace_perm
trace of permeability tensor
const FEBase *const & getFE(FEType type, unsigned int dim) const
MaterialProperty< std::vector< std::vector< Real > > > & _ddensity_dv
d(density_i)/d(variable_j)
MaterialProperty< std::vector< std::vector< Real > > > & _dsat_dv
d(saturation_i)/d(variable_j)
MaterialProperty< std::vector< std::vector< Real > > > & _dseff_dv
d(Seff_i)/d(variable_j)
MooseUnits pow(const MooseUnits &, int)
static const std::string k
Definition: NS.h:124
MaterialProperty< std::vector< std::vector< Real > > > & _dmass
d(fluid mass_i)/dP_j (a vector of masses for multicomponent)
static InputParameters validParams()
MaterialProperty< std::vector< std::vector< RealVectorValue > > > & _dtauvel_SUPG_dp
std::vector< std::vector< std::vector< Real > > > _d2density
d^2(density)/dp_j/dP_k - used in various derivative calculations
const Elem *const & _current_elem
MaterialProperty< std::vector< Real > > & _viscosity
fluid viscosity (or viscosities in the multiphase case)
virtual void computeProperties()