use chrono::{Duration, NaiveDateTime};
use std::fmt;
#[derive(Clone, Copy, PartialEq, Eq, Debug, EnumString, AsStaticStr, EnumIter, Hash)]
pub enum Model {
#[strum(
to_string = "gfs",
serialize = "gfs3",
serialize = "GFS",
serialize = "GFS3"
)]
GFS,
#[strum(
to_string = "nam",
serialize = "namm",
serialize = "NAM",
serialize = "NAMM"
)]
NAM,
#[strum(to_string = "nam4km", serialize = "NAM4KM")]
NAM4KM,
#[strum(to_string = "local_wrf", serialize = "LOCAL_WRF")]
LocalWrf,
#[strum(to_string = "other_model", serialize = "OTHER")]
Other,
}
impl fmt::Display for Model {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Model::*;
match *self {
GFS => write!(f, "{}", stringify!(GFS)),
NAM => write!(f, "{}", stringify!(NAM)),
NAM4KM => write!(f, "{}", stringify!(NAM4KM)),
LocalWrf => write!(f, "{}", stringify!(LocalWRf)),
Other => write!(f, "{}", stringify!(Other)),
}
}
}
impl Model {
pub fn hours_between_runs(self) -> i64 {
match self {
Model::GFS => 6,
Model::NAM => 6,
Model::NAM4KM => 6,
Model::LocalWrf => 24, Model::Other => 24, }
}
pub fn base_hour(self) -> i64 {
match self {
_ => 0,
}
}
pub fn all_runs(
self,
start: &NaiveDateTime,
end: &NaiveDateTime,
) -> impl Iterator<Item = NaiveDateTime> {
debug_assert!(start <= end);
let delta_t = self.hours_between_runs();
let mut round_start = start.date().and_hms(0, 0, 0) + Duration::hours(self.base_hour());
while round_start > *start {
round_start -= Duration::hours(self.hours_between_runs());
}
while round_start < *start {
round_start += Duration::hours(self.hours_between_runs());
}
while round_start > *end {
round_start -= Duration::hours(self.hours_between_runs());
}
let steps: i64 = (*end - round_start).num_hours() / self.hours_between_runs();
(0..=steps).map(move |step| round_start + Duration::hours(step * delta_t))
}
}
#[cfg(test)]
mod unit {
use super::*;
use chrono::NaiveDate;
#[test]
fn test_all_runs() {
assert_eq!(
Model::GFS.hours_between_runs(),
6,
"test pre-condition failed."
);
let start = &NaiveDate::from_ymd(2018, 9, 1).and_hms(0, 0, 0);
let end = &NaiveDate::from_ymd(2018, 9, 2).and_hms(0, 0, 0);
assert_eq!(Model::GFS.all_runs(start, end).count(), 5);
let start = &NaiveDate::from_ymd(2018, 9, 1).and_hms(0, 1, 0);
let end = &NaiveDate::from_ymd(2018, 9, 2).and_hms(0, 0, 0);
assert_eq!(Model::GFS.all_runs(start, end).count(), 4);
}
}