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}