OGS
WellboreCompensateNeumannBoundaryConditionLocalAssembler.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#pragma once
5
6#include <Eigen/LU>
7#include <limits>
8
18
19namespace ProcessLib
20{
21
23{
24 double pressure;
25 double velocity;
26 double enthalpy;
27};
28
30{
32
33 // Used for mapping boundary nodes to bulk nodes.
34 std::unique_ptr<NumLib::LocalToGlobalIndexMap> dof_table_boundary_pressure;
35 std::unique_ptr<NumLib::LocalToGlobalIndexMap> dof_table_boundary_velocity;
36 std::unique_ptr<NumLib::LocalToGlobalIndexMap> dof_table_boundary_enthalpy;
37
39};
40
41template <typename ShapeFunction, int GlobalDim>
44 GlobalDim>
45{
46 using Base =
50
51public:
55 MeshLib::Element const& e,
56 std::size_t const local_matrix_size,
57 NumLib::GenericIntegrationMethod const& integration_method,
58 bool const is_axially_symmetric,
60 : Base(e, is_axially_symmetric, integration_method),
61 _element(e),
62 _data(data),
63 _local_matrix_size(local_matrix_size)
64 {
65 }
66
67 void assemble(std::size_t const mesh_item_id,
68 NumLib::LocalToGlobalIndexMap const& dof_table_boundary,
69 double const /*t*/, std::vector<GlobalVector*> const& x,
70 int const process_id, GlobalMatrix* /*K*/, GlobalVector& b,
71 GlobalMatrix* /*Jac*/) override
72 {
74 _local_rhs.setZero();
75
76 unsigned const n_integration_points =
77 Base::_integration_method.getNumberOfPoints();
78
79 auto const indices_current_variable =
80 NumLib::getIndices(mesh_item_id, dof_table_boundary);
81 auto const indices_pressure = NumLib::getIndices(
82 mesh_item_id, *_data.dof_table_boundary_pressure);
83 auto const indices_velocity = NumLib::getIndices(
84 mesh_item_id, *_data.dof_table_boundary_velocity);
85 auto const indices_enthalpy = NumLib::getIndices(
86 mesh_item_id, *_data.dof_table_boundary_enthalpy);
87
88 std::vector<double> const local_pressure =
89 x[process_id]->get(indices_pressure);
90 std::vector<double> const local_velocity =
91 x[process_id]->get(indices_velocity);
92 std::vector<double> const local_enthalpy =
93 x[process_id]->get(indices_enthalpy);
94
95 auto const& medium = *_data.media_map.getMedium(_element.getID());
96 auto const& liquid_phase = medium.phase("AqueousLiquid");
97 auto const& gas_phase = medium.phase("Gas");
98
100 pos.setElementID(_element.getID());
101
103
104 for (unsigned ip = 0; ip < n_integration_points; ip++)
105 {
106 auto const& n_and_weight = Base::_ns_and_weights[ip];
107 auto const& N = n_and_weight.N;
108 auto const& w = n_and_weight.weight;
109
110 double pressure_int_pt = 0.0;
111 double velocity_int_pt = 0.0;
112 double enthalpy_int_pt = 0.0;
113
114 NumLib::shapeFunctionInterpolate(local_pressure, N,
115 pressure_int_pt);
116 NumLib::shapeFunctionInterpolate(local_velocity, N,
117 velocity_int_pt);
118 NumLib::shapeFunctionInterpolate(local_enthalpy, N,
119 enthalpy_int_pt);
120
121 vars.liquid_phase_pressure = pressure_int_pt;
122 vars.enthalpy = enthalpy_int_pt;
123
124 double liquid_water_density =
125 liquid_phase
126 .property(
128 .template value<double>(vars, pos, 0, 0);
129
130 double const vapour_water_density =
131 gas_phase
132 .property(
134 .template value<double>(vars, pos, 0, 0);
135
136 double const h_sat_liq_w =
137 liquid_phase
138 .property(
140 .template value<double>(vars, pos, 0, 0);
141
142 double const h_sat_vap_w =
143 gas_phase
144 .property(
146 .template value<double>(vars, pos, 0, 0);
147
148 double const dryness =
149 std::max(0., (enthalpy_int_pt - h_sat_liq_w) /
150 (h_sat_vap_w - h_sat_liq_w));
151
152 double const T_int_pt =
153 (dryness == 0)
154 ? liquid_phase
155 .property(
157 .template value<double>(vars, pos, 0, 0)
158 : gas_phase
160 saturation_temperature)
161 .template value<double>(vars, pos, 0, 0);
162
163 vars.temperature = T_int_pt;
164
165 // For the calculation of the void fraction of vapour,
166 // see Rohuani, Z., and E. Axelsson. "Calculation of volume void
167 // fraction in a subcooled and quality region." International
168 // Journal of Heat and Mass Transfer 17 (1970): 383-393.
169
170 // Profile parameter of drift flux
171 double const C_0 = 1 + 0.12 * (1 - dryness);
172
173 // For the surface tension calculation, see
174 // Cooper, J. R., and R. B. Dooley. "IAPWS release on surface
175 // tension of ordinary water substance." International Association
176 // for the Properties of Water and Steam (1994).
177 double const sigma_gl = 0.2358 *
178 std::pow((1 - T_int_pt / 647.096), 1.256) *
179 (1 - 0.625 * (1 - T_int_pt / 647.096));
180 // drift flux velocity
181 double const u_gu =
182 1.18 * (1 - dryness) *
183 std::pow((9.81) * sigma_gl *
184 (liquid_water_density - vapour_water_density),
185 0.25) /
186 std::pow(liquid_water_density, 0.5);
187
188 // solving void fraction of vapour using local Newton
189 // iteration.
190 double alpha = 0;
191 if (dryness != 0)
192 {
193 // Local Newton solver
194 using LocalJacobianMatrix =
195 Eigen::Matrix<double, 1, 1, Eigen::RowMajor>;
196 using LocalResidualVector = Eigen::Matrix<double, 1, 1>;
197 using LocalUnknownVector = Eigen::Matrix<double, 1, 1>;
198 LocalJacobianMatrix J_loc;
199
200 Eigen::PartialPivLU<LocalJacobianMatrix> linear_solver(1);
201
202 auto const update_residual = [&](LocalResidualVector& residual)
203 {
204 residual(0) = dryness * liquid_water_density *
205 (alpha * vapour_water_density +
206 (1 - alpha) * liquid_water_density) *
207 velocity_int_pt -
208 alpha * C_0 * dryness * liquid_water_density *
209 (alpha * vapour_water_density +
210 (1 - alpha) * liquid_water_density) *
211 velocity_int_pt -
212 alpha * C_0 * (1 - dryness) *
213 vapour_water_density *
214 (alpha * vapour_water_density +
215 (1 - alpha) * liquid_water_density) *
216 velocity_int_pt -
217 alpha * vapour_water_density *
218 liquid_water_density * u_gu;
219 };
220
221 auto const update_jacobian = [&](LocalJacobianMatrix& jacobian)
222 {
223 jacobian(0) =
224 dryness * liquid_water_density * velocity_int_pt *
225 (vapour_water_density - liquid_water_density) -
226 (C_0 * dryness * liquid_water_density +
227 C_0 * (1 - dryness) * vapour_water_density) *
228 (2 * alpha * vapour_water_density +
229 (1 - 2 * alpha) * liquid_water_density) *
230 velocity_int_pt -
231 vapour_water_density * liquid_water_density * u_gu;
232 };
233
234 auto const update_solution =
235 [&](LocalUnknownVector const& increment)
236 {
237 // increment solution vectors
238 alpha += increment[0];
239 };
240
241 const int maximum_iterations(20);
242 const double residuum_tolerance(1.e-10);
243 const double increment_tolerance(0);
244
245 auto newton_solver = NumLib::NewtonRaphson(
246 linear_solver, update_jacobian, update_residual,
247 update_solution,
248 {maximum_iterations, residuum_tolerance,
249 increment_tolerance});
250
251 auto const success_iterations = newton_solver.solve(J_loc);
252
253 if (!success_iterations)
254 {
255 WARN(
256 "Attention! Steam void fraction has not been correctly "
257 "calculated!");
258 }
259 }
260
261 if (alpha == 0)
262 {
263 liquid_water_density =
264 liquid_phase
266 .template value<double>(vars, pos, 0, 0);
267 }
268
269 double const mix_density = vapour_water_density * alpha +
270 liquid_water_density * (1 - alpha);
271
272 // slip parameter between two phases
273 double const gamma =
274 alpha * liquid_water_density * vapour_water_density *
275 mix_density / (1 - alpha) /
276 std::pow((alpha * C_0 * vapour_water_density +
277 (1 - alpha * C_0) * liquid_water_density),
278 2) *
279 std::pow((C_0 - 1) * velocity_int_pt + u_gu, 2);
280
281 double const neumann_ip_values =
282 _data.coefficients.pressure * mix_density * velocity_int_pt +
283 _data.coefficients.velocity *
284 (mix_density * velocity_int_pt * velocity_int_pt + gamma) +
285 _data.coefficients.enthalpy * mix_density * velocity_int_pt *
286 velocity_int_pt * velocity_int_pt * 0.5;
287 _local_rhs.noalias() += N.transpose() * neumann_ip_values * w;
288 }
289
290 b.add(indices_current_variable, _local_rhs);
291 }
292
293private:
297};
298
299} // namespace ProcessLib
MathLib::EigenMatrix GlobalMatrix
MathLib::EigenVector GlobalVector
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
void add(IndexType rowId, double v)
add entry
Definition EigenVector.h:70
std::optional< int > solve(JacobianMatrix &jacobian) const
void setElementID(std::size_t element_id)
GenericNaturalBoundaryConditionLocalAssembler(MeshLib::Element const &e, bool is_axially_symmetric, NumLib::GenericIntegrationMethod const &integration_method)
std::vector< NAndWeight, Eigen::aligned_allocator< NAndWeight > > const _ns_and_weights
WellboreCompensateNeumannBoundaryConditionLocalAssembler(MeshLib::Element const &e, std::size_t const local_matrix_size, NumLib::GenericIntegrationMethod const &integration_method, bool const is_axially_symmetric, WellboreCompensateNeumannBoundaryConditionData const &data)
void assemble(std::size_t const mesh_item_id, NumLib::LocalToGlobalIndexMap const &dof_table_boundary, double const, std::vector< GlobalVector * > const &x, int const process_id, GlobalMatrix *, GlobalVector &b, GlobalMatrix *) override
void shapeFunctionInterpolate(const NodalValues &, const ShapeMatrix &)
std::vector< GlobalIndexType > getIndices(std::size_t const mesh_item_id, NumLib::LocalToGlobalIndexMap const &dof_table)