sounding_analysis/lib.rs
1// FIXME: Add some examples of using analysis functions.
2/*!
3[](https://github.com/rnleach/sounding-analysis/actions)
4
5Functions and data types for analyzing soundings from radiosondes or models.
6
7Library to represent an atmospheric sounding with pressure as the vertical coordinate.
8
9# Examples
10```
11use optional::{Optioned, some};
12use metfor::{HectoPascal, Celsius, Feet};
13
14use sounding_analysis::{Sounding, StationInfo};
15
16fn main() {
17
18 // Create pressure profile
19 let pressure_profile: Vec<Optioned<HectoPascal>> =
20 vec![1000.0, 925.0, 850.0, 700.0, 500.0, 300.0, 250.0, 100.0]
21 .into_iter()
22 .map(HectoPascal)
23 .map(some)
24 .collect();
25
26 // Create a temperature profile
27 let temperature_profile: Vec<Optioned<Celsius>> =
28 vec![13.0, 7.0, 5.0, -4.5, -20.6, -44.0, -52.0, -56.5]
29 .into_iter()
30 .map(Celsius)
31 .map(some)
32 .collect();
33
34 // Create some station info
35 let stn = StationInfo::new_with_values(None, None, (45.6789, -115.6789), Feet(992.0));
36
37 // Create a valid time. This uses a `chrono::NaiveDateTime`, and you should always assume
38 // that valid times are in UTC.
39 let vt = chrono::NaiveDate::from_ymd_opt(2018,3,8).unwrap().and_hms_opt(12,0,0).unwrap();
40
41 // Use the builder pattern to construct a sounding.
42 let snd = Sounding::new()
43 .with_station_info(stn)
44 .with_valid_time(vt)
45 .with_lead_time(24) // Lead time in hours for forecast soundings.
46 .with_pressure_profile(pressure_profile)
47 .with_temperature_profile(temperature_profile)
48 .with_station_pressure(some(HectoPascal(1013.25)))
49 .with_sfc_temperature(some(Celsius(15.0)));
50
51 // Top down and bottom up iterators are provided. If surface data is available, it is
52 // inserted into the profile.
53 let mut iter = snd.top_down();
54
55 let mut data_row = iter.next().unwrap();
56 assert_eq!(data_row.pressure, some(HectoPascal(100.0)));
57 assert_eq!(data_row.temperature, some(Celsius(-56.5)));
58
59 data_row = iter.next().unwrap();
60 assert_eq!(data_row.pressure, some(HectoPascal(250.0)));
61 assert_eq!(data_row.temperature, some(Celsius(-52.0)));
62
63 data_row = iter.next().unwrap();
64 assert_eq!(data_row.pressure, some(HectoPascal(300.0)));
65 assert_eq!(data_row.temperature, some(Celsius(-44.0)));
66
67 data_row = iter.next().unwrap();
68 assert_eq!(data_row.pressure, some(HectoPascal(500.0)));
69 assert_eq!(data_row.temperature, some(Celsius(-20.6)));
70
71 data_row = iter.next().unwrap();
72 assert_eq!(data_row.pressure, some(HectoPascal(700.0)));
73 assert_eq!(data_row.temperature, some(Celsius(-4.5)));
74
75 data_row = iter.next().unwrap();
76 assert_eq!(data_row.pressure, some(HectoPascal(850.0)));
77 assert_eq!(data_row.temperature, some(Celsius(5.0)));
78
79 data_row = iter.next().unwrap();
80 assert_eq!(data_row.pressure, some(HectoPascal(925.0)));
81 assert_eq!(data_row.temperature, some(Celsius(7.0)));
82
83 data_row = iter.next().unwrap();
84 assert_eq!(data_row.pressure, some(HectoPascal(1000.0)));
85 assert_eq!(data_row.temperature, some(Celsius(13.0)));
86
87 // THIS ONE IS THE SURFACE DATA!
88 data_row = iter.next().unwrap();
89 assert_eq!(data_row.pressure, some(HectoPascal(1013.25)));
90 assert_eq!(data_row.temperature, some(Celsius(15.0)));
91
92 assert_eq!(iter.next(), None);
93
94 // Profiles and surface values can also be accessed via getter methods. Read the docs!
95}
96```
97
98You probably noticed a lot of `optional::Optioned`s in the example. Basically, anything can be
99missing, and missing values are common in upper air soundings. For example, at high altitude the
100dew point or humidity are often missing (if not totally inaccurate).
101
102*/
103#![doc(test(attr(deny(warnings))))]
104#![deny(missing_docs)]
105
106//
107// API
108//
109pub use crate::{
110 error::{AnalysisError, Result},
111 fire::{hot_dry_windy, pft, pft_analysis, PFTAnalysis},
112 indexes::precipitable_water,
113 interpolation::{linear_interpolate, linear_interpolate_sounding},
114 layers::{
115 cold_surface_temperature_layer, dendritic_snow_zone, effective_inflow_layer,
116 hail_growth_zone, inversions, layer_agl, melting_freezing_energy_area, pressure_layer,
117 sfc_based_inversion, warm_surface_temperature_layer, warm_temperature_layer_aloft,
118 warm_wet_bulb_layer_aloft, Layer, Layers,
119 },
120 levels::{
121 freezing_levels, max_temperature_in_layer, max_temperature_in_profile,
122 max_wet_bulb_in_layer, max_wet_bulb_in_profile, wet_bulb_zero_levels, Level, Levels,
123 },
124 parcel::{
125 average_parcel, convective_parcel, effective_layer_parcel, lowest_level_parcel,
126 mixed_layer_parcel, most_unstable_parcel, pressure_parcel, surface_parcel, Parcel,
127 },
128 parcel_profile::{
129 dcape, lift_parcel, mix_down, robust_convective_parcel_ascent, ParcelAscentAnalysis,
130 ParcelProfile,
131 },
132 precip_type::{
133 bourgouin_precip_type, check_precip_type_intensity, nssl_precip_type, PrecipType,
134 },
135 profile::{
136 equivalent_potential_temperature, hydrolapse, potential_temperature, relative_humidity,
137 relative_humidity_ice, sfc_to_level_temperature_lapse_rate, temperature_lapse_rate,
138 theta_e_lapse_rate, wet_bulb,
139 },
140 sounding::{DataRow, Sounding, StationInfo},
141 wind::{bunkers_storm_motion, mean_wind, sr_helicity},
142};
143
144pub mod experimental;
145
146#[doc(hidden)]
147pub use crate::sounding::doctest;
148
149//
150// Internal use only
151//
152
153// Modules
154mod error;
155mod fire;
156mod indexes;
157mod interpolation;
158mod layers;
159mod levels;
160mod parcel;
161mod parcel_profile;
162mod precip_type;
163mod profile;
164mod sounding;
165mod wind;