ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_CloudChamberWallFlux.H
Go to the documentation of this file.
1 #ifndef ERF_CLOUD_CHAMBER_WALL_FLUX_H_
2 #define ERF_CLOUD_CHAMBER_WALL_FLUX_H_
3 
4 #include <AMReX_Array4.H>
5 #include <AMReX_Box.H>
6 #include <AMReX_GpuContainers.H>
7 #include <AMReX_Math.H>
8 #include <AMReX_MultiFab.H>
9 
10 #include "ERF_Constants.H"
11 #include "ERF_DataStruct.H"
12 #include "ERF_EOS.H"
13 #include "ERF_IndexDefines.H"
14 #include "ERF_MicrophysicsUtils.H"
17 
18 #include <cmath>
19 #include <type_traits>
20 
22 
23 enum OwnedChannel : unsigned char {
24  OwnNone = 0,
25  OwnMomentum = 1 << 0,
26  OwnHeat = 1 << 1,
27  OwnVapor = 1 << 2,
28  OwnCloudWater = 1 << 3
29 };
30 
31 struct WallFlux {
32  amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> traction_on_fluid{};
36  unsigned char owned_channels = OwnNone;
37 };
38 
45  unsigned char valid = 0;
46 };
47 
50  int iterations = 0;
51 };
52 
53 enum class ScalarChannel : unsigned char {
54  None,
55  Heat,
56  Vapor,
58 };
59 
69  // Explicit distance of this scalar sample from the physical wall.
73  int gravity_sign = 0;
74 };
75 
80 };
81 
84  amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> u_t{};
91  int gravity_sign = 0;
92 };
93 
97 };
98 
99 static_assert(std::is_trivially_copyable_v<WallFlux>);
100 static_assert(std::is_standard_layout_v<WallFlux>);
101 static_assert(std::is_trivially_copyable_v<FaceRuntimeCoefficients>);
102 static_assert(std::is_standard_layout_v<FaceRuntimeCoefficients>);
103 static_assert(std::is_trivially_copyable_v<MostStabilityResult>);
104 static_assert(std::is_standard_layout_v<MostStabilityResult>);
105 static_assert(std::is_trivially_copyable_v<ScalarWallSample>);
106 static_assert(std::is_standard_layout_v<ScalarWallSample>);
107 static_assert(std::is_trivially_copyable_v<NeutralLogMomentumState>);
108 static_assert(std::is_standard_layout_v<NeutralLogMomentumState>);
109 static_assert(std::is_trivially_copyable_v<MomentumWallSample>);
110 static_assert(std::is_standard_layout_v<MomentumWallSample>);
111 static_assert(std::is_trivially_copyable_v<ScalarFluxReplacement>);
112 static_assert(std::is_standard_layout_v<ScalarFluxReplacement>);
113 
114 AMREX_GPU_HOST_DEVICE
115 AMREX_FORCE_INLINE
116 bool
118 {
119  using namespace erf_wall_thermodynamics;
120  return wall.moisture == MoistureMode::WetEquilibrium &&
121  wall.vapor.model == ScalarModel::BulkAero &&
122  wall.vapor.provider == CoefficientProvider::MOST;
123 }
124 
125 AMREX_GPU_HOST_DEVICE
126 AMREX_FORCE_INLINE
127 bool
129 {
130  using namespace erf_wall_thermodynamics;
131  return (wall.momentum.model == MomentumModel::BulkAero &&
132  wall.momentum.provider == CoefficientProvider::MOST) ||
133  (wall.heat.model == ScalarModel::BulkAero &&
134  wall.heat.provider == CoefficientProvider::MOST) ||
135  wall_uses_most_vapor(wall);
136 }
137 
138 AMREX_GPU_HOST_DEVICE
139 AMREX_FORCE_INLINE
141 scalar_channel_from_quantity (int quantity) noexcept
142 {
143  if (quantity == RhoTheta_comp) { return ScalarChannel::Heat; }
144  if (quantity == RhoQ1_comp) { return ScalarChannel::Vapor; }
145  if (quantity == RhoQ2_comp) { return ScalarChannel::CloudWater; }
146  return ScalarChannel::None;
147 }
148 
149 AMREX_GPU_HOST_DEVICE
150 AMREX_FORCE_INLINE
151 int
153 {
154  switch (channel) {
155  case ScalarChannel::Heat:
156  return PrimTheta_comp;
158  return PrimQ1_comp;
160  return PrimQ2_comp;
161  case ScalarChannel::None:
162  break;
163  }
164  return -1;
165 }
166 
167 AMREX_GPU_HOST_DEVICE
168 AMREX_FORCE_INLINE
169 bool
172  ScalarChannel channel) noexcept
173 {
174  using namespace erf_wall_thermodynamics;
175 
176  switch (channel) {
177  case ScalarChannel::Heat:
178  return wall.thermal.mode == ThermalMode::FixedPhysicalTemperature;
181  return wall.moisture != MoistureMode::LegacyNumerical;
182  case ScalarChannel::None:
183  return false;
184  }
185 
186  return false;
187 }
188 
189 AMREX_GPU_HOST_DEVICE
190 AMREX_FORCE_INLINE
191 unsigned char
193 {
194  switch (channel) {
195  case ScalarChannel::Heat:
196  return OwnHeat;
198  return OwnVapor;
200  return OwnCloudWater;
201  case ScalarChannel::None:
202  return OwnNone;
203  }
204 
205  return OwnNone;
206 }
207 
208 AMREX_GPU_HOST_DEVICE
209 AMREX_FORCE_INLINE
210 bool
211 owns (const WallFlux& flux, ScalarChannel channel) noexcept
212 {
213  return (flux.owned_channels & scalar_channel_mask(channel)) != 0;
214 }
215 
216 AMREX_GPU_HOST_DEVICE
217 AMREX_FORCE_INLINE
218 NeutralLogMomentumState
220  amrex::Real wall_distance,
221  amrex::Real z0_m) noexcept
222 {
223  const amrex::Real log_m = std::log(wall_distance / z0_m);
224  const amrex::Real k_over_log = KAPPA / log_m;
225  return {log_m, k_over_log * k_over_log, k_over_log * U_t};
226 }
227 
228 AMREX_GPU_HOST_DEVICE
229 AMREX_FORCE_INLINE
232  amrex::Real z0_m,
233  amrex::Real z0_scalar) noexcept
234 {
235  const amrex::Real log_m = std::log(wall_distance / z0_m);
236  const amrex::Real log_s = std::log(wall_distance / z0_scalar);
237  return (KAPPA * KAPPA) / (log_m * log_s);
238 }
239 
240 AMREX_GPU_HOST_DEVICE
241 AMREX_FORCE_INLINE
242 MostStabilityResult
244  amrex::Real D_m,
245  amrex::Real D_s) noexcept
246 {
247  similarity_funs sfuns;
248  amrex::Real zeta = amrex::Real(0.0);
249  bool converged = false;
250  int iterations = 0;
251  constexpr int max_iters = 100;
252  for (int iter = 0; iter < max_iters; ++iter) {
253  const amrex::Real zeta_old = zeta;
254  const amrex::Real psi_m = sfuns.calc_psi_m2(zeta_old);
255  const amrex::Real psi_s = sfuns.calc_psi_h2(zeta_old);
256  const amrex::Real A_m = amrex::max(D_m - psi_m, amrex::Real(1.0));
257  const amrex::Real A_s = amrex::max(D_s - psi_s, amrex::Real(1.0));
258  const amrex::Real zeta_new = amrex::Real(0.5) * zeta_old +
259  amrex::Real(0.5) * Ri * A_m * A_m / A_s;
261  amrex::Math::isfinite(static_cast<double>(zeta_new)),
262  "Cloud Chamber MOST produced a nonfinite stability coordinate");
263  zeta = zeta_new;
264  iterations = iter + 1;
265  if (std::abs(zeta - zeta_old) <= amrex::Real(1.0e-3)) {
266  converged = true;
267  break;
268  }
269  }
271  converged, "Cloud Chamber MOST fixed-point iteration did not converge");
272  return {zeta, iterations};
273 }
274 
275 AMREX_GPU_HOST_DEVICE
276 AMREX_FORCE_INLINE
277 FaceRuntimeCoefficients
280  amrex::Real theta_air,
281  amrex::Real qv_air,
282  amrex::Real p_hse,
284  amrex::Real U_t,
285  amrex::Real wall_distance,
286  int gravity_sign) noexcept
287 {
288  using namespace erf_wall_thermodynamics;
289  FaceRuntimeCoefficients result{};
290  const bool most_momentum =
291  wall.momentum.model == MomentumModel::BulkAero &&
292  wall.momentum.provider == CoefficientProvider::MOST;
293  const bool most_heat =
294  wall.heat.model == ScalarModel::BulkAero &&
295  wall.heat.provider == CoefficientProvider::MOST;
296  const bool most_vapor = wall_uses_most_vapor(wall);
297  if (!(most_momentum || most_heat || most_vapor)) {
298  result.valid = 1;
299  return result;
300  }
301 
302  const amrex::Real theta_wall = wall.thermal.temperature_K *
303  std::pow(p_0 / p_hse, rdOcp);
304  amrex::Real qv_wall = qv_air;
305  if (wall.moisture == MoistureMode::WetEquilibrium) {
306  erf_qsatw(wall.thermal.temperature_K, p_hse * amrex::Real(0.01), qv_wall);
307  }
308  const amrex::Real theta_v_air = theta_air * (amrex::Real(1.0) + epsv * qv_air);
309  const amrex::Real theta_v_wall = theta_wall * (amrex::Real(1.0) + epsv * qv_wall);
310  const amrex::Real U_most = amrex::max(U_t, amrex::Real(0.01));
311  const amrex::Real Ri_b = gravity_sign == 0 ? amrex::Real(0.0) :
312  amrex::Real(gravity_sign) * CONST_GRAV * wall_distance / theta_air *
313  (theta_v_air - theta_v_wall) / (U_most * U_most);
314  const amrex::Real Ri = amrex::max(amrex::Real(-4.0),
315  amrex::min(amrex::Real(4.0), Ri_b));
316 
317  const amrex::Real z0_m = wall.momentum.z0_m;
318  const amrex::Real z0_h = wall.heat.z0 > amrex::Real(0.0) ?
319  wall.heat.z0 : z0_m;
320  const amrex::Real z0_q = wall.vapor.z0 > amrex::Real(0.0) ?
321  wall.vapor.z0 : z0_m;
322  const amrex::Real D_m = std::log(wall_distance / z0_m);
323  const amrex::Real D_h = std::log(wall_distance / z0_h);
324  const amrex::Real D_q = std::log(wall_distance / z0_q);
325 
326  // A coupled MOST heat/vapor face is host-constrained to have equal scalar
327  // roughness. For a single active scalar channel, that channel supplies
328  // the scalar resistance used by the bulk-Richardson fixed point.
329  const amrex::Real z0_stability = most_heat ? z0_h :
330  (most_vapor ? z0_q : z0_m);
331  const amrex::Real D_stability = std::log(wall_distance / z0_stability);
332  const auto stability = most_stability_coordinate(Ri, D_m, D_stability);
333  const amrex::Real zeta = stability.zeta;
334 
335  similarity_funs sfuns;
336  const amrex::Real psi_m = sfuns.calc_psi_m2(zeta);
337  const amrex::Real psi_h = sfuns.calc_psi_h2(zeta);
338  const amrex::Real A_m = amrex::max(D_m - psi_m, amrex::Real(1.0));
339  const amrex::Real A_h = amrex::max(D_h - psi_h, amrex::Real(1.0));
340  const amrex::Real A_q = amrex::max(D_q - psi_h, amrex::Real(1.0));
341  result.C_D = (KAPPA / A_m) * (KAPPA / A_m);
342  result.C_H = KAPPA * KAPPA / (A_m * A_h);
343  result.C_E = KAPPA * KAPPA / (A_m * A_q);
344  result.u_star = KAPPA * U_most / A_m;
345  result.zeta = zeta;
346  result.valid = 1;
348  amrex::Math::isfinite(static_cast<double>(result.C_D)) &&
349  amrex::Math::isfinite(static_cast<double>(result.C_H)) &&
350  amrex::Math::isfinite(static_cast<double>(result.C_E)),
351  "Cloud Chamber MOST produced nonfinite transfer coefficients");
352  return result;
353 }
354 
355 AMREX_GPU_HOST_DEVICE
356 AMREX_FORCE_INLINE
357 amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>
359  const NeutralLogMomentumState& neutral) noexcept
360 {
361  const amrex::Real factor =
362  -sample.rho * neutral.C_D * sample.U_t;
363  return {factor * sample.u_t[0],
364  factor * sample.u_t[1],
365  factor * sample.u_t[2]};
366 }
367 
368 AMREX_GPU_HOST_DEVICE
369 AMREX_FORCE_INLINE
372  amrex::Real U_t,
373  amrex::Real dx_inv) noexcept
374 {
375  return coefficient * U_t * dx_inv;
376 }
377 
378 
379 AMREX_GPU_HOST_DEVICE
380 AMREX_FORCE_INLINE
383 {
384  // For a fixed C_D, the maximum absolute row sum of the two-component
385  // tangential Jacobian of C_D |u_t| u_t is (3 + sqrt(2))/2 * C_D |u_t|.
386  // Cloud Chamber MOST applies this factor to its frozen current C_D.
387  return (amrex::Real(3.0) + std::sqrt(amrex::Real(2.0))) / amrex::Real(2.0);
388 }
389 
390 AMREX_GPU_HOST_DEVICE
391 AMREX_FORCE_INLINE
394  int component,
395  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& low_rate,
396  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& high_rate) noexcept
397 {
398  amrex::Real result = amrex::Real(0.0);
399  for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
400  if (dir != component) {
401  result += low_rate[dir] + high_rate[dir];
402  }
403  }
404  return result;
405 }
406 
407 AMREX_GPU_HOST_DEVICE
408 AMREX_FORCE_INLINE
412  amrex::Real U_t,
413  amrex::Real dx_inv,
414  const FaceRuntimeCoefficients& runtime = FaceRuntimeCoefficients{}) noexcept
415 {
416  using namespace erf_wall_thermodynamics;
417  amrex::Real C_D = amrex::Real(0.0);
418  const amrex::Real wall_distance = amrex::Real(0.5) / dx_inv;
419  if (wall.momentum.model !=
420  MomentumModel::ResolvedNoSlip) {
421  if (wall.momentum.model == MomentumModel::NeutralRoughnessLog) {
423  U_t, wall_distance, wall.momentum.z0_m).C_D;
424  } else if (wall.momentum.model == MomentumModel::BulkAero) {
425  if (wall.momentum.provider == CoefficientProvider::MOST) {
426  AMREX_ALWAYS_ASSERT(runtime.valid != 0);
427  C_D = runtime.C_D;
428  } else {
429  C_D = wall.momentum.C_D;
430  }
431  }
432  }
433  return momentum_infinity_row_sum_factor() * C_D * U_t * dx_inv;
434 }
435 
436 AMREX_GPU_HOST_DEVICE
437 AMREX_FORCE_INLINE
438 bool
441  ScalarChannel channel) noexcept
442 {
443  using namespace erf_wall_thermodynamics;
444 
445  switch (channel) {
446  case ScalarChannel::Heat:
447  return wall.thermal.mode == ThermalMode::FixedPhysicalTemperature &&
448  (wall.heat.model == ScalarModel::BulkAero ||
449  wall.heat.model == ScalarModel::NeutralRoughnessLog);
451  return wall.moisture == MoistureMode::WetEquilibrium &&
452  (wall.vapor.model == ScalarModel::BulkAero ||
453  wall.vapor.model == ScalarModel::NeutralRoughnessLog);
455  case ScalarChannel::None:
456  return false;
457  }
458 
459  return false;
460 }
461 
462 AMREX_GPU_HOST_DEVICE
463 AMREX_FORCE_INLINE
464 bool
466  const erf_wall_thermodynamics::FaceWall& wall) noexcept
467 {
468  return wall.momentum.model !=
470 }
471 
472 AMREX_GPU_HOST_DEVICE
473 AMREX_FORCE_INLINE
474 bool
476  const erf_wall_thermodynamics::FaceWall& wall) noexcept
477 {
478  return requires_tangential_momentum(wall) ||
481 }
482 
483 AMREX_GPU_HOST_DEVICE
484 AMREX_FORCE_INLINE
488  amrex::Real U_t,
489  amrex::Real dx_inv,
490  const FaceRuntimeCoefficients& runtime) noexcept
491 {
492  using namespace erf_wall_thermodynamics;
494  return amrex::Real(0.0);
495  }
496  if (wall_uses_most(wall)) {
497  AMREX_ALWAYS_ASSERT(runtime.valid != 0);
498  }
499  const amrex::Real wall_distance = amrex::Real(0.5) / dx_inv;
500  amrex::Real rate = momentum_rate_for_face(wall, U_t, dx_inv, runtime);
501 
502  if (wall.thermal.mode == ThermalMode::FixedPhysicalTemperature) {
503  if (wall.heat.model == ScalarModel::BulkAero) {
504  const amrex::Real C_H = wall.heat.provider == CoefficientProvider::MOST ?
505  runtime.C_H : wall.heat.coefficient;
506  rate = amrex::max(rate, neutral_scalar_rate(C_H, U_t, dx_inv));
507  } else if (wall.heat.model == ScalarModel::NeutralRoughnessLog) {
508  rate = amrex::max(rate, neutral_scalar_rate(
510  wall_distance, wall.momentum.z0_m, wall.heat.z0),
511  U_t, dx_inv));
512  }
513  }
514  if (wall.moisture == MoistureMode::WetEquilibrium) {
515  if (wall.vapor.model == ScalarModel::BulkAero) {
516  const amrex::Real C_E = wall.vapor.provider == CoefficientProvider::MOST ?
517  runtime.C_E : wall.vapor.coefficient;
518  rate = amrex::max(rate, neutral_scalar_rate(C_E, U_t, dx_inv));
519  } else if (wall.vapor.model == ScalarModel::NeutralRoughnessLog) {
520  rate = amrex::max(rate, neutral_scalar_rate(
522  wall_distance, wall.momentum.z0_m, wall.vapor.z0),
523  U_t, dx_inv));
524  }
525  }
526  return rate;
527 }
528 
529 AMREX_GPU_HOST_DEVICE
530 AMREX_FORCE_INLINE
534  amrex::Real U_t,
535  amrex::Real dx_inv) noexcept
536 {
537  return wall_rate_for_face(wall, U_t, dx_inv, FaceRuntimeCoefficients{});
538 }
539 
540 AMREX_GPU_HOST_DEVICE
541 AMREX_FORCE_INLINE
545  amrex::Real theta_air,
546  amrex::Real qv_air,
547  amrex::Real p_hse,
549  amrex::Real U_t,
550  amrex::Real dx_inv,
551  int gravity_sign) noexcept
552 {
554  wall, theta_air, qv_air, p_hse, rdOcp, U_t,
555  amrex::Real(0.5) / dx_inv, gravity_sign);
556  return wall_rate_for_face(wall, U_t, dx_inv, runtime);
557 }
558 
559 template <int DIR, bool HIGH>
560 AMREX_GPU_HOST_DEVICE
561 AMREX_FORCE_INLINE
564 {
565  // Wall evaluators are inward-positive. ERF stores coordinate-positive
566  // face fluxes, so this is the one low/high sign adapter for every scalar.
567  amrex::ignore_unused(DIR);
568  return HIGH ? -inward : inward;
569 }
570 
571 template <int DIR, bool HIGH>
572 AMREX_GPU_HOST_DEVICE
573 AMREX_FORCE_INLINE
574 amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>
576  amrex::Real tangent_a,
577  amrex::Real tangent_b) noexcept
578 {
579  // Physical traction result/orientation support. The stress adapter maps
580  // this pure result into ERF tau_ij arrays for active wall models.
581  amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> result{};
582  result[DIR] = to_coordinate_flux<DIR,HIGH>(normal_in);
583  if constexpr (DIR == 0) {
584  result[1] = tangent_a;
585  result[2] = tangent_b;
586  } else if constexpr (DIR == 1) {
587  result[0] = tangent_a;
588  result[2] = tangent_b;
589  } else {
590  result[0] = tangent_a;
591  result[1] = tangent_b;
592  }
593  return result;
594 }
595 
596 AMREX_GPU_HOST_DEVICE
597 AMREX_FORCE_INLINE
600  amrex::Real C_H,
601  amrex::Real U_t,
602  amrex::Real wall_temperature_K,
603  amrex::Real theta_air,
604  amrex::Real p_hse,
605  amrex::Real rdOcp) noexcept
606 {
607  const amrex::Real theta_wall =
608  wall_temperature_K * std::pow(p_0 / p_hse, rdOcp);
609  return rho * C_H * U_t * (theta_wall - theta_air);
610 }
611 
612 AMREX_GPU_HOST_DEVICE
613 AMREX_FORCE_INLINE
616  amrex::Real C_E,
617  amrex::Real U_t,
618  amrex::Real wall_temperature_K,
619  amrex::Real qv_air,
620  amrex::Real p_hse) noexcept
621 {
622  amrex::Real qv_wall = amrex::Real(0.0);
623  erf_qsatw(wall_temperature_K, p_hse * amrex::Real(0.01), qv_wall);
624  return rho * C_E * U_t * (qv_wall - qv_air);
625 }
626 
627 AMREX_GPU_HOST_DEVICE
628 AMREX_FORCE_INLINE
629 amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>
631  int dir, int i, int j, int k,
632  const amrex::Array4<const amrex::Real>& u,
633  const amrex::Array4<const amrex::Real>& v,
634  const amrex::Array4<const amrex::Real>& w,
635  const erf_wall_thermodynamics::FaceWall& wall) noexcept
636 {
637  const amrex::Real uc =
638  amrex::Real(0.5) * (u(i,j,k) + u(i+1,j,k)) - wall.wall_velocity[0];
639  const amrex::Real vc =
640  amrex::Real(0.5) * (v(i,j,k) + v(i,j+1,k)) - wall.wall_velocity[1];
641  const amrex::Real wc =
642  amrex::Real(0.5) * (w(i,j,k) + w(i,j,k+1)) - wall.wall_velocity[2];
643  amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> result{uc, vc, wc};
644  result[dir] = amrex::Real(0.0);
645  return result;
646 }
647 
648 AMREX_GPU_HOST_DEVICE
649 AMREX_FORCE_INLINE
652  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& u_t) noexcept
653 {
654  return std::sqrt(u_t[0]*u_t[0] + u_t[1]*u_t[1] + u_t[2]*u_t[2]);
655 }
656 
657 AMREX_GPU_HOST_DEVICE
658 AMREX_FORCE_INLINE
661  int i, int j, int k,
662  const amrex::Array4<const amrex::Real>& u,
663  const amrex::Array4<const amrex::Real>& v,
664  const amrex::Array4<const amrex::Real>& w,
665  const erf_wall_thermodynamics::FaceWall& wall) noexcept
666 {
667  return tangential_magnitude(
668  relative_tangential_velocity_cell_centered(dir, i, j, k, u, v, w, wall));
669 }
670 
671 AMREX_GPU_HOST_DEVICE
672 AMREX_FORCE_INLINE
675  int i, int j, int k,
676  const amrex::Array4<const amrex::Real>& velocity,
677  const erf_wall_thermodynamics::FaceWall& wall) noexcept
678 {
679  const amrex::Real uc = velocity(i,j,k,0) - wall.wall_velocity[0];
680  const amrex::Real vc = velocity(i,j,k,1) - wall.wall_velocity[1];
681  const amrex::Real wc = velocity(i,j,k,2) - wall.wall_velocity[2];
682  const amrex::Real normal = (dir == 0) ? uc : ((dir == 1) ? vc : wc);
683  const amrex::Real t0 = uc - ((dir == 0) ? normal : amrex::Real(0.0));
684  const amrex::Real t1 = vc - ((dir == 1) ? normal : amrex::Real(0.0));
685  const amrex::Real t2 = wc - ((dir == 2) ? normal : amrex::Real(0.0));
686  return std::sqrt(t0*t0 + t1*t1 + t2*t2);
687 }
688 
689 AMREX_GPU_HOST_DEVICE
690 AMREX_FORCE_INLINE
694  amrex::Real alpha_T,
695  amrex::Real wall_temperature_K,
696  amrex::Real theta_air,
697  amrex::Real p_hse,
698  amrex::Real dx_inv,
699  amrex::Real rdOcp) noexcept
700 {
701  const amrex::Real theta_wall =
702  wall_temperature_K * std::pow(p_0 / p_hse, rdOcp);
703  return rho * alpha_T * (theta_wall - theta_air) *
704  amrex::Real(2.0) * dx_inv;
705 }
706 
707 AMREX_GPU_HOST_DEVICE
708 AMREX_FORCE_INLINE
712  amrex::Real alpha_C,
713  amrex::Real wall_temperature_K,
714  amrex::Real qv_air,
715  amrex::Real p_hse,
716  amrex::Real dx_inv) noexcept
717 {
718  amrex::Real qv_wall = amrex::Real(0.0);
719  erf_qsatw(
720  wall_temperature_K,
721  p_hse * amrex::Real(0.01),
722  qv_wall);
723  return rho * alpha_C * (qv_wall - qv_air) *
724  amrex::Real(2.0) * dx_inv;
725 }
726 
727 AMREX_GPU_HOST_DEVICE
728 AMREX_FORCE_INLINE
729 WallFlux
732  const MomentumWallSample& sample) noexcept
733 {
734  using namespace erf_wall_thermodynamics;
735 
736  WallFlux result{};
737  switch (wall.momentum.model) {
738  case MomentumModel::ResolvedNoSlip:
739  return result;
740  case MomentumModel::NeutralRoughnessLog: {
741  result.owned_channels = OwnMomentum;
742  const auto neutral = neutral_log_momentum_state(
743  sample.U_t, sample.wall_distance, wall.momentum.z0_m);
744  result.traction_on_fluid =
745  neutral_log_traction_on_fluid(sample, neutral);
746  return result;
747  }
748  case MomentumModel::BulkAero: {
749  result.owned_channels = OwnMomentum;
750  if (sample.U_t == amrex::Real(0.0)) { return result; }
751  amrex::Real C_D = wall.momentum.C_D;
752  if (wall.momentum.provider == CoefficientProvider::MOST) {
753  const auto runtime = most_wall_coefficients(
754  wall, sample.theta_air, sample.qv_air, sample.p_hse,
755  sample.rdOcp, sample.U_t, sample.wall_distance,
756  sample.gravity_sign);
757  AMREX_ALWAYS_ASSERT(runtime.valid != 0);
758  C_D = runtime.C_D;
759  }
760  const amrex::Real factor = -sample.rho * C_D * sample.U_t;
761  result.traction_on_fluid = {
762  factor * sample.u_t[0], factor * sample.u_t[1], factor * sample.u_t[2]};
763  return result;
764  }
765  }
766  AMREX_ALWAYS_ASSERT(false);
767  return result;
768 }
769 
770 AMREX_GPU_HOST_DEVICE
771 AMREX_FORCE_INLINE
772 WallFlux
775  ScalarChannel channel,
776  const ScalarWallSample& sample) noexcept
777 {
778  using namespace erf_wall_thermodynamics;
779 
780  WallFlux result{};
781  if (!wall_owns_scalar_channel(wall, channel)) {
782  return result;
783  }
784 
785  result.owned_channels = scalar_channel_mask(channel);
786 
787  switch (channel) {
788  case ScalarChannel::Heat:
789  if (sample.U_t == amrex::Real(0.0) &&
790  wall.heat.model != ScalarModel::ResolvedMolecular) {
791  return result;
792  }
793  switch (wall.heat.model) {
794  case ScalarModel::ResolvedMolecular:
795  result.rhoTheta_in = resolved_theta_flux_in(
796  sample.rho,
797  sample.alpha_T,
798  wall.thermal.temperature_K,
799  sample.scalar_air,
800  sample.p_hse,
801  sample.dx_inv,
802  sample.rdOcp);
803  return result;
804 
805  case ScalarModel::BulkAero: {
806  amrex::Real C_H = wall.heat.coefficient;
807  if (wall.heat.provider == CoefficientProvider::MOST) {
808  const auto runtime = most_wall_coefficients(
809  wall, sample.theta_air, sample.qv_air, sample.p_hse,
810  sample.rdOcp, sample.U_t, sample.wall_distance,
811  sample.gravity_sign);
812  AMREX_ALWAYS_ASSERT(runtime.valid != 0);
813  C_H = runtime.C_H;
814  }
815  result.rhoTheta_in = bulk_theta_flux_in(
816  sample.rho,
817  C_H,
818  sample.U_t,
819  wall.thermal.temperature_K,
820  sample.scalar_air,
821  sample.p_hse,
822  sample.rdOcp);
823  return result;
824  }
825  case ScalarModel::NeutralRoughnessLog:
826  result.rhoTheta_in = bulk_theta_flux_in(
827  sample.rho,
829  sample.wall_distance,
830  wall.momentum.z0_m,
831  wall.heat.z0),
832  sample.U_t,
833  wall.thermal.temperature_K,
834  sample.scalar_air,
835  sample.p_hse,
836  sample.rdOcp);
837  return result;
838  }
839  AMREX_ALWAYS_ASSERT(false);
840  return result;
841 
843  if (wall.moisture == MoistureMode::DryImpermeable) {
844  return result;
845  }
846  if (sample.U_t == amrex::Real(0.0) &&
847  wall.vapor.model != ScalarModel::ResolvedMolecular) {
848  return result;
849  }
850  switch (wall.vapor.model) {
851  case ScalarModel::ResolvedMolecular:
852  result.rhoQv_in = resolved_vapor_flux_in(
853  sample.rho,
854  sample.alpha_C,
855  wall.thermal.temperature_K,
856  sample.scalar_air,
857  sample.p_hse,
858  sample.dx_inv);
859  return result;
860 
861  case ScalarModel::BulkAero: {
862  amrex::Real C_E = wall.vapor.coefficient;
863  if (wall.vapor.provider == CoefficientProvider::MOST) {
864  const auto runtime = most_wall_coefficients(
865  wall, sample.theta_air, sample.qv_air, sample.p_hse,
866  sample.rdOcp, sample.U_t, sample.wall_distance,
867  sample.gravity_sign);
868  AMREX_ALWAYS_ASSERT(runtime.valid != 0);
869  C_E = runtime.C_E;
870  }
871  result.rhoQv_in = bulk_vapor_flux_in(
872  sample.rho,
873  C_E,
874  sample.U_t,
875  wall.thermal.temperature_K,
876  sample.scalar_air,
877  sample.p_hse);
878  return result;
879  }
880  case ScalarModel::NeutralRoughnessLog:
881  result.rhoQv_in = bulk_vapor_flux_in(
882  sample.rho,
884  sample.wall_distance,
885  wall.momentum.z0_m,
886  wall.vapor.z0),
887  sample.U_t,
888  wall.thermal.temperature_K,
889  sample.scalar_air,
890  sample.p_hse);
891  return result;
892  }
893  AMREX_ALWAYS_ASSERT(false);
894  return result;
895 
897  return result;
898 
899  case ScalarChannel::None:
900  return result;
901  }
902 
903  return result;
904 }
905 
906 AMREX_GPU_HOST_DEVICE
907 AMREX_FORCE_INLINE
909 scalar_flux_in (const WallFlux& flux, ScalarChannel channel) noexcept
910 {
911  switch (channel) {
912  case ScalarChannel::Heat:
913  return flux.rhoTheta_in;
915  return flux.rhoQv_in;
917  return flux.rhoQc_in;
918  case ScalarChannel::None:
919  return amrex::Real(0.0);
920  }
921 
922  return amrex::Real(0.0);
923 }
924 
925 template <int DIR, bool HIGH>
926 AMREX_GPU_HOST_DEVICE
927 AMREX_FORCE_INLINE
928 ScalarFluxReplacement
930  amrex::Real old_flux,
931  amrex::Real inward_flux,
932  amrex::Real dx_inv) noexcept
933 {
934  const amrex::Real new_flux =
935  to_coordinate_flux<DIR,HIGH>(inward_flux);
936  const amrex::Real correction =
937  (new_flux - old_flux) * dx_inv;
938  return {
939  new_flux,
940  HIGH ? -correction : correction
941  };
942 }
943 
944 template <int DIR, bool HIGH>
945 AMREX_FORCE_INLINE
946 void apply_face (const amrex::Box& bx,
947  const amrex::Box& domain,
948  const int quantity,
949  const int flux_comp,
950  const amrex::Array4<const amrex::Real>& state,
951  const amrex::Array4<const amrex::Real>& prim,
952  const amrex::Array4<const amrex::Real>& base_state,
953  const amrex::Array4<const amrex::Real>& u,
954  const amrex::Array4<const amrex::Real>& v,
955  const amrex::Array4<const amrex::Real>& w,
956  const amrex::Array4<amrex::Real>& rhs,
957  const amrex::Array4<amrex::Real>& xflux,
958  const amrex::Array4<amrex::Real>& yflux,
959  const amrex::Array4<amrex::Real>& zflux,
960  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& dx_inv,
962  const amrex::Real alpha_T,
963  const amrex::Real alpha_C,
964  const amrex::Real rdOcp,
965  const bool cloudy)
966 {
967  // A tile may belong to an interior BoxArray box. Do not relocate that
968  // tile to a global boundary: its Array4 views do not own data there.
969  if constexpr (HIGH) {
970  if (bx.bigEnd(DIR) != domain.bigEnd(DIR)) { return; }
971  } else {
972  if (bx.smallEnd(DIR) != domain.smallEnd(DIR)) { return; }
973  }
974 
975  const ScalarChannel channel =
977  if (channel == ScalarChannel::None) { return; }
978 
979  const auto wall = walls[2*DIR + (HIGH ? 1 : 0)];
980  if (!wall_owns_scalar_channel(wall, channel)) { return; }
981 
982  const int prim_comp = primitive_component(channel);
983  AMREX_ALWAYS_ASSERT(prim_comp >= 0);
984 
985  const int cell_face = HIGH ? domain.bigEnd(DIR) : domain.smallEnd(DIR);
986  amrex::Box face_cells = bx;
987  face_cells.setSmall(DIR, cell_face);
988  face_cells.setBig(DIR, cell_face);
989  face_cells &= domain;
990  if (face_cells.isEmpty()) { return; }
991  AMREX_ALWAYS_ASSERT(bx.contains(face_cells));
992 
993  const bool needs_speed = requires_tangential_speed(wall, channel);
994  const auto& flux =
995  (DIR == 0) ? xflux : ((DIR == 1) ? yflux : zflux);
996 
997  amrex::ParallelFor(face_cells,
998  [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
999  {
1000  const int fi = HIGH && DIR == 0 ? i + 1 : i;
1001  const int fj = HIGH && DIR == 1 ? j + 1 : j;
1002  const int fk = HIGH && DIR == 2 ? k + 1 : k;
1003 
1004  const amrex::Real old_flux = flux(fi,fj,fk,flux_comp);
1005  const ScalarWallSample sample{
1006  state(i,j,k,Rho_comp),
1007  prim(i,j,k,prim_comp),
1008  base_state(i,j,k,BaseState::p0_comp),
1009  needs_speed ?
1010  tangential_speed(DIR, i, j, k, u, v, w, wall) :
1011  amrex::Real(0.0),
1012  alpha_T,
1013  alpha_C,
1014  dx_inv[DIR],
1015  rdOcp,
1016  amrex::Real(0.5) / dx_inv[DIR],
1017  prim(i,j,k,PrimTheta_comp),
1018  cloudy ? prim(i,j,k,PrimQ1_comp) : amrex::Real(0.0),
1019  DIR == 2 ? (HIGH ? -1 : 1) : 0
1020  };
1021 
1022  const WallFlux physical =
1023  evaluate_scalar_flux_in(wall, channel, sample);
1024  if (!owns(physical, channel)) { return; }
1025 
1026  const ScalarFluxReplacement update =
1027  scalar_flux_replacement<DIR,HIGH>(
1028  old_flux,
1029  scalar_flux_in(physical, channel),
1030  dx_inv[DIR]);
1031 
1032  flux(fi,fj,fk,flux_comp) = update.coordinate_flux;
1033  rhs(i,j,k,quantity) += update.rhs_delta;
1034  });
1035 }
1036 
1037 inline void apply (const amrex::Box& bx, const amrex::Box& domain,
1038  const int quantity, const int flux_comp,
1039  const amrex::Array4<const amrex::Real>& state,
1040  const amrex::Array4<const amrex::Real>& prim,
1041  const amrex::Array4<const amrex::Real>& base_state,
1042  const amrex::Array4<const amrex::Real>& u,
1043  const amrex::Array4<const amrex::Real>& v,
1044  const amrex::Array4<const amrex::Real>& w,
1045  const amrex::Array4<amrex::Real>& rhs,
1046  const amrex::Array4<amrex::Real>& xflux,
1047  const amrex::Array4<amrex::Real>& yflux,
1048  const amrex::Array4<amrex::Real>& zflux,
1049  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& dx_inv,
1050  const erf_wall_thermodynamics::Boundary& walls,
1051  const amrex::Real alpha_T, const amrex::Real alpha_C,
1052  const amrex::Real rdOcp,
1053  const bool cloudy = false)
1054 {
1055  apply_face<0,false>(bx,domain,quantity,flux_comp,state,prim,base_state,u,v,w,rhs,xflux,yflux,zflux,dx_inv,walls,alpha_T,alpha_C,rdOcp,cloudy);
1056  apply_face<0,true >(bx,domain,quantity,flux_comp,state,prim,base_state,u,v,w,rhs,xflux,yflux,zflux,dx_inv,walls,alpha_T,alpha_C,rdOcp,cloudy);
1057  apply_face<1,false>(bx,domain,quantity,flux_comp,state,prim,base_state,u,v,w,rhs,xflux,yflux,zflux,dx_inv,walls,alpha_T,alpha_C,rdOcp,cloudy);
1058  apply_face<1,true >(bx,domain,quantity,flux_comp,state,prim,base_state,u,v,w,rhs,xflux,yflux,zflux,dx_inv,walls,alpha_T,alpha_C,rdOcp,cloudy);
1059  apply_face<2,false>(bx,domain,quantity,flux_comp,state,prim,base_state,u,v,w,rhs,xflux,yflux,zflux,dx_inv,walls,alpha_T,alpha_C,rdOcp,cloudy);
1060  apply_face<2,true >(bx,domain,quantity,flux_comp,state,prim,base_state,u,v,w,rhs,xflux,yflux,zflux,dx_inv,walls,alpha_T,alpha_C,rdOcp,cloudy);
1061 }
1062 
1064  const erf_wall_thermodynamics::Boundary& walls) noexcept
1065 {
1066  for (const auto& wall : walls) {
1069  return true;
1070  }
1071  }
1072  return false;
1073 }
1074 
1075 AMREX_FORCE_INLINE
1078  amrex::Real wall_cfl = amrex::Real(0.5)) noexcept
1079 {
1080  return max_rate > amrex::Real(0.0) ?
1081  wall_cfl / max_rate : amrex::Real(1.0e30);
1082 }
1083 
1084 } // namespace erf_cloud_chamber_wall_flux
1085 
1086 #endif
constexpr amrex::Real epsv
Definition: ERF_Constants.H:40
constexpr amrex::Real KAPPA
Definition: ERF_Constants.H:55
constexpr amrex::Real p_0
Definition: ERF_Constants.H:53
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:56
#define PrimQ1_comp
Definition: ERF_IndexDefines.H:61
#define PrimQ2_comp
Definition: ERF_IndexDefines.H:62
#define Rho_comp
Definition: ERF_IndexDefines.H:39
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:40
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:46
#define PrimTheta_comp
Definition: ERF_IndexDefines.H:58
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:45
const Real rdOcp
Definition: ERF_InitCustomPert_ABL.H:72
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_cloud_chamber_config.active, "Cloud Chamber: initializer reached without a parsed configuration")
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:264
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
Real w
Definition: ERF_Plotfile2DInterpolator.cpp:22
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ p0_comp
Definition: ERF_IndexDefines.H:77
@ fi
Definition: ERF_AdvanceMorrison.cpp:107
@ rho
Definition: ERF_Kessler.H:25
Definition: ERF_CloudChamberWallFlux.H:21
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool owns(const WallFlux &flux, ScalarChannel channel) noexcept
Definition: ERF_CloudChamberWallFlux.H:211
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real tangential_magnitude(const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &u_t) noexcept
Definition: ERF_CloudChamberWallFlux.H:651
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real bulk_vapor_flux_in(amrex::Real rho, amrex::Real C_E, amrex::Real U_t, amrex::Real wall_temperature_K, amrex::Real qv_air, amrex::Real p_hse) noexcept
Definition: ERF_CloudChamberWallFlux.H:615
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE WallFlux evaluate_momentum_traction(const erf_wall_thermodynamics::FaceWall &wall, const MomentumWallSample &sample) noexcept
Definition: ERF_CloudChamberWallFlux.H:730
void apply(const amrex::Box &bx, const amrex::Box &domain, const int quantity, const int flux_comp, const amrex::Array4< const amrex::Real > &state, const amrex::Array4< const amrex::Real > &prim, const amrex::Array4< const amrex::Real > &base_state, const amrex::Array4< const amrex::Real > &u, const amrex::Array4< const amrex::Real > &v, const amrex::Array4< const amrex::Real > &w, const amrex::Array4< amrex::Real > &rhs, const amrex::Array4< amrex::Real > &xflux, const amrex::Array4< amrex::Real > &yflux, const amrex::Array4< amrex::Real > &zflux, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx_inv, const erf_wall_thermodynamics::Boundary &walls, const amrex::Real alpha_T, const amrex::Real alpha_C, const amrex::Real rdOcp, const bool cloudy=false)
Definition: ERF_CloudChamberWallFlux.H:1037
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE MostStabilityResult most_stability_coordinate(amrex::Real Ri, amrex::Real D_m, amrex::Real D_s) noexcept
Definition: ERF_CloudChamberWallFlux.H:243
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real tangential_speed_cell_centered(int dir, int i, int j, int k, const amrex::Array4< const amrex::Real > &velocity, const erf_wall_thermodynamics::FaceWall &wall) noexcept
Definition: ERF_CloudChamberWallFlux.H:674
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real bulk_theta_flux_in(amrex::Real rho, amrex::Real C_H, amrex::Real U_t, amrex::Real wall_temperature_K, amrex::Real theta_air, amrex::Real p_hse, amrex::Real rdOcp) noexcept
Definition: ERF_CloudChamberWallFlux.H:599
bool has_velocity_dependent_scalar_wall(const erf_wall_thermodynamics::Boundary &walls) noexcept
Definition: ERF_CloudChamberWallFlux.H:1063
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real wall_rate_for_face(const erf_wall_thermodynamics::FaceWall &wall, amrex::Real U_t, amrex::Real dx_inv, const FaceRuntimeCoefficients &runtime) noexcept
Definition: ERF_CloudChamberWallFlux.H:486
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real neutral_log_scalar_coefficient(amrex::Real wall_distance, amrex::Real z0_m, amrex::Real z0_scalar) noexcept
Definition: ERF_CloudChamberWallFlux.H:231
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE WallFlux evaluate_scalar_flux_in(const erf_wall_thermodynamics::FaceWall &wall, ScalarChannel channel, const ScalarWallSample &sample) noexcept
Definition: ERF_CloudChamberWallFlux.H:773
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE NeutralLogMomentumState neutral_log_momentum_state(amrex::Real U_t, amrex::Real wall_distance, amrex::Real z0_m) noexcept
Definition: ERF_CloudChamberWallFlux.H:219
AMREX_FORCE_INLINE amrex::Real wall_dt_from_max_rate(amrex::Real max_rate, amrex::Real wall_cfl=amrex::Real(0.5)) noexcept
Definition: ERF_CloudChamberWallFlux.H:1077
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool wall_rate_requires_tangential_speed(const erf_wall_thermodynamics::FaceWall &wall) noexcept
Definition: ERF_CloudChamberWallFlux.H:475
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > traction_from_local_inward(amrex::Real normal_in, amrex::Real tangent_a, amrex::Real tangent_b) noexcept
Definition: ERF_CloudChamberWallFlux.H:575
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real to_coordinate_flux(amrex::Real inward) noexcept
Definition: ERF_CloudChamberWallFlux.H:563
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > relative_tangential_velocity_cell_centered(int dir, int i, int j, int k, const amrex::Array4< const amrex::Real > &u, const amrex::Array4< const amrex::Real > &v, const amrex::Array4< const amrex::Real > &w, const erf_wall_thermodynamics::FaceWall &wall) noexcept
Definition: ERF_CloudChamberWallFlux.H:630
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real resolved_vapor_flux_in(amrex::Real rho, amrex::Real alpha_C, amrex::Real wall_temperature_K, amrex::Real qv_air, amrex::Real p_hse, amrex::Real dx_inv) noexcept
Definition: ERF_CloudChamberWallFlux.H:710
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool requires_tangential_speed(const erf_wall_thermodynamics::FaceWall &wall, ScalarChannel channel) noexcept
Definition: ERF_CloudChamberWallFlux.H:439
ScalarChannel
Definition: ERF_CloudChamberWallFlux.H:53
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE FaceRuntimeCoefficients most_wall_coefficients(const erf_wall_thermodynamics::FaceWall &wall, amrex::Real theta_air, amrex::Real qv_air, amrex::Real p_hse, amrex::Real rdOcp, amrex::Real U_t, amrex::Real wall_distance, int gravity_sign) noexcept
Definition: ERF_CloudChamberWallFlux.H:278
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > neutral_log_traction_on_fluid(const MomentumWallSample &sample, const NeutralLogMomentumState &neutral) noexcept
Definition: ERF_CloudChamberWallFlux.H:358
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real resolved_theta_flux_in(amrex::Real rho, amrex::Real alpha_T, amrex::Real wall_temperature_K, amrex::Real theta_air, amrex::Real p_hse, amrex::Real dx_inv, amrex::Real rdOcp) noexcept
Definition: ERF_CloudChamberWallFlux.H:692
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ScalarChannel scalar_channel_from_quantity(int quantity) noexcept
Definition: ERF_CloudChamberWallFlux.H:141
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real scalar_flux_in(const WallFlux &flux, ScalarChannel channel) noexcept
Definition: ERF_CloudChamberWallFlux.H:909
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE unsigned char scalar_channel_mask(ScalarChannel channel) noexcept
Definition: ERF_CloudChamberWallFlux.H:192
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real momentum_row_sum_rate(int component, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &low_rate, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &high_rate) noexcept
Definition: ERF_CloudChamberWallFlux.H:393
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real momentum_rate_for_face(const erf_wall_thermodynamics::FaceWall &wall, amrex::Real U_t, amrex::Real dx_inv, const FaceRuntimeCoefficients &runtime=FaceRuntimeCoefficients{}) noexcept
Definition: ERF_CloudChamberWallFlux.H:410
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool wall_owns_scalar_channel(const erf_wall_thermodynamics::FaceWall &wall, ScalarChannel channel) noexcept
Definition: ERF_CloudChamberWallFlux.H:170
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool wall_uses_most_vapor(const erf_wall_thermodynamics::FaceWall &wall) noexcept
Definition: ERF_CloudChamberWallFlux.H:117
OwnedChannel
Definition: ERF_CloudChamberWallFlux.H:23
@ OwnVapor
Definition: ERF_CloudChamberWallFlux.H:27
@ OwnNone
Definition: ERF_CloudChamberWallFlux.H:24
@ OwnHeat
Definition: ERF_CloudChamberWallFlux.H:26
@ OwnCloudWater
Definition: ERF_CloudChamberWallFlux.H:28
@ OwnMomentum
Definition: ERF_CloudChamberWallFlux.H:25
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real neutral_scalar_rate(amrex::Real coefficient, amrex::Real U_t, amrex::Real dx_inv) noexcept
Definition: ERF_CloudChamberWallFlux.H:371
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int primitive_component(ScalarChannel channel) noexcept
Definition: ERF_CloudChamberWallFlux.H:152
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool requires_tangential_momentum(const erf_wall_thermodynamics::FaceWall &wall) noexcept
Definition: ERF_CloudChamberWallFlux.H:465
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real tangential_speed(int dir, int i, int j, int k, const amrex::Array4< const amrex::Real > &u, const amrex::Array4< const amrex::Real > &v, const amrex::Array4< const amrex::Real > &w, const erf_wall_thermodynamics::FaceWall &wall) noexcept
Definition: ERF_CloudChamberWallFlux.H:660
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE ScalarFluxReplacement scalar_flux_replacement(amrex::Real old_flux, amrex::Real inward_flux, amrex::Real dx_inv) noexcept
Definition: ERF_CloudChamberWallFlux.H:929
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real momentum_infinity_row_sum_factor() noexcept
Definition: ERF_CloudChamberWallFlux.H:382
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool wall_uses_most(const erf_wall_thermodynamics::FaceWall &wall) noexcept
Definition: ERF_CloudChamberWallFlux.H:128
AMREX_FORCE_INLINE void apply_face(const amrex::Box &bx, const amrex::Box &domain, const int quantity, const int flux_comp, const amrex::Array4< const amrex::Real > &state, const amrex::Array4< const amrex::Real > &prim, const amrex::Array4< const amrex::Real > &base_state, const amrex::Array4< const amrex::Real > &u, const amrex::Array4< const amrex::Real > &v, const amrex::Array4< const amrex::Real > &w, const amrex::Array4< amrex::Real > &rhs, const amrex::Array4< amrex::Real > &xflux, const amrex::Array4< amrex::Real > &yflux, const amrex::Array4< amrex::Real > &zflux, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx_inv, const erf_wall_thermodynamics::Boundary &walls, const amrex::Real alpha_T, const amrex::Real alpha_C, const amrex::Real rdOcp, const bool cloudy)
Definition: ERF_CloudChamberWallFlux.H:946
Definition: ERF_WallThermodynamics.H:9
amrex::GpuArray< FaceWall, 2 *AMREX_SPACEDIM > Boundary
Definition: ERF_WallThermodynamics.H:70
real(c_double), parameter t0
Definition: ERF_module_model_constants.F90:39
Definition: ERF_CloudChamberWallFlux.H:39
amrex::Real C_E
Definition: ERF_CloudChamberWallFlux.H:42
amrex::Real C_H
Definition: ERF_CloudChamberWallFlux.H:41
unsigned char valid
Definition: ERF_CloudChamberWallFlux.H:45
amrex::Real C_D
Definition: ERF_CloudChamberWallFlux.H:40
amrex::Real zeta
Definition: ERF_CloudChamberWallFlux.H:44
amrex::Real u_star
Definition: ERF_CloudChamberWallFlux.H:43
Definition: ERF_CloudChamberWallFlux.H:82
amrex::Real rho
Definition: ERF_CloudChamberWallFlux.H:83
amrex::Real U_t
Definition: ERF_CloudChamberWallFlux.H:85
int gravity_sign
Definition: ERF_CloudChamberWallFlux.H:91
amrex::Real wall_distance
Definition: ERF_CloudChamberWallFlux.H:86
amrex::Real p_hse
Definition: ERF_CloudChamberWallFlux.H:89
amrex::Real theta_air
Definition: ERF_CloudChamberWallFlux.H:87
amrex::Real rdOcp
Definition: ERF_CloudChamberWallFlux.H:90
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > u_t
Definition: ERF_CloudChamberWallFlux.H:84
amrex::Real qv_air
Definition: ERF_CloudChamberWallFlux.H:88
Definition: ERF_CloudChamberWallFlux.H:48
int iterations
Definition: ERF_CloudChamberWallFlux.H:50
amrex::Real zeta
Definition: ERF_CloudChamberWallFlux.H:49
Definition: ERF_CloudChamberWallFlux.H:76
amrex::Real C_D
Definition: ERF_CloudChamberWallFlux.H:78
amrex::Real u_star
Definition: ERF_CloudChamberWallFlux.H:79
amrex::Real log_m
Definition: ERF_CloudChamberWallFlux.H:77
Definition: ERF_CloudChamberWallFlux.H:94
amrex::Real coordinate_flux
Definition: ERF_CloudChamberWallFlux.H:95
amrex::Real rhs_delta
Definition: ERF_CloudChamberWallFlux.H:96
Definition: ERF_CloudChamberWallFlux.H:60
amrex::Real rdOcp
Definition: ERF_CloudChamberWallFlux.H:68
int gravity_sign
Definition: ERF_CloudChamberWallFlux.H:73
amrex::Real scalar_air
Definition: ERF_CloudChamberWallFlux.H:62
amrex::Real qv_air
Definition: ERF_CloudChamberWallFlux.H:72
amrex::Real rho
Definition: ERF_CloudChamberWallFlux.H:61
amrex::Real dx_inv
Definition: ERF_CloudChamberWallFlux.H:67
amrex::Real theta_air
Definition: ERF_CloudChamberWallFlux.H:71
amrex::Real wall_distance
Definition: ERF_CloudChamberWallFlux.H:70
amrex::Real alpha_T
Definition: ERF_CloudChamberWallFlux.H:65
amrex::Real p_hse
Definition: ERF_CloudChamberWallFlux.H:63
amrex::Real alpha_C
Definition: ERF_CloudChamberWallFlux.H:66
amrex::Real U_t
Definition: ERF_CloudChamberWallFlux.H:64
Definition: ERF_CloudChamberWallFlux.H:31
amrex::Real rhoTheta_in
Definition: ERF_CloudChamberWallFlux.H:33
amrex::Real rhoQv_in
Definition: ERF_CloudChamberWallFlux.H:34
unsigned char owned_channels
Definition: ERF_CloudChamberWallFlux.H:36
amrex::Real rhoQc_in
Definition: ERF_CloudChamberWallFlux.H:35
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > traction_on_fluid
Definition: ERF_CloudChamberWallFlux.H:32
Definition: ERF_WallThermodynamics.H:61
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > wall_velocity
Definition: ERF_WallThermodynamics.H:67
ScalarTransfer vapor
Definition: ERF_WallThermodynamics.H:66
ScalarTransfer heat
Definition: ERF_WallThermodynamics.H:65
MoistureMode moisture
Definition: ERF_WallThermodynamics.H:63
MomentumTransfer momentum
Definition: ERF_WallThermodynamics.H:64
ThermalBoundary thermal
Definition: ERF_WallThermodynamics.H:62
amrex::Real z0_m
Definition: ERF_WallThermodynamics.H:51
CoefficientProvider provider
Definition: ERF_WallThermodynamics.H:49
amrex::Real C_D
Definition: ERF_WallThermodynamics.H:50
MomentumModel model
Definition: ERF_WallThermodynamics.H:48
amrex::Real coefficient
Definition: ERF_WallThermodynamics.H:57
CoefficientProvider provider
Definition: ERF_WallThermodynamics.H:56
amrex::Real z0
Definition: ERF_WallThermodynamics.H:58
ScalarModel model
Definition: ERF_WallThermodynamics.H:55
amrex::Real temperature_K
Definition: ERF_WallThermodynamics.H:44
ThermalMode mode
Definition: ERF_WallThermodynamics.H:43
Definition: ERF_MOSTUtils.H:37
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_h2(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:74
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_m2(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:49