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>
54 amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>
prob_lo = {};
55 amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>
prob_hi = {};
56 amrex::GpuArray<WallSpec, 2 * AMREX_SPACEDIM>
walls = {};
65 for (
int n = 0; n < 2 * AMREX_SPACEDIM; ++n) {
66 boundary[n] =
walls[n].wall;
73 for (
const auto& wall :
walls) {
86 for (
const auto& wall :
walls) {
87 if (wall.wall.momentum.model ==
89 wall.wall.momentum.model ==
91 wall.wall.heat.model ==
93 wall.wall.heat.model ==
95 (wall.wall.vapor.model ==
99 (wall.wall.vapor.model ==
101 wall.wall.moisture ==
135 switch (contract.
mode) {
139 return "Cloud Chamber: physical moist initialization requires prob.initial_relative_humidity";
142 return "Cloud Chamber: prob.initial_relative_humidity requires an active moisture model";
145 return "Cloud Chamber: physical_temperature_rh cannot be combined with legacy theta/qv profile keys";
150 return "Cloud Chamber: legacy_theta_qv cannot be combined with physical temperature/RH profile keys";
168 switch (moisture_type) {
170 case MoistureType::SatAdj:
171 case MoistureType::MoistNoCondensation:
172 case MoistureType::Kessler_NoRain:
173 case MoistureType::Kessler:
174 case MoistureType::SAM_NoPrecip_NoIce:
175 case MoistureType::SAM_NoIce:
176 case MoistureType::SAM:
177 case MoistureType::WSM6:
178 case MoistureType::WDM6:
179 case MoistureType::Morrison_NoIce:
180 case MoistureType::Morrison:
182 case MoistureType::SBM:
183 case MoistureType::SuperDroplets:
199 AMREX_GPU_HOST_DEVICE
205 return bottom + (top - bottom) * (coordinate - lower) /
length;
219 AMREX_GPU_HOST_DEVICE
222 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& lo,
223 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
length,
230 return amplitude * sx * sy * sz;
242 AMREX_GPU_HOST_DEVICE
246 int nx,
int ny) noexcept
260 AMREX_GPU_HOST_DEVICE
264 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& lo,
265 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
length,
272 return U_0 * sx * sx *
280 AMREX_GPU_HOST_DEVICE
284 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& lo,
285 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
length,
301 AMREX_GPU_HOST_DEVICE
317 AMREX_GPU_HOST_DEVICE
322 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>
length = {
327 config.initial_temperature_bottom :
config.theta_bottom;
331 config.temperature_perturbation_amplitude :
config.theta_perturbation_amplitude;
345 AMREX_GPU_HOST_DEVICE
362 AMREX_GPU_HOST_DEVICE
371 const amrex::Real ev_Pa = relative_humidity * es_Pa;
372 return RdoRv * ev_Pa / (pressure_Pa - ev_Pa);
377 return std::isfinite(
static_cast<double>(value));
383 amrex::Error(
"Cloud Chamber: " + key +
" must be finite");
426 const std::string& face)
434 contract.
heat_model ==
"neutral_roughness_log";
437 const bool any_neutral =
438 momentum_neutral || heat_neutral || vapor_neutral;
440 const bool any_channel_key =
452 return "Cloud Chamber: " + face +
453 " cannot combine wall_transfer_model with per-channel wall model keys";
458 !momentum_bulk && !momentum_neutral) {
459 return "Cloud Chamber: " + face +
460 ".momentum_transfer_model must be resolved_noslip, bulk_aero, "
461 "neutral_roughness_log, or law_of_wall_momentum";
469 contract.
heat_model !=
"resolved_molecular" && !heat_bulk && !heat_neutral) {
470 return "Cloud Chamber: " + face +
471 ".heat_transfer_model must be resolved_molecular, bulk_aero, or neutral_roughness_log";
474 contract.
vapor_model !=
"resolved_molecular" && !vapor_bulk && !vapor_neutral) {
475 return "Cloud Chamber: " + face +
476 ".vapor_transfer_model must be resolved_molecular, bulk_aero, or neutral_roughness_log";
479 const bool bulk_active = heat_bulk || vapor_bulk || momentum_bulk;
482 if (most_provider && !(face ==
"zlo" || face ==
"zhi")) {
483 return "Cloud Chamber: " + face +
484 " supports coefficient_source = most only on zlo or zhi";
486 if ((any_neutral || (bulk_active && most_provider)) &&
488 return "Cloud Chamber: " + face +
489 " requires z0_m for the active neutral/MOST wall-transfer channels";
491 if ((heat_neutral || (heat_bulk && most_provider)) &&
493 return "Cloud Chamber: " + face +
494 " requires z0_h for neutral roughness-log heat or MOST heat";
496 if ((vapor_neutral || (vapor_bulk && most_provider)) &&
498 return "Cloud Chamber: " + face +
499 " requires z0_q for neutral roughness-log vapor or MOST vapor";
502 !(any_neutral || (bulk_active && most_provider))) {
503 return "Cloud Chamber: " + face +
504 ".z0_m requires a neutral_roughness_log or MOST channel";
507 !(heat_neutral || (heat_bulk && most_provider))) {
508 return "Cloud Chamber: " + face +
509 ".z0_h requires neutral_roughness_log heat or MOST heat";
512 !(vapor_neutral || (vapor_bulk && most_provider))) {
513 return "Cloud Chamber: " + face +
514 ".z0_q requires neutral_roughness_log vapor or MOST vapor";
522 return "Cloud Chamber: " + face +
523 " active roughness lengths z0_m, z0_h, and z0_q must be finite and positive";
530 return "Cloud Chamber: " + face +
531 " active bulk_aero channels require coefficient_source = fixed or most";
534 return "Cloud Chamber: " + face +
535 ".coefficient_source is only valid when bulk_aero is active";
538 if (momentum_bulk && !most_provider &&
540 return "Cloud Chamber: " + face +
541 " requires C_D when momentum_transfer_model = bulk_aero with coefficient_source = fixed";
544 return "Cloud Chamber: " + face +
545 ".C_D is not valid with coefficient_source = most";
548 return "Cloud Chamber: " + face +
549 " requires C_H when heat_transfer_model = bulk_aero";
552 return "Cloud Chamber: " + face +
553 ".C_H is not valid with coefficient_source = most";
556 return "Cloud Chamber: " + face +
557 " requires C_E when vapor_transfer_model = bulk_aero";
560 return "Cloud Chamber: " + face +
561 ".C_E is not valid with coefficient_source = most";
564 return "Cloud Chamber: " + face +
565 ".C_D requires momentum_transfer_model = bulk_aero";
568 return "Cloud Chamber: " + face +
569 ".C_H requires heat_transfer_model = bulk_aero";
572 return "Cloud Chamber: " + face +
573 ".C_E requires vapor_transfer_model = bulk_aero";
584 return "Cloud Chamber: " + face +
585 " bulk coefficients C_D, C_H, and C_E must be finite and nonnegative";
592 const std::string& face,
603 if (wet_wall && heat_most && vapor_most &&
605 return "Cloud Chamber: " + face +
606 " coupled heat/vapor MOST requires z0_h == z0_q because the "
607 "prescribed-temperature bulk-Richardson closure uses one scalar "
608 "similarity resistance; z0_h=" +
609 std::to_string(
static_cast<double>(contract.
z0_h)) +
611 std::to_string(
static_cast<double>(contract.
z0_q));
618 amrex::ParmParse pp_geom(
"geometry");
620 pp_geom.getarr(
"is_periodic",
periodic);
621 if (
periodic.size() != AMREX_SPACEDIM) {
622 amrex::Error(
"Cloud Chamber: geometry.is_periodic must provide three values");
624 for (
int d = 0; d < AMREX_SPACEDIM; ++d) {
626 amrex::Error(
"Cloud Chamber: geometry.is_periodic must be 0 0 0");
633 amrex::ParmParse pp_erf(
"erf");
635 if (pp_erf.query(
"terrain_type", value) &&
636 amrex::toLower(value) !=
"none") {
637 amrex::Error(
"Cloud Chamber: erf.terrain_type must be None; terrain and embedded boundaries are out of scope");
640 if (pp_erf.query(
"buildings_type", value) &&
641 amrex::toLower(value) !=
"none") {
642 amrex::Error(
"Cloud Chamber: erf.buildings_type must be None; immersed buildings are out of scope");
645 if (pp_erf.query(
"mesh_type", value) &&
646 amrex::toLower(value) !=
"constantdz") {
647 amrex::Error(
"Cloud Chamber: erf.mesh_type must be ConstantDz");
651 amrex::Error(
"Cloud Chamber: the vertical grid must be uniform (no erf.grid_stretching_ratio, "
652 "erf.initial_dz or erf.terrain_z_levels)");
657 const std::string& face)
659 if (
pp.contains(
"physical_temperature") ||
pp.contains(
"relative_humidity") ||
660 pp.contains(
"rh") ||
pp.contains(
"roughness") ||
661 pp.contains(
"roughness_length") ||
pp.contains(
"z0") ||
662 pp.contains(
"most") ||
pp.contains(
"MOST")) {
663 amrex::Error(
"Cloud Chamber: " + face +
664 " must use temperature and moisture for physical walls; "
665 "roughness aliases and legacy aliases are unsupported");
672 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
dx)
674 for (
int n = 0; n < 2 * AMREX_SPACEDIM; ++n) {
675 const auto& wall = walls[n];
676 const int dir = n / 2;
679 const auto check = [&](
bool active,
const char* key,
681 if (!active) {
return {}; }
684 return "Cloud Chamber: " + face +
" " + key +
685 " requires 0 < " + key +
" < z_ref; " + key +
"=" +
686 std::to_string(
static_cast<double>(
z0)) +
688 std::to_string(
static_cast<double>(z_ref));
692 const bool momentum_neutral =
693 wall.momentum.model ==
695 const bool heat_neutral =
698 const bool vapor_neutral =
701 const bool any_neutral =
702 momentum_neutral || heat_neutral || vapor_neutral;
703 const bool most_momentum =
706 const bool most_heat =
709 const bool most_vapor =
712 const auto momentum_error = check(
713 any_neutral || most_momentum || most_heat || most_vapor,
714 "z0_m", wall.momentum.z0_m);
715 if (!momentum_error.empty()) {
return momentum_error; }
716 const auto heat_error = check(
717 heat_neutral || most_heat,
718 "z0_h", wall.heat.z0);
719 if (!heat_error.empty()) {
return heat_error; }
720 const auto vapor_error = check(
721 vapor_neutral || most_vapor,
722 "z0_q", wall.vapor.z0);
723 if (!vapor_error.empty()) {
return vapor_error; }
731 const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>&
dx)
734 if (!error.empty()) { amrex::Error(error); }
739 const MoistureType selected_moisture_model)
743 for (
int d = 0; d < AMREX_SPACEDIM; ++d) {
749 amrex::Error(
"Cloud Chamber: geometry.prob_hi must exceed geometry.prob_lo in every direction");
753 amrex::ParmParse pp_erf(
"erf");
755 if (!pp_erf.query(
"anelastic", anelastic) || anelastic != 1) {
756 amrex::Error(
"Cloud Chamber: erf.anelastic = 1 is required");
758 bool use_gravity =
false;
759 if (!pp_erf.query(
"use_gravity", use_gravity) || !use_gravity) {
760 amrex::Error(
"Cloud Chamber: erf.use_gravity = true is required");
763 amrex::ParmParse pp_amr(
"amr");
765 pp_amr.query(
"max_level", max_level);
766 if (max_level != 0) {
767 amrex::Error(
"Cloud Chamber: amr.max_level must be 0");
772 amrex::ParmParse
pp_prob(
"prob");
777 if (std::abs(
p_inf -
p_0) > pressure_tolerance) {
778 amrex::Error(
"Cloud Chamber: prob.p_inf must match ERF's p_0 = 100000 Pa within 1e-6 relative tolerance");
783 amrex::Error(
"Cloud Chamber: selected moisture model is unsupported; use an Eulerian model from the supported moisture allowlist");
786 if (!
config.has_moisture && pp_erf.contains(
"moisture_model")) {
787 amrex::Error(
"Cloud Chamber: omit erf.moisture_model for dry mode instead of explicitly selecting None");
789 if (!
config.has_moisture &&
791 amrex::Error(
"Cloud Chamber: qv_bottom/qv_top require an active moisture model");
794 std::string init_mode;
795 pp_prob.get(
"thermodynamic_initialization", init_mode);
796 init_mode = amrex::toLower(init_mode);
797 if (init_mode ==
"physical_temperature_rh") {
798 config.physical_initialization =
true;
801 if (amrex::toLower(
init_type) !=
"constantdensity") {
802 amrex::Error(
"Cloud Chamber: physical initialization requires the existing HSE-backed erf.init_type = ConstantDensity path");
804 std::string molec_diff_type;
805 pp_erf.get(
"molec_diff_type", molec_diff_type);
806 if (amrex::toLower(molec_diff_type) !=
"constantalpha") {
807 amrex::Error(
"Cloud Chamber: physical wall transfer requires erf.molec_diff_type = ConstantAlpha");
809 bool vert_implicit =
false;
810 pp_erf.query(
"vert_implicit", vert_implicit);
812 amrex::Error(
"Cloud Chamber: physical wall transfer requires erf.vert_implicit = false");
814 pp_prob.get(
"initial_temperature_bottom",
config.initial_temperature_bottom);
815 pp_prob.get(
"initial_temperature_top",
config.initial_temperature_top);
816 const bool has_initial_relative_humidity =
pp_prob.contains(
"initial_relative_humidity");
817 auto physical_contract_error = [&](
bool has_legacy_profile_keys) {
821 has_initial_relative_humidity,
822 has_legacy_profile_keys,
826 std::string contract_error = physical_contract_error(
false);
827 if (!contract_error.empty()) {
828 amrex::Error(contract_error);
830 if (
config.has_moisture) {
831 pp_prob.get(
"initial_relative_humidity",
config.initial_relative_humidity);
833 pp_prob.query(
"temperature_perturbation_amplitude",
834 config.temperature_perturbation_amplitude);
835 const bool has_legacy_profile_keys =
pp_prob.contains(
"theta_bottom") ||
836 pp_prob.contains(
"theta_top") ||
837 pp_prob.contains(
"theta_perturbation_amplitude") ||
838 pp_prob.contains(
"qv_bottom") ||
840 contract_error = physical_contract_error(has_legacy_profile_keys);
841 if (!contract_error.empty()) {
842 amrex::Error(contract_error);
847 config.temperature_perturbation_amplitude);
850 amrex::Error(
"Cloud Chamber: physical initial temperatures must be positive");
852 if (
config.has_moisture) {
856 amrex::Error(
"Cloud Chamber: initial_relative_humidity must lie in [0,1]");
859 }
else if (init_mode ==
"legacy_theta_qv") {
860 config.physical_initialization =
false;
866 pp_prob.contains(
"initial_temperature_bottom") ||
867 pp_prob.contains(
"initial_temperature_top") ||
868 pp_prob.contains(
"initial_relative_humidity") ||
869 pp_prob.contains(
"temperature_perturbation_amplitude")};
871 if (!contract_error.empty()) {
872 amrex::Error(contract_error);
876 pp_prob.query(
"theta_perturbation_amplitude",
877 config.theta_perturbation_amplitude);
879 amrex::Error(
"Cloud Chamber: prob.thermodynamic_initialization must be physical_temperature_rh or legacy_theta_qv");
881 std::string perturbation_mode =
"deterministic_sine";
882 pp_prob.query(
"perturbation_mode", perturbation_mode);
883 if (amrex::toLower(perturbation_mode) !=
"deterministic_sine") {
884 amrex::Error(
"Cloud Chamber: prob.perturbation_mode must be deterministic_sine");
886 if (!
config.physical_initialization) {
890 config.theta_perturbation_amplitude);
893 amrex::Error(
"Cloud Chamber: theta profile values must be positive");
897 if (
config.has_moisture) {
898 if (!
config.physical_initialization) {
905 amrex::Error(
"Cloud Chamber: qv profile values must be nonnegative");
912 for (
int n = 0; n < 2 * AMREX_SPACEDIM; ++n) {
913 const std::string face =
face_name(faces[n]);
914 amrex::ParmParse pp_face(face.c_str());
917 if (!pp_face.query(
"type", type) ||
918 amrex::toLower(type) !=
"noslipwall") {
919 amrex::Error(
"Cloud Chamber: " + face +
".type must be NoSlipWall");
922 wall.
face = faces[n];
924 std::string transfer =
"resolved_molecular";
925 if (pp_face.query(
"wall_transfer_model", transfer)) {
927 transfer = amrex::toLower(transfer);
928 if (transfer !=
"resolved_molecular") {
929 amrex::Error(
"Cloud Chamber: only resolved_molecular wall transfer is supported");
932 if (pp_face.query(
"momentum_transfer_model", transfer_contract.
momentum_model)) {
936 if (pp_face.query(
"heat_transfer_model", transfer_contract.
heat_model)) {
940 if (pp_face.query(
"vapor_transfer_model", transfer_contract.
vapor_model)) {
960 if (pp_face.query(
"z0_m", transfer_contract.
z0_m)) {
964 if (pp_face.query(
"z0_h", transfer_contract.
z0_h)) {
968 if (pp_face.query(
"z0_q", transfer_contract.
z0_q)) {
972 const std::string transfer_error =
974 if (!transfer_error.empty()) {
975 amrex::Error(transfer_error);
977 const bool any_channel_key =
988 if (!
config.physical_initialization && any_channel_key) {
989 amrex::Error(
"Cloud Chamber: per-channel wall transfer keys require physical temperature initialization");
991 if (
config.physical_initialization) {
992 if (pp_face.contains(
"theta") || pp_face.contains(
"qv") ||
993 pp_face.contains(
"theta_grad") || pp_face.contains(
"qv_grad")) {
994 amrex::Error(
"Cloud Chamber: physical walls cannot combine temperature/moisture with legacy theta/qv wall keys");
997 amrex::Error(
"Cloud Chamber: missing required physical " + face +
".temperature");
1001 amrex::Error(
"Cloud Chamber: " + face +
".temperature must be positive Kelvin");
1003 std::string moisture;
1004 pp_face.get(
"moisture", moisture);
1005 moisture = amrex::toLower(moisture);
1006 if (moisture ==
"dry") {
1008 }
else if (moisture ==
"wet") {
1010 if (!
config.has_moisture) {
1011 amrex::Error(
"Cloud Chamber: wet walls require an active moisture model");
1014 amrex::Error(
"Cloud Chamber: " + face +
".moisture must be dry or wet");
1016 const std::string coupled_most_error =
1018 transfer_contract, face,
1021 if (!coupled_most_error.empty()) {
1022 amrex::Error(coupled_most_error);
1025 if (transfer_contract.
momentum_model ==
"law_of_wall_momentum") {
1035 transfer_contract.
heat_model ==
"bulk_aero" ?
1037 (transfer_contract.
heat_model ==
"neutral_roughness_log" ?
1043 (transfer_contract.
vapor_model ==
"neutral_roughness_log" ?
1069 amrex::Error(
"Cloud Chamber: missing required " + face +
".theta");
1075 if (
config.has_moisture && !pp_face.contains(
"qv")) {
1076 amrex::Error(
"Cloud Chamber: legacy cloudy walls require " + face +
".qv");
1079 for (
int d = 0; d < AMREX_SPACEDIM; ++d) {
1080 if (pp_face.contains(
"velocity")) {
1081 amrex::Error(
"Cloud Chamber: wall velocity metadata is not active; use NoSlipWall with zero velocity");
1086 for (
int d = 0; d < AMREX_SPACEDIM; ++d) {
1089 amrex::Error(
"Cloud Chamber: every rectangular dimension must be finite and positive");
constexpr amrex::Real p_0
Definition: ERF_Constants.H:69
constexpr amrex::Real RdoRv
Definition: ERF_Constants.H:60
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:8
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:12
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:16
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:18
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
@ None
Definition: ERF_LSM_Types.H:6
Definition: ERF_CloudChamber.H:19
void require_zero_periodicity()
Definition: ERF_CloudChamber.H:616
WallFace
Definition: ERF_CloudChamber.H:28
std::string wall_coupled_most_roughness_error(const WallTransferContract &contract, const std::string &face, bool wet_wall)
Definition: ERF_CloudChamber.H:591
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:262
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:221
std::string wall_transfer_contract_error(const WallTransferContract &contract, const std::string &face)
Definition: ERF_CloudChamber.H:425
std::string wall_roughness_geometry_error(const erf_wall_thermodynamics::Boundary &walls, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx)
Definition: ERF_CloudChamber.H:670
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:244
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:347
Config parse_config(const amrex::Real *problo, const amrex::Real *probhi, const MoistureType selected_moisture_model)
Definition: ERF_CloudChamber.H:737
bool supports_moisture_model(const MoistureType moisture_type) noexcept
Return whether a moisture type is supported by the Cloud Chamber.
Definition: ERF_CloudChamber.H:166
std::string face_name(WallFace face)
Definition: ERF_CloudChamber.H:387
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:364
void require_finite(const std::string &key, amrex::Real value)
Definition: ERF_CloudChamber.H:380
void validate_wall_roughness_geometry(const erf_wall_thermodynamics::Boundary &walls, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx)
Definition: ERF_CloudChamber.H:729
InitializationMode
Definition: ERF_CloudChamber.H:110
void reject_unsupported_face_keys(amrex::ParmParse &pp, const std::string &face)
Definition: ERF_CloudChamber.H:656
void require_no_unsupported_geometry()
Definition: ERF_CloudChamber.H:631
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:319
std::string initialization_contract_error(const InitializationContract &contract)
Validate the initialization contract and return an error message if violated.
Definition: ERF_CloudChamber.H:133
bool finite(amrex::Real value) noexcept
Definition: ERF_CloudChamber.H:375
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:201
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:303
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:282
@ 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
static MeshType mesh_type
Vertical mesh representation.
Definition: ERF_DataStruct.H:2604
Configuration parameters for cloud chamber initialization.
Definition: ERF_CloudChamber.H:41
amrex::Real qv_top
Definition: ERF_CloudChamber.H:53
amrex::GpuArray< WallSpec, 2 *AMREX_SPACEDIM > walls
Definition: ERF_CloudChamber.H:56
erf_wall_thermodynamics::Boundary wall_boundary() const noexcept
Collect thermodynamic boundary conditions for all chamber walls.
Definition: ERF_CloudChamber.H:62
bool active
Definition: ERF_CloudChamber.H:42
bool has_moisture
Definition: ERF_CloudChamber.H:43
amrex::Real initial_temperature_top
Definition: ERF_CloudChamber.H:46
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > prob_hi
Definition: ERF_CloudChamber.H:55
bool has_wall_rate_channel() const noexcept
Definition: ERF_CloudChamber.H:84
amrex::Real qv_bottom
Definition: ERF_CloudChamber.H:52
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > prob_lo
Definition: ERF_CloudChamber.H:54
amrex::Real initial_temperature_bottom
Definition: ERF_CloudChamber.H:45
amrex::Real temperature_perturbation_amplitude
Definition: ERF_CloudChamber.H:48
amrex::Real theta_perturbation_amplitude
Definition: ERF_CloudChamber.H:51
amrex::Real theta_bottom
Definition: ERF_CloudChamber.H:49
amrex::Real initial_relative_humidity
Definition: ERF_CloudChamber.H:47
bool has_bulk_scalar_wall() const noexcept
Definition: ERF_CloudChamber.H:71
amrex::Real theta_top
Definition: ERF_CloudChamber.H:50
bool physical_initialization
Definition: ERF_CloudChamber.H:44
Contract used to validate initialization parameter consistency.
Definition: ERF_CloudChamber.H:118
InitializationMode mode
Definition: ERF_CloudChamber.H:119
bool has_initial_relative_humidity
Definition: ERF_CloudChamber.H:122
bool has_physical_profile_keys
Definition: ERF_CloudChamber.H:124
bool has_moisture
Definition: ERF_CloudChamber.H:121
bool has_legacy_profile_keys
Definition: ERF_CloudChamber.H:123
Metadata describing a chamber wall.
Definition: ERF_CloudChamber.H:33
erf_wall_thermodynamics::FaceWall wall
Definition: ERF_CloudChamber.H:35
WallFace face
Definition: ERF_CloudChamber.H:34
Definition: ERF_CloudChamber.H:400
amrex::Real z0_m
Definition: ERF_CloudChamber.H:419
std::string heat_model
Definition: ERF_CloudChamber.H:413
bool momentum_model_specified
Definition: ERF_CloudChamber.H:402
amrex::Real z0_q
Definition: ERF_CloudChamber.H:421
bool z0_h_specified
Definition: ERF_CloudChamber.H:410
bool coefficient_source_specified
Definition: ERF_CloudChamber.H:405
std::string coefficient_source
Definition: ERF_CloudChamber.H:415
std::string vapor_model
Definition: ERF_CloudChamber.H:414
bool z0_q_specified
Definition: ERF_CloudChamber.H:411
std::string momentum_model
Definition: ERF_CloudChamber.H:412
amrex::Real z0_h
Definition: ERF_CloudChamber.H:420
bool legacy_aggregate_specified
Definition: ERF_CloudChamber.H:401
bool vapor_model_specified
Definition: ERF_CloudChamber.H:404
amrex::Real momentum_coefficient
Definition: ERF_CloudChamber.H:416
bool heat_coefficient_specified
Definition: ERF_CloudChamber.H:407
amrex::Real heat_coefficient
Definition: ERF_CloudChamber.H:417
bool heat_model_specified
Definition: ERF_CloudChamber.H:403
bool momentum_coefficient_specified
Definition: ERF_CloudChamber.H:406
bool z0_m_specified
Definition: ERF_CloudChamber.H:409
amrex::Real vapor_coefficient
Definition: ERF_CloudChamber.H:418
bool vapor_coefficient_specified
Definition: ERF_CloudChamber.H:408
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