Skip to main content

grib/def/grib2/
template4.rs

1use grib_template_derive::{Dump, TryFromSlice, WriteToBuffer};
2
3/// Product definition template 4.0 - Analysis or forecast at a horizontal level
4/// or in a horizontal layer at a point in time.
5#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
6pub struct Template4_0 {
7    pub param: param_set::ProductParam,
8    pub generating_process: param_set::GeneratingProcess,
9    #[dump(doc(
10        cutoff_hours = "Hours of observational data cutoff after reference time (see Note 1)",
11        cutoff_minutes = "Minutes of observational data cutoff after reference time",
12    ))]
13    pub forecast_time: param_set::ForecastTime,
14    pub horizontal: param_set::Horizontal,
15}
16
17/// Product definition template 4.1 - Individual ensemble forecast, control and
18/// perturbed, at a horizontal level or in a horizontal layer at a point in
19/// time.
20#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
21pub struct Template4_1 {
22    pub param: param_set::ProductParam,
23    #[dump(doc(
24        process_id = "Forecast generating process identifier (defined by originating centre).",
25    ))]
26    pub generating_process: param_set::GeneratingProcess,
27    pub forecast_time: param_set::ForecastTime,
28    pub horizontal: param_set::Horizontal,
29    pub emsemble_forecast: param_set::EnsembleForecast,
30}
31
32/// Product definition template 4.2 - Derived forecast based on all ensemble
33/// members at a horizontal level or in a horizontal layer at a point in time.
34#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
35pub struct Template4_2 {
36    pub param: param_set::ProductParam,
37    #[dump(doc(
38        process_id = "Forecast generating process identifier (defined by originating centre).",
39    ))]
40    pub generating_process: param_set::GeneratingProcess,
41    pub forecast_time: param_set::ForecastTime,
42    pub horizontal: param_set::Horizontal,
43    pub derived_forecast: param_set::DerivedForecast,
44}
45
46/// Product definition template 4.5 - Probability forecasts at a horizontal
47/// level or in a horizontal layer at a point in time.
48#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
49pub struct Template4_5 {
50    pub param: param_set::ProductParam,
51    #[dump(doc(
52        process_id = "Forecast generating process identifier (defined by originating centre).",
53    ))]
54    pub generating_process: param_set::GeneratingProcess,
55    pub forecast_time: param_set::ForecastTime,
56    pub horizontal: param_set::Horizontal,
57    pub probability_forecasts: param_set::ProbabilityForecasts,
58}
59
60/// Product definition template 4.6 - Percentile forecasts at a horizontal level
61/// or in a horizontal layer at a point in time.
62#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
63pub struct Template4_6 {
64    pub param: param_set::ProductParam,
65    pub generating_process: param_set::GeneratingProcess,
66    pub forecast_time: param_set::ForecastTime,
67    pub horizontal: param_set::Horizontal,
68    pub percentile_forecasts: param_set::PercentileForecasts,
69}
70
71/// Product definition template 4.8 - Average, accumulation, and/or extreme
72/// values or other statistically processed values at a horizontal level or in a
73/// horizontal layer in a continuous or non-continuous time interval.
74///
75/// # Examples
76///
77/// ```
78/// use grib::{
79///     TryFromSlice,
80///     def::grib2::template::{Template4_8, param_set},
81/// };
82///
83/// fn main() -> Result<(), Box<dyn std::error::Error>> {
84///     let buf = std::fs::read(
85///         "testdata/icon_global_icosahedral_single-level_2021112018_000_TOT_PREC.grib2",
86///     )?;
87///
88///     // Section 4 starts at 0x63; the template follows its 9-octet header.
89///     let mut pos = 0x6c;
90///     let actual = Template4_8::try_from_slice(&buf, &mut pos)?;
91///     let expected = Template4_8 {
92///         param: param_set::ProductParam {
93///             category: 1,
94///             num: 52,
95///         },
96///         generating_process: param_set::GeneratingProcess {
97///             process_type: 2,
98///             background_process: 0,
99///             process_id: 1,
100///         },
101///         forecast_time: param_set::ForecastTime {
102///             cutoff_hours: 0,
103///             cutoff_minutes: 0,
104///             time: param_set::TimeRange { unit: 0, len: 0 },
105///         },
106///         horizontal: param_set::Horizontal {
107///             first_surface: param_set::FixedSurface {
108///                 surface_type: 1,
109///                 value: param_set::ScaledValue {
110///                     scale_factor: 0,
111///                     scaled_value: 0,
112///                 },
113///             },
114///             second_surface: param_set::FixedSurface {
115///                 surface_type: 255,
116///                 value: param_set::ScaledValue {
117///                     scale_factor: -127,
118///                     scaled_value: -2147483647,
119///                 },
120///             },
121///         },
122///         time_interval: param_set::Statistical {
123///             end_of_overall_time_interval: param_set::DateTime {
124///                 year: 2021,
125///                 month: 11,
126///                 day: 20,
127///                 hour: 18,
128///                 minute: 0,
129///                 second: 0,
130///             },
131///             num_time_ranges: 1,
132///             num_missing: 0,
133///             time_ranges: vec![param_set::StatisticalProcess {
134///                 statistical_process_type: 1,
135///                 time_increment_type: 2,
136///                 time_range: param_set::TimeRange { unit: 0, len: 0 },
137///                 time_increment: param_set::TimeRange { unit: 255, len: 0 },
138///             }],
139///         },
140///     };
141///     assert_eq!(actual, expected);
142///     assert_eq!(pos, 0x9d);
143///
144///     Ok(())
145/// }
146/// ```
147#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
148pub struct Template4_8 {
149    pub param: param_set::ProductParam,
150    pub generating_process: param_set::GeneratingProcess,
151    pub forecast_time: param_set::ForecastTime,
152    pub horizontal: param_set::Horizontal,
153    pub time_interval: param_set::Statistical,
154}
155
156/// Product definition template 4.9 - Probability forecasts at a horizontal
157/// level or in a horizontal layer in a continuous or non-continuous time
158/// interval.
159#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
160pub struct Template4_9 {
161    pub param: param_set::ProductParam,
162    #[dump(doc(
163        process_id = "Forecast generating process identifier (defined by originating centre).",
164    ))]
165    pub generating_process: param_set::GeneratingProcess,
166    pub forecast_time: param_set::ForecastTime,
167    pub horizontal: param_set::Horizontal,
168    pub probability_forecasts: param_set::ProbabilityForecasts,
169    pub time_interval: param_set::Statistical,
170}
171
172/// Product definition template 4.10 - Percentile forecasts at a horizontal
173/// level or in a horizontal layer in a continuous or non-continuous time
174/// interval.
175#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
176pub struct Template4_10 {
177    pub param: param_set::ProductParam,
178    #[dump(doc(
179        process_id = "Forecast generating process identifier (defined by originating centre).",
180    ))]
181    pub generating_process: param_set::GeneratingProcess,
182    pub forecast_time: param_set::ForecastTime,
183    pub horizontal: param_set::Horizontal,
184    pub percentile_forecasts: param_set::PercentileForecasts,
185    pub time_interval: param_set::Statistical,
186}
187
188/// Product definition template 4.11 - Individual ensemble forecast, control and
189/// perturbed, at a horizontal level or in a horizontal layer in a continuous or
190/// non-continuous time interval.
191#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
192pub struct Template4_11 {
193    pub param: param_set::ProductParam,
194    #[dump(doc(
195        process_id = "Forecast generating process identifier (defined by originating centre).",
196    ))]
197    pub generating_process: param_set::GeneratingProcess,
198    pub forecast_time: param_set::ForecastTime,
199    pub horizontal: param_set::Horizontal,
200    pub emsemble_forecast: param_set::EnsembleForecast,
201    pub time_interval: param_set::Statistical,
202}
203
204/// Product definition template 4.12 - Derived forecasts based on all ensemble
205/// members at a horizontal level or in a horizontal layer in a continuous or
206/// non-continuous time interval.
207#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
208pub struct Template4_12 {
209    pub param: param_set::ProductParam,
210    #[dump(doc(
211        process_id = "Forecast generating process identifier (defined by originating centre).",
212    ))]
213    pub generating_process: param_set::GeneratingProcess,
214    pub forecast_time: param_set::ForecastTime,
215    pub horizontal: param_set::Horizontal,
216    pub derived_forecast: param_set::DerivedForecast,
217    pub time_interval: param_set::Statistical,
218}
219
220pub(crate) mod param_set {
221    use grib_template_derive::{Dump, TryFromSlice, WriteToBuffer};
222
223    use super::super::template::param_set::{DateTime, ScaledValue, TimeRange};
224
225    #[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
226    pub struct ProductParam {
227        /// Parameter category (see Code Table 4.1).
228        pub category: u8,
229        /// Parameter number (see Code Table 4.2).
230        pub num: u8,
231    }
232
233    #[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
234    pub struct GeneratingProcess {
235        /// Type of generating process (see Code Table 4.3).
236        pub process_type: u8,
237        /// Background generating process identifier (defined by originating
238        /// centre).
239        pub background_process: u8,
240        /// Analysis or forecast generating processes identifier (defined by
241        /// originating centre).
242        pub process_id: u8,
243    }
244
245    #[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
246    pub struct ForecastTime {
247        /// Hours after reference time of data cutoff (see Note 1).
248        pub cutoff_hours: u16,
249        /// Minutes after reference time of data cutoff.
250        pub cutoff_minutes: u8,
251        /// Forecast time.
252        #[dump(doc(
253            unit = "Indicator of unit of time range (see Code Table 4.4).",
254            len = "Forecast time in units defined by octet 18.",
255        ))]
256        pub time: TimeRange<i32>,
257    }
258
259    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
260    pub struct Horizontal {
261        #[dump(doc(
262            surface_type = "Type of first fixed surface (see Code Table 4.5).",
263            value(
264                scale_factor = "Scale factor of first fixed surface.",
265                scaled_value = "Scaled value of first fixed surface.",
266            ),
267        ))]
268        pub first_surface: FixedSurface,
269        #[dump(doc(
270            surface_type = "Type of second fixed surface (see Code Table 4.5).",
271            value(
272                scale_factor = "Scale factor of second fixed surface.",
273                scaled_value = "Scaled value of second fixed surface.",
274            ),
275        ))]
276        pub second_surface: FixedSurface,
277    }
278
279    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
280    pub struct FixedSurface {
281        /// Type of fixed surface (see Code Table 4.5).
282        pub surface_type: u8,
283        /// Scaled value of fixed surface.
284        pub value: ScaledValue<i8, i32>,
285    }
286
287    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
288    pub struct EnsembleForecast {
289        /// Type of ensemble forecast (see Code Table 4.6).
290        pub ensemble_forecast_type: u8,
291        ///  Perturbation number.
292        pub perturbation_num: u8,
293        /// Number of forecasts in ensemble.
294        pub num_forecasts: u8,
295    }
296
297    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
298    pub struct DerivedForecast {
299        /// Derived forecast (see Code Table 4.7).
300        pub derived_forecast_type: u8,
301        /// Number of forecasts in ensemble.
302        pub num_forecasts: u8,
303    }
304
305    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
306    pub struct ProbabilityForecasts {
307        /// Forecast probability number.
308        pub forecast_probability_num: u8,
309        /// Total number of forecast probabilities.
310        pub total_num_forecast_probabilities: u8,
311        /// Probability type (see Code Table 4.9).
312        pub probability_type: u8,
313        /// Lower limit.
314        #[dump(doc(
315            scale_factor = "Scale factor of lower limit.",
316            scaled_value = "Scaled value of lower limit.",
317        ))]
318        pub lower_limit: ScaledValue<i8, i32>,
319        /// Upper limit.
320        #[dump(doc(
321            scale_factor = "Scale factor of upper limit.",
322            scaled_value = "Scaled value of upper limit.",
323        ))]
324        pub upper_limit: ScaledValue<i8, i32>,
325    }
326
327    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
328    pub struct PercentileForecasts {
329        /// Percentile value (from 100% to 0%).
330        pub percentile_value: u8,
331    }
332
333    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
334    pub struct Statistical {
335        /// Time of end of overall time interval.
336        pub end_of_overall_time_interval: DateTime,
337        /// n - Number of time range specifications describing the time
338        /// intervals used to calculate the statistically processed field.
339        pub num_time_ranges: u8,
340        /// Total number of data values missing in statistical process.
341        pub num_missing: u32,
342        #[grib_template(len = "num_time_ranges")]
343        pub time_ranges: Vec<StatisticalProcess>,
344    }
345
346    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
347    pub struct StatisticalProcess {
348        /// Statistical process used to calculate the processed field from the
349        /// field at each time increment during the time range (see Code Table
350        /// 4.10).
351        pub statistical_process_type: u8,
352        /// Type of time increment between successive fields used in the
353        /// statistical processing (see Code Table 4.11).
354        pub time_increment_type: u8,
355        /// Time range over which statistical processing is done.
356        #[dump(doc(
357            unit = "Indicator of unit of time for time range over which statistical processing is done (see Code Table 4.4).",
358            len = "Length of the time range over which statistical processing is done, in units defined by the previous octet.",
359        ))]
360        pub time_range: TimeRange<u32>,
361        /// Time increment between successive fields.
362        #[dump(doc(
363            unit = "Indicator of unit of time for the increment between the successive fields used (see Code Table 4.4).",
364            len = "Time increment between successive fields, in units defined by the previous octet (see Notes 3 and 4).",
365        ))]
366        pub time_increment: TimeRange<u32>,
367    }
368}