from __future__ import annotations
import numpy as np
from rustmatrix import (HydroMix, MixtureComponent, Scatterer, orientation,
radar)
from rustmatrix import psd as rs_psd
from rustmatrix.refractive import m_w_10C, mi
from rustmatrix.tmatrix_aux import (
K_w_sqr,
dsr_thurai_2007,
geom_horiz_back,
geom_horiz_forw,
wl_C,
)
def build_rain() -> Scatterer:
s = Scatterer(
wavelength=wl_C,
m=m_w_10C[wl_C],
Kw_sqr=K_w_sqr[wl_C],
ddelt=1e-4,
ndgs=2,
)
integ = rs_psd.PSDIntegrator()
integ.D_max = 6.0
integ.num_points = 64
integ.axis_ratio_func = lambda D: 1.0 / dsr_thurai_2007(D)
integ.geometries = (geom_horiz_back, geom_horiz_forw)
s.psd_integrator = integ
s.psd_integrator.init_scatter_table(s)
return s
def build_snow() -> Scatterer:
s = Scatterer(
wavelength=wl_C,
m=mi(wl_C, 0.2),
Kw_sqr=K_w_sqr[wl_C],
axis_ratio=0.6,
ddelt=1e-4,
ndgs=2,
)
s.orient = orientation.orient_averaged_fixed
s.or_pdf = orientation.gaussian_pdf(std=40.0, mean=90.0)
s.n_alpha = 6
s.n_beta = 12
integ = rs_psd.PSDIntegrator()
integ.D_max = 8.0
integ.num_points = 64
integ.geometries = (geom_horiz_back, geom_horiz_forw)
s.psd_integrator = integ
s.psd_integrator.init_scatter_table(s)
return s
def build_graupel() -> Scatterer:
s = Scatterer(
wavelength=wl_C,
m=mi(wl_C, 0.4),
Kw_sqr=K_w_sqr[wl_C],
axis_ratio=0.8,
ddelt=1e-4,
ndgs=2,
)
s.orient = orientation.orient_averaged_fixed
s.or_pdf = orientation.gaussian_pdf(std=40.0, mean=90.0)
s.n_alpha = 6
s.n_beta = 12
integ = rs_psd.PSDIntegrator()
integ.D_max = 8.0
integ.num_points = 64
integ.geometries = (geom_horiz_back, geom_horiz_forw)
s.psd_integrator = integ
s.psd_integrator.init_scatter_table(s)
return s
def observables(x) -> dict:
x.set_geometry(geom_horiz_back)
Zh = radar.refl(x, h_pol=True)
Zdr = radar.Zdr(x)
rho = radar.rho_hv(x)
delta = np.degrees(radar.delta_hv(x))
x.set_geometry(geom_horiz_forw)
Kdp = radar.Kdp(x)
Ai = radar.Ai(x, h_pol=True)
return dict(Zh=10 * np.log10(Zh), Zdr=10 * np.log10(Zdr), rho=rho,
delta=delta, Kdp=Kdp, Ai=Ai)
def print_row(name: str, x) -> None:
o = observables(x)
print(f"{name:<24} {o['Zh']:>7.2f} {o['Zdr']:>+7.3f} "
f"{o['rho']:>8.5f} {o['delta']:>+8.4f} "
f"{o['Kdp']:>+9.4f} {o['Ai']:>9.5f}")
def main() -> None:
rain = build_rain()
snow = build_snow()
graupel = build_graupel()
rain_psd = rs_psd.GammaPSD(D0=1.5, Nw=8e3, mu=4, D_max=6.0)
snow_psd_light = rs_psd.ExponentialPSD(N0=5e3, Lambda=2.0, D_max=8.0)
snow_psd_heavy = rs_psd.ExponentialPSD(N0=1.5e5, Lambda=2.0, D_max=8.0)
graupel_psd = rs_psd.ExponentialPSD(N0=4e3, Lambda=1.4, D_max=8.0)
rain.psd = rain_psd
header = (f"{'case':<24} {'Z_h':>7} {'Z_dr':>7} "
f"{'ρ_hv':>8} {'δ_hv':>8} {'K_dp':>9} {'A_i':>9}")
units = (f"{'':<24} {'[dBZ]':>7} {'[dB]':>7} "
f"{'':>8} {'[°]':>8} {'[°/km]':>9} {'[dB/km]':>9}")
print(header)
print(units)
print("-" * len(header))
mix_rain_lightsnow = HydroMix([
MixtureComponent(rain, rain_psd, "rain"),
MixtureComponent(snow, snow_psd_light, "snow"),
])
mix_rain_heavysnow = HydroMix([
MixtureComponent(rain, rain_psd, "rain"),
MixtureComponent(snow, snow_psd_heavy, "snow"),
])
mix_rain_graupel = HydroMix([
MixtureComponent(rain, rain_psd, "rain"),
MixtureComponent(graupel, graupel_psd, "graupel"),
])
print_row("rain only", rain)
snow.psd = snow_psd_light
print_row("light snow only", snow)
snow.psd = snow_psd_heavy
print_row("heavy snow only", snow)
graupel.psd = graupel_psd
print_row("graupel only", graupel)
print_row("rain + light snow", mix_rain_lightsnow)
print_row("rain + heavy snow", mix_rain_heavysnow)
print_row("rain + graupel", mix_rain_graupel)
rain.set_geometry(geom_horiz_back)
snow.psd = snow_psd_heavy
snow.set_geometry(geom_horiz_back)
mix_rain_heavysnow.set_geometry(geom_horiz_back)
zh_sum = radar.refl(rain) + radar.refl(snow)
zh_mix = radar.refl(mix_rain_heavysnow)
print(f"\nlinear Z_h additivity (heavy snow mixture): "
f"rain + snow = {zh_sum:.3e}, mix = {zh_mix:.3e}, "
f"rel. diff = {abs(zh_sum - zh_mix) / zh_mix:.2e}")
if __name__ == "__main__":
main()