Skip to main content

grib/def/grib2/
template3.rs

1use grib_template_derive::{Dump, TryFromSlice, WriteToBuffer};
2
3/// Grid definition template 3.0 - latitude/longitude (or equidistant
4/// cylindrical, or Plate Carrée).
5#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
6pub struct Template3_0 {
7    pub earth: param_set::EarthShape,
8    pub lat_lon: param_set::LatLonGrid,
9}
10
11/// Grid definition template 3.1 - rotated latitude/longitude (or equidistant
12/// cylindrical, or Plate Carrée).
13///
14/// # Examples
15///
16/// ```
17/// use std::io::Read;
18///
19/// use grib::{
20///     TryFromSlice,
21///     def::grib2::template::{Template3_1, param_set},
22/// };
23///
24/// fn main() -> Result<(), Box<dyn std::error::Error>> {
25///     let mut buf = Vec::new();
26///
27///     let f = std::fs::File::open(
28///         "testdata/20260219T00Z_MSC_HRDPS_CAPE_Sfc_RLatLon0.0225_PT000H.grib2",
29///     )?;
30///     let mut f = std::io::BufReader::new(f);
31///     f.read_to_end(&mut buf)?;
32///
33///     let mut pos = 0x33;
34///     let actual = Template3_1::try_from_slice(&buf, &mut pos)?;
35///     let expected = Template3_1 {
36///         earth: param_set::EarthShape {
37///             shape: 6,
38///             spherical_earth_radius: param_set::ScaledValue {
39///                 scale_factor: 0xff,
40///                 scaled_value: 0xffffffff,
41///             },
42///             major_axis: param_set::ScaledValue {
43///                 scale_factor: 0xff,
44///                 scaled_value: 0xffffffff,
45///             },
46///             minor_axis: param_set::ScaledValue {
47///                 scale_factor: 0xff,
48///                 scaled_value: 0xffffffff,
49///             },
50///         },
51///         lat_lon: param_set::LatLonGrid {
52///             grid: param_set::Grid {
53///                 ni: 2540,
54///                 nj: 1290,
55///                 initial_production_domain_basic_angle: 0,
56///                 basic_angle_subdivisions: 0xffffffff,
57///                 first_point_lat: -12302501,
58///                 first_point_lon: 345178780,
59///                 resolution_and_component_flags: param_set::ResolutionAndComponentFlags(
60///                     0b00111000,
61///                 ),
62///                 last_point_lat: 16700001,
63///                 last_point_lon: 42306283,
64///             },
65///             scanning_mode: param_set::ScanningMode(0b01000000),
66///             i_direction_inc: 22500,
67///             j_direction_inc: 22500,
68///         },
69///         rotation: param_set::Rotation {
70///             south_pole_lat: -36088520,
71///             south_pole_lon: 245305142,
72///             rot_angle: 0.,
73///         },
74///     };
75///     assert_eq!(actual, expected);
76///
77///     Ok(())
78/// }
79/// ```
80#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
81pub struct Template3_1 {
82    pub earth: param_set::EarthShape,
83    pub lat_lon: param_set::LatLonGrid,
84    pub rotation: param_set::Rotation,
85}
86
87/// Grid definition template 3.2 - stretched latitude/longitude (or equidistant
88/// cylindrical, or Plate Carrée).
89#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
90pub struct Template3_2 {
91    pub earth: param_set::EarthShape,
92    pub lat_lon: param_set::LatLonGrid,
93    pub stretching: param_set::Stretching,
94}
95
96/// Grid definition template 3.3 - stretched and rotated latitude/longitude (or
97/// equidistant cylindrical, or Plate Carrée).
98#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
99pub struct Template3_3 {
100    pub earth: param_set::EarthShape,
101    pub lat_lon: param_set::LatLonGrid,
102    pub rotation: param_set::Rotation,
103    pub stretching: param_set::Stretching,
104}
105
106/// Grid definition template 3.10 - Mercator.
107///
108/// # Examples
109///
110/// ```
111/// use std::io::{BufReader, Read};
112///
113/// use grib::{
114///     TryFromSlice,
115///     def::grib2::template::{Template3_10, param_set},
116/// };
117///
118/// fn main() -> Result<(), Box<dyn std::error::Error>> {
119///     let mut buf = Vec::new();
120///
121///     let f = std::fs::File::open("testdata/ds.wwa.bin.xz")?;
122///     let f = BufReader::new(f);
123///     let mut f = xz2::bufread::XzDecoder::new(f);
124///     f.read_to_end(&mut buf)?;
125///
126///     let mut pos = 0xa6;
127///     let actual = Template3_10::try_from_slice(&buf, &mut pos)?;
128///     let expected = Template3_10 {
129///         earth_shape: param_set::EarthShape {
130///             shape: 1,
131///             spherical_earth_radius: param_set::ScaledValue {
132///                 scale_factor: 0,
133///                 scaled_value: 6371200,
134///             },
135///             major_axis: param_set::ScaledValue {
136///                 scale_factor: 0,
137///                 scaled_value: 0,
138///             },
139///             minor_axis: param_set::ScaledValue {
140///                 scale_factor: 0,
141///                 scaled_value: 0,
142///             },
143///         },
144///         ni: 2517,
145///         nj: 1793,
146///         first_point_lat: -30419200,
147///         first_point_lon: 129906005,
148///         resolution_and_component_flags: param_set::ResolutionAndComponentFlags(0b00000000),
149///         lad: 20000000,
150///         last_point_lat: 80010000,
151///         last_point_lon: 10710000,
152///         scanning_mode: param_set::ScanningMode(0b01010000),
153///         orientation: 0,
154///         di: 10000000,
155///         dj: 10000000,
156///     };
157///     assert_eq!(actual, expected);
158///
159///     Ok(())
160/// }
161/// ```
162#[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
163pub struct Template3_10 {
164    pub earth_shape: param_set::EarthShape,
165    /// Ni - number of points along a parallel.
166    pub ni: u32,
167    /// Nj - number of points along a meridian.
168    pub nj: u32,
169    /// La1 - latitude of first grid point.
170    pub first_point_lat: i32,
171    /// Lo1 - longitude of first grid point.
172    pub first_point_lon: u32,
173    pub resolution_and_component_flags: param_set::ResolutionAndComponentFlags,
174    /// LaD - Latitude(s) at which the Mercator projection intersects the Earth
175    /// (Latitude(s) where Di and Dj are specified).
176    pub lad: i32,
177    /// La2 - latitude of last grid point.
178    pub last_point_lat: i32,
179    /// Lo2 - longitude of last grid point.
180    pub last_point_lon: u32,
181    pub scanning_mode: param_set::ScanningMode,
182    /// Orientation of the grid, angle between i direction on the map and the
183    /// equator (see Note 1).
184    pub orientation: u32,
185    /// Di - longitudinal direction grid length (see Note 2).
186    pub di: u32,
187    /// Dj - latitudinal direction grid length (see Note 2).
188    pub dj: u32,
189}
190
191/// Grid definition template 3.20 - polar stereographic projection.
192///
193/// # Examples
194///
195/// ```
196/// use std::io::{BufReader, Read};
197///
198/// use grib::{
199///     TryFromSlice,
200///     def::grib2::template::{Template3_20, param_set},
201/// };
202///
203/// fn main() -> Result<(), Box<dyn std::error::Error>> {
204///     let mut buf = Vec::new();
205///
206///     let f = std::fs::File::open(
207///         "testdata/CMC_RDPA_APCP-024-0100cutoff_SFC_0_ps10km_2023121806_000.grib2.xz",
208///     )?;
209///     let f = BufReader::new(f);
210///     let mut f = xz2::bufread::XzDecoder::new(f);
211///     f.read_to_end(&mut buf)?;
212///
213///     let mut pos = 0x33;
214///     let actual = Template3_20::try_from_slice(&buf, &mut pos)?;
215///     let expected = Template3_20 {
216///         earth_shape: param_set::EarthShape {
217///             shape: 6,
218///             spherical_earth_radius: param_set::ScaledValue {
219///                 scale_factor: 0xff,
220///                 scaled_value: 0xffffffff,
221///             },
222///             major_axis: param_set::ScaledValue {
223///                 scale_factor: 0xff,
224///                 scaled_value: 0xffffffff,
225///             },
226///             minor_axis: param_set::ScaledValue {
227///                 scale_factor: 0xff,
228///                 scaled_value: 0xffffffff,
229///             },
230///         },
231///         ni: 935,
232///         nj: 824,
233///         first_point_lat: 18145030,
234///         first_point_lon: 217107456,
235///         resolution_and_component_flags: param_set::ResolutionAndComponentFlags(0b00001000),
236///         lad: 60000000,
237///         lov: 249000000,
238///         dx: 10000000,
239///         dy: 10000000,
240///         projection_centre: param_set::ProjectionCentreFlag(0b00000000),
241///         scanning_mode: param_set::ScanningMode(0b01000000),
242///     };
243///     assert_eq!(actual, expected);
244///
245///     Ok(())
246/// }
247/// ```
248#[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
249pub struct Template3_20 {
250    pub earth_shape: param_set::EarthShape,
251    /// Nx - number of points along the x-axis.
252    pub ni: u32,
253    /// Ny - number of points along the y-axis.
254    pub nj: u32,
255    /// La1 - latitude of first grid point.
256    pub first_point_lat: i32,
257    /// Lo1 - longitude of first grid point.
258    pub first_point_lon: u32,
259    pub resolution_and_component_flags: param_set::ResolutionAndComponentFlags,
260    /// LaD - latitude where Dx and Dy are specified.
261    pub lad: i32,
262    /// LoV - orientation of the grid (see Note 2).
263    pub lov: i32,
264    /// Dx - x-direction grid length (see Note 3).
265    pub dx: u32,
266    /// Dy - y-direction grid length (see Note 3).
267    pub dy: u32,
268    pub projection_centre: param_set::ProjectionCentreFlag,
269    pub scanning_mode: param_set::ScanningMode,
270}
271
272/// Grid definition template 3.30 - Lambert conformal.
273///
274/// # Examples
275///
276/// ```
277/// use std::io::{BufReader, Read};
278///
279/// use grib::{
280///     TryFromSlice,
281///     def::grib2::template::{Template3_30, param_set},
282/// };
283///
284/// fn main() -> Result<(), Box<dyn std::error::Error>> {
285///     let mut buf = Vec::new();
286///
287///     let f = std::fs::File::open("testdata/ds.critfireo.bin.xz")?;
288///     let f = BufReader::new(f);
289///     let mut f = xz2::bufread::XzDecoder::new(f);
290///     f.read_to_end(&mut buf)?;
291///
292///     let mut pos = 0x83;
293///     let actual = Template3_30::try_from_slice(&buf, &mut pos)?;
294///     let expected = Template3_30 {
295///         earth_shape: param_set::EarthShape {
296///             shape: 1,
297///             spherical_earth_radius: param_set::ScaledValue {
298///                 scale_factor: 0,
299///                 scaled_value: 6371200,
300///             },
301///             major_axis: param_set::ScaledValue {
302///                 scale_factor: 0,
303///                 scaled_value: 0,
304///             },
305///             minor_axis: param_set::ScaledValue {
306///                 scale_factor: 0,
307///                 scaled_value: 0,
308///             },
309///         },
310///         ni: 2145,
311///         nj: 1377,
312///         first_point_lat: 20190000,
313///         first_point_lon: 238449996,
314///         resolution_and_component_flags: param_set::ResolutionAndComponentFlags(0b00000000),
315///         lad: 25000000,
316///         lov: 265000000,
317///         dx: 2539703,
318///         dy: 2539703,
319///         projection_centre: param_set::ProjectionCentreFlag(0b00000000),
320///         scanning_mode: param_set::ScanningMode(0b01010000),
321///         latin1: 25000000,
322///         latin2: 25000000,
323///         south_pole_lat: -90000000,
324///         south_pole_lon: 0,
325///     };
326///     assert_eq!(actual, expected);
327///
328///     Ok(())
329/// }
330/// ```
331#[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
332pub struct Template3_30 {
333    pub earth_shape: param_set::EarthShape,
334    /// Nx - number of points along the x-axis.
335    pub ni: u32,
336    /// Ny - number of points along the y-axis.
337    pub nj: u32,
338    /// La1 - latitude of first grid point.
339    pub first_point_lat: i32,
340    /// Lo1 - longitude of first grid point.
341    pub first_point_lon: u32,
342    pub resolution_and_component_flags: param_set::ResolutionAndComponentFlags,
343    /// LaD - latitude where Dx and Dy are specified.
344    pub lad: i32,
345    /// LoV - longitude of meridian parallel to y-axis along which latitude
346    /// increases as the y-coordinate increases.
347    pub lov: u32,
348    /// Dx - x-direction grid length (see Note 1).
349    pub dx: u32,
350    /// Dy - y-direction grid length (see Note 1).
351    pub dy: u32,
352    pub projection_centre: param_set::ProjectionCentreFlag,
353    pub scanning_mode: param_set::ScanningMode,
354    /// Latin 1 - first latitude from the pole at which the secant cone cuts the
355    /// sphere.
356    pub latin1: i32,
357    /// Latin 2 - second latitude from the pole at which the secant cone cuts
358    /// the sphere.
359    pub latin2: i32,
360    /// Latitude of the southern pole of projection.
361    pub south_pole_lat: i32,
362    /// Longitude of the southern pole of projection.
363    pub south_pole_lon: u32,
364}
365
366/// Grid definition template 3.40 - Gaussian latitude/longitude.
367#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
368pub struct Template3_40 {
369    pub earth: param_set::EarthShape,
370    pub gaussian: param_set::GaussianGrid,
371}
372
373/// Grid definition template 3.41 - rotated Gaussian latitude/longitude.
374#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
375pub struct Template3_41 {
376    pub earth: param_set::EarthShape,
377    pub gaussian: param_set::GaussianGrid,
378    pub rotation: param_set::Rotation,
379}
380
381/// Grid definition template 3.42 - stretched Gaussian latitude/longitude.
382#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
383pub struct Template3_42 {
384    pub earth: param_set::EarthShape,
385    pub gaussian: param_set::GaussianGrid,
386    pub stretching: param_set::Stretching,
387}
388
389/// Grid definition template 3.43 - stretched and rotated Gaussian
390/// latitude/longitude.
391#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
392pub struct Template3_43 {
393    pub earth: param_set::EarthShape,
394    pub gaussian: param_set::GaussianGrid,
395    pub rotation: param_set::Rotation,
396    pub stretching: param_set::Stretching,
397}
398
399/// Grid definition template 3.101 - general unstructured grid.
400#[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
401pub struct Template3_101 {
402    /// Shape of the Earth (see Code table 3.2).
403    pub earth_shape: u8,
404    /// Number of grid used (defined by originating centre).
405    #[grib_template(num_octets = 3)]
406    pub grid_num: u32,
407    /// Number of grid in reference (to allow annotating for Arakawa C-grid on
408    /// arbitrary grid) (see Note).
409    pub ref_grid_num: u8,
410    /// Universally Unique Identifier of horizontal grid.
411    pub uuid: [u8; 16],
412}
413
414pub(crate) mod param_set {
415    use grib_template_derive::{Dump, TryFromSlice, WriteToBuffer};
416
417    use super::super::template::param_set::ScaledValue;
418
419    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
420    pub struct EarthShape {
421        /// Shape of the Earth (see Code table 3.2).
422        pub shape: u8,
423        /// Radius of spherical Earth.
424        #[dump(doc(
425            scale_factor = "Scale factor of radius of spherical Earth.",
426            scaled_value = "Scaled value of radius of spherical Earth.",
427        ))]
428        pub spherical_earth_radius: ScaledValue<u8, u32>,
429        /// Major axis of oblate spheroid Earth.
430        #[dump(doc(
431            scale_factor = "Scale factor of major axis of oblate spheroid Earth.",
432            scaled_value = "Scaled value of major axis of oblate spheroid Earth.",
433        ))]
434        pub major_axis: ScaledValue<u8, u32>,
435        /// Minor axis of oblate spheroid Earth.
436        #[dump(doc(
437            scale_factor = "Scale factor of minor axis of oblate spheroid Earth.",
438            scaled_value = "Scaled value of minor axis of oblate spheroid Earth.",
439        ))]
440        pub minor_axis: ScaledValue<u8, u32>,
441    }
442
443    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
444    pub struct LatLonGrid {
445        pub grid: Grid,
446        /// Di - i direction increment (see Notes 1 and 5).
447        pub i_direction_inc: u32,
448        /// Dj - j direction increment (see Notes 1 and 5).
449        pub j_direction_inc: u32,
450        pub scanning_mode: ScanningMode,
451    }
452
453    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
454    pub struct GaussianGrid {
455        pub grid: Grid,
456        /// Di - i direction increment (see Notes 1 and 5).
457        pub i_direction_inc: u32,
458        /// N - number of parallels between a pole and the Equator (see Note 2).
459        pub n: u32,
460        pub scanning_mode: ScanningMode,
461    }
462
463    #[derive(Debug, PartialEq, Eq, Clone, TryFromSlice, WriteToBuffer, Dump)]
464    pub struct Grid {
465        /// Ni - number of points along a parallel.
466        pub ni: u32,
467        /// Nj - number of points along a meridian.
468        pub nj: u32,
469        /// Basic angle of the initial production domain (see Note 1).
470        pub initial_production_domain_basic_angle: u32,
471        /// Subdivisions of basic angle used to define extreme longitudes and
472        /// latitudes, and direction increments (see Note 1).
473        pub basic_angle_subdivisions: u32,
474        /// La1 - latitude of first grid point (see Note 1).
475        pub first_point_lat: i32,
476        /// Lo1 - longitude of first grid point (see Note 1).
477        pub first_point_lon: u32,
478        pub resolution_and_component_flags: ResolutionAndComponentFlags,
479        /// La2 - latitude of last grid point (see Note 1).
480        pub last_point_lat: i32,
481        /// Lo2 - longitude of last grid point (see Note 1).
482        pub last_point_lon: u32,
483    }
484
485    #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromSlice, WriteToBuffer, Dump)]
486    pub struct ProjectionCentreFlag(
487        /// Projection centre flag (see Flag table 3.5).
488        pub u8,
489    );
490
491    #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromSlice, WriteToBuffer, Dump)]
492    pub struct ResolutionAndComponentFlags(
493        /// Resolution and component flags (see Flag table 3.3).
494        pub u8,
495    );
496
497    #[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
498    pub struct Rotation {
499        /// Latitude of the southern pole of projection.
500        pub south_pole_lat: i32,
501        /// Longitude of the southern pole of projection.
502        pub south_pole_lon: u32,
503        /// Angle of rotation of projection.
504        pub rot_angle: f32,
505    }
506
507    #[derive(Debug, PartialEq, Clone, TryFromSlice, WriteToBuffer, Dump)]
508    pub struct Stretching {
509        /// Latitude of the pole of stretching.
510        pub pole_lat: i32,
511        /// Longitude of the pole of stretching.
512        pub pole_lon: u32,
513        /// Stretching factor.
514        pub factor: u32,
515    }
516
517    #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromSlice, WriteToBuffer, Dump)]
518    pub struct ScanningMode(
519        /// Scanning mode (flags - see Flag table 3.4).
520        pub u8,
521    );
522}