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, 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::def::grib2::template::{Template3_1, param_set};
20/// use grib_template_helpers::TryFromSlice;
21///
22/// fn main() -> Result<(), Box<dyn std::error::Error>> {
23///     let mut buf = Vec::new();
24///
25///     let f = std::fs::File::open(
26///         "testdata/20260219T00Z_MSC_HRDPS_CAPE_Sfc_RLatLon0.0225_PT000H.grib2",
27///     )?;
28///     let mut f = std::io::BufReader::new(f);
29///     f.read_to_end(&mut buf)?;
30///
31///     let mut pos = 0x33;
32///     let actual = Template3_1::try_from_slice(&buf, &mut pos)?;
33///     let expected = Template3_1 {
34///         earth: param_set::EarthShape {
35///             shape: 6,
36///             spherical_earth_radius_scale_factor: 0xff,
37///             spherical_earth_radius_scaled_value: 0xffffffff,
38///             major_axis_scale_factor: 0xff,
39///             major_axis_scaled_value: 0xffffffff,
40///             minor_axis_scale_factor: 0xff,
41///             minor_axis_scaled_value: 0xffffffff,
42///         },
43///         rotated: param_set::LatLonGrid {
44///             grid: param_set::Grid {
45///                 ni: 2540,
46///                 nj: 1290,
47///                 initial_production_domain_basic_angle: 0,
48///                 basic_angle_subdivisions: 0xffffffff,
49///                 first_point_lat: -12302501,
50///                 first_point_lon: 345178780,
51///                 resolution_and_component_flags: param_set::ResolutionAndComponentFlags(
52///                     0b00111000,
53///                 ),
54///                 last_point_lat: 16700001,
55///                 last_point_lon: 42306283,
56///             },
57///             scanning_mode: param_set::ScanningMode(0b01000000),
58///             i_direction_inc: 22500,
59///             j_direction_inc: 22500,
60///         },
61///         rotation: param_set::Rotation {
62///             south_pole_lat: -36088520,
63///             south_pole_lon: 245305142,
64///             rot_angle: 0.,
65///         },
66///     };
67///     assert_eq!(actual, expected);
68///
69///     Ok(())
70/// }
71/// ```
72#[derive(Debug, PartialEq, TryFromSlice, WriteToBuffer, Dump)]
73pub struct Template3_1 {
74    pub earth: param_set::EarthShape,
75    pub rotated: param_set::LatLonGrid,
76    pub rotation: param_set::Rotation,
77}
78
79/// Grid definition template 3.20 - polar stereographic projection.
80///
81/// # Examples
82///
83/// ```
84/// use std::io::{BufReader, Read};
85///
86/// use grib::def::grib2::template::{Template3_20, param_set};
87/// use grib_template_helpers::TryFromSlice;
88///
89/// fn main() -> Result<(), Box<dyn std::error::Error>> {
90///     let mut buf = Vec::new();
91///
92///     let f = std::fs::File::open(
93///         "testdata/CMC_RDPA_APCP-024-0100cutoff_SFC_0_ps10km_2023121806_000.grib2.xz",
94///     )?;
95///     let f = BufReader::new(f);
96///     let mut f = xz2::bufread::XzDecoder::new(f);
97///     f.read_to_end(&mut buf)?;
98///
99///     let mut pos = 0x33;
100///     let actual = Template3_20::try_from_slice(&buf, &mut pos)?;
101///     let expected = Template3_20 {
102///         earth_shape: param_set::EarthShape {
103///             shape: 6,
104///             spherical_earth_radius_scale_factor: 0xff,
105///             spherical_earth_radius_scaled_value: 0xffffffff,
106///             major_axis_scale_factor: 0xff,
107///             major_axis_scaled_value: 0xffffffff,
108///             minor_axis_scale_factor: 0xff,
109///             minor_axis_scaled_value: 0xffffffff,
110///         },
111///         ni: 935,
112///         nj: 824,
113///         first_point_lat: 18145030,
114///         first_point_lon: 217107456,
115///         resolution_and_component_flags: param_set::ResolutionAndComponentFlags(0b00001000),
116///         lad: 60000000,
117///         lov: 249000000,
118///         dx: 10000000,
119///         dy: 10000000,
120///         projection_centre: param_set::ProjectionCentreFlag(0b00000000),
121///         scanning_mode: param_set::ScanningMode(0b01000000),
122///     };
123///     assert_eq!(actual, expected);
124///
125///     Ok(())
126/// }
127/// ```
128#[derive(Debug, PartialEq, Eq, TryFromSlice, WriteToBuffer, Dump)]
129pub struct Template3_20 {
130    pub earth_shape: param_set::EarthShape,
131    /// Nx - number of points along the x-axis.
132    pub ni: u32,
133    /// Ny - number of points along the y-axis.
134    pub nj: u32,
135    /// La1 - latitude of first grid point.
136    pub first_point_lat: i32,
137    /// Lo1 - longitude of first grid point.
138    pub first_point_lon: u32,
139    pub resolution_and_component_flags: param_set::ResolutionAndComponentFlags,
140    /// LaD - latitude where Dx and Dy are specified.
141    pub lad: i32,
142    /// LoV - orientation of the grid (see Note 2).
143    pub lov: i32,
144    /// Dx - x-direction grid length (see Note 3).
145    pub dx: u32,
146    /// Dy - y-direction grid length (see Note 3).
147    pub dy: u32,
148    pub projection_centre: param_set::ProjectionCentreFlag,
149    pub scanning_mode: param_set::ScanningMode,
150}
151
152/// Grid definition template 3.30 - Lambert conformal.
153///
154/// # Examples
155///
156/// ```
157/// use std::io::{BufReader, Read};
158///
159/// use grib::def::grib2::template::{Template3_30, param_set};
160/// use grib_template_helpers::TryFromSlice;
161///
162/// fn main() -> Result<(), Box<dyn std::error::Error>> {
163///     let mut buf = Vec::new();
164///
165///     let f = std::fs::File::open("testdata/ds.critfireo.bin.xz")?;
166///     let f = BufReader::new(f);
167///     let mut f = xz2::bufread::XzDecoder::new(f);
168///     f.read_to_end(&mut buf)?;
169///
170///     let mut pos = 0x83;
171///     let actual = Template3_30::try_from_slice(&buf, &mut pos)?;
172///     let expected = Template3_30 {
173///         earth_shape: param_set::EarthShape {
174///             shape: 1,
175///             spherical_earth_radius_scale_factor: 0,
176///             spherical_earth_radius_scaled_value: 6371200,
177///             major_axis_scale_factor: 0,
178///             major_axis_scaled_value: 0,
179///             minor_axis_scale_factor: 0,
180///             minor_axis_scaled_value: 0,
181///         },
182///         ni: 2145,
183///         nj: 1377,
184///         first_point_lat: 20190000,
185///         first_point_lon: 238449996,
186///         resolution_and_component_flags: param_set::ResolutionAndComponentFlags(0b00000000),
187///         lad: 25000000,
188///         lov: 265000000,
189///         dx: 2539703,
190///         dy: 2539703,
191///         projection_centre: param_set::ProjectionCentreFlag(0b00000000),
192///         scanning_mode: param_set::ScanningMode(0b01010000),
193///         latin1: 25000000,
194///         latin2: 25000000,
195///         south_pole_lat: -90000000,
196///         south_pole_lon: 0,
197///     };
198///     assert_eq!(actual, expected);
199///
200///     Ok(())
201/// }
202/// ```
203#[derive(Debug, PartialEq, Eq, TryFromSlice, WriteToBuffer, Dump)]
204pub struct Template3_30 {
205    pub earth_shape: param_set::EarthShape,
206    /// Nx - number of points along the x-axis.
207    pub ni: u32,
208    /// Ny - number of points along the y-axis.
209    pub nj: u32,
210    /// La1 - latitude of first grid point.
211    pub first_point_lat: i32,
212    /// Lo1 - longitude of first grid point.
213    pub first_point_lon: u32,
214    pub resolution_and_component_flags: param_set::ResolutionAndComponentFlags,
215    /// LaD - latitude where Dx and Dy are specified.
216    pub lad: i32,
217    /// LoV - longitude of meridian parallel to y-axis along which latitude
218    /// increases as the y-coordinate increases.
219    pub lov: u32,
220    /// Dx - x-direction grid length (see Note 1).
221    pub dx: u32,
222    /// Dy - y-direction grid length (see Note 1).
223    pub dy: u32,
224    pub projection_centre: param_set::ProjectionCentreFlag,
225    pub scanning_mode: param_set::ScanningMode,
226    /// Latin 1 - first latitude from the pole at which the secant cone cuts the
227    /// sphere.
228    pub latin1: i32,
229    /// Latin 2 - second latitude from the pole at which the secant cone cuts
230    /// the sphere.
231    pub latin2: i32,
232    /// Latitude of the southern pole of projection.
233    pub south_pole_lat: i32,
234    /// Longitude of the southern pole of projection.
235    pub south_pole_lon: u32,
236}
237
238/// Grid definition template 3.40 - Gaussian latitude/longitude.
239#[derive(Debug, PartialEq, TryFromSlice, WriteToBuffer, Dump)]
240pub struct Template3_40 {
241    pub earth: param_set::EarthShape,
242    pub gaussian: param_set::GaussianGrid,
243}
244
245/// Grid definition template 3.101 - general unstructured grid.
246#[derive(Debug, PartialEq, TryFromSlice, WriteToBuffer, Dump)]
247pub struct Template3_101 {
248    /// Shape of the Earth (see Code table 3.2).
249    pub earth_shape: u8,
250    /// Number of grid used (defined by originating centre).
251    #[grib_template(num_octets = 3)]
252    pub grid_num: u32,
253    /// Number of grid in reference (to allow annotating for Arakawa C-grid on
254    /// arbitrary grid) (see Note).
255    pub ref_grid_num: u8,
256    /// Universally Unique Identifier of horizontal grid.
257    pub uuid: [u8; 16],
258}
259
260pub(crate) mod param_set {
261    use grib_template_derive::{Dump, TryFromSlice, WriteToBuffer};
262
263    #[derive(Debug, PartialEq, Eq, TryFromSlice, WriteToBuffer, Dump)]
264    pub struct EarthShape {
265        /// Shape of the Earth (see Code table 3.2).
266        pub shape: u8,
267        /// Scale factor of radius of spherical Earth.
268        pub spherical_earth_radius_scale_factor: u8,
269        /// Scaled value of radius of spherical Earth.
270        pub spherical_earth_radius_scaled_value: u32,
271        /// Scale factor of major axis of oblate spheroid Earth.
272        pub major_axis_scale_factor: u8,
273        /// Scaled value of major axis of oblate spheroid Earth.
274        pub major_axis_scaled_value: u32,
275        /// Scale factor of minor axis of oblate spheroid Earth.
276        pub minor_axis_scale_factor: u8,
277        /// Scaled value of minor axis of oblate spheroid Earth.
278        pub minor_axis_scaled_value: u32,
279    }
280
281    #[derive(Debug, PartialEq, Eq, TryFromSlice, WriteToBuffer, Dump)]
282    pub struct LatLonGrid {
283        pub grid: Grid,
284        /// Di - i direction increment (see Notes 1 and 5).
285        pub i_direction_inc: u32,
286        /// Dj - j direction increment (see Notes 1 and 5).
287        pub j_direction_inc: u32,
288        pub scanning_mode: ScanningMode,
289    }
290
291    #[derive(Debug, PartialEq, Eq, TryFromSlice, WriteToBuffer, Dump)]
292    pub struct GaussianGrid {
293        pub grid: Grid,
294        /// Di - i direction increment (see Notes 1 and 5).
295        pub i_direction_inc: u32,
296        /// N - number of parallels between a pole and the Equator (see Note 2).
297        pub n: u32,
298        pub scanning_mode: ScanningMode,
299    }
300
301    #[derive(Debug, PartialEq, Eq, TryFromSlice, WriteToBuffer, Dump)]
302    pub struct Grid {
303        /// Ni - number of points along a parallel.
304        pub ni: u32,
305        /// Nj - number of points along a meridian.
306        pub nj: u32,
307        /// Basic angle of the initial production domain (see Note 1).
308        pub initial_production_domain_basic_angle: u32,
309        /// Subdivisions of basic angle used to define extreme longitudes and
310        /// latitudes, and direction increments (see Note 1).
311        pub basic_angle_subdivisions: u32,
312        /// La1 - latitude of first grid point (see Note 1).
313        pub first_point_lat: i32,
314        /// Lo1 - longitude of first grid point (see Note 1).
315        pub first_point_lon: u32,
316        pub resolution_and_component_flags: ResolutionAndComponentFlags,
317        /// La2 - latitude of last grid point (see Note 1).
318        pub last_point_lat: i32,
319        /// Lo2 - longitude of last grid point (see Note 1).
320        pub last_point_lon: u32,
321    }
322
323    #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromSlice, WriteToBuffer, Dump)]
324    pub struct ProjectionCentreFlag(
325        /// Projection centre flag (see Flag table 3.5).
326        pub u8,
327    );
328
329    #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromSlice, WriteToBuffer, Dump)]
330    pub struct ResolutionAndComponentFlags(
331        /// Resolution and component flags (see Flag table 3.3).
332        pub u8,
333    );
334
335    #[derive(Debug, PartialEq, TryFromSlice, WriteToBuffer, Dump)]
336    pub struct Rotation {
337        /// Latitude of the southern pole of projection.
338        pub south_pole_lat: i32,
339        /// Longitude of the southern pole of projection.
340        pub south_pole_lon: u32,
341        /// Angle of rotation of projection.
342        pub rot_angle: f32,
343    }
344
345    #[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromSlice, WriteToBuffer, Dump)]
346    pub struct ScanningMode(
347        /// Scanning mode (flags - see Flag table 3.4).
348        pub u8,
349    );
350}