{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tutorial 04 \u2014 Oriented ice crystals at W-band\n",
"\n",
"Ice crystals fall with a preferred orientation and a spread of\n",
"canting angles around it. The orientation PDF captures the spread\n",
"and feeds directly into the dual-pol observables. This notebook\n",
"compares the three orientation-averaging strategies rustmatrix\n",
"ships with: none, fixed-quadrature, and adaptive.\n"
]
},
{
"cell_type": "code",
"metadata": {},
"execution_count": null,
"outputs": [],
"source": [
"import time\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"from rustmatrix import Scatterer, orientation as rs_orient, radar\n",
"from rustmatrix.tmatrix_aux import geom_horiz_back, wl_W\n",
"from rustmatrix.refractive import mi\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## One crystal, three averaging schemes\n"
]
},
{
"cell_type": "code",
"metadata": {},
"execution_count": null,
"outputs": [],
"source": [
"D_eq_mm = 0.5\n",
"ice_m = mi(wl_W, 0.9)\n",
"pdf = rs_orient.gaussian_pdf(std=20.0, mean=90.0)\n",
"base = dict(radius=D_eq_mm/2, wavelength=wl_W, m=ice_m,\n",
" axis_ratio=0.5, ddelt=1e-4, ndgs=2)\n",
"\n",
"schemes = [\n",
" ('single', rs_orient.orient_single, {'or_pdf': pdf}),\n",
" ('fixed 6\u00d712', rs_orient.orient_averaged_fixed,\n",
" {'or_pdf': pdf, 'n_alpha': 6, 'n_beta': 12}),\n",
" ('adaptive', rs_orient.orient_averaged_adaptive, {'or_pdf': pdf}),\n",
"]\n",
"rows = []\n",
"for name, orient, extra in schemes:\n",
" s = Scatterer(**base, **extra)\n",
" s.orient = orient\n",
" s.set_geometry(geom_horiz_back)\n",
" t0 = time.perf_counter()\n",
" zdr = radar.Zdr(s)\n",
" elapsed = time.perf_counter() - t0\n",
" rows.append((name, 10*np.log10(zdr), elapsed))\n",
" print(f'{name:<12} Z_dr = {10*np.log10(zdr):+.4f} dB ({elapsed*1000:.1f} ms)')\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Canting-angle spread sensitivity\n",
"\n",
"Sweep the Gaussian PDF's `std` parameter to see how rapidly Z_dr\n",
"collapses as the orientation spread widens.\n"
]
},
{
"cell_type": "code",
"metadata": {},
"execution_count": null,
"outputs": [],
"source": [
"stds = np.array([1, 5, 10, 15, 20, 30, 45, 60])\n",
"zdrs = np.empty_like(stds, dtype=float)\n",
"for i, sd in enumerate(stds):\n",
" s = Scatterer(**base)\n",
" s.orient = rs_orient.orient_averaged_fixed\n",
" s.or_pdf = rs_orient.gaussian_pdf(std=float(sd), mean=90.0)\n",
" s.n_alpha, s.n_beta = 6, 12\n",
" s.set_geometry(geom_horiz_back)\n",
" zdrs[i] = 10 * np.log10(radar.Zdr(s))\n",
"\n",
"fig, ax = plt.subplots(figsize=(7, 4))\n",
"ax.plot(stds, zdrs, 'C0-o')\n",
"ax.set_xlabel('canting-angle \u03c3 [deg]')\n",
"ax.set_ylabel('Z_dr [dB]')\n",
"ax.set_title('W-band prolate ice column, oriented')\n",
"ax.grid(True, alpha=0.3)\n",
"fig.tight_layout();\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}