/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
TwoPhaseTransport.H
Go to the documentation of this file.
1#ifndef TWOPHASETRANSPORT_H
2#define TWOPHASETRANSPORT_H
3
6#include "AMReX_ParmParse.H"
7
8namespace amr_wind::transport {
9
13class TwoPhaseTransport : public TransportModel::Register<TwoPhaseTransport>
14{
15public:
16 static constexpr bool constant_properties = false;
17
18 static std::string identifier() { return "TwoPhaseTransport"; }
19
20 explicit TwoPhaseTransport(const CFDSim& sim)
21 : m_repo(sim.repo()), m_physics_mgr(sim.physics_manager())
22 {
23 amrex::ParmParse pp("transport");
24 pp.query("viscosity_fluid1", m_mu1);
25 pp.query("viscosity_fluid2", m_mu2);
26 pp.query("laminar_prandtl_fluid1", m_Pr1);
27 pp.query("laminar_prandtl_fluid2", m_Pr2);
28 pp.query("turbulent_prandtl", m_Prt);
29
30 // Check for single-phase quantities and warn
31 if (pp.contains("viscosity")) {
32 amrex::Print()
33 << "WARNING: single-phase viscosity has been specified but "
34 "will not be used! (TwoPhaseTransport)\n";
35 }
36 if (pp.contains("laminar_prandtl")) {
37 amrex::Print()
38 << "WARNING: single-phase laminar_prandtl has been specified "
39 "but will not be used! (TwoPhaseTransport)\n";
40 }
41
42 // Backwards compatibility
43 amrex::ParmParse pp_boussinesq_buoyancy("BoussinesqBuoyancy");
44 amrex::ParmParse pp_abl("ABL");
45 if (pp.contains("thermal_expansion_coefficient")) {
46 pp.get("thermal_expansion_coefficient", m_constant_beta);
47 if (pp_boussinesq_buoyancy.contains("thermal_expansion_coeff")) {
48 amrex::Print()
49 << "WARNING: BoussinesqBuoyancy.thermal_expansion_coeff "
50 "option has been deprecated in favor of "
51 "transport.thermal_expansion_coefficient. Ignoring the "
52 "BoussinesqBuoyancy option in favor of the transport "
53 "option."
54 << std::endl;
55 }
56 } else if (pp_boussinesq_buoyancy.contains("thermal_expansion_coeff")) {
57 amrex::Print()
58 << "WARNING: BoussinesqBuoyancy.thermal_expansion_coeff option "
59 "has been deprecated in favor of "
60 "transport.thermal_expansion_coefficient. Please replace "
61 "this option."
62 << std::endl;
63 pp_boussinesq_buoyancy.get(
64 "thermal_expansion_coeff", m_constant_beta);
65 }
66
67 if (pp.contains("reference_temperature")) {
68 pp.get("reference_temperature", m_reference_temperature);
69 if (pp_boussinesq_buoyancy.contains("reference_temperature")) {
70 amrex::Print()
71 << "WARNING: BoussinesqBuoyancy.reference_temperature "
72 "option has been deprecated in favor of "
73 "transport.reference_temperature. Ignoring the "
74 "BoussinesqBuoyancy option in favor of the transport "
75 "option."
76 << std::endl;
77 } else if (pp_abl.contains("reference_temperature")) {
78 amrex::Print()
79 << "WARNING: ABL.reference_temperature "
80 "option has been deprecated in favor of "
81 "transport.reference_temperature. Ignoring the "
82 "ABL option in favor of the transport "
83 "option."
84 << std::endl;
85 }
86 } else if (pp_boussinesq_buoyancy.contains("reference_temperature")) {
87 amrex::Print()
88 << "WARNING: BoussinesqBuoyancy.reference_temperature option "
89 "has been deprecated in favor of "
90 "transport.reference_temperature. Please replace "
91 "this option."
92 << std::endl;
93 pp_boussinesq_buoyancy.get(
94 "reference_temperature", m_reference_temperature);
95 } else if (pp_abl.contains("reference_temperature")) {
96 amrex::Print() << "WARNING: ABL.reference_temperature option "
97 "has been deprecated in favor of "
98 "transport.reference_temperature. Please replace "
99 "this option."
100 << std::endl;
101 pp_abl.get("reference_temperature", m_reference_temperature);
102 }
103 }
104
105 ~TwoPhaseTransport() override = default;
106
107 inline amrex::Real laminar_prandtl1() const { return m_Pr1; }
108 inline amrex::Real laminar_prandtl2() const { return m_Pr2; }
109
110 inline amrex::Real turbulent_prandtl() const { return m_Prt; }
111
112 static inline amrex::Real laminar_schmidt(const std::string& scalar_name)
113 {
114 amrex::ParmParse pp("transport");
115 const std::string key = scalar_name + "_laminar_schmidt";
116 amrex::Real lam_schmidt = 1.0;
117 pp.query(key.c_str(), lam_schmidt);
118 return lam_schmidt;
119 }
120
121 static inline amrex::Real turbulent_schmidt(const std::string& scalar_name)
122 {
123 amrex::ParmParse pp("transport");
124 const std::string key = scalar_name + "_turbulent_schmidt";
125 amrex::Real turb_schmidt = 1.0;
126 pp.query(key.c_str(), turb_schmidt);
127 return turb_schmidt;
128 }
129
131 inline std::unique_ptr<ScratchField> mu() override
132 {
133 // Select the interface capturing method
134 auto mu = m_repo.create_scratch_field(1, m_ngrow);
135
136 auto ifacetype = get_iface_method();
137 if (ifacetype == InterfaceCapturingMethod::VOF) {
138
139 const auto& vof = m_repo.get_field("vof");
140
141 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
142 const auto& volfrac_arrs = vof(lev).const_arrays();
143 const auto& visc_arrs = (*mu)(lev).arrays();
144 const amrex::Real mu1 = m_mu1;
145 const amrex::Real mu2 = m_mu2;
146 amrex::ParallelFor(
147 (*mu)(lev), mu->num_grow(),
148 [=] AMREX_GPU_DEVICE(
149 int nbx, int i, int j, int k) noexcept {
150 visc_arrs[nbx](i, j, k) =
151 mu1 * volfrac_arrs[nbx](i, j, k) +
152 mu2 * (1.0 - volfrac_arrs[nbx](i, j, k));
153 });
154 }
155 amrex::Gpu::streamSynchronize();
156
157 } else if (ifacetype == InterfaceCapturingMethod::LS) {
158
159 const auto& levelset = m_repo.get_field("levelset");
160 const auto& geom = m_repo.mesh().Geom();
161
162 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
163 const auto& dx = geom[lev].CellSizeArray();
164 const auto& visc_arrs = (*mu)(lev).arrays();
165 const auto& phi_arrs = levelset(lev).const_arrays();
166 const amrex::Real eps = std::cbrt(2. * dx[0] * dx[1] * dx[2]);
167 const amrex::Real mu1 = m_mu1;
168 const amrex::Real mu2 = m_mu2;
169
170 amrex::ParallelFor(
171 (*mu)(lev), mu->num_grow(),
172 [=] AMREX_GPU_DEVICE(
173 int nbx, int i, int j, int k) noexcept {
174 amrex::Real smooth_heaviside;
175 if (phi_arrs[nbx](i, j, k) > eps) {
176 smooth_heaviside = 1.0;
177 } else if (phi_arrs[nbx](i, j, k) < -eps) {
178 smooth_heaviside = 0.;
179 } else {
180 smooth_heaviside =
181 0.5 *
182 (1.0 + phi_arrs[nbx](i, j, k) / eps +
183 1.0 / M_PI *
184 std::sin(
185 phi_arrs[nbx](i, j, k) * M_PI / eps));
186 }
187 visc_arrs[nbx](i, j, k) =
188 mu1 * smooth_heaviside +
189 mu2 * (1.0 - smooth_heaviside);
190 });
191 }
192 amrex::Gpu::streamSynchronize();
193 }
194 return mu;
195 }
196
198 inline std::unique_ptr<ScratchField> alpha() override
199 {
200 // Select the interface capturing method
201 auto alpha = m_repo.create_scratch_field(1, m_ngrow);
202
203 auto ifacetype = get_iface_method();
204 if (ifacetype == InterfaceCapturingMethod::VOF) {
205
206 const auto& vof = m_repo.get_field("vof");
207
208 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
209 const auto& volfrac_arrs = vof(lev).const_arrays();
210 const auto& thdiff_arrs = (*alpha)(lev).arrays();
211 const amrex::Real mu1 = m_mu1;
212 const amrex::Real mu2 = m_mu2;
213 const amrex::Real Pr1 = m_Pr1;
214 const amrex::Real Pr2 = m_Pr2;
215 amrex::ParallelFor(
216 (*alpha)(lev), alpha->num_grow(),
217 [=] AMREX_GPU_DEVICE(
218 int nbx, int i, int j, int k) noexcept {
219 thdiff_arrs[nbx](i, j, k) =
220 mu1 / Pr1 * volfrac_arrs[nbx](i, j, k) +
221 mu2 / Pr2 * (1.0 - volfrac_arrs[nbx](i, j, k));
222 });
223 }
224
225 } else if (ifacetype == InterfaceCapturingMethod::LS) {
226 const auto& levelset = m_repo.get_field("levelset");
227 const auto& geom = m_repo.mesh().Geom();
228
229 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
230 const auto& dx = geom[lev].CellSizeArray();
231 const auto& visc_arrs = (*alpha)(lev).arrays();
232 const auto& phi_arrs = levelset(lev).const_arrays();
233 const amrex::Real eps = std::cbrt(2. * dx[0] * dx[1] * dx[2]);
234 const amrex::Real mu1 = m_mu1;
235 const amrex::Real mu2 = m_mu2;
236 const amrex::Real Pr1 = m_Pr1;
237 const amrex::Real Pr2 = m_Pr2;
238 amrex::ParallelFor(
239 (*alpha)(lev), alpha->num_grow(),
240 [=] AMREX_GPU_DEVICE(
241 int nbx, int i, int j, int k) noexcept {
242 amrex::Real smooth_heaviside;
243 if (phi_arrs[nbx](i, j, k) > eps) {
244 smooth_heaviside = 1.0;
245 } else if (phi_arrs[nbx](i, j, k) < -eps) {
246 smooth_heaviside = 0.;
247 } else {
248 smooth_heaviside =
249 0.5 *
250 (1.0 + phi_arrs[nbx](i, j, k) / eps +
251 1.0 / M_PI *
252 std::sin(
253 phi_arrs[nbx](i, j, k) * M_PI / eps));
254 }
255 visc_arrs[nbx](i, j, k) =
256 mu1 / Pr1 * smooth_heaviside +
257 mu2 / Pr2 * (1.0 - smooth_heaviside);
258 });
259 }
260 }
261 amrex::Gpu::streamSynchronize();
262 return alpha;
263 }
264
265 inline std::unique_ptr<ScratchField>
266 scalar_diffusivity(const std::string& scalar_name) override
267 {
268 amrex::Real lam_schmidt = laminar_schmidt(scalar_name);
269
270 amrex::Real inv_schmidt = 1.0 / lam_schmidt;
271 auto diff = mu();
272 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
273 (*diff)(lev).mult(inv_schmidt);
274 }
275
276 return diff;
277 }
278
280 inline std::unique_ptr<ScratchField> beta() const override
281 {
282 auto beta = m_repo.create_scratch_field(1, m_ngrow);
283 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
284#ifdef AMREX_USE_OMP
285#pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
286#endif
287 for (amrex::MFIter mfi((*beta)(lev)); mfi.isValid(); ++mfi) {
288 const auto& bx = mfi.tilebox();
289 const auto& beta_arr = (*beta)(lev).array(mfi);
290 beta_impl(lev, mfi, bx, beta_arr);
291 }
292 }
293 return beta;
294 }
295
297 inline void beta_impl(
298 const int lev,
299 const amrex::MFIter& mfi,
300 const amrex::Box& bx,
301 const amrex::Array4<amrex::Real>& beta) const override
302 {
303
304 if (m_constant_beta > 0.0) {
305 const amrex::Real beta_val = m_constant_beta;
306 amrex::ParallelFor(
307 bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
308 beta(i, j, k) = beta_val;
309 });
310 } else if (m_repo.field_exists("reference_temperature")) {
311 const auto& temp0 = m_repo.get_field("reference_temperature");
312 const auto& temp0_arr = temp0(lev).const_array(mfi);
313 amrex::ParallelFor(
314 bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
315 beta(i, j, k) = 1.0 / temp0_arr(i, j, k);
316 });
317 } else {
318 const amrex::Real beta_val = 1.0 / m_reference_temperature;
319 amrex::ParallelFor(
320 bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
321 beta(i, j, k) = beta_val;
322 });
323 }
324
325 auto ifacetype = get_iface_method();
326 if (ifacetype == InterfaceCapturingMethod::VOF) {
327 const auto& vof = m_repo.get_field("vof");
328 const auto& vof_arr = vof(lev).const_array(mfi);
329 amrex::ParallelFor(
330 bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
331 if (vof_arr(i, j, k) > constants::TIGHT_TOL) {
332 beta(i, j, k) = 0.0;
333 }
334 });
335 } else if (ifacetype == InterfaceCapturingMethod::LS) {
336 const auto& levelset = m_repo.get_field("levelset");
337 const auto& dx = m_repo.mesh().Geom(lev).CellSizeArray();
338 const auto& phi_arr = levelset(lev).const_array(mfi);
339 const amrex::Real eps = std::cbrt(2. * dx[0] * dx[1] * dx[2]);
340 amrex::ParallelFor(
341 bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
342 amrex::Real smooth_heaviside;
343 if (phi_arr(i, j, k) > eps) {
344 smooth_heaviside = 1.0;
345 } else if (phi_arr(i, j, k) < -eps) {
346 smooth_heaviside = 0.;
347 } else {
348 smooth_heaviside =
349 0.5 * (1.0 + phi_arr(i, j, k) / eps +
350 1.0 / M_PI *
351 std::sin(phi_arr(i, j, k) * M_PI / eps));
352 }
353 beta(i, j, k) *= (1 - smooth_heaviside);
354 });
355 }
356 }
357
358 inline amrex::Real reference_temperature() const override
359 {
361 }
362
364 inline std::unique_ptr<ScratchField> ref_theta() const override
365 {
366 if (m_reference_temperature < 0.0) {
367 amrex::Abort("Reference temperature was not set");
368 }
369
370 auto ref_theta = m_repo.create_scratch_field(1, m_ngrow);
371 for (int lev = 0; lev < m_repo.num_active_levels(); ++lev) {
372#ifdef AMREX_USE_OMP
373#pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
374#endif
375 for (amrex::MFIter mfi((*ref_theta)(lev)); mfi.isValid(); ++mfi) {
376 const auto& bx = mfi.tilebox();
377 const auto& ref_theta_arr = (*ref_theta)(lev).array(mfi);
378 ref_theta_impl(lev, mfi, bx, ref_theta_arr);
379 }
380 }
381 return ref_theta;
382 }
383
385 inline void ref_theta_impl(
386 const int lev,
387 const amrex::MFIter& mfi,
388 const amrex::Box& bx,
389 const amrex::Array4<amrex::Real>& ref_theta) const override
390 {
391 if (m_reference_temperature < 0.0) {
392 amrex::Abort("Reference temperature was not set");
393 }
394
395 if (m_repo.field_exists("reference_temperature")) {
396 auto& temp0 = m_repo.get_field("reference_temperature");
397 const auto& temp0_arr = temp0(lev).const_array(mfi);
398 amrex::ParallelFor(
399 bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
400 ref_theta(i, j, k) = temp0_arr(i, j, k);
401 });
402 } else {
403 const amrex::Real ref_theta_val = m_reference_temperature;
404 amrex::ParallelFor(
405 bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept {
406 ref_theta(i, j, k) = ref_theta_val;
407 });
408 }
409 }
410
411private:
414
417
419 amrex::Real m_mu1{1.0e-3};
420
422 amrex::Real m_mu2{1.0e-5};
423
425 amrex::Real m_Pr1{7.2};
426
428 amrex::Real m_Pr2{0.7};
429
431 amrex::Real m_Prt{1.0};
432
434 amrex::Real m_constant_beta{0.0};
435
437 amrex::Real m_reference_temperature{-1.0};
438
440 {
441 if (!m_physics_mgr.contains("MultiPhase")) {
442 amrex::Abort("TwoPhaseTransport requires MultiPhase physics");
443 }
444 const auto& multiphase = m_physics_mgr.get<MultiPhase>();
445 return multiphase.interface_capturing_method();
446 }
447};
448
449} // namespace amr_wind::transport
450
451#endif /* TWOPHASETRANSPORT_H */
Definition CFDSim.H:54
bool contains(const std::string &key) const
Query if an object exists using the lookup key.
Definition CollMgr.H:55
Definition FieldRepo.H:86
std::unique_ptr< ScratchField > create_scratch_field(const std::string &name, const int ncomp=1, const int nghost=0, const FieldLoc floc=FieldLoc::CELL) const
Definition FieldRepo.cpp:302
Field & get_field(const std::string &name, const FieldState fstate=FieldState::New) const
Definition FieldRepo.cpp:149
int num_active_levels() const noexcept
Total number of levels currently active in the AMR mesh.
Definition FieldRepo.H:361
bool field_exists(const std::string &name, const FieldState fstate=FieldState::New) const
Definition FieldRepo.cpp:215
const amrex::AmrCore & mesh() const
Return a reference to the underlying AMR mesh instance.
Definition FieldRepo.H:358
Definition MultiPhase.H:27
InterfaceCapturingMethod interface_capturing_method() const
Definition MultiPhase.cpp:80
Definition Physics.H:100
T & get()
Return a concrete physics instance.
Definition Physics.H:104
Definition TwoPhaseTransport.H:14
amrex::Real laminar_prandtl1() const
Definition TwoPhaseTransport.H:107
std::unique_ptr< ScratchField > ref_theta() const override
Return the reference temperature.
Definition TwoPhaseTransport.H:364
amrex::Real reference_temperature() const override
Definition TwoPhaseTransport.H:358
amrex::Real m_Prt
Turbulent Prandtl number.
Definition TwoPhaseTransport.H:431
std::unique_ptr< ScratchField > beta() const override
Return the thermal expansion coefficient.
Definition TwoPhaseTransport.H:280
std::unique_ptr< ScratchField > mu() override
Return the dynamic visocity field.
Definition TwoPhaseTransport.H:131
std::unique_ptr< ScratchField > scalar_diffusivity(const std::string &scalar_name) override
Definition TwoPhaseTransport.H:266
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:385
amrex::Real turbulent_prandtl() const
Definition TwoPhaseTransport.H:110
InterfaceCapturingMethod get_iface_method() const
Definition TwoPhaseTransport.H:439
amrex::Real m_reference_temperature
Reference temperature.
Definition TwoPhaseTransport.H:437
amrex::Real m_Pr1
Phase 1 (liquid) Prandtl number.
Definition TwoPhaseTransport.H:425
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:297
static constexpr bool constant_properties
Definition TwoPhaseTransport.H:16
TwoPhaseTransport(const CFDSim &sim)
Definition TwoPhaseTransport.H:20
amrex::Real m_constant_beta
Constant thermal expansion coefficient.
Definition TwoPhaseTransport.H:434
amrex::Real laminar_prandtl2() const
Definition TwoPhaseTransport.H:108
amrex::Real m_mu1
Phase 1 (liquid) dynamic molecular viscosity.
Definition TwoPhaseTransport.H:419
FieldRepo & m_repo
Reference to the field repository (for creating scratch fields)
Definition TwoPhaseTransport.H:413
static std::string identifier()
Definition TwoPhaseTransport.H:18
amrex::Real m_mu2
Phase 2 (gas) dynamic molecular viscosity.
Definition TwoPhaseTransport.H:422
static amrex::Real turbulent_schmidt(const std::string &scalar_name)
Definition TwoPhaseTransport.H:121
amrex::Real m_Pr2
Phase 2 (gas) Prandtl number.
Definition TwoPhaseTransport.H:428
static amrex::Real laminar_schmidt(const std::string &scalar_name)
Definition TwoPhaseTransport.H:112
const PhysicsMgr & m_physics_mgr
Reference to the physics manager.
Definition TwoPhaseTransport.H:416
std::unique_ptr< ScratchField > alpha() override
Return the thermal diffusivity field (later divided by density, though)
Definition TwoPhaseTransport.H:198
static constexpr amrex::Real TIGHT_TOL
A tight tolerance.
Definition constants.H:19
Definition CFDSim.H:26
InterfaceCapturingMethod
Definition MultiPhase.H:21