metrust 0.4.0__tar.gz → 0.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- metrust-0.4.2/BENCHMARKS.md +236 -0
- {metrust-0.4.0 → metrust-0.4.2}/Cargo.lock +1 -1
- {metrust-0.4.0 → metrust-0.4.2}/Cargo.toml +2 -2
- {metrust-0.4.0 → metrust-0.4.2}/PKG-INFO +9 -7
- {metrust-0.4.0 → metrust-0.4.2}/README.md +7 -5
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/Cargo.toml +1 -1
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/calc/atmo.rs +7 -4
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-math/src/thermo.rs +15 -6
- {metrust-0.4.0 → metrust-0.4.2}/docs/compatibility.md +5 -1
- {metrust-0.4.0 → metrust-0.4.2}/docs/guides/migration.md +1 -1
- {metrust-0.4.0 → metrust-0.4.2}/docs/index.md +6 -6
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/index.md +1 -1
- {metrust-0.4.0 → metrust-0.4.2}/mkdocs.yml +1 -1
- {metrust-0.4.0 → metrust-0.4.2}/pyproject.toml +2 -2
- {metrust-0.4.0 → metrust-0.4.2}/python/metrust/calc/__init__.py +3320 -1091
- metrust-0.4.2/tests/benchmarks/bench_01_hrrr_severe.py +1075 -0
- metrust-0.4.2/tests/benchmarks/bench_02_gfs_upper_air.py +831 -0
- metrust-0.4.2/tests/benchmarks/bench_03_rap_warm_front.py +900 -0
- metrust-0.4.2/tests/benchmarks/bench_04_nam_winter.py +846 -0
- metrust-0.4.2/tests/benchmarks/bench_05_hrrr_supercell.py +1152 -0
- metrust-0.4.2/tests/benchmarks/bench_06_gfs_jet.py +740 -0
- metrust-0.4.2/tests/benchmarks/bench_07_hrrr_fire.py +802 -0
- metrust-0.4.2/tests/benchmarks/bench_08_era5_tropical.py +1031 -0
- metrust-0.4.2/tests/benchmarks/bench_09_rap_aviation.py +1099 -0
- metrust-0.4.2/tests/benchmarks/bench_10_hrrr_squall.py +1375 -0
- metrust-0.4.2/tests/benchmarks/bench_11_gfs_cold_air.py +920 -0
- metrust-0.4.2/tests/benchmarks/bench_12_hrrr_pbl.py +1350 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/test_metpy_dropin_compat.py +165 -2
- metrust-0.4.2/tests/test_runtime_parity.py +442 -0
- metrust-0.4.2/tests/test_runtime_parity_interp_dataset.py +242 -0
- metrust-0.4.2/tests/test_runtime_parity_kinematics_extra.py +248 -0
- metrust-0.4.2/tests/test_runtime_parity_remaining.py +93 -0
- metrust-0.4.2/tests/test_runtime_parity_sounding_core.py +204 -0
- metrust-0.4.2/tests/test_runtime_parity_thermo_layers.py +251 -0
- metrust-0.4.2/tests/test_runtime_parity_utils_misc.py +226 -0
- metrust-0.4.2/tests/test_runtime_parity_wind_profiles.py +277 -0
- metrust-0.4.2/tests/test_signature_parity.py +53 -0
- {metrust-0.4.0 → metrust-0.4.2}/.github/workflows/ci.yml +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/.github/workflows/docs.yml +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/.github/workflows/release.yml +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/.gitignore +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/VERIFICATION.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/benches/bench_hrrr.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/benches/bench_hrrr_vs_metpy.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/benches/bench_python.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/benches/calc_bench.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/calc/kinematics.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/calc/mod.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/calc/severe.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/calc/smooth.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/calc/thermo.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/calc/utils.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/calc/wind.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/constants.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/interpolate/mod.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/gempak.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/gempak_dm.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/gempak_sounding.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/gempak_surface.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/gini.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/level3.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/metar.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/mod.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/station.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/io/wpc.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/lib.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/plots/mod.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/projections.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/src/units.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/tests/test_gempak.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/metrust/tests/test_new_functions.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/Cargo.toml +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/composite.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/download/cache.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/download/catalog.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/download/client.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/download/fallback.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/download/idx.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/download/mod.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/download/sources.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/download/streaming.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/dynamics.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/error.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/grid.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/mod.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/ops.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/parser.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/search.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/streaming.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/tables.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/tests.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/unpack.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/grib2/writer.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/gridmath.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/lib.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/metfuncs.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/cfs.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/ecmwf.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/era5.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/gefs.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/gfs.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/href.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/hrrr.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/hrrr_ak.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/latest.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/mod.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/mrms.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/nam.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/nbm.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/rap.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/rrfs.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/rtma.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/sref.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/urma.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/models/wpc.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/products.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/projection.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/regrid.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/ansi.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/colormap.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/contour.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/cross_section.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/encode.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/filled_contour.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/hodograph.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/mod.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/overlay.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/raster.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/skewt.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-core/src/render/station.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/Cargo.toml +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/src/error.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/src/field.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/src/lib.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/src/meta.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/src/projection.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/src/radial.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/src/site.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/src/sounding.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-field/src/time.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-math/Cargo.toml +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-math/src/composite.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-math/src/dynamics.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-math/src/gridmath.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-math/src/interpolate.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-math/src/lib.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-math/src/regrid.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/Cargo.toml +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/src/cells.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/src/color_table.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/src/derived.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/src/detection.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/src/level2.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/src/lib.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/src/products.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/src/render.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/crates/wx-radar/src/sites.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/demos/hrrr_diffusion_training.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/atmospheric.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/grid-composites.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/io.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/kinematics.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/moisture.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/severe.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/smoothing.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/thermodynamics.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/units.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/api/wind.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/guides/arrays.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/guides/installation.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/architecture.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/grid-kinematics.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/interpolation.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/io-formats.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/metpy-compatibility.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/moisture.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/parallelism.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/severe-weather.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/smoothing.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/thermodynamics.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/units-and-pint.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/methodology/wind.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/performance.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/tutorials/first-grid.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/tutorials/first-sounding.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/tutorials/reading-the-numbers.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/tutorials/recipes.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/docs/tutorials/weather-101.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/examples/cookbook_500hpa_grid.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/examples/cookbook_sounding.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/examples/sounderpy_dropin.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/python/metrust/__init__.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/python/metrust/constants/__init__.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/python/metrust/interpolate/__init__.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/python/metrust/io/__init__.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/python/metrust/plots/__init__.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/python/metrust/units.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/python/metrust/xarray.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/lib.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_atmo.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_constants.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_interpolate.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_io.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_kinematics.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_severe.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_smooth.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_thermo.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_utils.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/src/py_wind.rs +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/api_audit_calc.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/api_audit_other.md +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/benchmark.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/benchmark_gpu.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/sounding_3way.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/sounding_comparison.png +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/test_gpu_backend.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/test_python_compat.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/verify_constants.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/verify_edge_cases.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/verify_kinematics.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/verify_severe_atmo.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/verify_smooth_interp.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/verify_thermo.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/verify_units.py +0 -0
- {metrust-0.4.0 → metrust-0.4.2}/tests/verify_wind.py +0 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# Benchmarks
|
|
2
|
+
|
|
3
|
+
All results on **NVIDIA GeForce RTX 5090** (34.2 GB VRAM, Blackwell, 21,760 CUDA cores) with CuPy 14.0.1, met-cu 0.2.1, metrust 0.4.0. CPU is a 32-core AMD Ryzen with rayon parallelism.
|
|
4
|
+
|
|
5
|
+
## Three-Way Comparison: MetPy vs Rust vs CUDA
|
|
6
|
+
|
|
7
|
+
Real HRRR model output (40 isobaric levels, 1059 × 1799 grid, ~1.9M points per level). `python tests/benchmark_gpu.py`
|
|
8
|
+
|
|
9
|
+
### Scalar Thermodynamics (2D: 1059×1799)
|
|
10
|
+
|
|
11
|
+
| Function | MetPy | Rust | CUDA | Rust/MetPy | CUDA/Rust |
|
|
12
|
+
|---|---:|---:|---:|---:|---:|
|
|
13
|
+
| potential_temperature ★ | 11.2 ms | 13.0 ms | 7.9 ms | 0.9x | 1.6x |
|
|
14
|
+
| equiv_potential_temperature ★ | 303.1 ms | 16.5 ms | 9.1 ms | **18x** | 1.8x |
|
|
15
|
+
| dewpoint ★ | 33.6 ms | 10.8 ms | 8.8 ms | 3.1x | 1.2x |
|
|
16
|
+
| saturation_vapor_pressure | 66.7 ms | 8.2 ms | — | 8.1x | — |
|
|
17
|
+
| saturation_mixing_ratio | 78.6 ms | 13.7 ms | — | 5.7x | — |
|
|
18
|
+
| dewpoint_from_rh | 110.3 ms | 7.6 ms | — | **14x** | — |
|
|
19
|
+
| rh_from_dewpoint | 138.7 ms | 10.9 ms | — | **13x** | — |
|
|
20
|
+
| virtual_temperature | 31.1 ms | 19.7 ms | — | 1.6x | — |
|
|
21
|
+
| mixing_ratio | 11.6 ms | 8.5 ms | — | 1.4x | — |
|
|
22
|
+
| wet_bulb_temperature | >10 min | 26.9 ms | — | **>22,000x** | — |
|
|
23
|
+
|
|
24
|
+
### Grid Kinematics (2D: 1059×1799)
|
|
25
|
+
|
|
26
|
+
| Function | MetPy | Rust | CUDA | Rust/MetPy | CUDA/Rust |
|
|
27
|
+
|---|---:|---:|---:|---:|---:|
|
|
28
|
+
| vorticity ★ | 98.3 ms | 92.8 ms | 9.3 ms | 1.1x | **10x** |
|
|
29
|
+
| divergence | 96.1 ms | 91.2 ms | — | 1.1x | — |
|
|
30
|
+
| frontogenesis ★ | 733.0 ms | 339.4 ms | 12.2 ms | 2.2x | **28x** |
|
|
31
|
+
| q_vector ★ | 390.3 ms | 310.1 ms | 10.8 ms | 1.3x | **29x** |
|
|
32
|
+
| advection | 161.8 ms | 87.7 ms | — | 1.8x | — |
|
|
33
|
+
|
|
34
|
+
### 1D Sounding (40 levels, single column)
|
|
35
|
+
|
|
36
|
+
| Function | MetPy | Rust | Rust/MetPy |
|
|
37
|
+
|---|---:|---:|---:|
|
|
38
|
+
| parcel_profile | 5.5 ms | 0.074 ms | **74x** |
|
|
39
|
+
| cape_cin | 1.4 ms | 0.254 ms | 5.4x |
|
|
40
|
+
| lcl | 0.118 ms | 0.065 ms | 1.8x |
|
|
41
|
+
| lfc | 6.7 ms | 0.107 ms | **62x** |
|
|
42
|
+
| el | 6.6 ms | 0.112 ms | **59x** |
|
|
43
|
+
| precipitable_water | 2.1 ms | 0.057 ms | **36x** |
|
|
44
|
+
|
|
45
|
+
### Grid Composites (3D: 40×1059×1799 → 2D)
|
|
46
|
+
|
|
47
|
+
MetPy has no grid-level equivalents for these functions.
|
|
48
|
+
|
|
49
|
+
| Function | Rust | CUDA | CUDA/Rust |
|
|
50
|
+
|---|---:|---:|---:|
|
|
51
|
+
| compute_cape_cin ★ | 2.96 s | 674.5 ms | **4.4x** |
|
|
52
|
+
| compute_srh ★ | 223.5 ms | 135.8 ms | 1.6x |
|
|
53
|
+
| compute_shear ★ | 190.4 ms | 166.5 ms | 1.1x |
|
|
54
|
+
| compute_pw ★ | 191.6 ms | 107.9 ms | 1.8x |
|
|
55
|
+
| composite_refl_hydrometeors ★ | 154.2 ms | 232.2 ms | 0.7x |
|
|
56
|
+
|
|
57
|
+
### Summary
|
|
58
|
+
|
|
59
|
+
| Category | MetPy | Rust | CUDA |
|
|
60
|
+
|---|---:|---:|---:|
|
|
61
|
+
| Scalar thermo (×10) | 785 ms | 136 ms | 26 ms |
|
|
62
|
+
| Grid kinematics (×5) | 1.48 s | 921 ms | 32 ms |
|
|
63
|
+
| 1D sounding (×6) | 22 ms | 0.67 ms | — |
|
|
64
|
+
| Grid composites (×5) | — | 3.72 s | 1.32 s |
|
|
65
|
+
| **★ GPU-eligible total** | — | **4.50 s** | **1.37 s (3.3x)** |
|
|
66
|
+
|
|
67
|
+
★ = dispatches to CUDA when `set_backend("gpu")`.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Real-Data Verification Benchmarks
|
|
72
|
+
|
|
73
|
+
12 independent scenarios using actual HRRR and GFS GRIB2 data, verifying correctness across all 4 backends (MetPy, metrust CPU, met-cu GPU, metrust GPU) with ~230 deep statistical checks.
|
|
74
|
+
|
|
75
|
+
### Timing Highlights on Real Atmospheric Data
|
|
76
|
+
|
|
77
|
+
| Function | Grid | MetPy | Rust | met-cu GPU | vs MetPy | vs Rust |
|
|
78
|
+
|---|---|---:|---:|---:|---:|---:|
|
|
79
|
+
| frontogenesis | 721×1440 | 388 ms | 154 ms | 3.8 ms | **101x** | **40x** |
|
|
80
|
+
| equiv_potential_temp | 1059×1799 | 13.7 s | 464 ms | 163 ms | **84x** | **2.8x** |
|
|
81
|
+
| compute_srh | 200×200 | — | 124 ms | 2.7 ms | — | **46x** |
|
|
82
|
+
| q_vector | 1059×1799 | — | 115 ms | 4.6 ms | — | **25x** |
|
|
83
|
+
| compute_cape_cin | 200×200 | — | 317 ms | 13 ms | — | **24x** |
|
|
84
|
+
| vorticity | 721×1440 | 41.6 ms | 41.1 ms | 1.7 ms | **24x** | **24x** |
|
|
85
|
+
| potential_temp | 721×1440 | 28.4 ms | 5.5 ms | 1.7 ms | **17x** | **3.2x** |
|
|
86
|
+
|
|
87
|
+
### Full Pipeline (bench 10: HRRR squall line, 1059×1799×40)
|
|
88
|
+
|
|
89
|
+
| | Rust CPU | met-cu GPU | Speedup |
|
|
90
|
+
|---|---:|---:|---:|
|
|
91
|
+
| Total (6 functions) | 3.58 s | 762 ms | **4.7x** |
|
|
92
|
+
| CAPE alone | 2.84 s | 622 ms | **4.6x** |
|
|
93
|
+
| Kinematics alone | 230 ms | 10 ms | **23x** |
|
|
94
|
+
|
|
95
|
+
### 100 Real Soundings (bench 09: HRRR columns across CONUS)
|
|
96
|
+
|
|
97
|
+
| | MetPy | metrust | Speedup |
|
|
98
|
+
|---|---:|---:|---:|
|
|
99
|
+
| 100 soundings total | 676 ms | 72 ms | **9.4x** |
|
|
100
|
+
| Per sounding | 6.8 ms | 0.72 ms | 9.4x |
|
|
101
|
+
|
|
102
|
+
### Correctness Summary
|
|
103
|
+
|
|
104
|
+
All 12 benchmarks pass deep verification against MetPy as ground truth:
|
|
105
|
+
|
|
106
|
+
| Benchmark | Data | Checks | RMSE | Pearson r |
|
|
107
|
+
|---|---|---:|---|---|
|
|
108
|
+
| 01 HRRR Severe | 1059×1799×40 | 20/20 | ~1e-13 | 1.0000 |
|
|
109
|
+
| 02 GFS Upper Air | 721×1440 | 19/21 | ~1e-14 | 1.0000 |
|
|
110
|
+
| 03 HRRR Warm Front | 1059×1799 | All | ~1e-18 | 1.0000 |
|
|
111
|
+
| 04 HRRR Precip Water | 1059×1799×40 | 14/14 | ~1e-13 | 1.0000 |
|
|
112
|
+
| 05 HRRR Supercell | 1059×1799×40 | 16/20 | ~1e-13 | 0.99999 |
|
|
113
|
+
| 06 GFS Jet Stream | 721×1440 | 16/16 | ~1e-15 | 1.0000 |
|
|
114
|
+
| 07 HRRR Fire Weather | 1059×1799 | 16/16 | ~1e-14 | 1.0000 |
|
|
115
|
+
| 08 GFS Tropical | 121×201×33 | 15/15 | ~1e-15 | 1.0000 |
|
|
116
|
+
| 09 HRRR Soundings | 100×40 | 25/25 | ~12 J/kg (CAPE) | 0.9999 |
|
|
117
|
+
| 10 HRRR Squall Line | 1059×1799×40 | All | ~1e-13 | 1.0000 |
|
|
118
|
+
| 11 GFS Cold Air | 161×1440 | 19/19 | ~1e-14 | 1.0000 |
|
|
119
|
+
| 12 HRRR Boundary Layer | 1059×1799×40 | 35/35 | ~1e-13 | 1.0000 |
|
|
120
|
+
|
|
121
|
+
Non-passing checks are documented edge cases: frontogenesis boundary NaN (0.05% of points), CIN/LFC sentinel values on marginal soundings.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## met-cu Comprehensive Benchmark (202 Functions)
|
|
126
|
+
|
|
127
|
+
All 202 met-cu functions benchmarked against metrust CPU on 1,905,141 points (HRRR grid).
|
|
128
|
+
|
|
129
|
+
### Category Averages
|
|
130
|
+
|
|
131
|
+
| Category | Functions | Avg Speedup | Min | Max |
|
|
132
|
+
|---|---:|---:|---:|---:|
|
|
133
|
+
| Per-element thermo | 52 | **238x** | 1.0x | 971x |
|
|
134
|
+
| Wind per-element | 3 | **7.5x** | 6.3x | 9.3x |
|
|
135
|
+
| Grid stencil | 28 | **39x** | 3.7x | 108x |
|
|
136
|
+
| Column/sounding | 72 | **3.7x** | 0.0x | 85x |
|
|
137
|
+
|
|
138
|
+
### Top GPU Speedups
|
|
139
|
+
|
|
140
|
+
| Function | GPU | CPU | Speedup |
|
|
141
|
+
|---|---:|---:|---:|
|
|
142
|
+
| height_to_geopotential | 0.94 ms | 912 ms | **971x** |
|
|
143
|
+
| moist_air_specific_heat_pressure | 0.91 ms | 819 ms | **902x** |
|
|
144
|
+
| coriolis_parameter | 0.94 ms | 830 ms | **883x** |
|
|
145
|
+
| water_latent_heat_melting | 0.98 ms | 828 ms | **849x** |
|
|
146
|
+
| scale_height | 1.08 ms | 916 ms | **847x** |
|
|
147
|
+
| geopotential_to_height | 1.13 ms | 921 ms | **815x** |
|
|
148
|
+
| water_latent_heat_vaporization | 1.02 ms | 808 ms | **794x** |
|
|
149
|
+
| water_latent_heat_sublimation | 1.09 ms | 816 ms | **746x** |
|
|
150
|
+
| moist_air_gas_constant | 1.13 ms | 820 ms | **723x** |
|
|
151
|
+
| heat_index | 2.00 ms | 1035 ms | **517x** |
|
|
152
|
+
|
|
153
|
+
Note: The extreme speedups (>100x) are for functions where the metrust CPU path falls back to a Python scalar loop (`_vec_call`). The GPU kernel runs natively on the full array. These represent real user-facing speedups.
|
|
154
|
+
|
|
155
|
+
### Grid Stencil Functions (1059×1799)
|
|
156
|
+
|
|
157
|
+
| Function | GPU | CPU | Speedup |
|
|
158
|
+
|---|---:|---:|---:|
|
|
159
|
+
| shear_vorticity | 2.05 ms | 221 ms | **108x** |
|
|
160
|
+
| curvature_vorticity | 1.90 ms | 160 ms | **84x** |
|
|
161
|
+
| smooth_rectangular | 0.98 ms | 78 ms | **80x** |
|
|
162
|
+
| total_deformation | 2.26 ms | 144 ms | **64x** |
|
|
163
|
+
| vector_derivative | 2.41 ms | 153 ms | **63x** |
|
|
164
|
+
| geostrophic_wind | 2.24 ms | 117 ms | **52x** |
|
|
165
|
+
| q_vector | 5.37 ms | 240 ms | **45x** |
|
|
166
|
+
| frontogenesis | 5.86 ms | 257 ms | **44x** |
|
|
167
|
+
| vorticity | 2.02 ms | 75 ms | **37x** |
|
|
168
|
+
| smooth_n_point (5) | 0.95 ms | 32 ms | **33x** |
|
|
169
|
+
|
|
170
|
+
### Where GPU Is Slower
|
|
171
|
+
|
|
172
|
+
Single-column sounding functions are faster on CPU due to kernel launch overhead:
|
|
173
|
+
|
|
174
|
+
| Function | GPU | CPU | Ratio |
|
|
175
|
+
|---|---:|---:|---:|
|
|
176
|
+
| parcel_profile | 3.25 ms | 0.16 ms | 0.05x |
|
|
177
|
+
| moist_lapse | 3.15 ms | 0.13 ms | 0.04x |
|
|
178
|
+
| cape_cin (1 sounding) | 3.42 ms | 0.34 ms | 0.1x |
|
|
179
|
+
|
|
180
|
+
For single soundings, use CPU. For grid-level computation (1000+ columns), GPU wins.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Workflow-Level Speedups
|
|
185
|
+
|
|
186
|
+
metrust vs MetPy on real-world analysis workflows:
|
|
187
|
+
|
|
188
|
+
| Workflow | Speedup | Notes |
|
|
189
|
+
|---|---:|---|
|
|
190
|
+
| SounderPy compute-heavy subset | **29.7x** | Thermo + wind + severe params |
|
|
191
|
+
| MetPy Cookbook sounding analysis | **6.0x** | Full severe weather stack |
|
|
192
|
+
| MetPy Cookbook 500 hPa grid | **6.1x** | Vorticity, smoothing, advection |
|
|
193
|
+
| MetPy Cookbook Q-vectors | **6.1x** | Q-vector divergence |
|
|
194
|
+
| MetPy isentropic example | **2.3x** | Isentropic interpolation + Montgomery |
|
|
195
|
+
| Vorticity/divergence (global grid) | **2.3x** | Spherical corrections on 721×1440 |
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Rust Array Throughput
|
|
200
|
+
|
|
201
|
+
1M elements, 32-core Ryzen, rayon parallel:
|
|
202
|
+
|
|
203
|
+
| Function | Time | Throughput |
|
|
204
|
+
|---|---:|---:|
|
|
205
|
+
| potential_temperature | 1.8 ms | 550 M elem/s |
|
|
206
|
+
| wet_bulb_temperature | 7.3 ms | 137 M elem/s |
|
|
207
|
+
| wind_speed | 1.5 ms | 660 M elem/s |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Running the Benchmarks
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Three-way comparison (requires real HRRR data in data/)
|
|
215
|
+
python tests/benchmark_gpu.py # MetPy + Rust + CUDA
|
|
216
|
+
python tests/benchmark_gpu.py --no-metpy # Rust + CUDA only (faster)
|
|
217
|
+
|
|
218
|
+
# Real-data verification suite (requires HRRR + GFS GRIB files in data/)
|
|
219
|
+
python tests/benchmarks/bench_01_hrrr_severe.py
|
|
220
|
+
python tests/benchmarks/bench_02_gfs_upper_air.py
|
|
221
|
+
# ... through bench_12
|
|
222
|
+
|
|
223
|
+
# Run all verification benchmarks
|
|
224
|
+
for f in tests/benchmarks/bench_*.py; do python "$f"; done
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Data files needed in `data/`:
|
|
228
|
+
- `hrrr_prs.grib2` — HRRR pressure levels (~405 MB)
|
|
229
|
+
- `hrrr_sfc.grib2` — HRRR surface fields (~148 MB)
|
|
230
|
+
- `gfs_0p25.grib2` — GFS 0.25° analysis (~490 MB)
|
|
231
|
+
|
|
232
|
+
Download from NOAA AWS:
|
|
233
|
+
```bash
|
|
234
|
+
curl -Lo data/hrrr_prs.grib2 "https://noaa-hrrr-bdp-pds.s3.amazonaws.com/hrrr.20260328/conus/hrrr.t00z.wrfprsf00.grib2"
|
|
235
|
+
curl -Lo data/gfs_0p25.grib2 "https://noaa-gfs-bdp-pds.s3.amazonaws.com/gfs.20260328/00/atmos/gfs.t00z.pgrb2.0p25.f000"
|
|
236
|
+
```
|
|
@@ -8,9 +8,9 @@ license = "MIT"
|
|
|
8
8
|
|
|
9
9
|
[package]
|
|
10
10
|
name = "metrust-py"
|
|
11
|
-
version = "0.4.
|
|
11
|
+
version = "0.4.2"
|
|
12
12
|
edition.workspace = true
|
|
13
|
-
description = "Python bindings for metrust
|
|
13
|
+
description = "Python bindings for metrust, a Rust-powered MetPy-compatible calculation layer"
|
|
14
14
|
readme = "README.md"
|
|
15
15
|
|
|
16
16
|
[lib]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: metrust
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Classifier: Development Status :: 4 - Beta
|
|
5
5
|
Classifier: Intended Audience :: Science/Research
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -11,7 +11,7 @@ Requires-Dist: numpy>=1.20
|
|
|
11
11
|
Requires-Dist: pint>=0.20
|
|
12
12
|
Requires-Dist: met-cu>=0.2.1 ; extra == 'gpu'
|
|
13
13
|
Provides-Extra: gpu
|
|
14
|
-
Summary: Rust-powered
|
|
14
|
+
Summary: Rust-powered MetPy-compatible calculation layer with optional GPU acceleration
|
|
15
15
|
Keywords: meteorology,weather,rust,metpy,atmospheric-science,nwp,cape,sounding
|
|
16
16
|
Author: Fahrenheit Research
|
|
17
17
|
License: MIT
|
|
@@ -24,9 +24,9 @@ Project-URL: Repository, https://github.com/FahrenheitResearch/metrust-py
|
|
|
24
24
|
|
|
25
25
|
# metrust
|
|
26
26
|
|
|
27
|
-
**
|
|
27
|
+
**MetPy-compatible calculation layer, powered by Rust.**
|
|
28
28
|
|
|
29
|
-
150/150 `metpy.calc` functions implemented natively, plus 36 extras.
|
|
29
|
+
150/150 `metpy.calc` functions implemented natively, plus 36 extras. Often faster on real-world workflows. Verified against MetPy on SounderPy, MetPy Cookbook examples, and synthetic global grids.
|
|
30
30
|
|
|
31
31
|
```python
|
|
32
32
|
# The only change: swap the import
|
|
@@ -54,7 +54,7 @@ pip install metrust metpy
|
|
|
54
54
|
|
|
55
55
|
## What It Does
|
|
56
56
|
|
|
57
|
-
metrust implements every function in `metpy.calc` with a Rust backend compiled via PyO3. The Python API matches MetPy's signatures
|
|
57
|
+
metrust implements every function in `metpy.calc` with a Rust backend compiled via PyO3. The Python API now matches MetPy's public `metpy.calc` signatures and is designed for MetPy-compatible units, return types, and runtime behavior on the shared calculation surface:
|
|
58
58
|
|
|
59
59
|
```python
|
|
60
60
|
import numpy as np
|
|
@@ -108,6 +108,8 @@ The GPU backend currently targets the overlap where `met-cu` is already strong a
|
|
|
108
108
|
- `compute_pw`
|
|
109
109
|
- `composite_reflectivity_from_hydrometeors`
|
|
110
110
|
|
|
111
|
+
Eligible dispatch currently focuses on scalar thermo plus uniform 2-D Cartesian grid workloads. Latitude/longitude-derived spacing, map-scale corrections, and other projection-aware cases fall back to the Rust CPU backend.
|
|
112
|
+
|
|
111
113
|
`metrust` still returns the same Pint/NumPy-facing API surface. Unsupported cases automatically stay on the Rust CPU path.
|
|
112
114
|
|
|
113
115
|
## Speed
|
|
@@ -229,7 +231,7 @@ These forward to MetPy when installed:
|
|
|
229
231
|
- `metrust.xarray` (xarray accessor)
|
|
230
232
|
- `metrust.io.Level2File` (NEXRAD Level II)
|
|
231
233
|
|
|
232
|
-
Core `metrust.calc`
|
|
234
|
+
Core `metrust.calc` stays native Rust by default with no required MetPy dependency. A small parity-sensitive subset may delegate to MetPy when it is installed; otherwise those paths still fall back to local metrust implementations. The optional `met-cu` backend is an explicit accelerator, not a requirement.
|
|
233
235
|
|
|
234
236
|
## Examples
|
|
235
237
|
|
|
@@ -243,7 +245,7 @@ See `examples/` for complete drop-in demos:
|
|
|
243
245
|
|
|
244
246
|
```bash
|
|
245
247
|
cargo test --workspace # 1,186 Rust tests
|
|
246
|
-
python -m pytest tests/ -q #
|
|
248
|
+
python -m pytest tests/ -q # 30 Python tests (including MetPy compatibility regression)
|
|
247
249
|
```
|
|
248
250
|
|
|
249
251
|
## Documentation
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# metrust
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**MetPy-compatible calculation layer, powered by Rust.**
|
|
4
4
|
|
|
5
|
-
150/150 `metpy.calc` functions implemented natively, plus 36 extras.
|
|
5
|
+
150/150 `metpy.calc` functions implemented natively, plus 36 extras. Often faster on real-world workflows. Verified against MetPy on SounderPy, MetPy Cookbook examples, and synthetic global grids.
|
|
6
6
|
|
|
7
7
|
```python
|
|
8
8
|
# The only change: swap the import
|
|
@@ -30,7 +30,7 @@ pip install metrust metpy
|
|
|
30
30
|
|
|
31
31
|
## What It Does
|
|
32
32
|
|
|
33
|
-
metrust implements every function in `metpy.calc` with a Rust backend compiled via PyO3. The Python API matches MetPy's signatures
|
|
33
|
+
metrust implements every function in `metpy.calc` with a Rust backend compiled via PyO3. The Python API now matches MetPy's public `metpy.calc` signatures and is designed for MetPy-compatible units, return types, and runtime behavior on the shared calculation surface:
|
|
34
34
|
|
|
35
35
|
```python
|
|
36
36
|
import numpy as np
|
|
@@ -84,6 +84,8 @@ The GPU backend currently targets the overlap where `met-cu` is already strong a
|
|
|
84
84
|
- `compute_pw`
|
|
85
85
|
- `composite_reflectivity_from_hydrometeors`
|
|
86
86
|
|
|
87
|
+
Eligible dispatch currently focuses on scalar thermo plus uniform 2-D Cartesian grid workloads. Latitude/longitude-derived spacing, map-scale corrections, and other projection-aware cases fall back to the Rust CPU backend.
|
|
88
|
+
|
|
87
89
|
`metrust` still returns the same Pint/NumPy-facing API surface. Unsupported cases automatically stay on the Rust CPU path.
|
|
88
90
|
|
|
89
91
|
## Speed
|
|
@@ -205,7 +207,7 @@ These forward to MetPy when installed:
|
|
|
205
207
|
- `metrust.xarray` (xarray accessor)
|
|
206
208
|
- `metrust.io.Level2File` (NEXRAD Level II)
|
|
207
209
|
|
|
208
|
-
Core `metrust.calc`
|
|
210
|
+
Core `metrust.calc` stays native Rust by default with no required MetPy dependency. A small parity-sensitive subset may delegate to MetPy when it is installed; otherwise those paths still fall back to local metrust implementations. The optional `met-cu` backend is an explicit accelerator, not a requirement.
|
|
209
211
|
|
|
210
212
|
## Examples
|
|
211
213
|
|
|
@@ -219,7 +221,7 @@ See `examples/` for complete drop-in demos:
|
|
|
219
221
|
|
|
220
222
|
```bash
|
|
221
223
|
cargo test --workspace # 1,186 Rust tests
|
|
222
|
-
python -m pytest tests/ -q #
|
|
224
|
+
python -m pytest tests/ -q # 30 Python tests (including MetPy compatibility regression)
|
|
223
225
|
```
|
|
224
226
|
|
|
225
227
|
## Documentation
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name = "metrust"
|
|
3
3
|
version = "0.3.9"
|
|
4
4
|
edition = "2021"
|
|
5
|
-
description = "A pure-Rust
|
|
5
|
+
description = "A pure-Rust meteorology toolkit with a MetPy-compatible calculation layer"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
|
|
8
8
|
[dependencies]
|
|
@@ -225,10 +225,13 @@ pub fn heat_index(temperature_c: f64, relative_humidity_pct: f64) -> f64 {
|
|
|
225
225
|
let t_f = temperature_c * 9.0 / 5.0 + 32.0;
|
|
226
226
|
let rh = relative_humidity_pct;
|
|
227
227
|
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
// NWS two-step: compute Steadman, average with T, then decide
|
|
229
|
+
let steadman = 0.5 * (t_f + 61.0 + (t_f - 68.0) * 1.2 + rh * 0.094);
|
|
230
|
+
let hi_avg = (steadman + t_f) / 2.0;
|
|
231
|
+
|
|
232
|
+
if hi_avg < 80.0 {
|
|
233
|
+
// Below threshold, return the averaged Steadman result
|
|
234
|
+
return (hi_avg - 32.0) * 5.0 / 9.0;
|
|
232
235
|
}
|
|
233
236
|
|
|
234
237
|
// Rothfusz regression
|
|
@@ -456,7 +456,12 @@ pub fn cape_cin_core(
|
|
|
456
456
|
let tv_parc_prev = virtual_temp(t_parc_prev, p_prev, t_parc_prev);
|
|
457
457
|
let buoy_prev = tv_parc_prev - tv_env_prev;
|
|
458
458
|
|
|
459
|
-
if
|
|
459
|
+
if buoy_prev >= 0.0 {
|
|
460
|
+
// Previous level is also buoyant — no real crossing.
|
|
461
|
+
// The parcel is buoyant from the LCL (or surface)
|
|
462
|
+
// upward, so the LFC is at the LCL pressure.
|
|
463
|
+
p_lcl
|
|
464
|
+
} else if buoyancy != buoy_prev {
|
|
460
465
|
let frac = (0.0 - buoy_prev) / (buoyancy - buoy_prev);
|
|
461
466
|
p_prev + frac * (p_curr - p_prev)
|
|
462
467
|
} else {
|
|
@@ -1423,9 +1428,12 @@ pub fn sigma_to_pressure(sigma: f64, p_sfc: f64, p_top: f64) -> f64 {
|
|
|
1423
1428
|
/// t_f: temperature (Fahrenheit), rh: relative humidity (%).
|
|
1424
1429
|
/// Returns heat index in Fahrenheit.
|
|
1425
1430
|
pub fn heat_index(t_f: f64, rh: f64) -> f64 {
|
|
1426
|
-
//
|
|
1427
|
-
|
|
1428
|
-
|
|
1431
|
+
// NWS two-step: compute Steadman, average with T, then decide
|
|
1432
|
+
let steadman = 0.5 * (t_f + 61.0 + (t_f - 68.0) * 1.2 + rh * 0.094);
|
|
1433
|
+
let hi_avg = (steadman + t_f) / 2.0;
|
|
1434
|
+
|
|
1435
|
+
if hi_avg < 80.0 {
|
|
1436
|
+
return hi_avg;
|
|
1429
1437
|
}
|
|
1430
1438
|
|
|
1431
1439
|
// Rothfusz regression
|
|
@@ -3176,9 +3184,10 @@ mod tests {
|
|
|
3176
3184
|
|
|
3177
3185
|
#[test]
|
|
3178
3186
|
fn test_heat_index_below_80f() {
|
|
3179
|
-
//
|
|
3187
|
+
// NWS two-step: Steadman averaged with T when avg < 80F
|
|
3180
3188
|
let hi = heat_index(70.0, 50.0);
|
|
3181
|
-
let
|
|
3189
|
+
let steadman = 0.5 * (70.0 + 61.0 + (70.0 - 68.0) * 1.2 + 50.0 * 0.094);
|
|
3190
|
+
let expected = (steadman + 70.0) / 2.0;
|
|
3182
3191
|
assert!(
|
|
3183
3192
|
(hi - expected).abs() < 1e-10,
|
|
3184
3193
|
"Heat index at 70F/50%: got={hi}, expected={expected}"
|
|
@@ -7,9 +7,13 @@ in Rust versus what it delegates to MetPy.
|
|
|
7
7
|
|
|
8
8
|
## 1. Compatibility Model
|
|
9
9
|
|
|
10
|
-
metrust is a
|
|
10
|
+
metrust is a MetPy-compatible calculation layer for `metpy.calc`, backed by a compiled Rust
|
|
11
11
|
engine (`_metrust`). The compatibility model has three tiers:
|
|
12
12
|
|
|
13
|
+
Function coverage in the tables below is a functionality matrix. Public `metpy.calc` signatures now
|
|
14
|
+
match MetPy, and the compatibility tests cover explicit runtime regression cases on the shared
|
|
15
|
+
calculation surface.
|
|
16
|
+
|
|
13
17
|
| Tier | Description |
|
|
14
18
|
|------|-------------|
|
|
15
19
|
| **Native Rust** | Function is implemented entirely in Rust. The Python wrapper strips Pint units, calls the Rust function, and re-attaches units. No MetPy dependency. |
|
|
@@ -19,7 +19,7 @@ from metrust.units import units
|
|
|
19
19
|
|
|
20
20
|
That is the entire change for most code. Every function in `metrust.calc`
|
|
21
21
|
accepts the same Pint Quantity inputs and returns Pint Quantity outputs, using
|
|
22
|
-
the same function names and the same positional/keyword signatures as MetPy.
|
|
22
|
+
the same function names and the same public positional/keyword signatures as MetPy.
|
|
23
23
|
|
|
24
24
|
A project-wide find-and-replace from `metpy.` to `metrust.` is usually
|
|
25
25
|
sufficient. The table below shows the namespace mapping:
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## Meteorological Computation at the Speed of Rust
|
|
4
4
|
|
|
5
|
-
**metrust** is a Rust-powered,
|
|
6
|
-
|
|
5
|
+
**metrust** is a Rust-powered, MetPy-compatible calculation layer for [MetPy](https://unidata.github.io/MetPy/)'s calculation workflows.
|
|
6
|
+
For many `metpy.calc` workflows, changing one import line is enough. Many thermo and grid workloads run substantially faster.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -53,7 +53,7 @@ The surface is identical. Under the hood, every calculation runs through compile
|
|
|
53
53
|
|
|
54
54
|
### 150/150 MetPy Calc Functions (Plus 36 Extras)
|
|
55
55
|
|
|
56
|
-
Every function in `metpy.calc` has a metrust equivalent -- 100% API coverage. Plus 36 additional functions MetPy doesn't have (grid composites, fire weather indices, and more). The
|
|
56
|
+
Every function in `metpy.calc` has a metrust equivalent -- 100% API coverage. Plus 36 additional functions MetPy doesn't have (grid composites, fire weather indices, and more). The calculation layer is Rust-backed by default, with a small parity-sensitive subset optionally delegating to MetPy when it is installed.
|
|
57
57
|
Coverage spans the core of operational meteorology:
|
|
58
58
|
|
|
59
59
|
- **Thermodynamics** -- potential temperature, equivalent potential temperature, virtual temperature, wet-bulb temperature, LCL, LFC, EL, CAPE/CIN, parcel profiles, precipitable water, thickness hydrostatic, stability indices
|
|
@@ -149,8 +149,8 @@ All `metrust.calc` functions compile to native machine code through the Rust too
|
|
|
149
149
|
|
|
150
150
|
### No MetPy Dependency for Calculations
|
|
151
151
|
|
|
152
|
-
`pip install metrust` pulls in **only** NumPy and Pint. The
|
|
153
|
-
MetPy
|
|
152
|
+
`pip install metrust` pulls in **only** NumPy and Pint. The calculation layer stays self-contained by default.
|
|
153
|
+
A small parity-sensitive subset of `metrust.calc` can delegate to MetPy when MetPy is installed, but the default path remains the Rust backend.
|
|
154
154
|
|
|
155
155
|
### Optional MetPy for Plots, xarray, and Level 2
|
|
156
156
|
|
|
@@ -158,7 +158,7 @@ A handful of surfaces intentionally delegate to MetPy when it is installed:
|
|
|
158
158
|
|
|
159
159
|
| Surface | Behavior |
|
|
160
160
|
|---|---|
|
|
161
|
-
| `metrust.calc` |
|
|
161
|
+
| `metrust.calc` | Native Rust by default, with limited optional MetPy delegation on a few parity-sensitive paths. |
|
|
162
162
|
| `metrust.io.Level2File` | Forwards to MetPy's Level 2 reader when available. |
|
|
163
163
|
| `metrust.plots` | Forwards to `metpy.plots`. |
|
|
164
164
|
| `metrust.xarray` | Forwards to `metpy.xarray`. |
|
|
@@ -17,7 +17,7 @@ metrust started with SHARPpy-heritage algorithms — Wobus polynomial approximat
|
|
|
17
17
|
|
|
18
18
|
Over a series of systematic replacements, metrust moved to MetPy-exact algorithms:
|
|
19
19
|
|
|
20
|
-
- **Moist lapse rate** replaced with a fourth-order Runge-Kutta (RK4) integration of the full moist-adiabatic ODE, matching MetPy
|
|
20
|
+
- **Moist lapse rate** replaced with a fourth-order Runge-Kutta (RK4) integration of the full moist-adiabatic ODE, matching MetPy closely on the supported reference-pressure paths.
|
|
21
21
|
- **CAPE integration** switched from a simplified buoyancy sum to MetPy's exact formulation: `g * dTv / Tv * dz`, integrated over each layer.
|
|
22
22
|
- **Bunkers storm motion** moved to a pressure-weighted mean wind, matching the Bunkers et al. (2000) method that MetPy implements.
|
|
23
23
|
- **Isentropic interpolation** adopted a Newton solver on the exact theta equation rather than a lookup-table approach.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
site_name: metrust
|
|
2
|
-
site_description: Rust-powered meteorology toolkit
|
|
2
|
+
site_description: Rust-powered meteorology toolkit with a MetPy-compatible calculation layer
|
|
3
3
|
site_url: https://fahrenheitresearch.github.io/metrust-py/
|
|
4
4
|
repo_url: https://github.com/FahrenheitResearch/metrust-py
|
|
5
5
|
repo_name: FahrenheitResearch/metrust-py
|
|
@@ -4,8 +4,8 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "metrust"
|
|
7
|
-
version = "0.4.
|
|
8
|
-
description = "Rust-powered
|
|
7
|
+
version = "0.4.2"
|
|
8
|
+
description = "Rust-powered MetPy-compatible calculation layer with optional GPU acceleration"
|
|
9
9
|
requires-python = ">=3.9"
|
|
10
10
|
license = {text = "MIT"}
|
|
11
11
|
authors = [{name = "Fahrenheit Research"}]
|