ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_SurfaceMoisture.H
Go to the documentation of this file.
1 #ifndef ERF_SURFACE_MOISTURE_H_
2 #define ERF_SURFACE_MOISTURE_H_
3 
4 #include <AMReX_Math.H>
5 #include <AMReX_Algorithm.H>
6 
7 #include <ERF_MOSTUtils.H>
8 
9 #include <cmath>
10 
11 /**
12  * Pieces of the surface layer's land surface mixing ratio when the two-stream balance
13  * supplies the surface's moisture (erf.radiation.seb_surface_layer_uses_moisture): the
14  * surface evaporates at beta times the potential rate, and its mixing ratio is
15  * beta * q_sat + (1 - beta) * q_air. Without a soil type, beta is the soil-water factor.
16  * With one, the surface mixing ratio comes from two source fluxes instead
17  * (two_source_surface_mixing_ratio): bare soil evaporates from its pore air (RH q_sat)
18  * through its resistance, and with a vegetation type a canopy transpires from q_sat
19  * through its own, each in series with the aerodynamic resistance.
20  */
22 
23 /**
24  * Components of the per-column field the balance hands the surface layer
25  * (TwoStreamRadiation::seb_surface_moisture): the soil-water factor beta in [0, 1]; with a
26  * soil type, the bare-soil resistance [s/m] and the relative humidity of the bare soil's
27  * pore air; with a vegetation type as well, the vegetated fraction and the canopy
28  * resistance without its vapour-deficit factor [s/m]. Absent pieces are a fraction of 0,
29  * resistances of no_flux_resistance (1e6 s/m) and a relative humidity of 1.
30  */
31 enum Component : int {
38 };
39 
40 /**
41  * Surface mixing ratio of a surface with moisture availability beta: the saturation
42  * mixing ratio at the surface temperature where beta = 1, the air's own where beta = 0
43  * (no moisture flux), linear in between. A surface-layer moisture flux proportional to
44  * (q_surface - q_air) is then beta times the potential one.
45  *
46  * @param[in] beta moisture availability, clamped to [0, 1]
47  * @param[in] q_sat saturation mixing ratio at the surface temperature and pressure [kg/kg]
48  * @param[in] q_air mixing ratio of the air at the surface layer's reference height [kg/kg]
49  */
50 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
53  const amrex::Real q_sat,
54  const amrex::Real q_air)
55 {
56  const amrex::Real b = amrex::max(amrex::Real(0.0), amrex::min(amrex::Real(1.0), beta));
57  return b * q_sat + (amrex::Real(1.0) - b) * q_air;
58 }
59 
60 /**
61  * The vapour-deficit factor of the Jarvis canopy resistance,
62  * 1 / (1 + HS * max(0, q_sat - q_air)), floored at 0.01 as in Noah-MP
63  * (ResistanceCanopyStomataJarvisMod).
64  */
65 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
68  const amrex::Real q_sat,
69  const amrex::Real q_air)
70 {
71  const amrex::Real deficit = amrex::max(amrex::Real(0.0), q_sat - q_air);
72  return amrex::max(amrex::Real(0.01), amrex::Real(1.0) / (amrex::Real(1.0) + hs * deficit));
73 }
74 
75 /**
76  * The largest resistance [s/m]: a canopy or soil at this resistance does not transpire or
77  * evaporate. Noah-MP has no such cap; it keeps the resistances finite.
78  */
79 inline constexpr amrex::Real no_flux_resistance = amrex::Real(1.0e6);
80 
81 /**
82  * The canopy resistance the surface layer uses [s/m]: the balance's resistance without the
83  * vapour-deficit factor (TwoStream's seb_canopy_resistance_without_vpd) divided by that
84  * factor, capped at no_flux_resistance after the divide (the factor alone can raise it
85  * 100-fold).
86  *
87  * @param[in] r_c_without_vpd canopy resistance without the vapour-deficit factor [s/m]
88  * @param[in] hs the canopy's vapour-deficit parameter [1/(kg/kg)]
89  * @param[in] q_sat saturation mixing ratio at the surface temperature [kg/kg]
90  * @param[in] q_air mixing ratio of the air at the reference height [kg/kg]
91  */
92 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
94 canopy_resistance (const amrex::Real r_c_without_vpd,
95  const amrex::Real hs,
96  const amrex::Real q_sat,
97  const amrex::Real q_air)
98 {
99  // A local copy: amrex::min takes references, which CUDA cannot bind to
100  // a namespace constexpr in device code
101  const amrex::Real r_max = no_flux_resistance;
102  return amrex::min(r_max, r_c_without_vpd / vapour_deficit_factor(hs, q_sat, q_air));
103 }
104 
105 /**
106  * Aerodynamic resistance to the moisture flux between the surface and the reference
107  * height [s/m]: max(ln(z_ref / z0) - psi_h, 1) / (kappa u*).
108  *
109  * This is the limited CmPsih of the surface layer's surface_temp kernel
110  * (ERF_MOSTStress.H), which uses z0 for heat and moisture too. Its q* is
111  * kappa (q_air - q_surf) / CmPsih, so the flux is u* q* = (q_air - q_surf) / r_a.
112  * u* is floored at 1e-3 m/s.
113  */
114 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
117  const amrex::Real z0,
118  const amrex::Real psi_h,
119  const amrex::Real kappa,
120  const amrex::Real u_star)
121 {
122  const amrex::Real cm_psi_h = amrex::max(std::log(z_ref / z0) - psi_h, amrex::Real(1.0));
123  return cm_psi_h / (kappa * amrex::max(u_star, amrex::Real(1.0e-3)));
124 }
125 
126 /**
127  * The aerodynamic resistance [s/m] the surface layer's moisture flux sees over a land
128  * column whose skin temperature the two-stream balance gives it.
129  *
130  * Skin coupling needs erf.most.surf_temp, so that flux comes from the surface_temp
131  * kernel. Its stability function is Jimenez's psi_h2 at z_ref / L (calc_psi_h2), not
132  * Businger-Dyer's psi_h, and it is limited as in aerodynamic_resistance.
133  *
134  * The resistance uses the last u* and Obukhov length L. Before the first flux, u* is
135  * @p unset or non-finite, and a neutral first guess is used:
136  * u* = kappa max(U, U_min) / max(ln(z_ref / z0), 1), with psi_h2 = 0.
137  * An unset, non-finite or zero L also gives psi_h2 = 0.
138  */
139 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
142  const amrex::Real z_ref,
143  const amrex::Real z0,
144  const amrex::Real u_star,
145  const amrex::Real olen,
146  const amrex::Real wind,
147  const amrex::Real wind_min,
148  const amrex::Real kappa,
149  const amrex::Real unset)
150 {
151  amrex::Real ustar = u_star;
152  amrex::Real psi_h = amrex::Real(0.0);
153  if (ustar == unset || !amrex::Math::isfinite(ustar)) {
154  ustar = kappa * amrex::max(wind, wind_min) /
155  amrex::max(std::log(z_ref / z0), amrex::Real(1.0));
156  } else if (olen != unset && amrex::Math::isfinite(olen) && olen != amrex::Real(0.0)) {
157  psi_h = sfuns.calc_psi_h2(z_ref / olen);
158  }
159  return aerodynamic_resistance(z_ref, z0, psi_h, kappa, ustar);
160 }
161 
162 /**
163  * Surface mixing ratio [kg/kg] of a surface whose vegetated fraction f_veg transpires
164  * through a canopy resistance r_c from q_sat, and whose bare fraction evaporates through
165  * a soil resistance r_soil from its pore air, rh_ground * q_sat (Noah-MP's bare ground),
166  * each in series with the aerodynamic resistance r_a:
167  *
168  * q_surf = q_air + r_a [ f_veg (q_sat - q_air) / (r_a + r_c)
169  * + (1 - f_veg) (rh_ground q_sat - q_air) / (r_a + r_soil) ],
170  *
171  * so that the surface layer's flux (q_surf - q_air) / r_a is the sum of the two. With
172  * rh_ground = 1 it is beta q_sat + (1 - beta) q_air with
173  * beta = f_veg r_a/(r_a + r_c) + (1 - f_veg) r_a/(r_a + r_soil). Over dry soil q_surf can
174  * fall below q_air: the soil then takes up water vapour, as in Noah-MP.
175  */
176 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
179  const amrex::Real r_c,
180  const amrex::Real r_soil,
181  const amrex::Real f_veg,
182  const amrex::Real q_sat,
183  const amrex::Real rh_ground,
184  const amrex::Real q_air)
185 {
186  const amrex::Real f = amrex::max(amrex::Real(0.0), amrex::min(amrex::Real(1.0), f_veg));
187  const amrex::Real rh = amrex::max(amrex::Real(0.0), amrex::min(amrex::Real(1.0), rh_ground));
188  return q_air + r_a * (f * (q_sat - q_air) / (r_a + r_c) +
189  (amrex::Real(1.0) - f) * (rh * q_sat - q_air) / (r_a + r_soil));
190 }
191 
192 } // namespace erf_surface_moisture
193 
194 #endif
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:8
Real r_c
Definition: ERF_InitCustomPert_SquallLine.H:49
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ olen
Definition: ERF_SLM.H:104
@ ustar
Definition: ERF_SLM.H:28
@ beta
Definition: ERF_SLM.H:152
Definition: ERF_SurfaceMoisture.H:21
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real surface_mixing_ratio(const amrex::Real beta, const amrex::Real q_sat, const amrex::Real q_air)
Definition: ERF_SurfaceMoisture.H:52
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real canopy_resistance(const amrex::Real r_c_without_vpd, const amrex::Real hs, const amrex::Real q_sat, const amrex::Real q_air)
Definition: ERF_SurfaceMoisture.H:94
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real surface_layer_aerodynamic_resistance(const similarity_funs &sfuns, const amrex::Real z_ref, const amrex::Real z0, const amrex::Real u_star, const amrex::Real olen, const amrex::Real wind, const amrex::Real wind_min, const amrex::Real kappa, const amrex::Real unset)
Definition: ERF_SurfaceMoisture.H:141
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real two_source_surface_mixing_ratio(const amrex::Real r_a, const amrex::Real r_c, const amrex::Real r_soil, const amrex::Real f_veg, const amrex::Real q_sat, const amrex::Real rh_ground, const amrex::Real q_air)
Definition: ERF_SurfaceMoisture.H:178
constexpr amrex::Real no_flux_resistance
Definition: ERF_SurfaceMoisture.H:79
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real aerodynamic_resistance(const amrex::Real z_ref, const amrex::Real z0, const amrex::Real psi_h, const amrex::Real kappa, const amrex::Real u_star)
Definition: ERF_SurfaceMoisture.H:116
Component
Definition: ERF_SurfaceMoisture.H:31
@ GroundRelativeHumidity
Definition: ERF_SurfaceMoisture.H:36
@ SoilResistance
Definition: ERF_SurfaceMoisture.H:35
@ VegetationFraction
Definition: ERF_SurfaceMoisture.H:33
@ NumComponents
Definition: ERF_SurfaceMoisture.H:37
@ CanopyResistanceWithoutVPD
Definition: ERF_SurfaceMoisture.H:34
@ SoilFactor
Definition: ERF_SurfaceMoisture.H:32
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real vapour_deficit_factor(const amrex::Real hs, const amrex::Real q_sat, const amrex::Real q_air)
Definition: ERF_SurfaceMoisture.H:67
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