https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ADJunctionOneToOne1PhaseUserObject.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
11#include "THMIndicesVACE.h"
15#include "Numerics.h"
16#include "metaphysicl/parallel_numberarray.h"
17#include "metaphysicl/parallel_dualnumber.h"
18#include "metaphysicl/parallel_semidynamicsparsenumberarray.h"
19#include "libmesh/parallel_algebra.h"
20
22
23const std::vector<std::pair<std::string, unsigned int>>
25 std::pair<std::string, unsigned int>("rhoA", THMVACE1D::MASS),
26 std::pair<std::string, unsigned int>("rhouA", THMVACE1D::MOMENTUM),
27 std::pair<std::string, unsigned int>("rhoEA", THMVACE1D::ENERGY)};
28
30
33{
36
38 "A_elem", "Piecewise constant cross-sectional area of connected flow channels");
39 params.addRequiredCoupledVar("A_linear",
40 "Piecewise linear cross-sectional area of connected flow channels");
41 params.addRequiredCoupledVar("rhoA", "rho*A of the connected flow channels");
42 params.addRequiredCoupledVar("rhouA", "rhou*A of the connected flow channels");
43 params.addRequiredCoupledVar("rhoEA", "rhoE*A of the connected flow channels");
44
45 params.addRequiredParam<UserObjectName>("fluid_properties",
46 "Name of fluid properties user object");
47
48 params.addRequiredParam<UserObjectName>("numerical_flux", "Numerical flux user object name");
49
50 params.addRequiredParam<std::string>("junction_name", "Name of the junction component");
51
53 "Computes flux between two subdomains for 1-phase one-to-one junction");
54
55 return params;
56}
57
59 const InputParameters & params)
62
63 _A_linear(adCoupledValue("A_linear")),
64
65 _A_var(getVar("A_elem", 0)),
66 _rhoA_var(getVar("rhoA", 0)),
67 _rhouA_var(getVar("rhouA", 0)),
68 _rhoEA_var(getVar("rhoEA", 0)),
69
70 _fp(getUserObject<SinglePhaseFluidProperties>("fluid_properties")),
71
72 _numerical_flux(getUserObject<ADNumericalFlux3EqnBase>("numerical_flux")),
73
74 _junction_name(getParam<std::string>("junction_name")),
75
76 _dir(getMaterialProperty<RealVectorValue>("direction")),
77
78 _primitive_solutions(_n_connections),
79 _neighbor_primitive_solutions(_n_connections),
80
81 _fluxes(_n_connections),
82 _dof_indices(_n_connections, std::vector<dof_id_type>(THMVACE1D::N_FLUX_OUTPUTS, 0)),
83
84 _elem_ids(_n_connections),
85 _local_side_ids(_n_connections),
86
87 _areas_linear(_n_connections),
88 _directions(_n_connections),
89 _positions(_n_connections),
90 _neighbor_positions(_n_connections),
91 _delta_x(_n_connections),
92 _has_neighbor(_n_connections)
93{
99}
100
101void
103{
104 _connection_indices.clear();
105
106 // Broadcasts require vectors on all processes to have the same size
107 std::vector<ADReal> zero(THMVACE1D::N_PRIM_VARS, ADReal(0.));
108 for (unsigned int c = 0; c < _n_connections; c++)
109 {
110 _primitive_solutions[c] = zero;
112 }
113}
114
115void
117{
118 // Get connection index
119 const unsigned int c = getBoundaryIDIndex();
120 _connection_indices.push_back(c);
121
122 // Store DoF indices
123 for (const auto & varname_eq_index_pair : _varname_eq_index_pairs)
124 {
125 MooseVariable * var = getVar(varname_eq_index_pair.first, 0);
126 auto && dofs = var->dofIndices();
127 mooseAssert(dofs.size() == 1, "There should be only one DoF index.");
128 _dof_indices[c][varname_eq_index_pair.second] = dofs[0];
129 }
130
131 // Store primitive solution vectors for connection
132 const auto U_avg =
133 FlowModel1PhaseUtils::getElementalSolutionVector<true>(_current_elem, _U_vars, _is_implicit);
134 _primitive_solutions[c] = FlowModel1PhaseUtils::computePrimitiveSolutionVector<true>(U_avg, _fp);
135
136 // Get the neighbor solution and position. There should be one neighbor, unless
137 // there is only one element in the subdomain. Because broadcasting requires
138 // data sizes to be allocated on all processes, we cannot work with a vector
139 // of a size not known upfront, so we work with a single neighbor and have
140 // a flag that states whether there is one or zero neighbors.
141 std::vector<std::vector<GenericReal<true>>> W_neighbor;
142 std::vector<Point> x_neighbor;
143 getNeighborPrimitiveVariables(_current_elem, W_neighbor, x_neighbor);
144 if (W_neighbor.size() == 1)
145 {
146 _neighbor_primitive_solutions[c] = W_neighbor[0];
147 _neighbor_positions[c] = x_neighbor[0];
148 _has_neighbor[c] = true;
149 }
150 else
151 _has_neighbor[c] = false;
152
153 // Store element ID and local side ID for connection
154 _elem_ids[c] = _current_elem->id();
156
157 // Store direction, area, and position of channel at junction
159 _directions[c] = _dir[0];
160 _positions[c] = _q_point[0];
161 _delta_x[c] = (_positions[c] - _current_elem->vertex_average()) * _directions[c];
162}
163
164void
166{
167 const auto & junction_uo = static_cast<const ADJunctionOneToOne1PhaseUserObject &>(uo);
168
169 // Store the data computed/retrieved in the other threads
170 for (unsigned int i = 0; i < junction_uo._connection_indices.size(); i++)
171 {
172 const unsigned int c = junction_uo._connection_indices[i];
173
174 _dof_indices[c] = junction_uo._dof_indices[c];
175 _primitive_solutions[c] = junction_uo._primitive_solutions[c];
176 _neighbor_primitive_solutions[c] = junction_uo._neighbor_primitive_solutions[c];
177 _elem_ids[c] = junction_uo._elem_ids[c];
178 _local_side_ids[c] = junction_uo._local_side_ids[c];
179 _areas_linear[c] = junction_uo._areas_linear[c];
180 _directions[c] = junction_uo._directions[c];
181 _positions[c] = junction_uo._positions[c];
182 _neighbor_positions[c] = junction_uo._neighbor_positions[c];
183 _delta_x[c] = junction_uo._delta_x[c];
184 _has_neighbor[c] = junction_uo._has_neighbor[c];
185 }
186}
187
188void
190{
191 for (unsigned int i = 0; i < _n_connections; i++)
192 {
193 processor_id_type owner_proc = _processor_ids[i];
194 comm().broadcast(_primitive_solutions[i], owner_proc, true);
195 comm().broadcast(_neighbor_primitive_solutions[i], owner_proc, true);
196 comm().broadcast(_elem_ids[i], owner_proc, true);
197 comm().broadcast(_local_side_ids[i], owner_proc, true);
198 comm().broadcast(_areas_linear[i], owner_proc, true);
199 comm().broadcast(_directions[i], owner_proc, true);
200 comm().broadcast(_positions[i], owner_proc, true);
201 comm().broadcast(_neighbor_positions[i], owner_proc, true);
202 comm().broadcast(_delta_x[i], owner_proc, true);
203
204 // Vectors of bools are special, so we must broadcast a single bool instead
205 bool has_neighbor = _has_neighbor[i];
206 comm().broadcast(has_neighbor, owner_proc, true);
207 _has_neighbor[i] = has_neighbor;
208 }
209
210 const auto & W0_avg = _primitive_solutions[0];
211 const auto & W1_avg = _primitive_solutions[1];
212
213 // Multiplier for possibly different coordinate systems
214 const Real dir_mult = -_normal[0] * _normal[1];
215 auto W0_ref = W0_avg;
216 auto W1_ref = W1_avg;
217 W0_ref[THMVACE1D::VELOCITY] *= dir_mult;
218 W1_ref[THMVACE1D::VELOCITY] *= dir_mult;
219
220 std::vector<std::vector<GenericReal<true>>> W_neighbor0;
221 std::vector<Point> x_neighbor0;
222 if (_has_neighbor[0])
223 {
224 W_neighbor0.push_back(_neighbor_primitive_solutions[0]);
225 x_neighbor0.push_back(_neighbor_positions[0]);
226 }
227
228 std::vector<std::vector<GenericReal<true>>> W_neighbor1;
229 std::vector<Point> x_neighbor1;
230 if (_has_neighbor[1])
231 {
232 W_neighbor1.push_back(_neighbor_primitive_solutions[1]);
233 x_neighbor1.push_back(_neighbor_positions[1]);
234 }
235
236 const auto slopes0 = getBoundaryElementSlopes(
237 W0_avg, _positions[0], _directions[0], W_neighbor0, x_neighbor0, W1_ref);
238 const auto slopes1 = getBoundaryElementSlopes(
239 W1_avg, _positions[1], _directions[1], W_neighbor1, x_neighbor1, W0_ref);
240
241 auto W0 = W0_avg;
242 auto W1 = W1_avg;
243 for (unsigned int m = 0; m < THMVACE1D::N_PRIM_VARS; m++)
244 {
245 W0[m] = W0_avg[m] + slopes0[m] * _delta_x[0];
246 W1[m] = W1_avg[m] + slopes1[m] * _delta_x[1];
247 }
248
249 auto U0 =
250 FlowModel1PhaseUtils::computeConservativeSolutionVector<true>(W0, _areas_linear[0], _fp);
251 auto U1 =
252 FlowModel1PhaseUtils::computeConservativeSolutionVector<true>(W1, _areas_linear[1], _fp);
253 U1[THMVACE1D::RHOUA] *= dir_mult;
254
255 _fluxes[0] = _numerical_flux.getFlux(_local_side_ids[0], _elem_ids[0], true, U0, U1, _normal[0]);
256
257 _fluxes[1] = _numerical_flux.getFlux(_local_side_ids[0], _elem_ids[0], false, U0, U1, _normal[0]);
258 _fluxes[1][THMVACE1D::RHOA] *= dir_mult;
259 _fluxes[1][THMVACE1D::RHOEA] *= dir_mult;
260}
261
262const std::vector<ADReal> &
263ADJunctionOneToOne1PhaseUserObject::getFlux(const unsigned int & connection_index) const
264{
265 Threads::spin_mutex::scoped_lock lock(_spin_mutex);
266
267 return _fluxes[connection_index];
268}
269
270std::vector<ADReal>
272{
273 const auto U =
274 FlowModel1PhaseUtils::getElementalSolutionVector<true>(elem, _U_vars, _is_implicit);
275 return FlowModel1PhaseUtils::computePrimitiveSolutionVector<true>(U, _fp);
276}
registerMooseObject("ThermalHydraulicsApp", ADJunctionOneToOne1PhaseUserObject)
DualNumber< Real, DNDerivativeType, true > ADReal
Provides common interfaces for flow junction user objects.
unsigned int getBoundaryIDIndex()
Gets the index of the currently executing boundary within the vector of boundary IDs given to this Si...
static InputParameters validParams()
std::vector< unsigned int > _processor_ids
Owners of each side of the junction.
const unsigned int _n_connections
Number of connected flow channels.
const std::vector< Real > & _normal
Flow channel outward normals or junction inward normals.
Computes flux between two subdomains for 1-phase one-to-one junction.
std::vector< MooseVariable * > _U_vars
Conservative solution variables.
std::vector< unsigned int > _local_side_ids
Local side IDs for each connection.
static const std::vector< std::pair< std::string, unsigned int > > _varname_eq_index_pairs
Pairs of variable names vs. their corresponding equation indices.
const ADVariableValue & _A_linear
Piecewise linear cross-sectional area of connected flow channels.
const MaterialProperty< RealVectorValue > & _dir
Direction material property.
std::vector< std::vector< ADReal > > _primitive_solutions
Primitive solution vectors for each connection.
virtual std::vector< ADReal > computeElementPrimitiveVariables(const Elem *elem) const override
Computes the cell-average primitive variable values for an element.
std::vector< Point > _neighbor_positions
Positions at each connection's neighbor.
std::vector< bool > _has_neighbor
Flags for each connection having a neighbor.
std::vector< std::vector< dof_id_type > > _dof_indices
Degree of freedom indices; first index is connection, second is equation.
std::vector< ADReal > _areas_linear
Piecewise linear areas at each connection.
ADJunctionOneToOne1PhaseUserObject(const InputParameters &params)
static Threads::spin_mutex _spin_mutex
Thread lock.
const SinglePhaseFluidProperties & _fp
fluid properties user object
std::vector< unsigned int > _elem_ids
Element IDs for each connection.
std::vector< unsigned int > _connection_indices
Connection indices for this thread.
std::vector< Point > _positions
Positions at each connection.
virtual void threadJoin(const UserObject &uo) override
std::vector< Real > _delta_x
Position changes for each connection.
std::vector< std::vector< ADReal > > _neighbor_primitive_solutions
Primitive solution vectors for each connection's neighbor.
std::vector< RealVectorValue > _directions
Directions at each connection.
std::vector< std::vector< ADReal > > _fluxes
Flux vector.
const ADNumericalFlux3EqnBase & _numerical_flux
Numerical flux user object.
const std::vector< ADReal > & getFlux(const unsigned int &connection_index) const override
Gets the flux vector for a connection.
Base class for computing numerical fluxes for FlowModelSinglePhase.
MooseVariable * getVar(const std::string &var_name, unsigned int comp)
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
void addRequiredParam(const std::string &name, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
const std::vector< dof_id_type > & dofIndices() const final
virtual const std::vector< ADReal > & getFlux(const unsigned int iside, const dof_id_type ielem, bool res_side_is_left, const std::vector< ADReal > &UL_1d, const std::vector< ADReal > &UR_1d, Real nLR_dot_d) const
Gets the 1D flux vector for an element/side combination.
const unsigned int & _current_side
const MooseArray< Point > & _q_point
const Elem *const & _current_elem
Common class for single phase fluid properties.
Interface class for 1-D slope reconstruction.
virtual void getNeighborPrimitiveVariables(const Elem *elem, std::vector< std::vector< GenericReal< is_ad > > > &W_neighbor, std::vector< Point > &x_neighbor) const
Gets the primitive solution vector and position of neighbor(s)
std::vector< GenericReal< is_ad > > getBoundaryElementSlopes(const std::vector< GenericReal< is_ad > > &W_elem, const Point &x_elem, const RealVectorValue &dir, std::vector< std::vector< GenericReal< is_ad > > > W_neighbor, std::vector< Point > x_neighbor, const std::vector< GenericReal< is_ad > > &W_boundary) const
Gets limited slopes for the primitive variables in the 1-D direction for boundary element.
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
const Parallel::Communicator & comm() const
static const unsigned int N_PRIM_VARS
static const unsigned int N_FLUX_INPUTS
Number of numerical flux function inputs for 1D.