1use crate::{
2 parsers::Reader,
3 readers::{
4 Grib2Sections, Grib2Table4_3, Grib2Table4_4, Grib2Table4_6, Grib2Table4_7, Grib2TableA,
5 TableCategory, TypeAndUnit, grib2_lookup_table4_1, grib2_lookup_table4_5,
6 grib2_lookup_table42,
7 },
8 util::Date,
9};
10use alloc::string::String;
11
12#[derive(Debug, Clone, PartialEq)]
22pub enum Grib2ProductDefinition {
23 Grib2Template40(Grib2Template40),
25 Grib2Template41(Grib2Template41),
28 Grib2Template42(Grib2Template42),
31}
32impl Grib2ProductDefinition {
33 pub fn new<T: Reader>(template: u16, reader: &T, sections: &Grib2Sections) -> Self {
35 match template {
36 0 => Grib2ProductDefinition::Grib2Template40(Grib2Template40::new(reader, sections)),
37 1 => Grib2ProductDefinition::Grib2Template41(Grib2Template41::new(reader, sections)),
38 2 => Grib2ProductDefinition::Grib2Template42(Grib2Template42::new(reader, sections)),
39 _ => panic!("Template 4.{template} not defined"),
40 }
41 }
42
43 pub fn values(&self) -> &TableCategory {
45 match self {
46 Grib2ProductDefinition::Grib2Template40(template) => &template.values,
47 Grib2ProductDefinition::Grib2Template41(template) => &template.values,
48 Grib2ProductDefinition::Grib2Template42(template) => &template.values,
49 }
50 }
51}
52
53#[derive(Debug, Clone, PartialEq)]
60pub struct Grib2Template40 {
61 pub category: String,
63 pub values: TableCategory,
65 pub parameter_category: u8,
67 pub parameter_number: u8,
69 pub gen_process_type: Grib2Table4_3,
71 pub background_gen_process: u8,
73 pub forecast_gen_process: Grib2TableA,
75 pub hours_after_ref_time: u16,
77 pub min_after_ref_time: u8,
79 pub unit_of_time_range_indicator: Grib2Table4_4,
81 pub forecast_time: Date,
83 pub surface1: TypeAndUnit, pub surface1_type: u8,
87 pub surface1_scale: u8,
89 pub surface1_value: u32,
91 pub surface2: TypeAndUnit, pub surface2_type: u8,
95 pub surface2_scale: u8,
97 pub surface2_value: u32,
99}
100impl Grib2Template40 {
101 pub fn new<T: Reader>(reader: &T, sections: &Grib2Sections) -> Self {
110 let discipline = sections.indicator.as_ref().map(|d| u8::from(d.discipline)).unwrap_or(0);
111 let ref_time = sections.identification.as_ref().map(|i| i.ref_time).unwrap_or_default();
112 let parameter_category = reader.uint8(Some(9));
113 let parameter_number = reader.uint8(Some(10));
114 let gen_process_type = reader.uint8(Some(11));
115 let background_gen_process = reader.uint8(Some(12));
116 let forecast_gen_process = reader.uint8(Some(13));
117 let hours_after_ref_time = reader.uint16_be(Some(14));
118 let min_after_ref_time = reader.uint8(Some(16));
119 let unit_of_time_range_indicator: Grib2Table4_4 = reader.uint8(Some(17)).into();
120 let forecast_time = reader.uint32_be(Some(18));
121 let surface1_type = reader.uint8(Some(22));
122 let surface1_scale = reader.uint8(Some(23));
123 let surface1_value = reader.uint32_be(Some(24));
124 let surface2_type = reader.uint8(Some(28));
125 let surface2_scale = reader.uint8(Some(29));
126 let surface2_value = reader.uint32_be(Some(30));
127 let category = grib2_lookup_table4_1(discipline, parameter_category);
128 let values = grib2_lookup_table42(discipline, parameter_category)(parameter_number);
129 let surface1 = grib2_lookup_table4_5(surface1_type);
130 let surface2 = grib2_lookup_table4_5(surface2_type);
131
132 Self {
133 category,
134 values,
135 parameter_category,
136 parameter_number,
137 gen_process_type: gen_process_type.into(),
138 background_gen_process,
139 forecast_gen_process: forecast_gen_process.into(),
140 hours_after_ref_time,
141 min_after_ref_time,
142 unit_of_time_range_indicator,
143 forecast_time: calculate_forecast_time(
144 &ref_time,
145 forecast_time as i64,
146 &unit_of_time_range_indicator,
147 ),
148 surface1,
149 surface1_type,
150 surface1_scale,
151 surface1_value,
152 surface2,
153 surface2_type,
154 surface2_scale,
155 surface2_value,
156 }
157 }
158}
159
160#[derive(Debug, Clone, PartialEq)]
167pub struct Grib2Template41 {
168 pub category: String,
170 pub values: TableCategory,
172 pub parameter_category: u8,
174 pub parameter_number: u8,
176 pub gen_process_type: Grib2Table4_3,
178 pub background_gen_process: u8,
180 pub forecast_gen_process: Grib2TableA,
182 pub hours_after_ref_time: u16,
184 pub min_after_ref_time: u8,
186 pub unit_of_time_range_indicator: Grib2Table4_4,
188 pub forecast_time: Date,
190 pub surface1: TypeAndUnit,
192 pub surface1_type: u8,
194 pub surface1_scale: u8,
196 pub surface1_value: u32,
198 pub surface2: TypeAndUnit,
200 pub surface2_type: u8,
202 pub surface2_scale: u8,
204 pub surface2_value: u32,
206 pub ensemble_forecast_type: Grib2Table4_6,
208 pub perturbation_number: u8,
210 pub num_forecasts_in_ensemble: u8,
212}
213impl Grib2Template41 {
214 pub fn new<T: Reader>(reader: &T, sections: &Grib2Sections) -> Self {
223 let discipline = sections.indicator.as_ref().map(|d| u8::from(d.discipline)).unwrap_or(0);
224 let ref_time = sections.identification.as_ref().map(|i| i.ref_time).unwrap_or_default();
225 let parameter_category = reader.uint8(Some(9));
226 let parameter_number = reader.uint8(Some(10));
227 let gen_process_type = reader.uint8(Some(11));
228 let background_gen_process = reader.uint8(Some(12));
229 let forecast_gen_process = reader.uint8(Some(13));
230 let hours_after_ref_time = reader.uint16_be(Some(14));
231 let min_after_ref_time = reader.uint8(Some(16));
232 let unit_of_time_range_indicator = reader.uint8(Some(17));
233 let forecast_time = reader.uint32_be(Some(18));
234 let surface1_type = reader.uint8(Some(22));
235 let surface1_scale = reader.uint8(Some(23));
236 let surface1_value = reader.uint32_be(Some(24));
237 let surface2_type = reader.uint8(Some(28));
238 let surface2_scale = reader.uint8(Some(29));
239 let surface2_value = reader.uint32_be(Some(30));
240 let ensemble_forecast_type = reader.uint8(Some(34));
241 let perturbation_number = reader.uint8(Some(35));
242 let num_forecasts_in_ensemble = reader.uint8(Some(36));
243 let category = grib2_lookup_table4_1(discipline, parameter_category);
244 let values = grib2_lookup_table42(discipline, parameter_category)(parameter_number);
245 let surface1 = grib2_lookup_table4_5(surface1_type);
246 let surface2 = grib2_lookup_table4_5(surface2_type);
247 let unit_of_time_range_indicator = unit_of_time_range_indicator.into();
248
249 Self {
250 category,
251 values,
252 parameter_category,
253 parameter_number,
254 gen_process_type: gen_process_type.into(),
255 background_gen_process,
256 forecast_gen_process: forecast_gen_process.into(),
257 hours_after_ref_time,
258 min_after_ref_time,
259 unit_of_time_range_indicator,
260 forecast_time: calculate_forecast_time(
261 &ref_time,
262 forecast_time as i64,
263 &unit_of_time_range_indicator,
264 ),
265 surface1,
266 surface1_type,
267 surface1_scale,
268 surface1_value,
269 surface2,
270 surface2_type,
271 surface2_scale,
272 surface2_value,
273 ensemble_forecast_type: ensemble_forecast_type.into(),
274 perturbation_number,
275 num_forecasts_in_ensemble,
276 }
277 }
278}
279
280#[derive(Debug, Clone, PartialEq)]
287pub struct Grib2Template42 {
288 pub category: String,
290 pub values: TableCategory,
292 pub parameter_category: u8,
294 pub parameter_number: u8,
296 pub gen_process_type: Grib2Table4_3,
298 pub background_gen_process: u8,
300 pub forecast_gen_process: Grib2TableA,
302 pub hours_after_ref_time: u16,
304 pub min_after_ref_time: u8,
306 pub unit_of_time_range_indicator: Grib2Table4_4,
308 pub forecast_time: Date,
310 pub surface1: TypeAndUnit,
312 pub surface1_type: u8,
314 pub surface1_scale: u8,
316 pub surface1_value: u32,
318 pub surface2: TypeAndUnit,
320 pub surface2_type: u8,
322 pub surface2_scale: u8,
324 pub surface2_value: u32,
326 pub derived_forecast_type: Grib2Table4_7,
328 pub num_forecasts_in_ensemble: u8,
330}
331impl Grib2Template42 {
332 pub fn new<T: Reader>(reader: &T, sections: &Grib2Sections) -> Self {
341 let discipline = sections.indicator.as_ref().map(|d| u8::from(d.discipline)).unwrap_or(0);
342 let ref_time = sections.identification.as_ref().map(|i| i.ref_time).unwrap_or_default();
343 let parameter_category = reader.uint8(Some(9));
344 let parameter_number = reader.uint8(Some(10));
345 let gen_process_type = reader.uint8(Some(11));
346 let background_gen_process = reader.uint8(Some(12));
347 let forecast_gen_process = reader.uint8(Some(13));
348 let hours_after_ref_time = reader.uint16_be(Some(14));
349 let min_after_ref_time = reader.uint8(Some(16));
350 let unit_of_time_range_indicator = reader.uint8(Some(17));
351 let forecast_time = reader.uint32_be(Some(18));
352 let surface1_type = reader.uint8(Some(22));
353 let surface1_scale = reader.uint8(Some(23));
354 let surface1_value = reader.uint32_be(Some(24));
355 let surface2_type = reader.uint8(Some(28));
356 let surface2_scale = reader.uint8(Some(29));
357 let surface2_value = reader.uint32_be(Some(30));
358 let derived_forecast_type = reader.uint8(Some(34));
359 let num_forecasts_in_ensemble = reader.uint8(Some(35));
360 let category = grib2_lookup_table4_1(discipline, parameter_category);
361 let values = grib2_lookup_table42(discipline, parameter_category)(parameter_number);
362 let surface1 = grib2_lookup_table4_5(surface1_type);
363 let surface2 = grib2_lookup_table4_5(surface2_type);
364 let unit_of_time_range_indicator = unit_of_time_range_indicator.into();
365
366 Self {
367 category,
368 values,
369 parameter_category,
370 parameter_number,
371 gen_process_type: gen_process_type.into(),
372 background_gen_process,
373 forecast_gen_process: forecast_gen_process.into(),
374 hours_after_ref_time,
375 min_after_ref_time,
376 unit_of_time_range_indicator,
377 forecast_time: calculate_forecast_time(
378 &ref_time,
379 forecast_time as i64,
380 &unit_of_time_range_indicator,
381 ),
382 surface1,
383 surface1_type,
384 surface1_scale,
385 surface1_value,
386 surface2,
387 surface2_type,
388 surface2_scale,
389 surface2_value,
390 derived_forecast_type: derived_forecast_type.into(),
391 num_forecasts_in_ensemble,
392 }
393 }
394}
395
396pub fn calculate_forecast_time(ref_time: &Date, offset: i64, unit_of_time: &Grib2Table4_4) -> Date {
406 match unit_of_time {
407 Grib2Table4_4::Hour => Date::from_time(ref_time.get_time() + offset * 1000 * 60 * 60),
408 _ => {
409 panic!("Unable to calculate foercast time for unit: {}", unit_of_time);
410 }
411 }
412}