/home/runner/work/amr-wind/amr-wind/amr-wind/transport_models/TwoPhaseTransport.H Source File

AMR-Wind API: /home/runner/work/amr-wind/amr-wind/amr-wind/transport_models/TwoPhaseTransport.H Source File
AMR-Wind 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>
7#include "AMReX_ParmParse.H"
8#include "AMReX_REAL.H"
9
10using namespace amrex::literals;
11
12namespace amr_wind::transport {
13
17class TwoPhaseTransport : public TransportModel::Register<TwoPhaseTransport>
18{
19public:
20 static constexpr bool constant_properties = false;
21
22 static std::string identifier() { return "TwoPhaseTransport"; }
23
24 explicit TwoPhaseTransport(const CFDSim& sim)
25 : m_repo(sim.repo()), m_physics_mgr(sim.physics_manager())
26 {
27 amrex::ParmParse pp("transport");
28 pp.query("viscosity_fluid1", m_mu1);
29 pp.query("viscosity_fluid2", m_mu2);
30 pp.query("laminar_prandtl_fluid1", m_Pr1);
31 pp.query("laminar_prandtl_fluid2", m_Pr2);
32 pp.query("turbulent_prandtl", m_Prt);
33
34 // Check for single-phase quantities and warn
35 if (pp.contains("viscosity")) {
36 amrex::Print()
37 << "WARNING: single-phase viscosity has been specified but "
38 "will not be used! (TwoPhaseTransport)\n";
39 }
40 if (pp.contains("laminar_prandtl")) {
41 amrex::Print()
42 << "WARNING: single-phase laminar_prandtl has been specified "
43 "but will not be used! (TwoPhaseTransport)\n";
44 }
45
46 // Backwards compatibility
47 amrex::ParmParse pp_boussinesq_buoyancy("BoussinesqBuoyancy");
48 amrex::ParmParse pp_abl("ABL");
49 if (pp.contains("thermal_expansion_coefficient")) {
50 pp.get("thermal_expansion_coefficient", m_constant_beta);
51 if (pp_boussinesq_buoyancy.contains("thermal_expansion_coeff")) {
52 amrex::Print()
53 << "WARNING: BoussinesqBuoyancy.thermal_expansion_coeff "
54 "option has been deprecated in favor of "
55 "transport.thermal_expansion_coefficient. Ignoring the "
56 "BoussinesqBuoyancy option in favor of the transport "
57 "option."
58 << '\n';
59 }
60 } else if (pp_boussinesq_buoyancy.contains("thermal_expansion_coeff")) {
61 amrex::Print()
62 << "WARNING: BoussinesqBuoyancy.thermal_expansion_coeff option "
63 "has been deprecated in favor of "
64 "transport.thermal_expansion_coefficient. Please replace "
65 "this option."
66 << '\n';
67 pp_boussinesq_buoyancy.get(
68 "thermal_expansion_coeff", m_constant_beta);
69 }
70
71 if (pp.contains("reference_temperature")) {
72 pp.get("reference_temperature", m_reference_temperature);
73 if (pp_boussinesq_buoyancy.contains("reference_temperature")) {
74 amrex::Print()
75 << "WARNING: BoussinesqBuoyancy.reference_temperature "
76 "option has been deprecated in favor of "
77 "transport.reference_temperature. Ignoring the "
78 "BoussinesqBuoyancy option in favor of the transport "
79 "option."
80 << '\n';
81 } else if (pp_abl.contains("reference_temperature")) {
82 amrex::Print()
83 << "WARNING: ABL.reference_temperature "
84 "option has been deprecated in favor of "
85 "transport.reference_temperature. Ignoring the "
86 "ABL option in favor of the transport "
87 "option."
88 << '\n';
89 }
90 } else if (pp_boussinesq_buoyancy.contains("reference_temperature")) {
91 amrex::Print()
92 << "WARNING: BoussinesqBuoyancy.reference_temperature option "
93 "has been deprecated in favor of "
94 "transport.reference_temperature. Please replace "
95 "this option."
96 << '\n';
97 pp_boussinesq_buoyancy.get(
98 "reference_temperature", m_reference_temperature);
99 } else if (pp_abl.contains("reference_temperature")) {
100 amrex::Print() << "WARNING: ABL.reference_temperature option "
101 "has been deprecated in favor of "
102 "transport.reference_temperature. Please replace "
103 "this option."
104 << '\n';
105 pp_abl.get("reference_temperature", m_reference_temperature);
106 }
107 }
108
109 ~TwoPhaseTransport() override = default;
110
111 [[nodiscard]] amrex::Real laminar_prandtl1() const { return m_Pr1; }
112 [[nodiscard]] amrex::Real laminar_prandtl2() const { return m_Pr2; }
113
114 [[nodiscard]] amrex::Real turbulent_prandtl() const { return m_Prt; }
115
116 static amrex::Real laminar_schmidt(const std::string& scalar_name)
117 {
118 amrex::ParmParse pp("transport");
119 const std::string key = scalar_name + "_laminar_schmidt";
120 amrex::Real lam_schmidt = 1.0_rt;
121 pp.query(key, lam_schmidt);
122 return lam_schmidt;
123 }
124
125 static amrex::Real turbulent_schmidt(const std::string& scalar_name)
126 {
127 amrex::ParmParse pp("transport");
128 const std::string key = scalar_name + "_turbulent_schmidt";
129 amrex::Real turb_schmidt = 1.0_rt;
130 pp.query(key, turb_schmidt);
131 return turb_schmidt;
132 }
133
135 std::unique_ptr<ScratchField> mu() override
136 {
137 // Select the interface capturing method
138 auto mu = m_repo.create_scratch_field(1, m_ngrow);
139
140 auto ifacetype = get_iface_method();
141 if (ifacetype == InterfaceCapturingMethod::VOF) {
142
143 const auto& vof = m_repo.get_field("vof");
144
145 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
146 const auto& volfrac_arrs = vof(lev).const_arrays();
147 const auto& visc_arrs = (*mu)(lev).arrays();
148 const amrex::Real mu1 = m_mu1;
149 const amrex::Real mu2 = m_mu2;
150 amrex::ParallelFor(
151 (*mu)(lev), mu->num_grow(),
152 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) {
153 visc_arrs[nbx](i, j, k) =
154 (mu1 * volfrac_arrs[nbx](i, j, k)) +
155 (mu2 * (1.0_rt - volfrac_arrs[nbx](i, j, k)));
156 });
157 }
158 amrex::Gpu::streamSynchronize();
159
160 } else if (ifacetype == InterfaceCapturingMethod::LS) {
161
162 const auto& levelset = m_repo.get_field("levelset");
163 const auto& geom = m_repo.mesh().Geom();
164
165 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
166 const auto& dx = geom[lev].CellSizeArray();
167 const auto& visc_arrs = (*mu)(lev).arrays();
168 const auto& phi_arrs = levelset(lev).const_arrays();
169 const amrex::Real eps =
170 std::cbrt(2.0_rt * dx[0] * dx[1] * dx[2]);
171 const amrex::Real mu1 = m_mu1;
172 const amrex::Real mu2 = m_mu2;
173
174 amrex::ParallelFor(
175 (*mu)(lev), mu->num_grow(),
176 [=] AMREX_GPU_DEVICE(int nbx, int i, int j, int k) {
177 amrex::Real smooth_heaviside;
178 if (phi_arrs[nbx](i, j, k) > eps) {
179 smooth_heaviside = 1.0_rt;
180 } else if (phi_arrs[nbx](i, j, k) < -eps) {
181 smooth_heaviside = 0.0_rt;
182 } else {
183 smooth_heaviside =
184 0.5_rt *
185 (1.0_rt + phi_arrs[nbx](i, j, k) / eps +
186 1.0_rt / std::numbers::pi_v<amrex::Real> *
187 std::sin(
188 phi_arrs[nbx](i, j, k) *
189 std::numbers::pi_v<amrex::Real> /
190 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> /
259 eps));
260 }
261 visc_arrs[nbx](i, j, k) =
262 (mu1 / Pr1 * smooth_heaviside) +
263 (mu2 / Pr2 * (1.0_rt - smooth_heaviside));
264 });
265 }
266 }
267 amrex::Gpu::streamSynchronize();
268 return alpha;
269 }
270
271 std::unique_ptr<ScratchField>
272 scalar_diffusivity(const std::string& scalar_name) override
273 {
274 amrex::Real lam_schmidt = laminar_schmidt(scalar_name);
275
276 amrex::Real inv_schmidt = 1.0_rt / lam_schmidt;
277 auto diff = mu();
278 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
279 (*diff)(lev).mult(inv_schmidt);
280 }
281
282 return diff;
283 }
284
286 [[nodiscard]] std::unique_ptr<ScratchField> beta() const override
287 {
288 auto beta = m_repo.create_scratch_field(1, m_ngrow);
289 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
290#ifdef AMREX_USE_OMP
291#pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
292#endif
293 for (amrex::MFIter mfi((*beta)(lev)); mfi.isValid(); ++mfi) {
294 const auto& bx = mfi.tilebox();
295 const auto& beta_arr = (*beta)(lev).array(mfi);
296 beta_impl(lev, mfi, bx, beta_arr);
297 }
298 }
299 return beta;
300 }
301
304 const int lev,
305 const amrex::MFIter& mfi,
306 const amrex::Box& bx,
307 const amrex::Array4<amrex::Real>& beta) const override
308 {
309
310 if (m_constant_beta > 0.0_rt) {
311 const amrex::Real beta_val = m_constant_beta;
312 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
313 beta(i, j, k) = beta_val;
314 });
315 } else if (m_repo.field_exists("reference_temperature")) {
316 const auto& temp0 = m_repo.get_field("reference_temperature");
317 const auto& temp0_arr = temp0(lev).const_array(mfi);
318 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
319 beta(i, j, k) = 1.0_rt / temp0_arr(i, j, k);
320 });
321 } else {
322 const amrex::Real beta_val = 1.0_rt / m_reference_temperature;
323 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
324 beta(i, j, k) = beta_val;
325 });
326 }
327
328 auto ifacetype = get_iface_method();
329 if (ifacetype == InterfaceCapturingMethod::VOF) {
330 const auto& vof = m_repo.get_field("vof");
331 const auto& vof_arr = vof(lev).const_array(mfi);
332 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
333 if (vof_arr(i, j, k) > constants::TIGHT_TOL) {
334 beta(i, j, k) = 0.0_rt;
335 }
336 });
337 } else if (ifacetype == InterfaceCapturingMethod::LS) {
338 const auto& levelset = m_repo.get_field("levelset");
339 const auto& dx = m_repo.mesh().Geom(lev).CellSizeArray();
340 const auto& phi_arr = levelset(lev).const_array(mfi);
341 const amrex::Real eps = std::cbrt(2.0_rt * dx[0] * dx[1] * dx[2]);
342 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
343 amrex::Real smooth_heaviside;
344 if (phi_arr(i, j, k) > eps) {
345 smooth_heaviside = 1.0_rt;
346 } else if (phi_arr(i, j, k) < -eps) {
347 smooth_heaviside = 0.0_rt;
348 } else {
349 smooth_heaviside =
350 0.5_rt *
351 (1.0_rt + phi_arr(i, j, k) / eps +
352 1.0_rt / std::numbers::pi_v<amrex::Real> *
353 std::sin(
354 phi_arr(i, j, k) *
355 std::numbers::pi_v<amrex::Real> / eps));
356 }
357 beta(i, j, k) *= (1.0_rt - smooth_heaviside);
358 });
359 }
360 }
361
362 [[nodiscard]] amrex::Real reference_temperature() const override
363 {
365 }
366
368 [[nodiscard]] std::unique_ptr<ScratchField> ref_theta() const override
369 {
370 if (m_reference_temperature < 0.0_rt) {
371 amrex::Abort("Reference temperature was not set");
372 }
373
374 auto ref_theta = m_repo.create_scratch_field(1, m_ngrow);
375 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
376#ifdef AMREX_USE_OMP
377#pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
378#endif
379 for (amrex::MFIter mfi((*ref_theta)(lev)); mfi.isValid(); ++mfi) {
380 const auto& bx = mfi.tilebox();
381 const auto& ref_theta_arr = (*ref_theta)(lev).array(mfi);
382 ref_theta_impl(lev, mfi, bx, ref_theta_arr);
383 }
384 }
385 return ref_theta;
386 }
387
390 const int lev,
391 const amrex::MFIter& mfi,
392 const amrex::Box& bx,
393 const amrex::Array4<amrex::Real>& ref_theta) const override
394 {
395 if (m_reference_temperature < 0.0_rt) {
396 amrex::Abort("Reference temperature was not set");
397 }
398
399 if (m_repo.field_exists("reference_temperature")) {
400 auto& temp0 = m_repo.get_field("reference_temperature");
401 const auto& temp0_arr = temp0(lev).const_array(mfi);
402 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
403 ref_theta(i, j, k) = temp0_arr(i, j, k);
404 });
405 } else {
406 const amrex::Real ref_theta_val = m_reference_temperature;
407 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
408 ref_theta(i, j, k) = ref_theta_val;
409 });
410 }
411 }
412
413private:
416
419
421 amrex::Real m_mu1{1.0e-3_rt};
422
424 amrex::Real m_mu2{1.0e-5_rt};
425
427 amrex::Real m_Pr1{7.2_rt};
428
430 amrex::Real m_Pr2{0.7_rt};
431
433 amrex::Real m_Prt{1.0_rt};
434
436 amrex::Real m_constant_beta{0.0_rt};
437
439 amrex::Real m_reference_temperature{-1.0_rt};
440
442 {
443 if (!m_physics_mgr.contains("MultiPhase")) {
444 amrex::Abort("TwoPhaseTransport requires MultiPhase physics");
445 }
446 const auto& multiphase = m_physics_mgr.get<MultiPhase>();
447 return multiphase.interface_capturing_method();
448 }
449};
450
451} // namespace amr_wind::transport
452
453#endif /* TWOPHASETRANSPORT_H */
Definition CFDSim.H:54
Definition FieldRepo.H:86
Definition MultiPhase.H:31
Definition Physics.H:100
amrex::Real laminar_prandtl1() const
Definition TwoPhaseTransport.H:111
std::unique_ptr< ScratchField > ref_theta() const override
Return the reference temperature.
Definition TwoPhaseTransport.H:368
amrex::Real reference_temperature() const override
Definition TwoPhaseTransport.H:362
amrex::Real m_Prt
Turbulent Prandtl number.
Definition TwoPhaseTransport.H:433
std::unique_ptr< ScratchField > beta() const override
Return the thermal expansion coefficient.
Definition TwoPhaseTransport.H:286
std::unique_ptr< ScratchField > mu() override
Return the dynamic visocity field.
Definition TwoPhaseTransport.H:135
std::unique_ptr< ScratchField > scalar_diffusivity(const std::string &scalar_name) override
Definition TwoPhaseTransport.H:272
void ref_theta_impl(const int lev, const amrex::MFIter &mfi, const amrex::Box &bx, const amrex::Array4< amrex::Real > &ref_theta) const override
Compute the reference temperature.
Definition TwoPhaseTransport.H:389
amrex::Real turbulent_prandtl() const
Definition TwoPhaseTransport.H:114
InterfaceCapturingMethod get_iface_method() const
Definition TwoPhaseTransport.H:441
amrex::Real m_reference_temperature
Reference temperature.
Definition TwoPhaseTransport.H:439
amrex::Real m_Pr1
Phase 1 (liquid) Prandtl number.
Definition TwoPhaseTransport.H:427
void beta_impl(const int lev, const amrex::MFIter &mfi, const amrex::Box &bx, const amrex::Array4< amrex::Real > &beta) const override
Compute the thermal expansion coefficient.
Definition TwoPhaseTransport.H:303
static constexpr bool constant_properties
Definition TwoPhaseTransport.H:20
TwoPhaseTransport(const CFDSim &sim)
Definition TwoPhaseTransport.H:24
amrex::Real m_constant_beta
Constant thermal expansion coefficient.
Definition TwoPhaseTransport.H:436
amrex::Real laminar_prandtl2() const
Definition TwoPhaseTransport.H:112
amrex::Real m_mu1
Phase 1 (liquid) dynamic molecular viscosity.
Definition TwoPhaseTransport.H:421
FieldRepo & m_repo
Reference to the field repository (for creating scratch fields)
Definition TwoPhaseTransport.H:415
static std::string identifier()
Definition TwoPhaseTransport.H:22
amrex::Real m_mu2
Phase 2 (gas) dynamic molecular viscosity.
Definition TwoPhaseTransport.H:424
static amrex::Real turbulent_schmidt(const std::string &scalar_name)
Definition TwoPhaseTransport.H:125
amrex::Real m_Pr2
Phase 2 (gas) Prandtl number.
Definition TwoPhaseTransport.H:430
static amrex::Real laminar_schmidt(const std::string &scalar_name)
Definition TwoPhaseTransport.H:116
const PhysicsMgr & m_physics_mgr
Reference to the physics manager.
Definition TwoPhaseTransport.H:418
std::unique_ptr< ScratchField > alpha() override
Return the thermal diffusivity field (later divided by density, though)
Definition TwoPhaseTransport.H:203
static constexpr amrex::Real TIGHT_TOL
A tight tolerance.
Definition constants.H:17
Definition height_functions.H:8
Definition CFDSim.H:26
InterfaceCapturingMethod
Definition MultiPhase.H:25
@ VOF
Volume of fluid.
Definition MultiPhase.H:26
@ LS
Levelset.
Definition MultiPhase.H:27