mod indexes;
mod profile;
mod station_info;
use chrono::NaiveDateTime;
use error::*;
#[derive(Debug)]
pub struct UpperAir {
pub num: i32, pub valid_time: NaiveDateTime, pub lead_time: i32, pub lat: f64, pub lon: f64, pub elevation: f64,
pub show: f64, pub li: f64, pub swet: f64, pub kinx: f64, pub lclp: f64, pub pwat: f64, pub totl: f64, pub cape: f64, pub lclt: f64, pub cins: f64, pub eqlv: f64, pub lfc: f64, pub brch: f64,
pub pressure: Vec<f64>, pub temperature: Vec<f64>, pub wet_bulb: Vec<f64>, pub dew_point: Vec<f64>, pub theta_e: Vec<f64>, pub direction: Vec<f64>, pub speed: Vec<f64>, pub omega: Vec<f64>, pub height: Vec<f64>, pub cloud_fraction: Vec<f64>, }
impl UpperAir {
pub fn parse(text: &str) -> Result<UpperAir, Error> {
use self::indexes::Indexes;
use self::profile::Profile;
use self::station_info::StationInfo;
use parse_util::find_blank_line;
let mut break_point = find_blank_line(text).ok_or_else(BufkitFileError::new)?;
let (station_info_section, the_rest) = text.split_at(break_point);
break_point = find_blank_line(the_rest).ok_or_else(BufkitFileError::new)?;
let (index_section, upper_air_section) = the_rest.split_at(break_point);
let station_info = StationInfo::parse(station_info_section)?;
let indexes = Indexes::parse(index_section)?;
let upper_air = Profile::parse(upper_air_section)?;
Ok(UpperAir {
num: station_info.num,
valid_time: station_info.valid_time,
lead_time: station_info.lead_time,
lat: station_info.lat,
lon: station_info.lon,
elevation: station_info.elevation,
show: indexes.show,
li: indexes.li,
swet: indexes.swet,
kinx: indexes.kinx,
lclp: indexes.lclp,
pwat: indexes.pwat,
totl: indexes.totl,
cape: indexes.cape,
lclt: indexes.lclt,
cins: indexes.cins,
eqlv: indexes.eqlv,
lfc: indexes.lfc,
brch: indexes.brch,
pressure: upper_air.pressure,
temperature: upper_air.temperature,
wet_bulb: upper_air.wet_bulb,
dew_point: upper_air.dew_point,
theta_e: upper_air.theta_e,
direction: upper_air.direction,
speed: upper_air.speed,
omega: upper_air.omega,
height: upper_air.height,
cloud_fraction: upper_air.cloud_fraction,
})
}
pub fn validate(&self) -> Result<(), BufkitFileError> {
let len = self.pressure.len();
if len == 0 {
return Err(BufkitFileError::new());
}
let is_valid_length = |l| {
if l == 0 || l == len {
Ok(())
} else {
Err(BufkitFileError::new())
}
};
is_valid_length(self.temperature.len())?;
is_valid_length(self.wet_bulb.len())?;
is_valid_length(self.dew_point.len())?;
is_valid_length(self.theta_e.len())?;
is_valid_length(self.direction.len())?;
is_valid_length(self.speed.len())?;
is_valid_length(self.omega.len())?;
is_valid_length(self.height.len())?;
is_valid_length(self.cloud_fraction.len())?;
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
fn get_test_data() -> &'static str {
"STID = KMSO STNM = 727730 TIME = 170401/0100
SLAT = 46.87 SLON = -114.16 SELV = 1335.0
STIM = 1
SHOW = 8.12 LIFT = 8.00 SWET = 39.08 KINX = 14.88
LCLP = 780.77 PWAT = 9.28 TOTL = 39.55 CAPE = 0.00
LCLT = 272.88 CINS = 0.00 EQLV = -9999.00 LFCT = -9999.00
BRCH = 0.00
PRES TMPC TMWC DWPC THTE DRCT SKNT OMEG
CFRL HGHT
867.20 8.04 4.71 1.19 307.17 288.43 2.45 0.00
0.00 1353.07
863.50 7.64 4.42 0.99 306.96 293.63 3.40 0.00
0.00 1388.34
859.80 7.24 4.18 0.90 306.87 292.38 3.57 0.00
0.00 1423.71
856.10 6.94 3.99 0.81 306.89 292.38 3.57 0.00
0.00 1459.19
852.20 6.54 3.75 0.72 306.83 293.63 3.40 0.00
0.00 1496.70
848.30 6.14 3.52 0.65 306.78 293.63 3.40 0.00
0.00 1534.33
844.30 5.74 3.27 0.56 306.73 295.02 3.22 0.00
0.00 1573.06
840.30 5.44 3.09 0.49 306.81 295.02 3.22 0.00
0.00 1611.92
836.10 5.04 2.85 0.42 306.81 296.57 3.05 0.00
0.00 1652.86
831.70 4.54 2.55 0.32 306.69 298.30 2.87 0.00
0.00 1695.91
827.20 4.14 2.31 0.25 306.73 298.30 2.87 0.00
0.00 1740.11
822.60 3.74 2.17 0.40 307.00 304.99 2.37 0.00
0.00 1785.47
817.60 3.44 2.05 0.49 307.38 306.87 1.94 0.00
0.00 1835.00
812.50 3.04 1.84 0.49 307.57 309.81 1.52 0.00
0.00 1885.77
807.00 2.54 1.54 0.40 307.61 315.00 1.38 0.00
0.00 1940.80
801.10 2.04 1.04 -0.13 307.27 323.13 0.97 0.00
0.00 2000.13
794.60 1.44 0.66 -0.28 307.28 323.13 0.97 0.10
0.00 2065.88
787.00 0.64 0.15 -0.46 307.18 315.00 0.82 0.10
0.00 2143.23
778.20 -0.16 -0.39 -0.71 307.17 315.00 0.54 0.10
0.00 2233.47
768.10 -0.76 -1.33 -2.07 306.54 26.57 0.87 0.10
0.00 2338.03
756.50 -1.66 -2.29 -3.15 306.09 45.00 1.38 0.10
0.00 2459.47
743.50 -2.56 -3.39 -4.60 305.58 48.81 2.06 0.20
0.00 2597.31
728.70 -3.56 -4.82 -6.79 304.77 32.47 2.53 0.20
0.00 2756.60
712.10 -4.46 -6.45 -10.03 303.87 360.00 1.55 0.10
0.00 2938.45
693.70 -4.66 -7.82 -14.55 303.78 310.60 1.79 0.10
0.00 3144.54
673.70 -6.06 -9.48 -17.85 303.55 304.99 2.37 0.10
0.00 3374.08
652.00 -7.46 -11.05 -21.15 303.84 336.80 2.95 0.10
0.00 3629.57
629.00 -8.46 -12.58 -26.99 304.48 3.81 5.85 0.20
0.00 3908.49
605.10 -8.86 -13.70 -36.84 306.07 11.89 11.31 0.10
0.00 4208.48
580.60 -9.26 -14.46 -48.61 308.56 9.67 17.35 0.10
0.00 4528.02
555.50 -10.56 -15.48 -46.16 311.05 4.64 21.64 0.10
0.00 4868.57
530.00 -12.76 -16.86 -37.11 313.30 358.53 22.73 0.10
0.00 5228.30
504.20 -15.76 -18.96 -33.99 314.59 355.28 23.58 0.10
0.00 5606.56
478.10 -19.06 -21.32 -31.63 315.80 353.80 26.96 0.10
0.00 6004.58
451.90 -22.26 -23.73 -30.53 317.22 352.54 32.91 0.10
0.00 6421.27
425.50 -25.26 -26.27 -31.32 318.83 350.81 40.15 0.00
0.00 6860.87
399.00 -28.56 -29.45 -35.04 319.83 348.46 46.60 0.00
0.00 7324.52
372.10 -32.36 -33.18 -40.23 320.57 347.33 51.36 0.00
0.00 7820.49
344.70 -36.66 -37.33 -45.52 321.36 349.05 55.21 0.10
0.00 8354.86
316.80 -41.46 -41.91 -49.66 322.29 352.90 61.27 0.10
0.00 8933.26
289.20 -46.66 -46.90 -52.70 323.26 353.40 70.98 0.10
0.00 9544.55
263.10 -51.76 -51.92 -57.69 324.47 350.76 81.08 0.10
0.00 10164.59
239.40 -56.86 -56.94 -61.61 325.58 349.20 85.02 0.10
0.00 10769.30
218.00 -62.06 -62.12 -67.47 326.29 349.79 81.12 0.10
0.00 11355.03
198.70 -65.46 -65.51 -72.95 329.60 352.75 64.63 0.10
0.00 11923.20
181.30 -65.56 -65.62 -73.57 338.19 345.85 47.67 0.00
0.00 12480.21
165.60 -63.86 -63.95 -74.17 349.89 334.77 41.01 0.00
0.00 13032.85
151.10 -61.16 -9999.00 -9999.00 -9999.00 334.11 36.93 0.00
0.00 13597.84
137.30 -59.76 -9999.00 -9999.00 -9999.00 329.66 30.38 0.00
0.00 14194.10
124.00 -59.06 -9999.00 -9999.00 -9999.00 331.07 25.29 0.00
0.00 14831.55
111.30 -58.46 -9999.00 -9999.00 -9999.00 328.24 19.19 0.00
0.00 15509.64
98.90 -57.86 -9999.00 -9999.00 -9999.00 317.01 15.68 0.00
0.00 16252.97
86.90 -57.76 -9999.00 -9999.00 -9999.00 308.16 13.83 0.00
0.00 17068.31
75.10 -58.36 -9999.00 -9999.00 -9999.00 307.63 11.77 0.00
0.00 17987.13
63.60 -58.26 -58.80 -80.31 472.23 316.85 8.53 0.00
0.00 19032.36
52.30 -58.16 -9999.00 -9999.00 -9999.00 328.24 4.80 0.00
0.00 20263.10
41.00 -58.66 -59.44 -82.99 534.34 12.53 5.38 0.00
0.00 21793.21
29.80 -58.16 -59.27 -84.87 586.71 66.61 7.83 0.00
0.00 23798.77
18.70 -56.96 -58.85 -87.55 674.01 97.97 9.81 0.00
0.00 26739.45
7.60 -48.76 -55.67 -92.48 904.81 303.69 6.29 0.00
0.00 32545.28"
}
#[test]
fn test_parse() {
use chrono::NaiveDate;
let test_data = get_test_data();
let snd = UpperAir::parse(test_data);
assert!(snd.is_ok());
let snd = snd.unwrap();
assert_eq!(snd.num, 727730);
assert_eq!(
snd.valid_time,
NaiveDate::from_ymd(2017, 4, 1).and_hms(1, 0, 0)
);
assert_eq!(snd.lead_time, 1);
assert_eq!(snd.lat, 46.87);
assert_eq!(snd.lon, -114.16);
assert_eq!(snd.elevation, 1335.0);
assert_eq!(snd.show, 8.12);
assert_eq!(snd.li, 8.0);
assert_eq!(snd.swet, 39.08);
assert_eq!(snd.kinx, 14.88);
assert_eq!(snd.lclp, 780.77);
assert_eq!(snd.pwat, 9.28);
assert_eq!(snd.totl, 39.55);
assert_eq!(snd.cape, 0.0);
assert_eq!(snd.lclt, 272.88);
assert_eq!(snd.cins, 0.0);
assert_eq!(snd.eqlv, -9999.0);
assert_eq!(snd.lfc, -9999.0);
assert_eq!(snd.brch, 0.0);
assert_eq!(snd.pressure[2], 859.8);
assert_eq!(snd.temperature[2], 7.24);
assert_eq!(snd.wet_bulb[2], 4.18);
assert_eq!(snd.dew_point[2], 0.9);
assert_eq!(snd.theta_e[2], 306.87);
assert_eq!(snd.direction[2], 292.38);
assert_eq!(snd.speed[2], 3.57);
assert_eq!(snd.omega[2], 0.00);
assert_eq!(snd.height[2], 1423.71);
assert_eq!(snd.cloud_fraction[2], 0.0);
assert_eq!(snd.pressure.len(), 60);
assert_eq!(snd.temperature.len(), 60);
assert_eq!(snd.wet_bulb.len(), 60);
assert_eq!(snd.dew_point.len(), 60);
assert_eq!(snd.theta_e.len(), 60);
assert_eq!(snd.direction.len(), 60);
assert_eq!(snd.speed.len(), 60);
assert_eq!(snd.omega.len(), 60);
assert_eq!(snd.height.len(), 60);
assert_eq!(snd.cloud_fraction.len(), 60);
}
}