1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#![deny(missing_docs)]

/*!

Library to represent an atmospheric sounding with pressure as the vertical coordinate.
The base crate is meant to be a common base  for other crates to build on. These crates may be for 
managing a data-store, displaying data, or saving and loading files.

The emphasis of this crate is data representation and a common type for systems using sounding
data to build on and use.

# Examples
```
extern crate chrono;
extern crate sounding_base;

use sounding_base::{Sounding, StationInfo, Profile, Surface};

fn main() {

    // Create  pressure profile
    let pressure_profile: Vec<Option<f64>> = 
        vec![1000.0, 925.0, 850.0, 700.0, 500.0, 300.0, 250.0, 100.0]
            .iter()
            .map(|p| Some(*p))
            .collect();

    // Create a temperature profile
    let temperature_profile: Vec<Option<f64>> = 
        vec![13.0, 7.0, 5.0, -4.5, -20.6, -44.0, -52.0, -56.5]
            .iter()
            .map(|t| Some(*t))
            .collect();

    // Create some station info
    let stn = StationInfo::new_with_values(None, (45.6789, -115.6789), 992.0);

    // Create a valid time. This uses a `chrono::NaiveDateTime`, and you should always assume 
    // that valid times are in UTC.
    let vt = chrono::NaiveDate::from_ymd(2018,3,8).and_hms(12,0,0);

    // Use the builder pattern to construct a sounding.
    let snd = Sounding::new()
        .set_station_info(stn)
        .set_valid_time(vt)
        .set_lead_time(24)  // Lead time in hours for forecast soundings.
        .set_profile(Profile::Pressure, pressure_profile)
        .set_profile(Profile::Temperature, temperature_profile)
        // Surface values don't have to be `Option`
        .set_surface_value(Surface::StationPressure, 1013.25)
        // But they can be
        .set_surface_value(Surface::Temperature, Some(15.0)); 

    // Top down and bottom up iterators are provided. If surface data is available, it is 
    // inserted into the profile.
    let mut iter = snd.top_down();

    let mut data_row = iter.next().unwrap();
    assert!(data_row.pressure == Some(100.0));
    assert!(data_row.temperature == Some(-56.5));

    data_row = iter.next().unwrap();
    assert!(data_row.pressure == Some(250.0));
    assert!(data_row.temperature == Some(-52.0));

    data_row = iter.next().unwrap();
    assert!(data_row.pressure == Some(300.0));
    assert!(data_row.temperature == Some(-44.0));

    data_row = iter.next().unwrap();
    assert!(data_row.pressure == Some(500.0));
    assert!(data_row.temperature == Some(-20.6));

    data_row = iter.next().unwrap();
    assert!(data_row.pressure == Some(700.0));
    assert!(data_row.temperature == Some(-4.5));

    data_row = iter.next().unwrap();
    assert!(data_row.pressure == Some(850.0));
    assert!(data_row.temperature == Some(5.0));

    data_row = iter.next().unwrap();
    assert!(data_row.pressure == Some(925.0));
    assert!(data_row.temperature == Some(7.0));

    data_row = iter.next().unwrap();
    assert!(data_row.pressure == Some(1000.0));
    assert!(data_row.temperature == Some(13.0));


    // THIS ONE IS THE SURFACE DATA!
    data_row = iter.next().unwrap();
    assert!(data_row.pressure == Some(1013.25));
    assert!(data_row.temperature == Some(15.0));

    assert!(iter.next() == None);

    // Profiles and surface values can also be accessed via getter methods. Read the docs!
}
```

You probably noticed a lot of `Option`s in the example. Basically, anything can be missing, and
missing values are common in upper air soundings. For example, at high altitude the dew point or 
humidity are often missing (if not totally inaccurate).

*/

//
// API
//

pub use sounding::{DataRow, Profile, Sounding, StationInfo, Surface};

//
// Internal use only
//

extern crate chrono;
extern crate smallvec;

extern crate metfor;

mod sounding;