13 #include "MooseMesh.h"
14 #include "MooseVariable.h"
15 #include "SystemBase.h"
17 #include "libmesh/quadrature.h"
23 InputParameters params = validParams<Kernel>();
24 params.addRequiredParam<RealVectorValue>(
"gravity",
25 "Gravitational acceleration vector downwards (m/s^2)");
26 params.addRequiredParam<UserObjectName>(
27 "PorousFlowDictator",
"The UserObject that holds the list of PorousFlow variable names");
28 params.addParam<
unsigned>(
"full_upwind_threshold",
30 "If, for each timestep, the number of "
31 "upwind-downwind swaps in an element is less than "
32 "this quantity, then full upwinding is used for that element. "
33 "Otherwise the fallback scheme is employed.");
34 MooseEnum fallback_enum(
"quick harmonic",
"quick");
35 params.addParam<MooseEnum>(
"fallback_scheme",
37 "quick: use nodal mobility without "
38 "preserving mass. harmonic: use a "
39 "harmonic mean of nodal mobilities "
40 "and preserve fluid mass");
41 params.addClassDescription(
"Fully-upwinded advective Darcy flux");
47 _permeability(getMaterialProperty<RealTensorValue>(
"PorousFlow_permeability_qp")),
49 getMaterialProperty<std::vector<RealTensorValue>>(
"dPorousFlow_permeability_qp_dvar")),
50 _dpermeability_dgradvar(getMaterialProperty<std::vector<std::vector<RealTensorValue>>>(
51 "dPorousFlow_permeability_qp_dgradvar")),
53 getMaterialProperty<std::vector<Real>>(
"PorousFlow_fluid_phase_density_nodal")),
54 _dfluid_density_node_dvar(getMaterialProperty<std::vector<std::vector<Real>>>(
55 "dPorousFlow_fluid_phase_density_nodal_dvar")),
56 _fluid_density_qp(getMaterialProperty<std::vector<Real>>(
"PorousFlow_fluid_phase_density_qp")),
57 _dfluid_density_qp_dvar(getMaterialProperty<std::vector<std::vector<Real>>>(
58 "dPorousFlow_fluid_phase_density_qp_dvar")),
59 _fluid_viscosity(getMaterialProperty<std::vector<Real>>(
"PorousFlow_viscosity_nodal")),
60 _dfluid_viscosity_dvar(
61 getMaterialProperty<std::vector<std::vector<Real>>>(
"dPorousFlow_viscosity_nodal_dvar")),
62 _pp(getMaterialProperty<std::vector<Real>>(
"PorousFlow_porepressure_nodal")),
63 _grad_p(getMaterialProperty<std::vector<
RealGradient>>(
"PorousFlow_grad_porepressure_qp")),
64 _dgrad_p_dgrad_var(getMaterialProperty<std::vector<std::vector<Real>>>(
65 "dPorousFlow_grad_porepressure_qp_dgradvar")),
66 _dgrad_p_dvar(getMaterialProperty<std::vector<std::vector<
RealGradient>>>(
67 "dPorousFlow_grad_porepressure_qp_dvar")),
69 _num_phases(_dictator.numPhases()),
70 _gravity(getParam<RealVectorValue>(
"gravity")),
71 _perm_derivs(_dictator.usePermDerivs()),
72 _full_upwind_threshold(getParam<unsigned>(
"full_upwind_threshold")),
73 _fallback_scheme(getParam<MooseEnum>(
"fallback_scheme").getEnum<
FallbackEnum>()),
74 _proto_flux(_num_phases),
75 _jacobian(_num_phases),
79 #ifdef LIBMESH_HAVE_TBB_API
80 if (libMesh::n_threads() > 1)
81 mooseWarning(
"PorousFlowDarcyBase: num_upwinds and num_downwinds may not be computed "
82 "accurately when using TBB and greater than 1 thread");
89 Kernel::timestepSetup();
90 _num_upwinds = std::unordered_map<unsigned, std::vector<std::vector<unsigned>>>();
91 _num_downwinds = std::unordered_map<unsigned, std::vector<std::vector<unsigned>>>();
97 return _grad_test[_i][_qp] *
109 RealVectorValue deriv =
119 for (
unsigned int i = 0; i < LIBMESH_DIM; ++i)
124 return _grad_test[_i][_qp] * deriv;
130 mooseError(
"PorousFlowDarcyBase: computeQpResidual called");
159 const unsigned int pvar =
162 DenseMatrix<Number> & ke = _assembly.jacobianBlock(_var.number(), jvar);
170 const unsigned int num_nodes = _test.size();
177 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
179 for (_i = 0; _i < num_nodes; ++_i)
185 const unsigned elem = _current_elem->id();
201 for (
unsigned nod = 0; nod < num_nodes; ++nod)
217 for (
unsigned nod = 0; nod < num_nodes; ++nod)
218 max_swaps[ph] = std::max(
228 for (_i = 0; _i < _test.size(); _i++)
231 for (_j = 0; _j < _phi.size(); _j++)
232 for (_qp = 0; _qp < _qrule->n_points(); _qp++)
262 DenseVector<Number> & re = _assembly.residualBlock(_var.number());
264 _local_re.resize(re.size());
266 for (_i = 0; _i < _test.size(); _i++)
274 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
275 for (
unsigned int i = 0; i < _save_in.size(); i++)
276 _save_in[i]->sys().solution().add_vector(_local_re, _save_in[i]->dofIndices());
282 _local_ke.resize(ke.m(), ke.n());
285 for (_i = 0; _i < _test.size(); _i++)
286 for (_j = 0; _j < _phi.size(); _j++)
288 _local_ke(_i, _j) +=
_jacobian[ph][_i][_j];
292 if (_has_diag_save_in && jvar == _var.number())
294 unsigned int rows = ke.m();
295 DenseVector<Number> diag(rows);
296 for (
unsigned int i = 0; i < rows; i++)
297 diag(i) = _local_ke(i, i);
299 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
300 for (
unsigned int i = 0; i < _diag_save_in.size(); i++)
301 _diag_save_in[i]->sys().solution().add_vector(diag, _diag_save_in[i]->dofIndices());
339 const unsigned int num_nodes = _test.size();
344 Real total_mass_out = 0.0;
348 std::vector<Real> dtotal_mass_out;
349 std::vector<Real> dtotal_in;
352 dtotal_mass_out.assign(num_nodes, 0.0);
353 dtotal_in.assign(num_nodes, 0.0);
357 std::vector<bool> upwind_node(num_nodes);
358 for (
unsigned int n = 0; n < num_nodes; ++n)
362 upwind_node[n] =
true;
370 for (_j = 0; _j < _phi.size(); _j++)
373 if (_test.size() == _phi.size())
384 for (_j = 0; _j < _phi.size(); _j++)
385 dtotal_mass_out[_j] +=
_jacobian[ph][n][_j];
392 upwind_node[n] =
false;
395 for (_j = 0; _j < _phi.size(); _j++)
402 for (
unsigned int n = 0; n < num_nodes; ++n)
407 for (_j = 0; _j < _phi.size(); _j++)
409 _jacobian[ph][n][_j] *= total_mass_out / total_in;
411 _proto_flux[ph][n] * (dtotal_mass_out[_j] / total_in -
412 dtotal_in[_j] * total_mass_out / total_in / total_in);
423 const unsigned int num_nodes = _test.size();
429 for (
unsigned int n = 0; n < num_nodes; ++n)
438 for (_j = 0; _j < _phi.size(); _j++)
441 if (_test.size() == _phi.size())
460 const unsigned int num_nodes = _test.size();
462 std::vector<Real> mob(num_nodes);
463 unsigned num_zero = 0;
464 unsigned zero_mobility_node = std::numeric_limits<unsigned>::max();
465 Real harmonic_mob = 0;
466 for (
unsigned n = 0; n < num_nodes; ++n)
471 zero_mobility_node = n;
475 harmonic_mob += 1.0 / mob[n];
480 harmonic_mob = (1.0 * num_nodes) / harmonic_mob;
483 std::vector<Real> dharmonic_mob(num_nodes, 0.0);
486 const Real harm2 =
std::pow(harmonic_mob, 2) / (1.0 * num_nodes);
488 for (
unsigned n = 0; n < num_nodes; ++n)
490 else if (num_zero == 1)
491 dharmonic_mob[zero_mobility_node] =
492 num_nodes *
dmobility(zero_mobility_node, ph, pvar);
497 for (
unsigned n = 0; n < num_nodes; ++n)
498 for (_j = 0; _j < _phi.size(); _j++)
501 if (_test.size() == _phi.size())
506 for (
unsigned n = 0; n < num_nodes; ++n)