12 #include "libmesh/string_to_enum.h" 13 #include "libmesh/parallel_sync.h" 20 "Base class to compute the advective flux of fluid in PorousFlow situations. The velocity " 21 "is U * (-permeability * (grad(P) - density * gravity)), while derived classes define U. " 22 "The Kuzmin-Turek FEM-TVD multidimensional stabilization scheme is used");
24 "Gravitational acceleration vector downwards (m/s^2)");
26 "PorousFlowDictator",
"The UserObject that holds the list of PorousFlow variable names");
28 "phase", 0,
"The index corresponding to the phase for this UserObject");
29 MooseEnum families(
"LAGRANGE MONOMIAL HERMITE SCALAR HIERARCHIC CLOUGH XYZ SZABAB BERNSTEIN");
33 "FE Family to use (eg Lagrange). You only need to specify this is your porous_flow_vars in " 34 "your PorousFlowDictator have different families or orders");
35 MooseEnum orders(
"CONSTANT FIRST SECOND THIRD FOURTH");
39 "FE Order to use (eg First). You only need to specify this is your porous_flow_vars in your " 40 "PorousFlowDictator have different families or orders");
48 _num_vars(_dictator.numVariables()),
50 _phase(getParam<unsigned
int>(
"phase")),
51 _permeability(getMaterialProperty<
RealTensorValue>(
"PorousFlow_permeability_qp")),
53 getMaterialProperty<
std::vector<
RealTensorValue>>(
"dPorousFlow_permeability_qp_dvar")),
55 "dPorousFlow_permeability_qp_dgradvar")),
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 _grad_p(getMaterialProperty<
std::vector<
RealGradient>>(
"PorousFlow_grad_porepressure_qp")),
60 _dgrad_p_dgrad_var(getMaterialProperty<
std::vector<
std::vector<
Real>>>(
61 "dPorousFlow_grad_porepressure_qp_dgradvar")),
63 "dPorousFlow_grad_porepressure_qp_dvar")),
64 _fe_type(isParamValid(
"fe_family") && isParamValid(
"fe_order")
67 : _dictator.feType()),
68 _phi(_assembly.fePhi<
Real>(_fe_type)),
69 _grad_phi(_assembly.feGradPhi<
Real>(_fe_type)),
71 _du_dvar_computed_by_thread(),
74 _triples_to_receive(),
76 _perm_derivs(_dictator.usePermDerivs())
80 "Phase number entered is greater than the number of phases specified in the " 81 "Dictator. Remember that indexing starts at 0");
84 paramError(
"fe_order",
"If you specify fe_family you must also specify fe_order");
86 paramError(
"fe_family",
"If you specify fe_order you must also specify fe_family");
89 "The PorousFlowDictator cannot determine the appropriate FE type to use because " 90 "your porous_flow_vars are of different types. You must specify the appropriate " 91 "fe_family and fe_order to use.");
116 for (
unsigned local_k = 0; local_k <
_current_elem->n_nodes(); ++local_k)
119 for (
unsigned pvar = 0; pvar <
_num_vars; ++pvar)
131 for (
unsigned i = 0; i < LIBMESH_DIM; ++i)
145 const bool resizing_was_needed =
154 if (resizing_was_needed)
161 for (
dof_id_type sequential_i = 0; sequential_i < num_nodes; ++sequential_i)
163 const std::vector<dof_id_type> con_i =
165 const std::size_t num_con_i = con_i.size();
167 for (
unsigned j = 0;
j < num_con_i; ++
j)
168 for (
const auto & global_neighbor_to_i : con_i)
180 for (
dof_id_type sequential_i = 0; sequential_i < num_nodes; ++sequential_i)
182 const std::vector<dof_id_type> & con_i =
184 const std::size_t num_con_i = con_i.size();
185 for (
unsigned j = 0;
j < num_con_i; ++
j)
186 for (
const auto & global_neighbor_to_i : con_i)
205 for (
unsigned pvar = 0; pvar <
_num_vars; ++pvar)
218 for (
dof_id_type sequential_i = 0; sequential_i < num_nodes; ++sequential_i)
220 const std::vector<dof_id_type> & con_i =
222 const std::size_t num_con_i = con_i.size();
223 for (
unsigned j = 0;
j < num_con_i; ++
j)
224 for (
const auto & global_derivs : pfafc._dkij_dvar[sequential_i][
j])
225 for (
unsigned pvar = 0; pvar <
_num_vars; ++pvar)
226 _dkij_dvar[sequential_i][
j][global_derivs.first][pvar] += global_derivs.second[pvar];
232 pfafc._du_dvar_computed_by_thread[sequential_i])
233 _du_dvar[sequential_i] = pfafc._du_dvar[sequential_i];
236 const std::map<dof_id_type, std::vector<Real>> &
244 const std::map<dof_id_type, std::vector<Real>> &
262 const std::map<dof_id_type, Real> & dflux_out_du =
264 for (
const auto & node_du : dflux_out_du)
267 const Real dflux_out_du_j = node_du.second;
269 for (
unsigned pvar = 0; pvar <
_num_vars; ++pvar)
276 const std::vector<std::vector<Real>> & dflux_out_dKjk =
279 for (std::size_t index_j = 0; index_j < con_i.size(); ++index_j)
283 for (std::size_t index_k = 0; index_k < con_j.size(); ++index_k)
286 const Real dflux_out_dK_jk = dflux_out_dKjk[index_j][index_k];
287 const std::map<dof_id_type, std::vector<Real>> & dkj_dvarl =
getdK_dvar(node_j, node_k);
288 for (
const auto & nodel_deriv : dkj_dvarl)
291 for (
unsigned pvar = 0; pvar <
_num_vars; ++pvar)
292 _dflux_out_dvars[sequential_i][l][pvar] += dflux_out_dK_jk * nodel_deriv.second[pvar];
310 std::map<std::pair<dof_id_type, dof_id_type>, std::vector<dof_id_type>>>
313 if (this->
hasBlocks(elem->subdomain_id()))
318 if (tpr_global.find(elem_pid) == tpr_global.end())
319 tpr_global[elem_pid] =
320 std::map<std::pair<dof_id_type, dof_id_type>, std::vector<dof_id_type>>();
321 for (
unsigned i = 0; i < elem->n_nodes(); ++i)
322 for (
unsigned j = 0;
j < elem->n_nodes(); ++
j)
324 std::pair<dof_id_type, dof_id_type> the_pair(elem->node_id(i), elem->node_id(
j));
325 if (tpr_global[elem_pid].find(the_pair) == tpr_global[elem_pid].end())
326 tpr_global[elem_pid][the_pair] = std::vector<dof_id_type>();
328 for (
const auto & global_neighbor_to_i :
330 if (std::find(tpr_global[elem_pid][the_pair].begin(),
331 tpr_global[elem_pid][the_pair].end(),
332 global_neighbor_to_i) == tpr_global[elem_pid][the_pair].end())
333 tpr_global[elem_pid][the_pair].push_back(global_neighbor_to_i);
341 for (
const auto & kv : tpr_global)
345 for (
const auto & pr_vec : kv.second)
349 for (
const auto & global_nd : pr_vec.second)
359 auto triples_action_functor = [
this](
processor_id_type pid,
const std::vector<dof_id_type> & tts)
371 const std::size_t num = kv.second.size();
372 for (std::size_t i = 0; i < num; i += 3)
382 const std::size_t num = kv.second.size();
383 for (std::size_t i = 0; i < num; i += 3)
399 std::map<processor_id_type, std::vector<std::vector<Real>>> du_dvar_to_send;
403 du_dvar_to_send[pid] = std::vector<std::vector<Real>>();
404 for (
const auto & nd : kv.second)
405 du_dvar_to_send[pid].push_back(
_du_dvar[nd]);
408 auto du_action_functor =
409 [
this](
processor_id_type pid,
const std::vector<std::vector<Real>> & du_dvar_received)
411 const std::size_t msg_size = du_dvar_received.size();
416 <<
", in du_dvar communication is incompatible with nodes_to_receive, which has size " 418 for (
unsigned i = 0; i < msg_size; ++i)
421 Parallel::push_parallel_vector_data(this->
comm(), du_dvar_to_send, du_action_functor);
424 std::map<processor_id_type, std::vector<std::vector<Real>>> dkij_dvar_to_send;
428 dkij_dvar_to_send[pid] = std::vector<std::vector<Real>>();
429 const std::size_t num = kv.second.size();
430 for (std::size_t i = 0; i < num; i += 3)
433 const unsigned index_to_seq = kv.second[i + 1];
435 dkij_dvar_to_send[pid].push_back(
_dkij_dvar[sequential_id][index_to_seq][global_id]);
439 auto dk_action_functor =
440 [
this](
processor_id_type pid,
const std::vector<std::vector<Real>> & dkij_dvar_received)
443 mooseAssert(dkij_dvar_received.size() == num / 3,
444 "Message size, " << dkij_dvar_received.size()
445 <<
", in dkij_dvar communication is incompatible with " 446 "triples_to_receive, which has size " 448 for (std::size_t i = 0; i < num; i += 3)
453 for (
unsigned pvar = 0; pvar <
_num_vars; ++pvar)
454 _dkij_dvar[sequential_id][index_to_seq][global_id][pvar] += dkij_dvar_received[i / 3][pvar];
457 Parallel::push_parallel_vector_data(this->
comm(), dkij_dvar_to_send, dk_action_functor);
const std::vector< dof_id_type > & globalIDs() const
Vector of all global node IDs (node numbers in the mesh)
virtual Real computedU_dvar(unsigned i, unsigned pvar) const =0
Compute d(u)/d(porous_flow_variable)
virtual void finalize() override
virtual void buildCommLists() override
When using multiple processors, other processors will compute:
const bool _perm_derivs
Flag to check whether permeabiity derivatives are non-zero.
const MooseArray< Real > & _coord
const MaterialProperty< RealTensorValue > & _permeability
Permeability of porous material.
const VariablePhiGradient & _grad_phi
grad(Kuzmin-Turek shape function)
virtual void executeOnElement(dof_id_type global_i, dof_id_type global_j, unsigned local_i, unsigned local_j, unsigned qp) override
This is called by multiple times in execute() in a double loop over _current_elem's nodes (local_i an...
static InputParameters validParams()
const MaterialProperty< std::vector< std::vector< RealTensorValue > > > & _dpermeability_dgradvar
d(permeabiity)/d(grad(PorousFlow variable))
virtual void execute() override
dof_id_type sequentialID(dof_id_type global_node_ID) const
Return the sequential node ID corresponding to the global node ID This is guaranteed to lie in the ra...
const Parallel::Communicator & comm() const
const std::map< dof_id_type, std::vector< Real > > & getdFluxOut_dvars(unsigned node_id) const
Returns d(flux_out)/d(porous_flow_variables.
unsigned indexOfGlobalConnection(dof_id_type global_node_ID_from, dof_id_type global_node_ID_to) const
Return the index of global_node_ID_to in the globalConnectionsToGlobalID(global_node_ID_from) vector...
const VariablePhiValue & _phi
Kuzmin-Turek shape function.
virtual void executeOnElement(dof_id_type global_i, dof_id_type global_j, unsigned local_i, unsigned local_j, unsigned qp)
This is called by multiple times in execute() in a double loop over _current_elem's nodes (local_i an...
const MaterialProperty< std::vector< RealTensorValue > > & _dpermeability_dvar
d(permeabiity)/d(PorousFlow variable)
std::size_t _number_of_nodes
Number of nodes held by the _connections object.
const unsigned int _phase
The phase.
Base class to compute the advective flux of fluid in PorousFlow situations using the Kuzmin-Turek FEM...
const MaterialProperty< std::vector< RealGradient > > & _grad_p
Gradient of the pore pressure in each phase.
std::map< processor_id_type, std::vector< dof_id_type > > _triples_to_receive
_triples_to_receive[proc_id] indicates the dk(i, j)/du_nodal information that we will receive from pr...
bool isParamValid(const std::string &name) const
const std::vector< dof_id_type > & globalConnectionsToSequentialID(dof_id_type sequential_node_ID) const
Return all the nodes (global node IDs) connected to the given sequential node ID. ...
PorousFlowAdvectiveFluxCalculatorBase(const InputParameters ¶meters)
TensorValue< Real > RealTensorValue
uint8_t processor_id_type
virtual void initialize() override
virtual Real computeVelocity(unsigned i, unsigned j, unsigned qp) const override
Computes the transfer velocity between current node i and current node j at the current qp in the cur...
virtual void threadJoin(const UserObject &uo) override
virtual void exchangeGhostedInfo() override
Sends and receives multi-processor information regarding u_nodal and k_ij.
virtual void execute() override
static InputParameters validParams()
std::vector< bool > _du_dvar_computed_by_thread
Whether _du_dvar has been computed by the local thread.
const MaterialProperty< std::vector< Real > > & _fluid_density_qp
Fluid density for each phase (at the qp)
Real deriv(unsigned n, unsigned alpha, unsigned beta, Real x)
std::vector< std::map< dof_id_type, std::vector< Real > > > _dflux_out_dvars
_dflux_out_dvars[sequential_i][global_j][pvar] = d(flux_out[global version of sequential_i])/d(porous...
T string_to_enum(const std::string &s)
Base class to compute Advective fluxes.
PorousFlowConnectedNodes _connections
Holds the sequential and global nodal IDs, and info regarding mesh connections between them...
bool _resizing_needed
whether _kij, etc, need to be sized appropriately (and valence recomputed) at the start of the timest...
std::map< processor_id_type, std::vector< dof_id_type > > _nodes_to_send
_nodes_to_send[proc_id] = list of sequential nodal IDs.
const std::map< dof_id_type, Real > & getdFluxOutdu(dof_id_type node_i) const
Returns r where r[j] = d(flux out of global node i)/du(global node j) used in Jacobian computations...
const MaterialProperty< std::vector< std::vector< Real > > > & _dfluid_density_qp_dvar
Derivative of the fluid density for each phase wrt PorousFlow variables (at the qp) ...
std::vector< std::vector< Real > > _du_dvar
_du_dvar[sequential_i][a] = d(u[global version of sequential node i])/d(porous_flow_variable[a]) ...
std::map< processor_id_type, std::vector< dof_id_type > > _triples_to_send
_triples_to_send[proc_id] indicates the dk(i, j)/du_nodal information that we will send to proc_id...
const std::vector< std::vector< Real > > & getdFluxOutdKjk(dof_id_type node_i) const
Returns r where r[j][k] = d(flux out of global node i)/dK[connected node j][connected node k] used in...
void paramError(const std::string ¶m, Args... args) const
unsigned int numPhases() const
The number of fluid phases.
processor_id_type _my_pid
processor ID of this object
virtual void exchangeGhostedInfo()
Sends and receives multi-processor information regarding u_nodal and k_ij.
const MaterialProperty< std::vector< std::vector< Real > > > & _dgrad_p_dgrad_var
Derivative of Grad porepressure in each phase wrt grad(PorousFlow variables)
virtual void finalize() override
std::size_t numNodes() const
number of nodes known by this class
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Elem *const & _current_elem
This holds maps between the nonlinear variables used in a PorousFlow simulation and the variable numb...
FEProblemBase & _fe_problem
const MooseArray< Real > & _JxW
const unsigned _num_vars
Number of PorousFlow variables.
const PorousFlowDictator & _dictator
PorousFlowDictator UserObject.
virtual void buildCommLists()
When using multiple processors, other processors will compute:
const MaterialProperty< std::vector< std::vector< RealGradient > > > & _dgrad_p_dvar
Derivative of Grad porepressure in each phase wrt PorousFlow variables.
const RealVectorValue _gravity
Gravity.
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
std::map< processor_id_type, std::vector< dof_id_type > > _nodes_to_receive
_nodes_to_receive[proc_id] = list of sequential nodal IDs.
virtual void timestepSetup() override
const std::vector< dof_id_type > & globalConnectionsToGlobalID(dof_id_type global_node_ID) const
Return all the nodes (global node IDs) connected to the given global node ID.
virtual void timestepSetup() override
bool hasBlocks(const SubdomainName &name) const
virtual void initialize() override
const libMesh::ConstElemRange & getNonlinearEvaluableElementRange()
virtual void threadJoin(const UserObject &uo) override
std::vector< std::vector< std::map< dof_id_type, std::vector< Real > > > > _dkij_dvar
_dkij_dvar[sequential_i][j][global_k][a] = d(K[sequential_i][j])/d(porous_flow_variable[global_k][por...
void ErrorVector unsigned int
const std::map< dof_id_type, std::vector< Real > > & getdK_dvar(dof_id_type node_i, dof_id_type node_j) const
Returns, r, where r[global node k][a] = d(K[node_i][node_j])/d(porous_flow_variable[global node k][po...
bool consistentFEType() const
Whether the porous_flow_vars all have the same FEType or if no porous_flow_vars were provided...