from __future__ import annotations
import numpy as np
from rustmatrix import (HydroMix, MixtureComponent, Scatterer,
SpectralIntegrator, radar, spectra)
from rustmatrix.psd import ExponentialPSD, GammaPSD, PSDIntegrator
from rustmatrix.refractive import m_w_0C, mi
from rustmatrix.tmatrix_aux import K_w_sqr, geom_vert_back, wl_X, wl_W
SLW_DMAX = 0.2 SNOW_DMAX = 8.0
RHO_SNOW = 0.2
AXIS_SNOW = 0.6
def build_slw(wl: float) -> Scatterer:
s = Scatterer(wavelength=wl, m=m_w_0C[wl],
Kw_sqr=K_w_sqr[wl], axis_ratio=1.0,
ddelt=1e-4, ndgs=2)
integ = PSDIntegrator()
integ.D_max = SLW_DMAX
integ.num_points = 128
integ.geometries = (geom_vert_back,)
s.psd_integrator = integ
s.psd_integrator.init_scatter_table(s)
s.psd = GammaPSD(D0=0.03, Nw=1e11, mu=4, D_max=SLW_DMAX)
return s
def build_snow(wl: float) -> Scatterer:
s = Scatterer(wavelength=wl, m=mi(wl, RHO_SNOW),
Kw_sqr=K_w_sqr[wl], axis_ratio=AXIS_SNOW,
ddelt=1e-4, ndgs=2)
integ = PSDIntegrator()
integ.D_max = SNOW_DMAX
integ.num_points = 256
integ.geometries = (geom_vert_back,)
s.psd_integrator = integ
s.psd_integrator.init_scatter_table(s)
s.psd = ExponentialPSD(N0=5e3, Lambda=1.0, D_max=SNOW_DMAX)
return s
def sigma_b(wl: float, D_mm: float, m: complex, axis_ratio: float) -> float:
s = Scatterer(radius=D_mm / 2, wavelength=wl, m=m,
Kw_sqr=K_w_sqr[wl], axis_ratio=axis_ratio,
ddelt=1e-4, ndgs=2)
s.set_geometry(geom_vert_back)
return radar.radar_xsect(s)
def bulk_Zh_dBZ(s: Scatterer) -> float:
s.set_geometry(geom_vert_back)
return 10 * np.log10(radar.refl(s))
def main() -> None:
slw_X = build_slw(wl_X)
slw_W = build_slw(wl_W)
snow_X = build_snow(wl_X)
snow_W = build_snow(wl_W)
print("Billault-Roux et al. (2023) ACP — SLW vs. snow at cloud-radar frequencies")
print("-" * 72)
print("Single-particle σ_b(D) [mm²]:")
print(f" {'pop':<6} {'D [mm]':>8} {'X-band':>12} {'W-band':>12}")
for D in (0.03, 0.1):
sX = sigma_b(wl_X, D, m_w_0C[wl_X], 1.0)
sW = sigma_b(wl_W, D, m_w_0C[wl_W], 1.0)
print(f" {'SLW':<6} {D:>8.3f} {sX:>12.3e} {sW:>12.3e}")
for D in (0.5, 2.0, 5.0, 8.0):
sX = sigma_b(wl_X, D, mi(wl_X, RHO_SNOW), AXIS_SNOW)
sW = sigma_b(wl_W, D, mi(wl_W, RHO_SNOW), AXIS_SNOW)
print(f" {'snow':<6} {D:>8.3f} {sX:>12.3e} {sW:>12.3e}")
print()
print(f" {'':<8} {'Z_h X [dBZ]':>12} {'Z_h W [dBZ]':>12} {'DWR [dB]':>10}")
for name, sX, sW in (("SLW", slw_X, slw_W), ("snow", snow_X, snow_W)):
zX = bulk_Zh_dBZ(sX); zW = bulk_Zh_dBZ(sW)
print(f" {name:<8} {zX:>12.2f} {zW:>12.2f} {zX - zW:>10.2f}")
print()
mix = HydroMix([
MixtureComponent(slw_W, slw_W.psd, "slw"),
MixtureComponent(snow_W, snow_W.psd, "snow"),
])
kin = {
"slw": (lambda D: 0.003 * (D / 0.01) ** 2,
spectra.GaussianTurbulence(0.1)),
"snow": (spectra.fall_speed.locatelli_hobbs_1974_aggregates,
spectra.GaussianTurbulence(0.2)),
}
integ = SpectralIntegrator(
mix, component_kinematics=kin,
v_min=-1.0, v_max=3.0, n_bins=1024,
geometry_backscatter=geom_vert_back,
noise="realistic",
).run()
slw_only = SpectralIntegrator(
slw_W, fall_speed=kin["slw"][0], turbulence=kin["slw"][1],
v_min=-1.0, v_max=3.0, n_bins=1024,
geometry_backscatter=geom_vert_back,
).run()
snow_only = SpectralIntegrator(
snow_W, fall_speed=kin["snow"][0], turbulence=kin["snow"][1],
v_min=-1.0, v_max=3.0, n_bins=1024,
geometry_backscatter=geom_vert_back,
).run()
v_slw = slw_only.v[int(np.argmax(slw_only.sZ_h))]
v_snow = snow_only.v[int(np.argmax(snow_only.sZ_h))]
print("Bimodal W-band Doppler spectrum (SLW + snow HydroMix):")
print(f" SLW mode peak v = {v_slw:+.3f} m/s")
print(f" snow mode peak v = {v_snow:+.3f} m/s")
if __name__ == "__main__":
main()