1 #ifndef ERF_CLOUD_CHAMBER_H_
2 #define ERF_CLOUD_CHAMBER_H_
4 #include <AMReX_Array.H>
5 #include <AMReX_ParmParse.H>
6 #include <AMReX_REAL.H>
53 amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>
prob_lo = {};
54 amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>
prob_hi = {};
55 amrex::GpuArray<WallSpec, 2 * AMREX_SPACEDIM>
walls = {};
64 for (
int n = 0; n < 2 * AMREX_SPACEDIM; ++n) {
65 boundary[n] =
walls[n].wall;
72 for (
const auto& wall :
walls) {
85 for (
const auto& wall :
walls) {
86 if (wall.wall.momentum.model ==
88 wall.wall.momentum.model ==
90 wall.wall.heat.model ==
92 wall.wall.heat.model ==
94 (wall.wall.vapor.model ==
98 (wall.wall.vapor.model ==
100 wall.wall.moisture ==
133 switch (contract.
mode) {
137 return "Cloud Chamber: physical SatAdj initialization requires prob.initial_relative_humidity";
140 return "Cloud Chamber: prob.initial_relative_humidity is only used with erf.moisture_model = SatAdj";
143 return "Cloud Chamber: physical_temperature_rh cannot be combined with legacy theta/qv profile keys";
148 return "Cloud Chamber: legacy_theta_qv cannot be combined with physical temperature/RH profile keys";
166 AMREX_GPU_HOST_DEVICE
172 return bottom + (top - bottom) * (coordinate - lower) /
length;
186 AMREX_GPU_HOST_DEVICE
189 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& lo,
190 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
length,
197 return amplitude * sx * sy * sz;
209 AMREX_GPU_HOST_DEVICE
213 int nx,
int ny) noexcept
227 AMREX_GPU_HOST_DEVICE
231 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& lo,
232 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
length,
239 return U_0 * sx * sx *
247 AMREX_GPU_HOST_DEVICE
251 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& lo,
252 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
length,
268 AMREX_GPU_HOST_DEVICE
284 AMREX_GPU_HOST_DEVICE
289 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>
length = {
294 config.initial_temperature_bottom :
config.theta_bottom;
298 config.temperature_perturbation_amplitude :
config.theta_perturbation_amplitude;
312 AMREX_GPU_HOST_DEVICE
329 AMREX_GPU_HOST_DEVICE
338 const amrex::Real ev_Pa = relative_humidity * es_Pa;
339 return RdoRv * ev_Pa / (pressure_Pa - ev_Pa);
344 return std::isfinite(
static_cast<double>(value));
350 amrex::Error(
"Cloud Chamber: " + key +
" must be finite");
393 const std::string& face)
401 contract.
heat_model ==
"neutral_roughness_log";
404 const bool any_neutral =
405 momentum_neutral || heat_neutral || vapor_neutral;
407 const bool any_channel_key =
419 return "Cloud Chamber: " + face +
420 " cannot combine wall_transfer_model with per-channel wall model keys";
425 !momentum_bulk && !momentum_neutral) {
426 return "Cloud Chamber: " + face +
427 ".momentum_transfer_model must be resolved_noslip, bulk_aero, "
428 "neutral_roughness_log, or law_of_wall_momentum";
436 contract.
heat_model !=
"resolved_molecular" && !heat_bulk && !heat_neutral) {
437 return "Cloud Chamber: " + face +
438 ".heat_transfer_model must be resolved_molecular, bulk_aero, or neutral_roughness_log";
441 contract.
vapor_model !=
"resolved_molecular" && !vapor_bulk && !vapor_neutral) {
442 return "Cloud Chamber: " + face +
443 ".vapor_transfer_model must be resolved_molecular, bulk_aero, or neutral_roughness_log";
446 const bool bulk_active = heat_bulk || vapor_bulk || momentum_bulk;
449 if (most_provider && !(face ==
"zlo" || face ==
"zhi")) {
450 return "Cloud Chamber: " + face +
451 " supports coefficient_source = most only on zlo or zhi";
453 if ((any_neutral || (bulk_active && most_provider)) &&
455 return "Cloud Chamber: " + face +
456 " requires z0_m for the active neutral/MOST wall-transfer channels";
458 if ((heat_neutral || (heat_bulk && most_provider)) &&
460 return "Cloud Chamber: " + face +
461 " requires z0_h for neutral roughness-log heat or MOST heat";
463 if ((vapor_neutral || (vapor_bulk && most_provider)) &&
465 return "Cloud Chamber: " + face +
466 " requires z0_q for neutral roughness-log vapor or MOST vapor";
469 !(any_neutral || (bulk_active && most_provider))) {
470 return "Cloud Chamber: " + face +
471 ".z0_m requires a neutral_roughness_log or MOST channel";
474 !(heat_neutral || (heat_bulk && most_provider))) {
475 return "Cloud Chamber: " + face +
476 ".z0_h requires neutral_roughness_log heat or MOST heat";
479 !(vapor_neutral || (vapor_bulk && most_provider))) {
480 return "Cloud Chamber: " + face +
481 ".z0_q requires neutral_roughness_log vapor or MOST vapor";
489 return "Cloud Chamber: " + face +
490 " active roughness lengths z0_m, z0_h, and z0_q must be finite and positive";
497 return "Cloud Chamber: " + face +
498 " active bulk_aero channels require coefficient_source = fixed or most";
501 return "Cloud Chamber: " + face +
502 ".coefficient_source is only valid when bulk_aero is active";
505 if (momentum_bulk && !most_provider &&
507 return "Cloud Chamber: " + face +
508 " requires C_D when momentum_transfer_model = bulk_aero with coefficient_source = fixed";
511 return "Cloud Chamber: " + face +
512 ".C_D is not valid with coefficient_source = most";
515 return "Cloud Chamber: " + face +
516 " requires C_H when heat_transfer_model = bulk_aero";
519 return "Cloud Chamber: " + face +
520 ".C_H is not valid with coefficient_source = most";
523 return "Cloud Chamber: " + face +
524 " requires C_E when vapor_transfer_model = bulk_aero";
527 return "Cloud Chamber: " + face +
528 ".C_E is not valid with coefficient_source = most";
531 return "Cloud Chamber: " + face +
532 ".C_D requires momentum_transfer_model = bulk_aero";
535 return "Cloud Chamber: " + face +
536 ".C_H requires heat_transfer_model = bulk_aero";
539 return "Cloud Chamber: " + face +
540 ".C_E requires vapor_transfer_model = bulk_aero";
551 return "Cloud Chamber: " + face +
552 " bulk coefficients C_D, C_H, and C_E must be finite and nonnegative";
559 const std::string& face,
570 if (wet_wall && heat_most && vapor_most &&
572 return "Cloud Chamber: " + face +
573 " coupled heat/vapor MOST requires z0_h == z0_q because the "
574 "prescribed-temperature bulk-Richardson closure uses one scalar "
575 "similarity resistance; z0_h=" +
576 std::to_string(
static_cast<double>(contract.
z0_h)) +
578 std::to_string(
static_cast<double>(contract.
z0_q));
585 amrex::ParmParse pp_geom(
"geometry");
587 pp_geom.getarr(
"is_periodic",
periodic);
588 if (
periodic.size() != AMREX_SPACEDIM) {
589 amrex::Error(
"Cloud Chamber: geometry.is_periodic must provide three values");
591 for (
int d = 0; d < AMREX_SPACEDIM; ++d) {
593 amrex::Error(
"Cloud Chamber: geometry.is_periodic must be 0 0 0");
600 amrex::ParmParse pp_erf(
"erf");
602 if (pp_erf.query(
"terrain_type", value) &&
603 amrex::toLower(value) !=
"none") {
604 amrex::Error(
"Cloud Chamber: erf.terrain_type must be None; terrain and embedded boundaries are out of scope");
607 if (pp_erf.query(
"buildings_type", value) &&
608 amrex::toLower(value) !=
"none") {
609 amrex::Error(
"Cloud Chamber: erf.buildings_type must be None; immersed buildings are out of scope");
612 if (pp_erf.query(
"mesh_type", value) &&
613 amrex::toLower(value) !=
"constantdz") {
614 amrex::Error(
"Cloud Chamber: erf.mesh_type must be ConstantDz");
619 const std::string& face)
621 if (
pp.contains(
"physical_temperature") ||
pp.contains(
"relative_humidity") ||
622 pp.contains(
"rh") ||
pp.contains(
"roughness") ||
623 pp.contains(
"roughness_length") ||
pp.contains(
"z0") ||
624 pp.contains(
"most") ||
pp.contains(
"MOST")) {
625 amrex::Error(
"Cloud Chamber: " + face +
626 " must use temperature and moisture for physical walls; "
627 "roughness aliases and legacy aliases are unsupported");
634 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
dx)
636 for (
int n = 0; n < 2 * AMREX_SPACEDIM; ++n) {
637 const auto& wall = walls[n];
638 const int dir = n / 2;
641 const auto check = [&](
bool active,
const char* key,
643 if (!active) {
return {}; }
646 return "Cloud Chamber: " + face +
" " + key +
647 " requires 0 < " + key +
" < z_ref; " + key +
"=" +
648 std::to_string(
static_cast<double>(
z0)) +
650 std::to_string(
static_cast<double>(z_ref));
654 const bool momentum_neutral =
655 wall.momentum.model ==
657 const bool heat_neutral =
660 const bool vapor_neutral =
663 const bool any_neutral =
664 momentum_neutral || heat_neutral || vapor_neutral;
665 const bool most_momentum =
668 const bool most_heat =
671 const bool most_vapor =
674 const auto momentum_error = check(
675 any_neutral || most_momentum || most_heat || most_vapor,
676 "z0_m", wall.momentum.z0_m);
677 if (!momentum_error.empty()) {
return momentum_error; }
678 const auto heat_error = check(
679 heat_neutral || most_heat,
680 "z0_h", wall.heat.z0);
681 if (!heat_error.empty()) {
return heat_error; }
682 const auto vapor_error = check(
683 vapor_neutral || most_vapor,
684 "z0_q", wall.vapor.z0);
685 if (!vapor_error.empty()) {
return vapor_error; }
693 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
dx)
696 if (!error.empty()) { amrex::Error(error); }
704 for (
int d = 0; d < AMREX_SPACEDIM; ++d) {
710 amrex::Error(
"Cloud Chamber: geometry.prob_hi must exceed geometry.prob_lo in every direction");
714 amrex::ParmParse pp_erf(
"erf");
716 if (!pp_erf.query(
"anelastic", anelastic) || anelastic != 1) {
717 amrex::Error(
"Cloud Chamber: erf.anelastic = 1 is required");
719 bool use_gravity =
false;
720 if (!pp_erf.query(
"use_gravity", use_gravity) || !use_gravity) {
721 amrex::Error(
"Cloud Chamber: erf.use_gravity = true is required");
724 amrex::ParmParse pp_amr(
"amr");
726 pp_amr.query(
"max_level", max_level);
727 if (max_level != 0) {
728 amrex::Error(
"Cloud Chamber: amr.max_level must be 0");
733 amrex::ParmParse
pp_prob(
"prob");
738 if (std::abs(
p_inf -
p_0) > pressure_tolerance) {
739 amrex::Error(
"Cloud Chamber: prob.p_inf must match ERF's p_0 = 100000 Pa within 1e-6 relative tolerance");
743 std::string moisture_model;
744 const bool moisture_specified = pp_erf.query(
"moisture_model", moisture_model);
745 if (moisture_specified) {
746 moisture_model = amrex::toLower(moisture_model);
747 if (moisture_model !=
"satadj") {
748 amrex::Error(
"Cloud Chamber: moisture_model must be omitted for dry mode or set to SatAdj");
751 }
else if (
pp_prob.contains(
"qv_bottom") ||
pp_prob.contains(
"qv_top")) {
752 amrex::Error(
"Cloud Chamber: qv_bottom/qv_top require erf.moisture_model = SatAdj");
755 std::string init_mode;
756 pp_prob.get(
"thermodynamic_initialization", init_mode);
757 init_mode = amrex::toLower(init_mode);
758 if (init_mode ==
"physical_temperature_rh") {
759 config.physical_initialization =
true;
762 if (amrex::toLower(
init_type) !=
"constantdensity") {
763 amrex::Error(
"Cloud Chamber: physical initialization requires the existing HSE-backed erf.init_type = ConstantDensity path");
765 std::string molec_diff_type;
766 pp_erf.get(
"molec_diff_type", molec_diff_type);
767 if (amrex::toLower(molec_diff_type) !=
"constantalpha") {
768 amrex::Error(
"Cloud Chamber: physical wall transfer requires erf.molec_diff_type = ConstantAlpha");
770 bool vert_implicit =
false;
771 pp_erf.query(
"vert_implicit", vert_implicit);
773 amrex::Error(
"Cloud Chamber: physical wall transfer requires erf.vert_implicit = false");
775 pp_prob.get(
"initial_temperature_bottom",
config.initial_temperature_bottom);
776 pp_prob.get(
"initial_temperature_top",
config.initial_temperature_top);
777 const bool has_initial_relative_humidity =
pp_prob.contains(
"initial_relative_humidity");
778 auto physical_contract_error = [&](
bool has_legacy_profile_keys) {
782 has_initial_relative_humidity,
783 has_legacy_profile_keys,
787 std::string contract_error = physical_contract_error(
false);
788 if (!contract_error.empty()) {
789 amrex::Error(contract_error);
792 pp_prob.get(
"initial_relative_humidity",
config.initial_relative_humidity);
794 pp_prob.query(
"temperature_perturbation_amplitude",
795 config.temperature_perturbation_amplitude);
796 const bool has_legacy_profile_keys =
pp_prob.contains(
"theta_bottom") ||
797 pp_prob.contains(
"theta_top") ||
798 pp_prob.contains(
"theta_perturbation_amplitude") ||
799 pp_prob.contains(
"qv_bottom") ||
801 contract_error = physical_contract_error(has_legacy_profile_keys);
802 if (!contract_error.empty()) {
803 amrex::Error(contract_error);
808 config.temperature_perturbation_amplitude);
811 amrex::Error(
"Cloud Chamber: physical initial temperatures must be positive");
817 amrex::Error(
"Cloud Chamber: initial_relative_humidity must lie in [0,1]");
820 }
else if (init_mode ==
"legacy_theta_qv") {
821 config.physical_initialization =
false;
827 pp_prob.contains(
"initial_temperature_bottom") ||
828 pp_prob.contains(
"initial_temperature_top") ||
829 pp_prob.contains(
"initial_relative_humidity") ||
830 pp_prob.contains(
"temperature_perturbation_amplitude")};
832 if (!contract_error.empty()) {
833 amrex::Error(contract_error);
837 pp_prob.query(
"theta_perturbation_amplitude",
838 config.theta_perturbation_amplitude);
840 amrex::Error(
"Cloud Chamber: prob.thermodynamic_initialization must be physical_temperature_rh or legacy_theta_qv");
842 std::string perturbation_mode =
"deterministic_sine";
843 pp_prob.query(
"perturbation_mode", perturbation_mode);
844 if (amrex::toLower(perturbation_mode) !=
"deterministic_sine") {
845 amrex::Error(
"Cloud Chamber: prob.perturbation_mode must be deterministic_sine");
847 if (!
config.physical_initialization) {
851 config.theta_perturbation_amplitude);
854 amrex::Error(
"Cloud Chamber: theta profile values must be positive");
858 if (moisture_specified) {
859 if (!
config.physical_initialization) {
866 amrex::Error(
"Cloud Chamber: qv profile values must be nonnegative");
873 for (
int n = 0; n < 2 * AMREX_SPACEDIM; ++n) {
874 const std::string face =
face_name(faces[n]);
875 amrex::ParmParse pp_face(face.c_str());
878 if (!pp_face.query(
"type", type) ||
879 amrex::toLower(type) !=
"noslipwall") {
880 amrex::Error(
"Cloud Chamber: " + face +
".type must be NoSlipWall");
883 wall.
face = faces[n];
885 std::string transfer =
"resolved_molecular";
886 if (pp_face.query(
"wall_transfer_model", transfer)) {
888 transfer = amrex::toLower(transfer);
889 if (transfer !=
"resolved_molecular") {
890 amrex::Error(
"Cloud Chamber: only resolved_molecular wall transfer is supported");
893 if (pp_face.query(
"momentum_transfer_model", transfer_contract.
momentum_model)) {
897 if (pp_face.query(
"heat_transfer_model", transfer_contract.
heat_model)) {
901 if (pp_face.query(
"vapor_transfer_model", transfer_contract.
vapor_model)) {
921 if (pp_face.query(
"z0_m", transfer_contract.
z0_m)) {
925 if (pp_face.query(
"z0_h", transfer_contract.
z0_h)) {
929 if (pp_face.query(
"z0_q", transfer_contract.
z0_q)) {
933 const std::string transfer_error =
935 if (!transfer_error.empty()) {
936 amrex::Error(transfer_error);
938 const bool any_channel_key =
949 if (!
config.physical_initialization && any_channel_key) {
950 amrex::Error(
"Cloud Chamber: per-channel wall transfer keys require physical temperature initialization");
952 if (
config.physical_initialization) {
953 if (pp_face.contains(
"theta") || pp_face.contains(
"qv") ||
954 pp_face.contains(
"theta_grad") || pp_face.contains(
"qv_grad")) {
955 amrex::Error(
"Cloud Chamber: physical walls cannot combine temperature/moisture with legacy theta/qv wall keys");
958 amrex::Error(
"Cloud Chamber: missing required physical " + face +
".temperature");
962 amrex::Error(
"Cloud Chamber: " + face +
".temperature must be positive Kelvin");
964 std::string moisture;
965 pp_face.get(
"moisture", moisture);
966 moisture = amrex::toLower(moisture);
967 if (moisture ==
"dry") {
969 }
else if (moisture ==
"wet") {
972 amrex::Error(
"Cloud Chamber: wet walls require SatAdj moisture");
975 amrex::Error(
"Cloud Chamber: " + face +
".moisture must be dry or wet");
977 const std::string coupled_most_error =
979 transfer_contract, face,
982 if (!coupled_most_error.empty()) {
983 amrex::Error(coupled_most_error);
998 (transfer_contract.
heat_model ==
"neutral_roughness_log" ?
1004 (transfer_contract.
vapor_model ==
"neutral_roughness_log" ?
1030 amrex::Error(
"Cloud Chamber: missing required " + face +
".theta");
1036 if (
config.cloudy && !pp_face.contains(
"qv")) {
1037 amrex::Error(
"Cloud Chamber: legacy cloudy walls require " + face +
".qv");
1040 for (
int d = 0; d < AMREX_SPACEDIM; ++d) {
1041 if (pp_face.contains(
"velocity")) {
1042 amrex::Error(
"Cloud Chamber: wall velocity metadata is not active; use NoSlipWall with zero velocity");
1047 for (
int d = 0; d < AMREX_SPACEDIM; ++d) {
1050 amrex::Error(
"Cloud Chamber: every rectangular dimension must be finite and positive");
constexpr amrex::Real p_0
Definition: ERF_Constants.H:53
constexpr amrex::Real RdoRv
Definition: ERF_Constants.H:44
auto probhi
Definition: ERF_InitCustomPertVels_ABL.H:37
auto problo
Definition: ERF_InitCustomPertVels_ABL.H:36
const Real lx
Definition: ERF_InitCustomPertVels_CloudChamber.H:10
const int nx
Definition: ERF_InitCustomPertVels_CloudChamber.H:14
const int ny
Definition: ERF_InitCustomPertVels_CloudChamber.H:15
const Real v_scale
Definition: ERF_InitCustomPertVels_CloudChamber.H:16
const Real ly
Definition: ERF_InitCustomPertVels_CloudChamber.H:11
InitType init_type
Definition: ERF_InitCustomPertVels_EkmanSpiral.H:3
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:8
const Real dy
Definition: ERF_InitCustomPert_ABL.H:45
ParmParse pp_prob("prob")
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
const Real length
Definition: ERF_InitCustomPert_AnelasticWallDiffusion.H:14
const auto config
Definition: ERF_InitCustomPert_CloudChamber.H:37
amrex::Real p_inf
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:5
Real U_0
Definition: ERF_InitCustomPert_TurbulentInflow.H:13
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t, bool use_empirical=false)
Definition: ERF_MicrophysicsUtils.H:159
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_CloudChamber.H:18
void require_zero_periodicity()
Definition: ERF_CloudChamber.H:583
WallFace
Definition: ERF_CloudChamber.H:27
std::string wall_coupled_most_roughness_error(const WallTransferContract &contract, const std::string &face, bool wet_wall)
Definition: ERF_CloudChamber.H:558
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE amrex::Real initial_u_velocity_perturbation(amrex::Real x, amrex::Real y, amrex::Real z, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &lo, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &length, amrex::Real U_0, int nx, int ny) noexcept
Evaluate the x-face component of the Cloud Chamber initial velocity.
Definition: ERF_CloudChamber.H:229
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE amrex::Real deterministic_perturbation(amrex::Real x, amrex::Real y, amrex::Real z, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &lo, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &length, amrex::Real amplitude) noexcept
Compute a deterministic 3D sine perturbation.
Definition: ERF_CloudChamber.H:188
std::string wall_transfer_contract_error(const WallTransferContract &contract, const std::string &face)
Definition: ERF_CloudChamber.H:392
std::string wall_roughness_geometry_error(const erf_wall_thermodynamics::Boundary &walls, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx)
Definition: ERF_CloudChamber.H:632
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE amrex::Real staggered_velocity_v_scale(amrex::Real lx, amrex::Real ly, amrex::Real dx, amrex::Real dy, int nx, int ny) noexcept
Discrete derivative ratio for the staggered initial velocity field.
Definition: ERF_CloudChamber.H:211
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE amrex::Real qv_at(const Config &config, amrex::Real z) noexcept
Compute the water vapor mixing ratio at a given height.
Definition: ERF_CloudChamber.H:314
std::string face_name(WallFace face)
Definition: ERF_CloudChamber.H:354
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE amrex::Real vapor_mixing_ratio_from_relative_humidity(amrex::Real temperature_K, amrex::Real pressure_Pa, amrex::Real relative_humidity) noexcept
Convert relative humidity to water vapor mixing ratio.
Definition: ERF_CloudChamber.H:331
Config parse_config(const amrex::Real *problo, const amrex::Real *probhi)
Definition: ERF_CloudChamber.H:699
void require_finite(const std::string &key, amrex::Real value)
Definition: ERF_CloudChamber.H:347
void validate_wall_roughness_geometry(const erf_wall_thermodynamics::Boundary &walls, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx)
Definition: ERF_CloudChamber.H:691
InitializationMode
Definition: ERF_CloudChamber.H:109
void reject_unsupported_face_keys(amrex::ParmParse &pp, const std::string &face)
Definition: ERF_CloudChamber.H:618
void require_no_unsupported_geometry()
Definition: ERF_CloudChamber.H:598
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE amrex::Real theta_at(const Config &config, amrex::Real x, amrex::Real y, amrex::Real z) noexcept
Compute the potential temperature at a given location.
Definition: ERF_CloudChamber.H:286
std::string initialization_contract_error(const InitializationContract &contract)
Validate the initialization contract and return an error message if violated.
Definition: ERF_CloudChamber.H:131
bool finite(amrex::Real value) noexcept
Definition: ERF_CloudChamber.H:342
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE amrex::Real linear_profile(amrex::Real bottom, amrex::Real top, amrex::Real coordinate, amrex::Real lower, amrex::Real length) noexcept
Compute a linear profile between two values.
Definition: ERF_CloudChamber.H:168
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE amrex::Real initial_w_velocity_perturbation() noexcept
The Cloud Chamber initial vertical velocity perturbation.
Definition: ERF_CloudChamber.H:270
AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE amrex::Real initial_v_velocity_perturbation(amrex::Real x, amrex::Real y, amrex::Real z, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &lo, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &length, amrex::Real U_0, amrex::Real v_scale, int nx, int ny) noexcept
Evaluate the y-face component of the Cloud Chamber initial velocity.
Definition: ERF_CloudChamber.H:249
@ FixedPhysicalTemperature
amrex::GpuArray< FaceWall, 2 *AMREX_SPACEDIM > Boundary
Definition: ERF_WallThermodynamics.H:70
real(c_double), parameter, private pi
Definition: ERF_module_mp_morr_two_moment.F90:100
Configuration parameters for cloud chamber initialization.
Definition: ERF_CloudChamber.H:40
amrex::Real qv_top
Definition: ERF_CloudChamber.H:52
amrex::GpuArray< WallSpec, 2 *AMREX_SPACEDIM > walls
Definition: ERF_CloudChamber.H:55
erf_wall_thermodynamics::Boundary wall_boundary() const noexcept
Collect thermodynamic boundary conditions for all chamber walls.
Definition: ERF_CloudChamber.H:61
bool active
Definition: ERF_CloudChamber.H:41
amrex::Real initial_temperature_top
Definition: ERF_CloudChamber.H:45
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > prob_hi
Definition: ERF_CloudChamber.H:54
bool cloudy
Definition: ERF_CloudChamber.H:42
bool has_wall_rate_channel() const noexcept
Definition: ERF_CloudChamber.H:83
amrex::Real qv_bottom
Definition: ERF_CloudChamber.H:51
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > prob_lo
Definition: ERF_CloudChamber.H:53
amrex::Real initial_temperature_bottom
Definition: ERF_CloudChamber.H:44
amrex::Real temperature_perturbation_amplitude
Definition: ERF_CloudChamber.H:47
amrex::Real theta_perturbation_amplitude
Definition: ERF_CloudChamber.H:50
amrex::Real theta_bottom
Definition: ERF_CloudChamber.H:48
amrex::Real initial_relative_humidity
Definition: ERF_CloudChamber.H:46
bool has_bulk_scalar_wall() const noexcept
Definition: ERF_CloudChamber.H:70
amrex::Real theta_top
Definition: ERF_CloudChamber.H:49
bool physical_initialization
Definition: ERF_CloudChamber.H:43
Contract used to validate initialization parameter consistency.
Definition: ERF_CloudChamber.H:117
InitializationMode mode
Definition: ERF_CloudChamber.H:118
bool has_initial_relative_humidity
Definition: ERF_CloudChamber.H:120
bool has_physical_profile_keys
Definition: ERF_CloudChamber.H:122
bool has_legacy_profile_keys
Definition: ERF_CloudChamber.H:121
bool cloudy
Definition: ERF_CloudChamber.H:119
Metadata describing a chamber wall.
Definition: ERF_CloudChamber.H:32
erf_wall_thermodynamics::FaceWall wall
Definition: ERF_CloudChamber.H:34
WallFace face
Definition: ERF_CloudChamber.H:33
Definition: ERF_CloudChamber.H:367
amrex::Real z0_m
Definition: ERF_CloudChamber.H:386
std::string heat_model
Definition: ERF_CloudChamber.H:380
bool momentum_model_specified
Definition: ERF_CloudChamber.H:369
amrex::Real z0_q
Definition: ERF_CloudChamber.H:388
bool z0_h_specified
Definition: ERF_CloudChamber.H:377
bool coefficient_source_specified
Definition: ERF_CloudChamber.H:372
std::string coefficient_source
Definition: ERF_CloudChamber.H:382
std::string vapor_model
Definition: ERF_CloudChamber.H:381
bool z0_q_specified
Definition: ERF_CloudChamber.H:378
std::string momentum_model
Definition: ERF_CloudChamber.H:379
amrex::Real z0_h
Definition: ERF_CloudChamber.H:387
bool legacy_aggregate_specified
Definition: ERF_CloudChamber.H:368
bool vapor_model_specified
Definition: ERF_CloudChamber.H:371
amrex::Real momentum_coefficient
Definition: ERF_CloudChamber.H:383
bool heat_coefficient_specified
Definition: ERF_CloudChamber.H:374
amrex::Real heat_coefficient
Definition: ERF_CloudChamber.H:384
bool heat_model_specified
Definition: ERF_CloudChamber.H:370
bool momentum_coefficient_specified
Definition: ERF_CloudChamber.H:373
bool z0_m_specified
Definition: ERF_CloudChamber.H:376
amrex::Real vapor_coefficient
Definition: ERF_CloudChamber.H:385
bool vapor_coefficient_specified
Definition: ERF_CloudChamber.H:375
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