ndspec/lib.rs
1//! # ndspec
2//!
3//! `ndspec` is a crate for working with energy density spectra with a focus on ocean waves, wind, and related response spectra.
4//!
5//! The crate is organised into the following modules:
6//!
7//! * `core` - Core functionality for working with energy density spectra.
8//! * `waves` - Functions for calculating energy density spectra for ocean waves.
9//! * `wind` - Functions for calculating energy density spectra for wind.
10//! * `spectrum` - provides the Types `Spectrum1` and 'Spectrum2' for one-dimensional and two-dimensional spectra respectively.
11//!
12//! All wave and wind spectra can be converted into either a `Spectrum1` or
13//! `Spectrum2` Type. These types provide various traits for working
14//! with and evaluating energy density spectra.
15//!
16//! The crate is designed to be used in conjunction with the `ndarray`
17//! crate. The `ndarray::Array1` and `ndarray::Array2` types are
18//! underlying data structures adopted throughout.
19//!
20//! The crate also provides a Python extension that can be compiled and installed seperately.
21//!
22//! ## Installation
23//!
24//! Add the following to your `Cargo.toml` file:
25//!
26//! ```toml
27//! [dependencies]
28//! ndspec = "0.1.0"
29//! ```
30//!
31//! ## Usage
32//!
33//! The following example demonstrates how to calculate the energy density spectrum for a Bretschneider wave spectrum:
34//!
35//! ```
36//! use ndspec::prelude::*;
37//!
38//! let hs = 1.5;
39//! let tp = 18.0;
40//! let mut bretschneider = Bretschneider::new(hs, tp);
41//! let omega = Array1::linspace(0.1, PI, 100);
42//! let energy = bretschneider.set_omega(omega).energy();
43//! ```
44//!
45//! ## Python Extension
46//!
47//! The crate provides a Python extension that can be compiled and
48//! installed seperately. To build the extension, `maturin` is
49//! required and the `python-extension` feature must be enabled:
50//!
51//! ```bash
52//! maturin build --release --features python-extension
53//! ```
54//!
55//! and install with `pip`.
56//!
57//! ### Examples
58//!
59//! Define a Jonswap energy density spectrum from only Hs and Tp,
60//! convert to a `Spectrum1D` type, and then evaluate the most probable
61//! maximum amplitude over a 3 hour (10,800 s) time window:
62//! ```python
63//! import ndspec
64//! S = ndspec.Jonswap(hs=1.5, tp=10.0).to_spec1d()
65//! print(S.Ampm(10_800))
66//! ```
67//!
68//! Print out the help for the Jonswap class in Python::
69//! ```python
70//! import ndspec
71//! help(ndspec.Jonswap)
72//! ```
73//!
74#![cfg_attr(
75 feature = "doc-images",
76 cfg_attr(all(),
77 doc = ::embed_doc_image::embed_image!("label_matrix", "./assets/matrix.png")))
78]
79//!
80//! ![energy density data structure][label_matrix]
81//!
82
83//#![warn(missing_docs)]
84//#![warn(missing_doc_code_examples)]
85
86//
87pub mod azimuth;
88pub mod core;
89pub mod spectrums;
90pub mod waves;
91pub mod wind;
92
93//use embed_doc_image::embed_doc_image;
94
95#[cfg(feature = "python-extension")]
96use pyo3::prelude::*;
97
98/// ## The prelude
99///
100/// The purpose of this module is to:
101/// * define the namespace
102/// * keep all imports in a central location
103/// * help avoid the direct imports of traits defined by this crate in the parent module
104/// * provide a convenient and consistent way to import the main types, traits, and functions with a single import
105/// * provide access to useful external crate types and traits from a single import
106///
107/// ## Example:
108///
109/// ```
110/// use ndspec::prelude::*;
111/// ```
112pub mod prelude {
113
114 // constants
115 pub use crate::core::constants::{GRAVITY, KNOT, PI, RHO_AIR, RHO_SEA_WATER, TWO_PI};
116
117 // re-export of the core modules
118 pub use crate::core::ndarray_ext;
119 pub use crate::core::*;
120 pub use crate::spectrums::*;
121 pub use crate::waves::jonswap::{
122 convert_t1_to_tp, convert_tp_to_t1, convert_tp_to_tz, convert_tz_to_tp, lewis_allos, maxhs,
123 Jonswap,
124 };
125 pub use crate::waves::spreading::{spread_cos_2s, spread_cos_n, Spreading};
126 pub use crate::waves::{bretschneider, gaussian::gaussian_spectrum, jonswap, PiersonMoskowitz};
127 pub use crate::wind::*;
128
129 // re-export of external crate types and traits for convenience
130 pub use ndarray::{Array1, Array2};
131 pub use ndarray_stats::QuantileExt;
132
133 pub use crate::azimuth;
134}
135
136// convenience re-export of the prelude
137#[doc(hidden)]
138pub use crate::prelude::*;
139
140#[cfg(feature = "python-extension")]
141mod py_interface;
142
143#[cfg(feature = "python-extension")]
144#[pymodule]
145#[pyo3(name = "_libndspec")]
146fn ndspec(_py: Python, m: &PyModule) -> PyResult<()> {
147 m.add_function(wrap_pyfunction!(py_interface::version, m)?)?;
148
149 m.add_function(wrap_pyfunction!(py_interface::interp1, m)?)?;
150 m.add_function(wrap_pyfunction!(py_interface::interp2, m)?)?;
151
152 // py_azimuth.rs
153 m.add_function(wrap_pyfunction!(py_interface::convert_branch_180, m)?)?;
154 m.add_function(wrap_pyfunction!(py_interface::convert_branch_360, m)?)?;
155 m.add_function(wrap_pyfunction!(py_interface::rotation_matrix_2d, m)?)?;
156 m.add_function(wrap_pyfunction!(py_interface::convert_branch_180_vec, m)?)?;
157
158 // py_spectrums.rs
159 m.add_function(wrap_pyfunction!(py_interface::maxhs, m)?)?;
160 m.add_function(wrap_pyfunction!(py_interface::lewis_allos, m)?)?;
161 m.add_function(wrap_pyfunction!(py_interface::bretschneider, m)?)?;
162 m.add_function(wrap_pyfunction!(py_interface::jonswap, m)?)?;
163 m.add_function(wrap_pyfunction!(py_interface::gaussian, m)?)?;
164 m.add_function(wrap_pyfunction!(py_interface::convert_tp_to_tz, m)?)?;
165 m.add_function(wrap_pyfunction!(py_interface::convert_tz_to_tp, m)?)?;
166 m.add_function(wrap_pyfunction!(py_interface::convert_tp_to_t1, m)?)?;
167 m.add_function(wrap_pyfunction!(py_interface::convert_t1_to_tp, m)?)?;
168 m.add_function(wrap_pyfunction!(py_interface::spread_cos_n, m)?)?;
169 m.add_function(wrap_pyfunction!(py_interface::spread_cos_2s, m)?)?;
170 m.add_function(wrap_pyfunction!(py_interface::froya_10min, m)?)?;
171 m.add_function(wrap_pyfunction!(py_interface::froya_1hr, m)?)?;
172
173 m.add_class::<py_interface::Jonswap>()?;
174 m.add_class::<py_interface::Spreading>()?;
175 m.add_class::<py_interface::FrequencyResponse>()?;
176 m.add_class::<py_interface::Spectrum1D>()?;
177 m.add_class::<py_interface::Spectrum2D>()?;
178 Ok(())
179}