pycontrails 0.56.0__cp312-cp312-macosx_11_0_arm64.whl → 0.57.0__cp312-cp312-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pycontrails might be problematic. Click here for more details.

@@ -0,0 +1,27 @@
1
+ """Support for Himawari-8/9 satellite data access."""
2
+
3
+ from pycontrails.datalib.himawari.header_struct import (
4
+ HEADER_STRUCT_SCHEMA,
5
+ parse_himawari_header,
6
+ )
7
+ from pycontrails.datalib.himawari.himawari import (
8
+ HIMAWARI_8_9_SWITCH_DATE,
9
+ HIMAWARI_8_BUCKET,
10
+ HIMAWARI_9_BUCKET,
11
+ Himawari,
12
+ HimawariRegion,
13
+ extract_visualization,
14
+ to_true_color,
15
+ )
16
+
17
+ __all__ = [
18
+ "HEADER_STRUCT_SCHEMA",
19
+ "HIMAWARI_8_9_SWITCH_DATE",
20
+ "HIMAWARI_8_BUCKET",
21
+ "HIMAWARI_9_BUCKET",
22
+ "Himawari",
23
+ "HimawariRegion",
24
+ "extract_visualization",
25
+ "parse_himawari_header",
26
+ "to_true_color",
27
+ ]
@@ -0,0 +1,266 @@
1
+ """Support for parsing the Himawari-8/9 header structure.
2
+
3
+ See the latest user guide for details:
4
+ https://www.data.jma.go.jp/mscweb/en/himawari89/space_segment/hsd_sample/HS_D_users_guide_en_v13.pdf
5
+
6
+ If that link breaks, find the correct link here:
7
+ https://www.data.jma.go.jp/mscweb/en/himawari89/space_segment/sample_hisd.html
8
+ """
9
+
10
+ import struct
11
+ from typing import Any, TypedDict
12
+
13
+
14
+ class _HeaderBlock(TypedDict):
15
+ """An individual Himawari header block."""
16
+
17
+ name: str
18
+ fields: list[tuple[str, str, int, int, str | None]]
19
+
20
+
21
+ HEADER_STRUCT_SCHEMA: dict[int, _HeaderBlock] = {
22
+ 1: {
23
+ "name": "basic_information",
24
+ "fields": [
25
+ ("header_block_number", "I1", 1, 1, None),
26
+ ("block_length", "I2", 2, 1, None),
27
+ ("total_header_blocks", "I2", 2, 1, None),
28
+ ("byte_order", "I1", 1, 1, None),
29
+ ("satellite_name", "C", 1, 16, None),
30
+ ("processing_center_name", "C", 1, 16, None),
31
+ ("observation_area", "C", 1, 4, None),
32
+ ("other_obs_info", "C", 1, 2, None),
33
+ ("obs_timeline", "I2", 2, 1, None),
34
+ ("obs_start_time", "R8", 8, 1, None),
35
+ ("obs_end_time", "R8", 8, 1, None),
36
+ ("file_creation_time", "R8", 8, 1, None),
37
+ ("total_header_length", "I4", 4, 1, None),
38
+ ("total_data_length", "I4", 4, 1, None),
39
+ ("quality_flag_1", "I1", 1, 1, None),
40
+ ("quality_flag_2", "I1", 1, 1, None),
41
+ ("quality_flag_3", "I1", 1, 1, None),
42
+ ("quality_flag_4", "I1", 1, 1, None),
43
+ ("file_format_version", "C", 1, 32, None),
44
+ ("file_name", "C", 1, 128, None),
45
+ ("spare", "C", 40, 1, None),
46
+ ],
47
+ },
48
+ 2: {
49
+ "name": "data_information",
50
+ "fields": [
51
+ ("header_block_number", "I1", 1, 1, None),
52
+ ("block_length", "I2", 2, 1, None),
53
+ ("bits_per_pixel", "I2", 2, 1, None),
54
+ ("num_columns", "I2", 2, 1, None),
55
+ ("num_lines", "I2", 2, 1, None),
56
+ ("compression_flag", "I1", 1, 1, None),
57
+ ("spare", "C", 40, 1, None),
58
+ ],
59
+ },
60
+ 3: {
61
+ "name": "projection_information",
62
+ "fields": [
63
+ ("header_block_number", "I1", 1, 1, None),
64
+ ("block_length", "I2", 2, 1, None),
65
+ ("sub_lon", "R8", 8, 1, None),
66
+ ("cfac", "I4", 4, 1, None),
67
+ ("lfac", "I4", 4, 1, None),
68
+ ("coff", "R4", 4, 1, None),
69
+ ("loff", "R4", 4, 1, None),
70
+ ("dist_from_earth_center", "R8", 8, 1, None),
71
+ ("equatorial_radius", "R8", 8, 1, None),
72
+ ("polar_radius", "R8", 8, 1, None),
73
+ ("rec_minus_rpol_div_req_sq", "R8", 8, 1, None),
74
+ ("rpol_sq_div_req_sq", "R8", 8, 1, None),
75
+ ("req_sq_div_rpol_sq", "R8", 8, 1, None),
76
+ ("coeff_for_sd", "R8", 8, 1, None),
77
+ ("resampling_types", "I2", 2, 1, None),
78
+ ("resampling_size", "I2", 2, 1, None),
79
+ ("spare", "C", 40, 1, None),
80
+ ],
81
+ },
82
+ 4: {
83
+ "name": "navigation_information",
84
+ "fields": [
85
+ ("header_block_number", "I1", 1, 1, None),
86
+ ("block_length", "I2", 2, 1, None),
87
+ ("nav_info_time", "R8", 8, 1, None),
88
+ ("ssp_longitude", "R8", 8, 1, None),
89
+ ("ssp_latitude", "R8", 8, 1, None),
90
+ ("dist_from_earth_center_to_sat", "R8", 8, 1, None),
91
+ ("nadir_longitude", "R8", 8, 1, None),
92
+ ("nadir_latitude", "R8", 8, 1, None),
93
+ ("sun_position", "R8", 8, 3, None),
94
+ ("moon_position", "R8", 8, 3, None),
95
+ ("spare", "C", 40, 1, None),
96
+ ],
97
+ },
98
+ 5: {
99
+ "name": "calibration_information",
100
+ "fields": [
101
+ ("header_block_number", "I1", 1, 1, None),
102
+ ("block_length", "I2", 2, 1, None),
103
+ ("band_number", "I2", 2, 1, None),
104
+ ("central_wavelength", "R8", 8, 1, None),
105
+ ("valid_bits_per_pixel", "I2", 2, 1, None),
106
+ ("count_error_pixels", "I2", 2, 1, None),
107
+ ("count_outside_scan_area", "I2", 2, 1, None),
108
+ ("gain", "R8", 8, 1, None),
109
+ ("constant", "R8", 8, 1, None),
110
+ ("c0", "R8", 8, 1, "IR-BANDS"),
111
+ ("c1", "R8", 8, 1, "IR-BANDS"),
112
+ ("c2", "R8", 8, 1, "IR-BANDS"),
113
+ ("C0", "R8", 8, 1, "IR-BANDS"),
114
+ ("C1", "R8", 8, 1, "IR-BANDS"),
115
+ ("C2", "R8", 8, 1, "IR-BANDS"),
116
+ ("speed_of_light", "R8", 8, 1, "IR-BANDS"),
117
+ ("planck_constant", "R8", 8, 1, "IR-BANDS"),
118
+ ("boltzmann_constant", "R8", 8, 1, "IR-BANDS"),
119
+ ("spare", "C", 40, 1, "IR-BANDS"),
120
+ ("coeff_c_prime", "R8", 8, 1, "NIR-BANDS"),
121
+ ("spare", "C", 104, 1, "NIR-BANDS"),
122
+ ],
123
+ },
124
+ 6: {
125
+ "name": "inter_calibration_information",
126
+ "fields": [
127
+ ("header_block_number", "I1", 1, 1, None),
128
+ ("block_length", "I2", 2, 1, None),
129
+ ("gsics_intercept", "R8", 8, 1, None),
130
+ ("gsics_slope", "R8", 8, 1, None),
131
+ ("gsics_quad", "R8", 8, 1, None),
132
+ ("rad_bias_standard", "R8", 8, 1, None),
133
+ ("uncert_rad_bias", "R8", 8, 1, None),
134
+ ("rad_standard_scene", "R8", 8, 1, None),
135
+ ("gsics_validity_start", "R8", 8, 1, None),
136
+ ("gsics_validity_end", "R8", 8, 1, None),
137
+ ("rad_validity_upper", "R4", 4, 1, None),
138
+ ("rad_validity_lower", "R4", 4, 1, None),
139
+ ("gsics_file_name", "C", 1, 128, None),
140
+ ("spare", "C", 56, 1, None),
141
+ ],
142
+ },
143
+ 7: {
144
+ "name": "segment_information",
145
+ "fields": [
146
+ ("header_block_number", "I1", 1, 1, None),
147
+ ("block_length", "I2", 2, 1, None),
148
+ ("total_segments", "I1", 1, 1, None),
149
+ ("segment_seq_number", "I1", 1, 1, None),
150
+ ("first_line_number", "I2", 2, 1, None),
151
+ ("spare", "C", 40, 1, None),
152
+ ],
153
+ },
154
+ 8: {
155
+ "name": "navigation_correction_information",
156
+ "fields": [
157
+ ("header_block_number", "I1", 1, 1, None),
158
+ ("block_length", "I2", 2, 1, None),
159
+ ("center_col_rot", "R4", 4, 1, None),
160
+ ("center_line_rot", "R4", 4, 1, None),
161
+ ("rot_correction", "R8", 8, 1, None),
162
+ ("num_corr_data", "I2", 2, 1, None),
163
+ # The following fields are variable and depend on 'num_corr_data'
164
+ # These are not currently parsed
165
+ # ("line_after_rot", "I2", 2, 1, None),
166
+ # ("shift_amount_col", "R4", 4, 1, None),
167
+ # ("shift_amount_line", "R4", 4, 1, None),
168
+ # ("spare", "C", 40, 1, None),
169
+ ],
170
+ },
171
+ 9: {
172
+ "name": "observation_time_information",
173
+ "fields": [
174
+ ("header_block_number", "I1", 1, 1, None),
175
+ ("block_length", "I2", 2, 1, None),
176
+ ("num_obs_times", "I2", 2, 1, None),
177
+ # The following fields are variable and depend on 'num_obs_times'
178
+ # These are not currently parsed
179
+ # ("line_number", "I2", 2, 1, None),
180
+ # ("obs_time", "R8", 8, 1, None),
181
+ # ("spare", "C", 40, 1, None),
182
+ ],
183
+ },
184
+ 10: {
185
+ "name": "error_information",
186
+ "fields": [
187
+ ("header_block_number", "I1", 1, 1, None),
188
+ ("block_length", "I4", 4, 1, None),
189
+ ("num_error_data", "I2", 2, 1, None),
190
+ # The following fields are variable and depend on 'num_error_data'
191
+ # These are not currently parsed
192
+ # ("line_number", "I2", 2, 1, None),
193
+ # ("num_error_pixels", "I2", 2, 1, None),
194
+ # ("spare", "C", 40, 1, None),
195
+ ],
196
+ },
197
+ 11: {
198
+ "name": "spare",
199
+ "fields": [
200
+ ("header_block_number", "I1", 1, 1, None),
201
+ ("block_length", "I2", 2, 1, None),
202
+ ("spare", "C", 256, 1, None),
203
+ ],
204
+ },
205
+ }
206
+
207
+
208
+ def parse_himawari_header(content: bytes) -> dict:
209
+ """Parse the Himawari header data.
210
+
211
+ Skips variable-length fields and spares.
212
+ """
213
+ out = {}
214
+ offset = 0
215
+
216
+ # everything is little-endian (see the byte_order field in block #1)
217
+ typ_map = {
218
+ "I1": "B",
219
+ "I2": "H",
220
+ "I4": "I",
221
+ "R4": "f",
222
+ "R8": "d",
223
+ "C": "s",
224
+ }
225
+
226
+ for block_num, block_info in HEADER_STRUCT_SCHEMA.items():
227
+ offset_block_start = offset # blocks 8, 9, 10 are dynamic
228
+ block_data: dict[str, Any] = {}
229
+ block_name = block_info["name"]
230
+ fields = block_info["fields"]
231
+ block_length_value: int | None = None
232
+
233
+ for name, typ, size, count, cond in fields:
234
+ if block_num == 5 and cond: # deal with dynamic block 5
235
+ band_number = block_data["band_number"]
236
+ if cond == "IR-BANDS" and band_number <= 6:
237
+ continue
238
+ if cond == "NIR-BANDS" and band_number >= 7:
239
+ continue
240
+
241
+ if name == "spare": # skip spare fields
242
+ offset += size * count
243
+ continue
244
+
245
+ fmt = typ_map[typ]
246
+ if typ == "C":
247
+ raw = struct.unpack_from(f"{size * count}s", content, offset)[0]
248
+ value = raw.rstrip(b"\x00").decode("ascii", errors="ignore")
249
+ else:
250
+ value = struct.unpack_from(f"{count}{fmt}", content, offset)
251
+ if count == 1:
252
+ value = value[0]
253
+
254
+ block_data[name] = value
255
+ offset += size * count
256
+
257
+ if name == "block_length":
258
+ block_length_value = value
259
+
260
+ if block_length_value is None:
261
+ raise ValueError(f"Missing block_length in {block_name}")
262
+ offset = offset_block_start + block_length_value # only needed for blocks 8, 9, 10
263
+
264
+ out[block_name] = block_data
265
+
266
+ return out