Skip to main content

winds_engine/
lib.rs

1//! Deterministic wind data for trajectory simulation, consumed by
2//! rockets-engine.
3//!
4//! The wind-field types — the [`WindField`] trait, [`ConstantField`],
5//! [`ProfileField`], [`LogProfile`], [`EkmanProfile`] and the [`HeightOffset`]
6//! datum wrapper — are ballistics-engine's (its `wind` module, since
7//! ballistics-engine 0.49.0), re-exported here so this crate's pipelines and
8//! its consumers share one definition. Everything is stateless and
9//! reproducible from inputs: no wall clock or unseeded randomness anywhere,
10//! and no network except the `download` feature.
11//!
12//! - [`sounding`]: radiosonde interchange-format parsing.
13//! - [`validate`]: profile-vs-sounding comparison metrics.
14//! - [`terrain`]: a diagnostic mass-consistent terrain wind.
15//! - `grib` (feature): GRIB2 forecast files into a [`ProfileField`].
16//! - `download` (feature): live GFS/HRRR acquisition, the only networked
17//!   code in the crate.
18
19#[cfg(feature = "download")]
20pub mod download;
21#[cfg(feature = "grib")]
22pub mod grib;
23pub mod sounding;
24pub mod terrain;
25pub mod validate;
26
27pub use ballistics_engine::wind::{
28    ConstantField, EkmanProfile, HeightOffset, LogProfile, ProfileField, ProfileLevel, WindField,
29    WindFieldError, WindFieldParam, WindFieldRule,
30};
31pub use sounding::{Sounding, SoundingLevel};
32#[cfg(feature = "tiff")]
33pub use terrain::{geotiff_grid, geotransform, GeoTransform};
34pub use terrain::{
35    hgt_grid, local_en_m, monitors_from_geo_csv, HeightGrid, Monitor, SrtmResolution,
36    TerrainFlowField,
37};
38pub use validate::{LayerError, ValidationReport};
39
40/// Crate-wide error: invalid input with a field name and reason.
41#[derive(Debug, Clone, PartialEq)]
42pub struct Error {
43    /// The offending input or field.
44    pub field: &'static str,
45    /// Why it was rejected.
46    pub reason: String,
47}
48
49impl Error {
50    pub(crate) fn invalid(field: &'static str, reason: impl Into<String>) -> Self {
51        Self {
52            field,
53            reason: reason.into(),
54        }
55    }
56}
57
58impl std::fmt::Display for Error {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        write!(f, "{}: {}", self.field, self.reason)
61    }
62}
63
64impl std::error::Error for Error {}
65
66/// Crate-wide result.
67pub type Result<T> = std::result::Result<T, Error>;