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