{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial 01 \u2014 A dielectric sphere at X-band, checked against Mie\n", "\n", "A T-matrix solver for nonspherical particles must reduce to classical\n", "Mie theory in the `axis_ratio = 1` limit. That reduction is the\n", "simplest end-to-end check we can do. This tutorial builds a 1 mm\n", "water sphere at X-band, computes its scattering and extinction\n", "cross-sections via the T-matrix path, and compares against the\n", "closed-form Mie expressions shipped with rustmatrix.\n" ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "from rustmatrix import Scatterer, mie_qsca, mie_qext, scatter\n", "from rustmatrix.tmatrix_aux import geom_horiz_back, wl_X\n", "from rustmatrix.refractive import m_w_10C\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Build a sphere scatterer at X-band\n" ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "radius_mm = 1.0\n", "wavelength_mm = wl_X\n", "m = m_w_10C[wl_X]\n", "\n", "s = Scatterer(radius=radius_mm, wavelength=wavelength_mm, m=m,\n", " axis_ratio=1.0, ddelt=1e-4, ndgs=2)\n", "s.set_geometry(geom_horiz_back)\n", "S, Z = s.get_SZ()\n", "S\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cross-sections \u2014 T-matrix vs Mie\n" ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "size_param = 2.0 * np.pi * radius_mm / wavelength_mm\n", "sigma_sca_tm = scatter.sca_xsect(s, h_pol=True)\n", "sigma_ext_tm = scatter.ext_xsect(s, h_pol=True)\n", "\n", "geom = np.pi * radius_mm ** 2\n", "sigma_sca_mie = mie_qsca(size_param, m.real, m.imag) * geom\n", "sigma_ext_mie = mie_qext(size_param, m.real, m.imag) * geom\n", "\n", "print(f'rel err \u03c3_sca = {abs(sigma_sca_tm-sigma_sca_mie)/sigma_sca_mie:.2e}')\n", "print(f'rel err \u03c3_ext = {abs(sigma_ext_tm-sigma_ext_mie)/sigma_ext_mie:.2e}')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Q_sca and Q_ext across a size-parameter sweep\n", "\n", "Plotting both curves side by side makes the Mie ripple pattern\n", "visible and confirms that the T-matrix follows it point-for-point.\n" ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "xs = np.linspace(0.1, 10.0, 40)\n", "q_sca_mie = np.array([mie_qsca(x, m.real, m.imag) for x in xs])\n", "q_ext_mie = np.array([mie_qext(x, m.real, m.imag) for x in xs])\n", "q_sca_tm = np.empty_like(xs)\n", "q_ext_tm = np.empty_like(xs)\n", "for i, x in enumerate(xs):\n", " r = x * wavelength_mm / (2.0 * np.pi)\n", " si = Scatterer(radius=r, wavelength=wavelength_mm, m=m,\n", " axis_ratio=1.0, ddelt=1e-4, ndgs=2)\n", " si.set_geometry(geom_horiz_back)\n", " g = np.pi * r ** 2\n", " q_sca_tm[i] = scatter.sca_xsect(si) / g\n", " q_ext_tm[i] = scatter.ext_xsect(si) / g\n", "\n", "fig, ax = plt.subplots(figsize=(7, 4))\n", "ax.plot(xs, q_sca_mie, 'k-', label='Q_sca (Mie)')\n", "ax.plot(xs, q_ext_mie, 'k--', label='Q_ext (Mie)')\n", "ax.plot(xs, q_sca_tm, 'C1o', markersize=4, label='Q_sca (T-matrix)')\n", "ax.plot(xs, q_ext_tm, 'C2s', markersize=4, label='Q_ext (T-matrix)')\n", "ax.set_xlabel('size parameter x = 2\u03c0r/\u03bb')\n", "ax.set_ylabel('efficiency')\n", "ax.legend()\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 }