/home/runner/work/kynema-sgf/kynema-sgf/src/transport_models/TwoPhaseTransport.H Source File

Kynema-SGF API: /home/runner/work/kynema-sgf/kynema-sgf/src/transport_models/TwoPhaseTransport.H Source File
Kynema-SGF API v0.1.0
CFD solver for wind plant simulations
Loading...
Searching...
No Matches
TwoPhaseTransport.H
Go to the documentation of this file.
1#ifndef TWOPHASETRANSPORT_H
2#define TWOPHASETRANSPORT_H
3
4#include <numbers>
8#include "AMReX_ParmParse.H"
9#include "AMReX_REAL.H"
10
11using namespace amrex::literals;
12
13namespace kynema_sgf::transport {
14
18class TwoPhaseTransport : public TransportModel::Register<TwoPhaseTransport>
19{
20public:
21 static constexpr bool constant_properties = false;
22
23 static std::string identifier() { return "TwoPhaseTransport"; }
24
25 explicit TwoPhaseTransport(const CFDSim& sim)
26 : m_repo(sim.repo()), m_physics_mgr(sim.physics_manager())
27 {
28 amrex::ParmParse pp("transport");
29 pp.query("viscosity_fluid1", m_mu1);
30 pp.query("viscosity_fluid2", m_mu2);
31 pp.query("laminar_prandtl_fluid1", m_Pr1);
32 pp.query("laminar_prandtl_fluid2", m_Pr2);
33 pp.query("turbulent_prandtl", m_Prt);
34
35 // Check for single-phase quantities and warn
36 if (pp.contains("viscosity")) {
37 amrex::Print()
38 << "WARNING: single-phase viscosity has been specified but "
39 "will not be used! (TwoPhaseTransport)\n";
40 }
41 if (pp.contains("laminar_prandtl")) {
42 amrex::Print()
43 << "WARNING: single-phase laminar_prandtl has been specified "
44 "but will not be used! (TwoPhaseTransport)\n";
45 }
46
47 // Backwards compatibility
48 amrex::ParmParse pp_boussinesq_buoyancy("BoussinesqBuoyancy");
49 amrex::ParmParse pp_abl("ABL");
50 if (pp.contains("thermal_expansion_coefficient")) {
51 pp.get("thermal_expansion_coefficient", m_constant_beta);
52 if (pp_boussinesq_buoyancy.contains("thermal_expansion_coeff")) {
53 amrex::Print()
54 << "WARNING: BoussinesqBuoyancy.thermal_expansion_coeff "
55 "option has been deprecated in favor of "
56 "transport.thermal_expansion_coefficient. Ignoring the "
57 "BoussinesqBuoyancy option in favor of the transport "
58 "option."
59 << '\n';
60 }
61 } else if (pp_boussinesq_buoyancy.contains("thermal_expansion_coeff")) {
62 amrex::Print()
63 << "WARNING: BoussinesqBuoyancy.thermal_expansion_coeff option "
64 "has been deprecated in favor of "
65 "transport.thermal_expansion_coefficient. Please replace "
66 "this option."
67 << '\n';
68 pp_boussinesq_buoyancy.get(
69 "thermal_expansion_coeff", m_constant_beta);
70 }
71
72 if (pp.contains("reference_temperature")) {
73 pp.get("reference_temperature", m_reference_temperature);
74 if (pp_boussinesq_buoyancy.contains("reference_temperature")) {
75 amrex::Print()
76 << "WARNING: BoussinesqBuoyancy.reference_temperature "
77 "option has been deprecated in favor of "
78 "transport.reference_temperature. Ignoring the "
79 "BoussinesqBuoyancy option in favor of the transport "
80 "option."
81 << '\n';
82 } else if (pp_abl.contains("reference_temperature")) {
83 amrex::Print()
84 << "WARNING: ABL.reference_temperature "
85 "option has been deprecated in favor of "
86 "transport.reference_temperature. Ignoring the "
87 "ABL option in favor of the transport "
88 "option."
89 << '\n';
90 }
91 } else if (pp_boussinesq_buoyancy.contains("reference_temperature")) {
92 amrex::Print()
93 << "WARNING: BoussinesqBuoyancy.reference_temperature option "
94 "has been deprecated in favor of "
95 "transport.reference_temperature. Please replace "
96 "this option."
97 << '\n';
98 pp_boussinesq_buoyancy.get(
99 "reference_temperature", m_reference_temperature);
100 } else if (pp_abl.contains("reference_temperature")) {
101 amrex::Print() << "WARNING: ABL.reference_temperature option "
102 "has been deprecated in favor of "
103 "transport.reference_temperature. Please replace "
104 "this option."
105 << '\n';
106 pp_abl.get("reference_temperature", m_reference_temperature);
107 }
108 }
109
110 ~TwoPhaseTransport() override = default;
111
112 [[nodiscard]] amrex::Real laminar_prandtl1() const { return m_Pr1; }
113 [[nodiscard]] amrex::Real laminar_prandtl2() const { return m_Pr2; }
114
115 [[nodiscard]] amrex::Real turbulent_prandtl() const { return m_Prt; }
116
117 static amrex::Real laminar_schmidt(const std::string& scalar_name)
118 {
119 amrex::ParmParse pp("transport");
120 const std::string key = scalar_name + "_laminar_schmidt";
121 amrex::Real lam_schmidt = 1.0_rt;
122 pp.query(key, lam_schmidt);
123 return lam_schmidt;
124 }
125
126 static amrex::Real turbulent_schmidt(const std::string& scalar_name)
127 {
128 amrex::ParmParse pp("transport");
129 const std::string key = scalar_name + "_turbulent_schmidt";
130 amrex::Real turb_schmidt = 1.0_rt;
131 pp.query(key, turb_schmidt);
132 return turb_schmidt;
133 }
134
136 std::unique_ptr<ScratchField> mu() override
137 {
138 // Select the interface capturing method
139 auto mu = m_repo.create_scratch_field(1, m_ngrow);
140
141 auto ifacetype = get_iface_method();
142 if (ifacetype == InterfaceCapturingMethod::VOF) {
143
144 const auto& vof = m_repo.get_field("vof");
145
146 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
147 const auto& volfrac_arrs = vof(lev).const_arrays();
148 const auto& visc_arrs = (*mu)(lev).arrays();
149 const amrex::Real mu1 = m_mu1;
150 const amrex::Real mu2 = m_mu2;
151 amrex::ParallelFor(
152 (*mu)(lev), mu->num_grow(),
153 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) {
154 visc_arrs[nbx](i, j, k) =
155 (mu1 * volfrac_arrs[nbx](i, j, k)) +
156 (mu2 * (1.0_rt - volfrac_arrs[nbx](i, j, k)));
157 });
158 }
159 amrex::Gpu::streamSynchronize();
160
161 } else if (ifacetype == InterfaceCapturingMethod::LS) {
162
163 const auto& levelset = m_repo.get_field("levelset");
164 const auto& geom = m_repo.mesh().Geom();
165
166 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
167 const auto& dx = geom[lev].CellSizeArray();
168 const auto& visc_arrs = (*mu)(lev).arrays();
169 const auto& phi_arrs = levelset(lev).const_arrays();
170 const amrex::Real eps =
171 std::cbrt(2.0_rt * dx[0] * dx[1] * dx[2]);
172 const amrex::Real mu1 = m_mu1;
173 const amrex::Real mu2 = m_mu2;
174
175 amrex::ParallelFor(
176 (*mu)(lev), mu->num_grow(),
177 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) {
178 amrex::Real smooth_heaviside;
179 if (phi_arrs[nbx](i, j, k) > eps) {
180 smooth_heaviside = 1.0_rt;
181 } else if (phi_arrs[nbx](i, j, k) < -eps) {
182 smooth_heaviside = 0.0_rt;
183 } else {
184 smooth_heaviside =
185 0.5_rt *
186 (1.0_rt + (phi_arrs[nbx](i, j, k) / eps) +
187 (1.0_rt / std::numbers::pi_v<amrex::Real> *
188 std::sin(
189 phi_arrs[nbx](i, j, k) *
190 std::numbers::pi_v<amrex::Real> / eps)));
191 }
192 visc_arrs[nbx](i, j, k) =
193 (mu1 * smooth_heaviside) +
194 (mu2 * (1.0_rt - smooth_heaviside));
195 });
196 }
197 amrex::Gpu::streamSynchronize();
198 }
199 return mu;
200 }
201
203 std::unique_ptr<ScratchField> alpha() override
204 {
205 // Select the interface capturing method
206 auto alpha = m_repo.create_scratch_field(1, m_ngrow);
207
208 auto ifacetype = get_iface_method();
209 if (ifacetype == InterfaceCapturingMethod::VOF) {
210
211 const auto& vof = m_repo.get_field("vof");
212
213 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
214 const auto& volfrac_arrs = vof(lev).const_arrays();
215 const auto& thdiff_arrs = (*alpha)(lev).arrays();
216 const amrex::Real mu1 = m_mu1;
217 const amrex::Real mu2 = m_mu2;
218 const amrex::Real Pr1 = m_Pr1;
219 const amrex::Real Pr2 = m_Pr2;
220 amrex::ParallelFor(
221 (*alpha)(lev), alpha->num_grow(),
222 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) {
223 thdiff_arrs[nbx](i, j, k) =
224 (mu1 / Pr1 * volfrac_arrs[nbx](i, j, k)) +
225 (mu2 / Pr2 * (1.0_rt - volfrac_arrs[nbx](i, j, k)));
226 });
227 }
228
229 } else if (ifacetype == InterfaceCapturingMethod::LS) {
230 const auto& levelset = m_repo.get_field("levelset");
231 const auto& geom = m_repo.mesh().Geom();
232
233 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
234 const auto& dx = geom[lev].CellSizeArray();
235 const auto& visc_arrs = (*alpha)(lev).arrays();
236 const auto& phi_arrs = levelset(lev).const_arrays();
237 const amrex::Real eps =
238 std::cbrt(2.0_rt * dx[0] * dx[1] * dx[2]);
239 const amrex::Real mu1 = m_mu1;
240 const amrex::Real mu2 = m_mu2;
241 const amrex::Real Pr1 = m_Pr1;
242 const amrex::Real Pr2 = m_Pr2;
243 amrex::ParallelFor(
244 (*alpha)(lev), alpha->num_grow(),
245 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) {
246 amrex::Real smooth_heaviside;
247 if (phi_arrs[nbx](i, j, k) > eps) {
248 smooth_heaviside = 1.0_rt;
249 } else if (phi_arrs[nbx](i, j, k) < -eps) {
250 smooth_heaviside = 0.0_rt;
251 } else {
252 smooth_heaviside =
253 0.5_rt *
254 (1.0_rt + (phi_arrs[nbx](i, j, k) / eps) +
255 (1.0_rt / std::numbers::pi_v<amrex::Real> *
256 std::sin(
257 phi_arrs[nbx](i, j, k) *
258 std::numbers::pi_v<amrex::Real> / eps)));
259 }
260 visc_arrs[nbx](i, j, k) =
261 (mu1 / Pr1 * smooth_heaviside) +
262 (mu2 / Pr2 * (1.0_rt - smooth_heaviside));
263 });
264 }
265 }
266 amrex::Gpu::streamSynchronize();
267 return alpha;
268 }
269
270 std::unique_ptr<ScratchField>
271 scalar_diffusivity(const std::string& scalar_name) override
272 {
273 amrex::Real lam_schmidt = laminar_schmidt(scalar_name);
274
275 amrex::Real inv_schmidt = 1.0_rt / lam_schmidt;
276 auto diff = mu();
277 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
278 (*diff)(lev).mult(inv_schmidt);
279 }
280
281 return diff;
282 }
283
285 [[nodiscard]] std::unique_ptr<ScratchField> beta() const override
286 {
287 auto beta = m_repo.create_scratch_field(1, m_ngrow);
288 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
289 beta_fill(lev, (*beta)(lev));
290 }
291 return beta;
292 }
293
294 [[nodiscard]] amrex::Real reference_temperature() const override
295 {
297 }
298
299 void beta_fill(const int lev, amrex::MultiFab& beta_mf) const override
300 {
301 if (m_constant_beta > 0.0_rt) {
302 beta_mf.setVal(m_constant_beta);
303 } else if (m_repo.field_exists("reference_temperature")) {
304 const auto& temp0 = m_repo.get_field("reference_temperature");
305 auto const& beta_arrs = beta_mf.arrays();
306 auto const& temp0_arrs = temp0(lev).const_arrays();
307 amrex::ParallelFor(
308 beta_mf, amrex::IntVect(0), 1,
309 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k, int) {
310 beta_arrs[nbx](i, j, k) = 1.0_rt / temp0_arrs[nbx](i, j, k);
311 });
312 amrex::Gpu::streamSynchronize();
313 } else {
314 beta_mf.setVal(1.0_rt / m_reference_temperature);
315 }
316
317 auto ifacetype = get_iface_method();
318 if (ifacetype == InterfaceCapturingMethod::VOF) {
319 const auto& vof = m_repo.get_field("vof");
320 auto const& beta_arrs = beta_mf.arrays();
321 auto const& vof_arrs = vof(lev).const_arrays();
322 amrex::ParallelFor(
323 beta_mf, amrex::IntVect(0), 1,
324 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k, int) {
325 if (vof_arrs[nbx](i, j, k) > constants::VOF_TOL) {
326 beta_arrs[nbx](i, j, k) = 0.0_rt;
327 }
328 });
329 amrex::Gpu::streamSynchronize();
330 } else if (ifacetype == InterfaceCapturingMethod::LS) {
331 const auto& levelset = m_repo.get_field("levelset");
332 const auto& dx = m_repo.mesh().Geom(lev).CellSizeArray();
333 const amrex::Real eps = std::cbrt(2.0_rt * dx[0] * dx[1] * dx[2]);
334 auto const& beta_arrs = beta_mf.arrays();
335 auto const& phi_arrs = levelset(lev).const_arrays();
336 amrex::ParallelFor(
337 beta_mf, amrex::IntVect(0), 1,
338 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k, int) {
339 amrex::Real smooth_heaviside;
340 if (phi_arrs[nbx](i, j, k) > eps) {
341 smooth_heaviside = 1.0_rt;
342 } else if (phi_arrs[nbx](i, j, k) < -eps) {
343 smooth_heaviside = 0.0_rt;
344 } else {
345 smooth_heaviside =
346 0.5_rt *
347 (1.0_rt + (phi_arrs[nbx](i, j, k) / eps) +
348 (1.0_rt / std::numbers::pi_v<amrex::Real> *
349 std::sin(
350 phi_arrs[nbx](i, j, k) *
351 std::numbers::pi_v<amrex::Real> / eps)));
352 }
353 beta_arrs[nbx](i, j, k) *= (1.0_rt - smooth_heaviside);
354 });
355 amrex::Gpu::streamSynchronize();
356 }
357 }
358
359 void
360 ref_theta_fill(const int lev, amrex::MultiFab& ref_theta_mf) const override
361 {
362 if (m_reference_temperature < 0.0_rt) {
363 amrex::Abort("Reference temperature was not set");
364 }
365
366 if (m_repo.field_exists("reference_temperature")) {
367 const auto& temp0 = m_repo.get_field("reference_temperature");
368 amrex::MultiFab::Copy(ref_theta_mf, temp0(lev), 0, 0, 1, 0);
369 } else {
370 ref_theta_mf.setVal(m_reference_temperature);
371 }
372 }
373
375 [[nodiscard]] std::unique_ptr<ScratchField> ref_theta() const override
376 {
377 if (m_reference_temperature < 0.0_rt) {
378 amrex::Abort("Reference temperature was not set");
379 }
380
381 auto ref_theta = m_repo.create_scratch_field(1, m_ngrow);
382 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
383 ref_theta_fill(lev, (*ref_theta)(lev));
384 }
385 return ref_theta;
386 }
387
388private:
391
394
396 amrex::Real m_mu1{1.0e-3_rt};
397
399 amrex::Real m_mu2{1.0e-5_rt};
400
402 amrex::Real m_Pr1{7.2_rt};
403
405 amrex::Real m_Pr2{0.7_rt};
406
408 amrex::Real m_Prt{1.0_rt};
409
411 amrex::Real m_constant_beta{0.0_rt};
412
414 amrex::Real m_reference_temperature{-1.0_rt};
415
417 {
418 if (!m_physics_mgr.contains("MultiPhase")) {
419 amrex::Abort("TwoPhaseTransport requires MultiPhase physics");
420 }
421 const auto& multiphase = m_physics_mgr.get<MultiPhase>();
422 return multiphase.interface_capturing_method();
423 }
424};
425
426} // namespace kynema_sgf::transport
427
428#endif /* TWOPHASETRANSPORT_H */
Definition CFDSim.H:55
Definition FieldRepo.H:86
Definition MultiPhase.H:31
Definition Physics.H:100
static amrex::Real turbulent_schmidt(const std::string &scalar_name)
Definition TwoPhaseTransport.H:126
InterfaceCapturingMethod get_iface_method() const
Definition TwoPhaseTransport.H:416
amrex::Real reference_temperature() const override
Definition TwoPhaseTransport.H:294
std::unique_ptr< ScratchField > beta() const override
Return the thermal expansion coefficient.
Definition TwoPhaseTransport.H:285
amrex::Real laminar_prandtl1() const
Definition TwoPhaseTransport.H:112
amrex::Real m_Pr1
Phase 1 (liquid) Prandtl number.
Definition TwoPhaseTransport.H:402
void beta_fill(const int lev, amrex::MultiFab &beta_mf) const override
Definition TwoPhaseTransport.H:299
std::unique_ptr< ScratchField > mu() override
Return the dynamic visocity field.
Definition TwoPhaseTransport.H:136
std::unique_ptr< ScratchField > alpha() override
Return the thermal diffusivity field (later divided by density, though)
Definition TwoPhaseTransport.H:203
FieldRepo & m_repo
Reference to the field repository (for creating scratch fields)
Definition TwoPhaseTransport.H:390
TwoPhaseTransport(const CFDSim &sim)
Definition TwoPhaseTransport.H:25
const PhysicsMgr & m_physics_mgr
Reference to the physics manager.
Definition TwoPhaseTransport.H:393
amrex::Real m_constant_beta
Constant thermal expansion coefficient.
Definition TwoPhaseTransport.H:411
amrex::Real turbulent_prandtl() const
Definition TwoPhaseTransport.H:115
amrex::Real m_reference_temperature
Reference temperature.
Definition TwoPhaseTransport.H:414
std::unique_ptr< ScratchField > ref_theta() const override
Return the reference temperature.
Definition TwoPhaseTransport.H:375
static std::string identifier()
Definition TwoPhaseTransport.H:23
amrex::Real m_mu2
Phase 2 (gas) dynamic molecular viscosity.
Definition TwoPhaseTransport.H:399
static amrex::Real laminar_schmidt(const std::string &scalar_name)
Definition TwoPhaseTransport.H:117
void ref_theta_fill(const int lev, amrex::MultiFab &ref_theta_mf) const override
Definition TwoPhaseTransport.H:360
amrex::Real m_mu1
Phase 1 (liquid) dynamic molecular viscosity.
Definition TwoPhaseTransport.H:396
std::unique_ptr< ScratchField > scalar_diffusivity(const std::string &scalar_name) override
Definition TwoPhaseTransport.H:271
static constexpr bool constant_properties
Definition TwoPhaseTransport.H:21
amrex::Real m_Pr2
Phase 2 (gas) Prandtl number.
Definition TwoPhaseTransport.H:405
amrex::Real laminar_prandtl2() const
Definition TwoPhaseTransport.H:113
amrex::Real m_Prt
Turbulent Prandtl number.
Definition TwoPhaseTransport.H:408
static constexpr amrex::Real VOF_TOL
Tolerance for vof determining presence of liquid.
Definition constants.H:34
Definition height_functions.H:8
Definition CFDSim.H:27
InterfaceCapturingMethod
Definition MultiPhase.H:25
@ VOF
Volume of fluid.
Definition MultiPhase.H:26
@ LS
Levelset.
Definition MultiPhase.H:27