sdfr 1.4.9__py3-none-win_amd64.whl → 1.4.11__py3-none-win_amd64.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.
sdfr/SDF.py CHANGED
@@ -15,11 +15,21 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- import ctypes as ct
19
- import numpy as np
20
- import struct
21
- from enum import IntEnum
22
- from .loadlib import sdf_lib
18
+ """Constants and types for representing the blocks contained in an SDF file."""
19
+
20
+ import ctypes as _c
21
+ import numpy as _np
22
+ import struct as _struct
23
+ import re as _re
24
+ import io as _io
25
+ import hashlib as _hashlib
26
+ import tarfile as _tarfile
27
+ import gzip as _gzip
28
+ import os as _os
29
+ from enum import IntEnum as _IntEnum
30
+ from ._loadlib import sdf_lib as _sdf_lib
31
+ from typing import Dict as _Dict
32
+ from typing import Any as _Any
23
33
 
24
34
  # try:
25
35
  # import xarray as xr
@@ -30,92 +40,99 @@ from .loadlib import sdf_lib
30
40
  # got_xarray = False
31
41
 
32
42
 
33
- # Enum representation using ct
34
- class SdfBlockType(IntEnum):
35
- SDF_BLOCKTYPE_SCRUBBED = -1
36
- SDF_BLOCKTYPE_NULL = 0
37
- SDF_BLOCKTYPE_PLAIN_MESH = 1
38
- SDF_BLOCKTYPE_POINT_MESH = 2
39
- SDF_BLOCKTYPE_PLAIN_VARIABLE = 3
40
- SDF_BLOCKTYPE_POINT_VARIABLE = 4
41
- SDF_BLOCKTYPE_CONSTANT = 5
42
- SDF_BLOCKTYPE_ARRAY = 6
43
- SDF_BLOCKTYPE_RUN_INFO = 7
44
- SDF_BLOCKTYPE_SOURCE = 8
45
- SDF_BLOCKTYPE_STITCHED_TENSOR = 9
46
- SDF_BLOCKTYPE_STITCHED_MATERIAL = 10
47
- SDF_BLOCKTYPE_STITCHED_MATVAR = 11
48
- SDF_BLOCKTYPE_STITCHED_SPECIES = 12
49
- SDF_BLOCKTYPE_SPECIES = 13
50
- SDF_BLOCKTYPE_PLAIN_DERIVED = 14
51
- SDF_BLOCKTYPE_POINT_DERIVED = 15
52
- SDF_BLOCKTYPE_CONTIGUOUS_TENSOR = 16
53
- SDF_BLOCKTYPE_CONTIGUOUS_MATERIAL = 17
54
- SDF_BLOCKTYPE_CONTIGUOUS_MATVAR = 18
55
- SDF_BLOCKTYPE_CONTIGUOUS_SPECIES = 19
56
- SDF_BLOCKTYPE_CPU_SPLIT = 20
57
- SDF_BLOCKTYPE_STITCHED_OBSTACLE_GROUP = 21
58
- SDF_BLOCKTYPE_UNSTRUCTURED_MESH = 22
59
- SDF_BLOCKTYPE_STITCHED = 23
60
- SDF_BLOCKTYPE_CONTIGUOUS = 24
61
- SDF_BLOCKTYPE_LAGRANGIAN_MESH = 25
62
- SDF_BLOCKTYPE_STATION = 26
63
- SDF_BLOCKTYPE_STATION_DERIVED = 27
64
- SDF_BLOCKTYPE_DATABLOCK = 28
65
- SDF_BLOCKTYPE_NAMEVALUE = 29
66
-
67
-
68
- class SdfGeometry(IntEnum):
69
- SDF_GEOMETRY_NULL = 0
70
- SDF_GEOMETRY_CARTESIAN = 1
71
- SDF_GEOMETRY_CYLINDRICAL = 2
72
- SDF_GEOMETRY_SPHERICAL = 3
73
-
74
-
75
- class SdfStagger(IntEnum):
76
- SDF_STAGGER_CELL_CENTRE = 0
77
- SDF_STAGGER_FACE_X = 1
78
- SDF_STAGGER_FACE_Y = 2
79
- SDF_STAGGER_FACE_Z = 3
80
- SDF_STAGGER_EDGE_X = 4
81
- SDF_STAGGER_EDGE_Y = 5
82
- SDF_STAGGER_EDGE_Z = 6
83
- SDF_STAGGER_VERTEX = 7
84
-
85
-
86
- class SdfDataType(IntEnum):
87
- SDF_DATATYPE_NULL = 0
88
- SDF_DATATYPE_INTEGER4 = 1
89
- SDF_DATATYPE_INTEGER8 = 2
90
- SDF_DATATYPE_REAL4 = 3
91
- SDF_DATATYPE_REAL8 = 4
92
- SDF_DATATYPE_REAL16 = 5
93
- SDF_DATATYPE_CHARACTER = 6
94
- SDF_DATATYPE_LOGICAL = 7
95
- SDF_DATATYPE_OTHER = 8
43
+ # Enum representation using _c
44
+ class SdfBlockType(_IntEnum):
45
+ SCRUBBED = -1
46
+ NULL = 0
47
+ PLAIN_MESH = 1
48
+ POINT_MESH = 2
49
+ PLAIN_VARIABLE = 3
50
+ POINT_VARIABLE = 4
51
+ CONSTANT = 5
52
+ ARRAY = 6
53
+ RUN_INFO = 7
54
+ SOURCE = 8
55
+ STITCHED_TENSOR = 9
56
+ STITCHED_MATERIAL = 10
57
+ STITCHED_MATVAR = 11
58
+ STITCHED_SPECIES = 12
59
+ SPECIES = 13
60
+ PLAIN_DERIVED = 14
61
+ POINT_DERIVED = 15
62
+ CONTIGUOUS_TENSOR = 16
63
+ CONTIGUOUS_MATERIAL = 17
64
+ CONTIGUOUS_MATVAR = 18
65
+ CONTIGUOUS_SPECIES = 19
66
+ CPU_SPLIT = 20
67
+ STITCHED_OBSTACLE_GROUP = 21
68
+ UNSTRUCTURED_MESH = 22
69
+ STITCHED = 23
70
+ CONTIGUOUS = 24
71
+ LAGRANGIAN_MESH = 25
72
+ STATION = 26
73
+ STATION_DERIVED = 27
74
+ DATABLOCK = 28
75
+ NAMEVALUE = 29
76
+
77
+
78
+ class SdfGeometry(_IntEnum):
79
+ NULL = 0
80
+ CARTESIAN = 1
81
+ CYLINDRICAL = 2
82
+ SPHERICAL = 3
83
+
84
+
85
+ class SdfStagger(_IntEnum):
86
+ CELL_CENTRE = 0
87
+ FACE_X = 1
88
+ FACE_Y = 2
89
+ FACE_Z = 3
90
+ EDGE_X = 4
91
+ EDGE_Y = 5
92
+ EDGE_Z = 6
93
+ VERTEX = 7
94
+ HIDDEN0 = 10
95
+ HIDDEN1 = 11
96
+ HIDDEN2 = 12
97
+
98
+
99
+ class SdfDataType(_IntEnum):
100
+ NULL = 0
101
+ INTEGER4 = 1
102
+ INTEGER8 = 2
103
+ REAL4 = 3
104
+ REAL8 = 4
105
+ REAL16 = 5
106
+ CHARACTER = 6
107
+ LOGICAL = 7
108
+ OTHER = 8
109
+
110
+
111
+ class SdfMode(_IntEnum):
112
+ READ = 1
113
+ WRITE = 2
96
114
 
97
115
 
98
116
  _np_datatypes = [
99
117
  0,
100
- np.int32,
101
- np.int64,
102
- np.float32,
103
- np.float64,
104
- np.longdouble,
105
- np.byte,
106
- np.int32,
118
+ _np.int32,
119
+ _np.int64,
120
+ _np.float32,
121
+ _np.float64,
122
+ _np.longdouble,
123
+ _np.byte,
107
124
  bool,
108
125
  0,
109
126
  ]
110
127
  _ct_datatypes = [
111
128
  0,
112
- ct.c_int32,
113
- ct.c_int64,
114
- ct.c_float,
115
- ct.c_double,
116
- ct.c_longdouble,
117
- ct.c_char,
118
- ct.c_bool,
129
+ _c.c_int32,
130
+ _c.c_int64,
131
+ _c.c_float,
132
+ _c.c_double,
133
+ _c.c_longdouble,
134
+ _c.c_char,
135
+ _c.c_bool,
119
136
  0,
120
137
  ]
121
138
  _st_datatypes = [
@@ -131,223 +148,247 @@ _st_datatypes = [
131
148
  ]
132
149
 
133
150
  # Constants
134
- SDF_READ = 1
135
- SDF_WRITE = 2
136
- SDF_MAXDIMS = 4
151
+ _SDF_MAXDIMS = 4
137
152
 
138
153
 
139
- class SdfBlock(ct.Structure):
154
+ class SdfBlock(_c.Structure):
140
155
  pass # Forward declaration for self-referencing structure
141
156
 
142
157
 
143
- class SdfFile(ct.Structure):
158
+ class SdfFile(_c.Structure):
144
159
  pass # Forward declaration for function pointer compatibility
145
160
 
146
161
 
147
162
  SdfBlock._fields_ = [
148
- ("extents", ct.POINTER(ct.c_double)),
149
- ("dim_mults", ct.POINTER(ct.c_double)),
150
- ("station_x", ct.POINTER(ct.c_double)),
151
- ("station_y", ct.POINTER(ct.c_double)),
152
- ("station_z", ct.POINTER(ct.c_double)),
153
- ("mult", ct.c_double),
154
- ("time", ct.c_double),
155
- ("time_increment", ct.c_double),
156
- ("dims", ct.c_int64 * SDF_MAXDIMS),
157
- ("local_dims", ct.c_int64 * SDF_MAXDIMS),
158
- ("block_start", ct.c_int64),
159
- ("next_block_location", ct.c_int64),
160
- ("data_location", ct.c_int64),
161
- ("inline_block_start", ct.c_int64),
162
- ("inline_next_block_location", ct.c_int64),
163
- ("summary_block_start", ct.c_int64),
164
- ("summary_next_block_location", ct.c_int64),
165
- ("nelements", ct.c_int64),
166
- ("nelements_local", ct.c_int64),
167
- ("data_length", ct.c_int64),
168
- ("nelements_blocks", ct.POINTER(ct.c_int64)),
169
- ("data_length_blocks", ct.POINTER(ct.c_int64)),
170
- ("array_starts", ct.POINTER(ct.c_int64)),
171
- ("array_ends", ct.POINTER(ct.c_int64)),
172
- ("array_strides", ct.POINTER(ct.c_int64)),
173
- ("global_array_starts", ct.POINTER(ct.c_int64)),
174
- ("global_array_ends", ct.POINTER(ct.c_int64)),
175
- ("global_array_strides", ct.POINTER(ct.c_int64)),
176
- ("ndims", ct.c_int32),
177
- ("geometry", ct.c_int32),
178
- ("datatype", ct.c_int32),
179
- ("blocktype", ct.c_int32),
180
- ("info_length", ct.c_int32),
181
- ("type_size", ct.c_int32),
182
- ("stagger", ct.c_int32),
183
- ("datatype_out", ct.c_int32),
184
- ("type_size_out", ct.c_int32),
185
- ("nstations", ct.c_int32),
186
- ("nvariables", ct.c_int32),
187
- ("step", ct.c_int32),
188
- ("step_increment", ct.c_int32),
189
- ("dims_in", ct.POINTER(ct.c_int32)),
190
- ("station_nvars", ct.POINTER(ct.c_int32)),
191
- ("variable_types", ct.POINTER(ct.c_int32)),
192
- ("station_index", ct.POINTER(ct.c_int32)),
193
- ("station_move", ct.POINTER(ct.c_int32)),
194
- ("nm", ct.c_int),
195
- ("n_ids", ct.c_int),
196
- ("opt", ct.c_int),
197
- ("ng", ct.c_int),
198
- ("nfaces", ct.c_int),
199
- ("ngrids", ct.c_int),
200
- ("offset", ct.c_int),
201
- ("ngb", ct.c_int * 6),
202
- ("const_value", ct.c_byte * 16),
203
- ("id", ct.c_char_p),
204
- ("units", ct.c_char_p),
205
- ("mesh_id", ct.c_char_p),
206
- ("material_id", ct.c_char_p),
207
- ("vfm_id", ct.c_char_p),
208
- ("obstacle_id", ct.c_char_p),
209
- ("station_id", ct.c_char_p),
210
- ("name", ct.c_char_p),
211
- ("material_name", ct.c_char_p),
212
- ("must_read", ct.c_char_p),
213
- ("dim_labels", ct.POINTER(ct.c_char_p)),
214
- ("dim_units", ct.POINTER(ct.c_char_p)),
215
- ("station_ids", ct.POINTER(ct.c_char_p)),
216
- ("variable_ids", ct.POINTER(ct.c_char_p)),
217
- ("station_names", ct.POINTER(ct.c_char_p)),
218
- ("material_names", ct.POINTER(ct.c_char_p)),
219
- ("node_list", ct.POINTER(ct.c_int)),
220
- ("boundary_cells", ct.POINTER(ct.c_int)),
221
- ("grids", ct.POINTER(ct.c_void_p)),
222
- ("data", ct.c_void_p),
223
- ("done_header", ct.c_bool),
224
- ("done_info", ct.c_bool),
225
- ("done_data", ct.c_bool),
226
- ("dont_allocate", ct.c_bool),
227
- ("dont_display", ct.c_bool),
228
- ("dont_own_data", ct.c_bool),
229
- ("use_mult", ct.c_bool),
230
- ("next_block_modified", ct.c_bool),
231
- ("rewrite_metadata", ct.c_bool),
232
- ("in_file", ct.c_bool),
233
- ("ng_any", ct.c_bool),
234
- ("no_internal_ghost", ct.c_bool),
235
- ("next", ct.POINTER(SdfBlock)),
236
- ("prev", ct.POINTER(SdfBlock)),
237
- ("subblock", ct.POINTER(SdfBlock)),
238
- ("subblock2", ct.POINTER(SdfBlock)),
163
+ ("extents", _c.POINTER(_c.c_double)),
164
+ ("dim_mults", _c.POINTER(_c.c_double)),
165
+ ("station_x", _c.POINTER(_c.c_double)),
166
+ ("station_y", _c.POINTER(_c.c_double)),
167
+ ("station_z", _c.POINTER(_c.c_double)),
168
+ ("mult", _c.c_double),
169
+ ("time", _c.c_double),
170
+ ("time_increment", _c.c_double),
171
+ ("dims", _c.c_int64 * _SDF_MAXDIMS),
172
+ ("local_dims", _c.c_int64 * _SDF_MAXDIMS),
173
+ ("block_start", _c.c_int64),
174
+ ("next_block_location", _c.c_int64),
175
+ ("data_location", _c.c_int64),
176
+ ("inline_block_start", _c.c_int64),
177
+ ("inline_next_block_location", _c.c_int64),
178
+ ("summary_block_start", _c.c_int64),
179
+ ("summary_next_block_location", _c.c_int64),
180
+ ("nelements", _c.c_int64),
181
+ ("nelements_local", _c.c_int64),
182
+ ("data_length", _c.c_int64),
183
+ ("nelements_blocks", _c.POINTER(_c.c_int64)),
184
+ ("data_length_blocks", _c.POINTER(_c.c_int64)),
185
+ ("array_starts", _c.POINTER(_c.c_int64)),
186
+ ("array_ends", _c.POINTER(_c.c_int64)),
187
+ ("array_strides", _c.POINTER(_c.c_int64)),
188
+ ("global_array_starts", _c.POINTER(_c.c_int64)),
189
+ ("global_array_ends", _c.POINTER(_c.c_int64)),
190
+ ("global_array_strides", _c.POINTER(_c.c_int64)),
191
+ ("ndims", _c.c_int32),
192
+ ("geometry", _c.c_int32),
193
+ ("datatype", _c.c_int32),
194
+ ("blocktype", _c.c_int32),
195
+ ("info_length", _c.c_int32),
196
+ ("type_size", _c.c_int32),
197
+ ("stagger", _c.c_int32),
198
+ ("datatype_out", _c.c_int32),
199
+ ("type_size_out", _c.c_int32),
200
+ ("nstations", _c.c_int32),
201
+ ("nvariables", _c.c_int32),
202
+ ("step", _c.c_int32),
203
+ ("step_increment", _c.c_int32),
204
+ ("dims_in", _c.POINTER(_c.c_int32)),
205
+ ("station_nvars", _c.POINTER(_c.c_int32)),
206
+ ("variable_types", _c.POINTER(_c.c_int32)),
207
+ ("station_index", _c.POINTER(_c.c_int32)),
208
+ ("station_move", _c.POINTER(_c.c_int32)),
209
+ ("nm", _c.c_int),
210
+ ("n_ids", _c.c_int),
211
+ ("opt", _c.c_int),
212
+ ("ng", _c.c_int),
213
+ ("nfaces", _c.c_int),
214
+ ("ngrids", _c.c_int),
215
+ ("offset", _c.c_int),
216
+ ("ngb", _c.c_int * 6),
217
+ ("const_value", _c.c_byte * 16),
218
+ ("id", _c.c_char_p),
219
+ ("units", _c.c_char_p),
220
+ ("mesh_id", _c.c_char_p),
221
+ ("material_id", _c.c_char_p),
222
+ ("vfm_id", _c.c_char_p),
223
+ ("obstacle_id", _c.c_char_p),
224
+ ("station_id", _c.c_char_p),
225
+ ("name", _c.c_char_p),
226
+ ("material_name", _c.c_char_p),
227
+ ("must_read", _c.c_char_p),
228
+ ("dim_labels", _c.POINTER(_c.c_char_p)),
229
+ ("dim_units", _c.POINTER(_c.c_char_p)),
230
+ ("station_ids", _c.POINTER(_c.c_char_p)),
231
+ ("variable_ids", _c.POINTER(_c.c_char_p)),
232
+ ("station_names", _c.POINTER(_c.c_char_p)),
233
+ ("material_names", _c.POINTER(_c.c_char_p)),
234
+ ("node_list", _c.POINTER(_c.c_int)),
235
+ ("boundary_cells", _c.POINTER(_c.c_int)),
236
+ ("grids", _c.POINTER(_c.c_void_p)),
237
+ ("data", _c.c_void_p),
238
+ ("done_header", _c.c_bool),
239
+ ("done_info", _c.c_bool),
240
+ ("done_data", _c.c_bool),
241
+ ("dont_allocate", _c.c_bool),
242
+ ("dont_display", _c.c_bool),
243
+ ("dont_own_data", _c.c_bool),
244
+ ("use_mult", _c.c_bool),
245
+ ("next_block_modified", _c.c_bool),
246
+ ("rewrite_metadata", _c.c_bool),
247
+ ("in_file", _c.c_bool),
248
+ ("ng_any", _c.c_bool),
249
+ ("no_internal_ghost", _c.c_bool),
250
+ ("next", _c.POINTER(SdfBlock)),
251
+ ("prev", _c.POINTER(SdfBlock)),
252
+ ("subblock", _c.POINTER(SdfBlock)),
253
+ ("subblock2", _c.POINTER(SdfBlock)),
239
254
  (
240
255
  "populate_data",
241
- ct.CFUNCTYPE(
242
- ct.POINTER(SdfBlock), ct.POINTER(SdfFile), ct.POINTER(SdfBlock)
256
+ _c.CFUNCTYPE(
257
+ _c.POINTER(SdfBlock), _c.POINTER(SdfFile), _c.POINTER(SdfBlock)
243
258
  ),
244
259
  ),
245
- ("cpu_split", ct.c_int * SDF_MAXDIMS),
246
- ("starts", ct.c_int * SDF_MAXDIMS),
247
- ("proc_min", ct.c_int * 3),
248
- ("proc_max", ct.c_int * 3),
249
- ("ndim_labels", ct.c_int),
250
- ("ndim_units", ct.c_int),
251
- ("nstation_ids", ct.c_int),
252
- ("nvariable_ids", ct.c_int),
253
- ("nstation_names", ct.c_int),
254
- ("nmaterial_names", ct.c_int),
255
- ("option", ct.c_int),
256
- ("mimetype", ct.c_char_p),
257
- ("checksum_type", ct.c_char_p),
258
- ("checksum", ct.c_char_p),
259
- ("mmap", ct.c_char_p),
260
- ("mmap_len", ct.c_int64),
261
- ("derived", ct.c_bool),
260
+ ("cpu_split", _c.c_int * _SDF_MAXDIMS),
261
+ ("starts", _c.c_int * _SDF_MAXDIMS),
262
+ ("proc_min", _c.c_int * 3),
263
+ ("proc_max", _c.c_int * 3),
264
+ ("ndim_labels", _c.c_int),
265
+ ("ndim_units", _c.c_int),
266
+ ("nstation_ids", _c.c_int),
267
+ ("nvariable_ids", _c.c_int),
268
+ ("nstation_names", _c.c_int),
269
+ ("nmaterial_names", _c.c_int),
270
+ ("option", _c.c_int),
271
+ ("mimetype", _c.c_char_p),
272
+ ("checksum_type", _c.c_char_p),
273
+ ("checksum", _c.c_char_p),
274
+ ("mmap", _c.c_char_p),
275
+ ("mmap_len", _c.c_int64),
276
+ ("derived", _c.c_bool),
277
+ ("id_orig", _c.c_char_p),
278
+ ("name_orig", _c.c_char_p),
262
279
  ]
263
280
 
264
281
  SdfFile._fields_ = [
265
- ("dbg_count", ct.c_int64),
266
- ("sdf_lib_version", ct.c_int32),
267
- ("sdf_lib_revision", ct.c_int32),
268
- ("sdf_extension_version", ct.c_int32),
269
- ("sdf_extension_revision", ct.c_int32),
270
- ("file_version", ct.c_int32),
271
- ("file_revision", ct.c_int32),
272
- ("dbg", ct.c_char_p),
273
- ("dbg_buf", ct.c_char_p),
274
- ("extension_names", ct.POINTER(ct.c_char_p)),
275
- ("time", ct.c_double),
276
- ("first_block_location", ct.c_int64),
277
- ("summary_location", ct.c_int64),
278
- ("start_location", ct.c_int64),
279
- ("soi", ct.c_int64),
280
- ("sof", ct.c_int64),
281
- ("current_location", ct.c_int64),
282
- ("jobid1", ct.c_int32),
283
- ("jobid2", ct.c_int32),
284
- ("endianness", ct.c_int32),
285
- ("summary_size", ct.c_int32),
286
- ("block_header_length", ct.c_int32),
287
- ("string_length", ct.c_int32),
288
- ("id_length", ct.c_int32),
289
- ("code_io_version", ct.c_int32),
290
- ("step", ct.c_int32),
291
- ("nblocks", ct.c_int32),
292
- ("nblocks_file", ct.c_int32),
293
- ("error_code", ct.c_int32),
294
- ("rank", ct.c_int),
295
- ("ncpus", ct.c_int),
296
- ("ndomains", ct.c_int),
297
- ("rank_master", ct.c_int),
298
- ("indent", ct.c_int),
299
- ("print", ct.c_int),
300
- ("buffer", ct.c_char_p),
301
- ("filename", ct.c_char_p),
302
- ("done_header", ct.c_bool),
303
- ("restart_flag", ct.c_bool),
304
- ("other_domains", ct.c_bool),
305
- ("use_float", ct.c_bool),
306
- ("use_summary", ct.c_bool),
307
- ("use_random", ct.c_bool),
308
- ("station_file", ct.c_bool),
309
- ("swap", ct.c_bool),
310
- ("inline_metadata_read", ct.c_bool),
311
- ("summary_metadata_read", ct.c_bool),
312
- ("inline_metadata_invalid", ct.c_bool),
313
- ("summary_metadata_invalid", ct.c_bool),
314
- ("tmp_flag", ct.c_bool),
315
- ("metadata_modified", ct.c_bool),
316
- ("can_truncate", ct.c_bool),
317
- ("first_block_modified", ct.c_bool),
318
- ("code_name", ct.c_char_p),
319
- ("error_message", ct.c_char_p),
320
- ("blocklist", ct.POINTER(SdfBlock)),
321
- ("tail", ct.POINTER(SdfBlock)),
322
- ("current_block", ct.POINTER(SdfBlock)),
323
- ("last_block_in_file", ct.POINTER(SdfBlock)),
324
- ("mmap", ct.c_char_p),
325
- ("ext_data", ct.c_void_p),
326
- ("stack_handle", ct.c_void_p),
327
- ("array_count", ct.c_int),
328
- ("fd", ct.c_int),
329
- ("purge_duplicated_ids", ct.c_int),
330
- ("internal_ghost_cells", ct.c_int),
331
- ("ignore_nblocks", ct.c_int),
282
+ ("dbg_count", _c.c_int64),
283
+ ("sdf_lib_version", _c.c_int32),
284
+ ("sdf_lib_revision", _c.c_int32),
285
+ ("sdf_extension_version", _c.c_int32),
286
+ ("sdf_extension_revision", _c.c_int32),
287
+ ("file_version", _c.c_int32),
288
+ ("file_revision", _c.c_int32),
289
+ ("dbg", _c.c_char_p),
290
+ ("dbg_buf", _c.c_char_p),
291
+ ("extension_names", _c.POINTER(_c.c_char_p)),
292
+ ("time", _c.c_double),
293
+ ("first_block_location", _c.c_int64),
294
+ ("summary_location", _c.c_int64),
295
+ ("start_location", _c.c_int64),
296
+ ("soi", _c.c_int64),
297
+ ("sof", _c.c_int64),
298
+ ("current_location", _c.c_int64),
299
+ ("jobid1", _c.c_int32),
300
+ ("jobid2", _c.c_int32),
301
+ ("endianness", _c.c_int32),
302
+ ("summary_size", _c.c_int32),
303
+ ("block_header_length", _c.c_int32),
304
+ ("string_length", _c.c_int32),
305
+ ("id_length", _c.c_int32),
306
+ ("code_io_version", _c.c_int32),
307
+ ("step", _c.c_int32),
308
+ ("nblocks", _c.c_int32),
309
+ ("nblocks_file", _c.c_int32),
310
+ ("error_code", _c.c_int32),
311
+ ("rank", _c.c_int),
312
+ ("ncpus", _c.c_int),
313
+ ("ndomains", _c.c_int),
314
+ ("rank_master", _c.c_int),
315
+ ("indent", _c.c_int),
316
+ ("print", _c.c_int),
317
+ ("buffer", _c.c_char_p),
318
+ ("filename", _c.c_char_p),
319
+ ("done_header", _c.c_bool),
320
+ ("restart_flag", _c.c_bool),
321
+ ("other_domains", _c.c_bool),
322
+ ("use_float", _c.c_bool),
323
+ ("use_summary", _c.c_bool),
324
+ ("use_random", _c.c_bool),
325
+ ("station_file", _c.c_bool),
326
+ ("swap", _c.c_bool),
327
+ ("inline_metadata_read", _c.c_bool),
328
+ ("summary_metadata_read", _c.c_bool),
329
+ ("inline_metadata_invalid", _c.c_bool),
330
+ ("summary_metadata_invalid", _c.c_bool),
331
+ ("tmp_flag", _c.c_bool),
332
+ ("metadata_modified", _c.c_bool),
333
+ ("can_truncate", _c.c_bool),
334
+ ("first_block_modified", _c.c_bool),
335
+ ("code_name", _c.c_char_p),
336
+ ("error_message", _c.c_char_p),
337
+ ("blocklist", _c.POINTER(SdfBlock)),
338
+ ("tail", _c.POINTER(SdfBlock)),
339
+ ("current_block", _c.POINTER(SdfBlock)),
340
+ ("last_block_in_file", _c.POINTER(SdfBlock)),
341
+ ("mmap", _c.c_char_p),
342
+ ("ext_data", _c.c_void_p),
343
+ ("stack_handle", _c.c_void_p),
344
+ ("array_count", _c.c_int),
345
+ ("fd", _c.c_int),
346
+ ("purge_duplicated_ids", _c.c_int),
347
+ ("internal_ghost_cells", _c.c_int),
348
+ ("ignore_nblocks", _c.c_int),
332
349
  ]
333
350
 
334
351
 
335
- class RunInfo(ct.Structure):
352
+ class RunInfo(_c.Structure):
336
353
  _fields_ = [
337
- ("defines", ct.c_int64),
338
- ("version", ct.c_int32),
339
- ("revision", ct.c_int32),
340
- ("compile_date", ct.c_int32),
341
- ("run_date", ct.c_int32),
342
- ("io_date", ct.c_int32),
343
- ("minor_rev", ct.c_int32),
344
- ("commit_id", ct.c_char_p),
345
- ("sha1sum", ct.c_char_p),
346
- ("compile_machine", ct.c_char_p),
347
- ("compile_flags", ct.c_char_p),
354
+ ("defines", _c.c_int64),
355
+ ("version", _c.c_int32),
356
+ ("revision", _c.c_int32),
357
+ ("compile_date", _c.c_int32),
358
+ ("run_date", _c.c_int32),
359
+ ("io_date", _c.c_int32),
360
+ ("minor_rev", _c.c_int32),
361
+ ("commit_id", _c.c_char_p),
362
+ ("sha1sum", _c.c_char_p),
363
+ ("compile_machine", _c.c_char_p),
364
+ ("compile_flags", _c.c_char_p),
348
365
  ]
349
366
 
350
367
 
368
+ class BlockDict(dict):
369
+ def __init__(self, _dict, block):
370
+ self.handle = block._handle
371
+ super().__init__(_dict)
372
+
373
+ def __setitem__(self, key, value):
374
+ h = self.handle
375
+ if key in (
376
+ "step",
377
+ "time",
378
+ "code_io_version",
379
+ "string_length",
380
+ "jobid1",
381
+ "jobid2",
382
+ ):
383
+ setattr(h.contents, key, value)
384
+ elif key == "code_name":
385
+ h._clib.sdf_set_code_name(h, value.encode("utf-8"))
386
+ else:
387
+ print(f'WARNING: unable to set header key "{key}"')
388
+ return
389
+ super().__setitem__(key, value)
390
+
391
+
351
392
  class BlockList:
352
393
  """Contains all the blocks"""
353
394
 
@@ -356,52 +397,63 @@ class BlockList:
356
397
  filename=None,
357
398
  convert=False,
358
399
  derived=True,
359
- mode=SDF_READ,
400
+ mode=SdfMode.READ,
360
401
  code_name="sdfr",
361
402
  restart=False,
362
403
  ):
363
404
  self._handle = None
364
- clib = sdf_lib
405
+ clib = _sdf_lib
365
406
  self._clib = clib
366
- clib.sdf_open.restype = ct.POINTER(SdfFile)
367
- clib.sdf_open.argtypes = [ct.c_char_p, ct.c_int, ct.c_int, ct.c_int]
368
- clib.sdf_new.restype = ct.POINTER(SdfFile)
369
- clib.sdf_new.argtypes = [ct.c_int, ct.c_int]
370
- clib.sdf_stack_init.argtypes = [ct.c_void_p]
371
- clib.sdf_read_blocklist.argtypes = [ct.c_void_p]
372
- clib.sdf_read_blocklist_all.argtypes = [ct.c_void_p]
373
- clib.sdf_helper_read_data.argtypes = [ct.c_void_p, ct.POINTER(SdfBlock)]
374
- clib.sdf_free_block_data.argtypes = [ct.c_void_p, ct.POINTER(SdfBlock)]
375
- clib.sdf_stack_destroy.argtypes = [ct.c_void_p]
376
- clib.sdf_close.argtypes = [ct.c_void_p]
377
- clib.sdf_write.argtypes = [ct.c_void_p, ct.c_char_p]
378
- clib.sdf_get_next_block.argtypes = [ct.c_void_p]
407
+ clib.sdf_open.restype = _c.POINTER(SdfFile)
408
+ clib.sdf_open.argtypes = [_c.c_char_p, _c.c_int, _c.c_int, _c.c_int]
409
+ clib.sdf_new.restype = _c.POINTER(SdfFile)
410
+ clib.sdf_new.argtypes = [_c.c_int, _c.c_int]
411
+ clib.sdf_stack_init.argtypes = [_c.c_void_p]
412
+ clib.sdf_read_blocklist.argtypes = [_c.c_void_p]
413
+ clib.sdf_read_blocklist_all.argtypes = [_c.c_void_p]
414
+ clib.sdf_helper_read_data.argtypes = [_c.c_void_p, _c.POINTER(SdfBlock)]
415
+ clib.sdf_free_block_data.argtypes = [_c.c_void_p, _c.POINTER(SdfBlock)]
416
+ clib.sdf_stack_destroy.argtypes = [_c.c_void_p]
417
+ clib.sdf_close.argtypes = [_c.c_void_p]
418
+ clib.sdf_write.argtypes = [_c.c_void_p, _c.c_char_p]
419
+ clib.sdf_get_next_block.argtypes = [_c.c_void_p]
379
420
  clib.sdf_set_namevalue.argtypes = [
380
- ct.POINTER(SdfBlock),
381
- ct.POINTER(ct.c_char_p),
382
- ct.POINTER(ct.c_void_p),
421
+ _c.POINTER(SdfBlock),
422
+ _c.POINTER(_c.c_char_p),
423
+ _c.POINTER(_c.c_void_p),
383
424
  ]
384
- clib.sdf_set_code_name.argtypes = [ct.c_void_p, ct.c_char_p]
425
+ clib.sdf_set_code_name.argtypes = [_c.c_void_p, _c.c_char_p]
385
426
  clib.sdf_set_block_name.argtypes = [
386
- ct.c_void_p,
387
- ct.c_char_p,
388
- ct.c_char_p,
427
+ _c.c_void_p,
428
+ _c.c_char_p,
429
+ _c.c_char_p,
389
430
  ]
390
431
  clib.sdf_set_defaults.argtypes = [
391
- ct.c_void_p,
392
- ct.POINTER(SdfBlock),
432
+ _c.c_void_p,
433
+ _c.POINTER(SdfBlock),
393
434
  ]
394
435
  clib.sdf_create_id.argtypes = [
395
- ct.c_void_p,
396
- ct.c_char_p,
436
+ _c.c_void_p,
437
+ _c.c_char_p,
397
438
  ]
398
- clib.sdf_create_id.restype = ct.POINTER(ct.c_char_p)
439
+ clib.sdf_create_id.restype = _c.POINTER(_c.c_char_p)
399
440
  clib.sdf_create_id_array.argtypes = [
400
- ct.c_void_p,
401
- ct.c_int,
402
- ct.POINTER(ct.c_char_p),
441
+ _c.c_void_p,
442
+ _c.c_int,
443
+ _c.POINTER(_c.c_char_p),
444
+ ]
445
+ clib.sdf_create_id_array.restype = _c.POINTER(_c.c_char_p)
446
+ clib.sdf_create_string.argtypes = [
447
+ _c.c_void_p,
448
+ _c.c_char_p,
449
+ ]
450
+ clib.sdf_create_string.restype = _c.POINTER(_c.c_char_p)
451
+ clib.sdf_create_string_array.argtypes = [
452
+ _c.c_void_p,
453
+ _c.c_int,
454
+ _c.POINTER(_c.c_char_p),
403
455
  ]
404
- clib.sdf_create_id_array.restype = ct.POINTER(ct.c_char_p)
456
+ clib.sdf_create_string_array.restype = _c.POINTER(_c.c_char_p)
405
457
 
406
458
  comm = 0
407
459
  use_mmap = 0
@@ -418,7 +470,7 @@ class BlockList:
418
470
  h._clib = clib
419
471
  self._handle = h
420
472
  clib.sdf_stack_init(h)
421
- if mode == SDF_READ:
473
+ if mode == SdfMode.READ:
422
474
  if derived:
423
475
  clib.sdf_read_blocklist_all(h)
424
476
  else:
@@ -428,7 +480,7 @@ class BlockList:
428
480
 
429
481
  block = h.contents.blocklist
430
482
  h.contents.restart_flag = restart
431
- self.Header = get_header(h.contents)
483
+ self._header = self._get_header(h.contents)
432
484
  mesh_id_map = {}
433
485
  mesh_vars = []
434
486
  self._block_ids = {"Header": self.Header}
@@ -440,77 +492,90 @@ class BlockList:
440
492
  blocktype = block.blocktype
441
493
  newblock = None
442
494
  newblock_mid = None
443
- name = get_member_name(block.name)
444
- if blocktype == SdfBlockType.SDF_BLOCKTYPE_ARRAY:
495
+ if block.name_orig:
496
+ name = _get_member_name(block.name_orig)
497
+ else:
498
+ name = _get_member_name(block.name)
499
+ if blocktype == SdfBlockType.ARRAY:
445
500
  newblock = BlockArray(block)
446
- elif blocktype == SdfBlockType.SDF_BLOCKTYPE_CONSTANT:
501
+ elif blocktype == SdfBlockType.CONSTANT:
447
502
  newblock = BlockConstant(block)
448
503
  elif (
449
- blocktype == SdfBlockType.SDF_BLOCKTYPE_CONTIGUOUS
450
- or blocktype == SdfBlockType.SDF_BLOCKTYPE_STITCHED
504
+ blocktype == SdfBlockType.CONTIGUOUS
505
+ or blocktype == SdfBlockType.STITCHED
451
506
  ):
452
- if block.stagger == 10 or block.stagger == 12:
507
+ if block.stagger in (SdfStagger.HIDDEN0, SdfStagger.HIDDEN2):
453
508
  newblock = BlockStitchedPath(block)
454
509
  else:
455
510
  newblock = BlockStitched(block)
511
+ mesh_vars.append(newblock)
456
512
  elif (
457
- blocktype == SdfBlockType.SDF_BLOCKTYPE_CONTIGUOUS_MATERIAL
458
- or blocktype == SdfBlockType.SDF_BLOCKTYPE_STITCHED_MATERIAL
513
+ blocktype == SdfBlockType.CONTIGUOUS_MATERIAL
514
+ or blocktype == SdfBlockType.STITCHED_MATERIAL
459
515
  ):
460
516
  newblock = BlockStitchedMaterial(block)
517
+ mesh_vars.append(newblock)
461
518
  elif (
462
- blocktype == SdfBlockType.SDF_BLOCKTYPE_CONTIGUOUS_MATVAR
463
- or blocktype == SdfBlockType.SDF_BLOCKTYPE_STITCHED_MATVAR
519
+ blocktype == SdfBlockType.CONTIGUOUS_MATVAR
520
+ or blocktype == SdfBlockType.STITCHED_MATVAR
464
521
  ):
465
522
  newblock = BlockStitchedMatvar(block)
523
+ mesh_vars.append(newblock)
466
524
  elif (
467
- blocktype == SdfBlockType.SDF_BLOCKTYPE_CONTIGUOUS_SPECIES
468
- or blocktype == SdfBlockType.SDF_BLOCKTYPE_STITCHED_SPECIES
525
+ blocktype == SdfBlockType.CONTIGUOUS_SPECIES
526
+ or blocktype == SdfBlockType.STITCHED_SPECIES
469
527
  ):
470
528
  newblock = BlockStitchedSpecies(block)
529
+ mesh_vars.append(newblock)
471
530
  elif (
472
- blocktype == SdfBlockType.SDF_BLOCKTYPE_CONTIGUOUS_TENSOR
473
- or blocktype == SdfBlockType.SDF_BLOCKTYPE_STITCHED_TENSOR
531
+ blocktype == SdfBlockType.CONTIGUOUS_TENSOR
532
+ or blocktype == SdfBlockType.STITCHED_TENSOR
474
533
  ):
475
534
  newblock = BlockStitchedTensor(block)
476
- elif blocktype == SdfBlockType.SDF_BLOCKTYPE_DATABLOCK:
535
+ mesh_vars.append(newblock)
536
+ elif blocktype == SdfBlockType.DATABLOCK:
477
537
  newblock = BlockData(block)
478
- elif blocktype == SdfBlockType.SDF_BLOCKTYPE_LAGRANGIAN_MESH:
538
+ elif blocktype == SdfBlockType.LAGRANGIAN_MESH:
479
539
  if block.datatype_out != 0:
480
540
  newblock = BlockLagrangianMesh(block)
481
541
  newblock_mid = block
482
542
  newblock_mid._grid_block = newblock
483
543
  mesh_id_map[newblock.id] = newblock
484
- elif blocktype == SdfBlockType.SDF_BLOCKTYPE_NAMEVALUE:
544
+ elif blocktype == SdfBlockType.NAMEVALUE:
485
545
  newblock = BlockNameValue(block)
486
546
  elif (
487
- blocktype == SdfBlockType.SDF_BLOCKTYPE_PLAIN_DERIVED
488
- or blocktype == SdfBlockType.SDF_BLOCKTYPE_PLAIN_VARIABLE
547
+ blocktype == SdfBlockType.PLAIN_DERIVED
548
+ or blocktype == SdfBlockType.PLAIN_VARIABLE
489
549
  ):
490
- newblock = BlockPlainVariable(block)
491
- mesh_vars.append(newblock)
492
- elif blocktype == SdfBlockType.SDF_BLOCKTYPE_PLAIN_MESH:
550
+ if block.datatype > 0:
551
+ newblock = BlockPlainVariable(block)
552
+ mesh_vars.append(newblock)
553
+ elif blocktype == SdfBlockType.PLAIN_MESH:
493
554
  if block.datatype_out != 0:
494
555
  newblock = BlockPlainMesh(block)
495
556
  newblock_mid = block
496
557
  newblock_mid._grid_block = newblock
497
558
  mesh_id_map[newblock.id] = newblock
498
559
  elif (
499
- blocktype == SdfBlockType.SDF_BLOCKTYPE_POINT_DERIVED
500
- or blocktype == SdfBlockType.SDF_BLOCKTYPE_POINT_VARIABLE
560
+ blocktype == SdfBlockType.POINT_DERIVED
561
+ or blocktype == SdfBlockType.POINT_VARIABLE
501
562
  ):
502
- newblock = BlockPointVariable(block)
503
- mesh_vars.append(newblock)
504
- elif blocktype == SdfBlockType.SDF_BLOCKTYPE_POINT_MESH:
563
+ if block.datatype > 0:
564
+ newblock = BlockPointVariable(block)
565
+ mesh_vars.append(newblock)
566
+ elif blocktype == SdfBlockType.POINT_MESH:
505
567
  newblock = BlockPointMesh(block)
506
568
  mesh_id_map[newblock.id] = newblock
507
- elif blocktype == SdfBlockType.SDF_BLOCKTYPE_RUN_INFO:
508
- self.Run_info = get_run_info(block)
509
- elif blocktype == SdfBlockType.SDF_BLOCKTYPE_STATION:
510
- sdict = BlockStation(block, name)
569
+ elif blocktype == SdfBlockType.RUN_INFO:
570
+ newblock = BlockRunInfo(block)
571
+ elif blocktype == SdfBlockType.STATION:
572
+ sdict = _BlockStation(block, name)
511
573
  self.__dict__.update({"StationBlocks": sdict})
512
574
  self._block_ids.update({block.id.decode(): sdict})
513
575
  self._block_names.update({block.name.decode(): sdict})
576
+ elif blocktype == SdfBlockType.CPU_SPLIT:
577
+ newblock = BlockCpuSplit(block)
578
+ name = "_" + name
514
579
  else:
515
580
  # Block not supported
516
581
  # print(name,SdfBlockType(blocktype).name)
@@ -527,10 +592,10 @@ class BlockList:
527
592
  block_mid._handle = h
528
593
  block_mid._blocklist = self
529
594
  blocktype = block_mid.blocktype
530
- name = get_member_name(block_mid.name) + "_mid"
531
- if blocktype == SdfBlockType.SDF_BLOCKTYPE_LAGRANGIAN_MESH:
595
+ name = _get_member_name(block_mid.name) + "_mid"
596
+ if blocktype == SdfBlockType.LAGRANGIAN_MESH:
532
597
  newblock = BlockLagrangianMesh(block_mid, mid=True)
533
- elif blocktype == SdfBlockType.SDF_BLOCKTYPE_PLAIN_MESH:
598
+ elif blocktype == SdfBlockType.PLAIN_MESH:
534
599
  newblock = BlockPlainMesh(block_mid, mid=True)
535
600
  if not newblock_mid.dont_display:
536
601
  self.__dict__[name] = newblock
@@ -551,10 +616,41 @@ class BlockList:
551
616
  self._clib.sdf_close(self._handle)
552
617
  self._handle = None
553
618
 
554
- def write(self, filename):
555
- if not self._handle:
556
- return
557
- self._clib.sdf_write(self._handle, filename.encode())
619
+ @property
620
+ def Header(self) -> _Dict[str, _Any]:
621
+ """SDF file header"""
622
+ return self._header
623
+
624
+ @Header.setter
625
+ def Header(self, value):
626
+ try:
627
+ for k, v in value.items():
628
+ self.Header[k] = v
629
+ except Exception:
630
+ print("failed")
631
+
632
+ def _get_header(self, h):
633
+ d = {}
634
+ for k in [
635
+ "filename",
636
+ "file_version",
637
+ "file_revision",
638
+ "code_name",
639
+ "step",
640
+ "time",
641
+ "jobid1",
642
+ "jobid2",
643
+ "code_io_version",
644
+ "restart_flag",
645
+ "other_domains",
646
+ "station_file",
647
+ ]:
648
+ attr = getattr(h, k)
649
+ if isinstance(attr, bytes):
650
+ d[k] = attr.decode()
651
+ else:
652
+ d[k] = attr
653
+ return BlockDict(d, self)
558
654
 
559
655
  def _set_block_name(self, id, name):
560
656
  self._clib.sdf_set_block_name(
@@ -563,13 +659,17 @@ class BlockList:
563
659
 
564
660
  def _create_id(self, values):
565
661
  tmp = self._clib.sdf_create_id(self._handle, values.encode("utf-8"))
566
- return ct.cast(tmp, ct.c_char_p)
662
+ return _c.cast(tmp, _c.c_char_p)
663
+
664
+ def _create_string(self, values):
665
+ tmp = self._clib.sdf_create_string(self._handle, values.encode("utf-8"))
666
+ return _c.cast(tmp, _c.c_char_p)
567
667
 
568
668
  def _string_array_ctype(self, values):
569
669
  strings = [s.encode("utf-8") for s in values]
570
- strings = [ct.create_string_buffer(s) for s in strings]
571
- strings = [ct.cast(s, ct.c_char_p) for s in strings]
572
- strings = (ct.c_char_p * len(values))(*strings)
670
+ strings = [_c.create_string_buffer(s) for s in strings]
671
+ strings = [_c.cast(s, _c.c_char_p) for s in strings]
672
+ strings = (_c.c_char_p * len(values))(*strings)
573
673
  return strings
574
674
 
575
675
  def _create_id_array(self, values):
@@ -577,240 +677,12 @@ class BlockList:
577
677
  res = self._clib.sdf_create_id_array(self._handle, len(values), values)
578
678
  return res
579
679
 
580
- def _add_preamble(self, id, name, datatype):
581
- self._clib.sdf_get_next_block(self._handle)
582
- h = self._handle.contents
583
- h.nblocks += 1
584
- h.nblocks_file += 1
585
- block = h.current_block.contents
586
- block._handle = self._handle
587
- block._blocklist = h.blocklist
588
- block._data = None
589
- block.datatype = datatype
590
- block.in_file = 1
591
- block.AddBlock = None
592
- self._set_block_name(id, name)
593
- return h, block
594
-
595
- def _add_post(self, block):
596
- if block.AddBlock:
597
- newblock = block.AddBlock(block)
598
- else:
599
- return
600
-
601
- id = block.id.decode()
602
- name = block.name.decode()
603
- if not block.dont_display:
604
- self.__dict__[name] = newblock
605
- if block._data is not None:
606
- newblock._data = block._data
607
- self._block_ids.update({id: newblock})
608
- self._block_names.update({name: newblock})
609
-
610
- def _add_constant(self, name, value=0, datatype=None, id=None):
611
- if datatype == SdfDataType.SDF_DATATYPE_CHARACTER:
612
- print(f'Block "{id}", unsupported datatype: {type(value)}')
613
- return
614
-
615
- h, block = self._add_preamble(id, name, datatype)
616
- block.blocktype = SdfBlockType.SDF_BLOCKTYPE_CONSTANT
617
- block.AddBlock = BlockConstant
618
-
619
- const_value = struct.pack(_st_datatypes[block.datatype], value)
620
- ct.memmove(block.const_value, const_value, 16)
621
-
622
- self._add_post(block)
623
-
624
- def _add_namevalue(self, name, value={}, datatype=None, id=None):
625
- h, block = self._add_preamble(id, name, datatype)
626
- block.blocktype = SdfBlockType.SDF_BLOCKTYPE_NAMEVALUE
627
- block.AddBlock = BlockNameValue
628
-
629
- nvalue = len(value)
630
- block.ndims = nvalue
631
- ctype = _ct_datatypes[block.datatype]
632
- if block.datatype == SdfDataType.SDF_DATATYPE_CHARACTER:
633
- vals = self._string_array_ctype(value.values())
634
- else:
635
- vals = (ctype * nvalue)(*value.values())
636
- names = self._string_array_ctype(value.keys())
637
- vals = ct.cast(vals, ct.POINTER(ct.c_void_p))
638
- self._clib.sdf_set_namevalue(block, names, vals)
639
-
640
- self._add_post(block)
641
-
642
- def _add_array(self, name, value=(), datatype=None, id=None):
643
- if datatype == SdfDataType.SDF_DATATYPE_CHARACTER:
644
- print(f'Block "{id}", unsupported datatype: {type(value[0])}')
645
- return
646
-
647
- h, block = self._add_preamble(id, name, datatype)
648
- block.blocktype = SdfBlockType.SDF_BLOCKTYPE_ARRAY
649
- block.AddBlock = BlockArray
650
-
651
- block._data = np.array(value)
652
- block.ndims = block._data.ndim
653
- for i in range(block.ndims):
654
- block.dims[i] = block._data.shape[i]
655
- block.data = block._data.ctypes.data_as(ct.c_void_p)
656
-
657
- self._add_post(block)
658
-
659
- def _add_plainvar(
660
- self,
661
- name,
662
- value=(),
663
- datatype=None,
664
- id=None,
665
- mult=None,
666
- units=None,
667
- mesh_id=None,
668
- stagger=None,
669
- ):
670
- if datatype == SdfDataType.SDF_DATATYPE_CHARACTER:
671
- print(f'Block "{id}", unsupported datatype: {type(value[0])}')
672
- return
673
- try:
674
- mult = float(mult)
675
- except Exception:
676
- if mult is not None:
677
- print(f"ERROR: unable to use mult parameter, {mult}")
678
- return
679
- try:
680
- stagger = SdfStagger(stagger)
681
- except Exception:
682
- if stagger is not None:
683
- print(f"ERROR: unable to use stagger parameter, {stagger}")
684
- return
685
- if units is not None and not isinstance(units, str):
686
- print(f"ERROR: unable to use units parameter, {units}")
687
- return
688
- if mesh_id is not None and not isinstance(mesh_id, str):
689
- print(f"ERROR: unable to use mesh_id parameter, {mesh_id}")
690
- return
691
-
692
- h, block = self._add_preamble(id, name, datatype)
693
- block.blocktype = SdfBlockType.SDF_BLOCKTYPE_PLAIN_VARIABLE
694
- block.AddBlock = BlockPlainVariable
695
-
696
- block._data = np.array(value, order="F")
697
- block.ndims = block._data.ndim
698
- for i in range(block.ndims):
699
- block.dims[i] = block._data.shape[i]
700
- block.data = block._data.ctypes.data_as(ct.c_void_p)
701
- if mult is not None:
702
- block.mult = mult
703
- if isinstance(units, str):
704
- block.units = self._create_id(units)
705
- if isinstance(mesh_id, str):
706
- block.mesh_id = self._create_id(mesh_id)
707
- if stagger:
708
- block.stagger = stagger
709
-
710
- self._clib.sdf_set_defaults(self._handle, block)
711
- self._add_post(block)
712
-
713
- def _add_mesh(
714
- self,
715
- name,
716
- value=None,
717
- datatype=None,
718
- id=None,
719
- units=None,
720
- labels=None,
721
- geometry=None,
722
- **kwargs,
723
- ):
724
- if datatype == SdfDataType.SDF_DATATYPE_CHARACTER:
725
- print(f'Block "{id}", unsupported datatype: {type(value[0])}')
726
- return
727
-
728
- h, block = self._add_preamble(id, name, datatype)
729
-
730
- keys = ["x", "y", "z"]
731
- keys = [k for k in keys if k in kwargs and kwargs[k] is not None]
732
- val = np.concatenate([kwargs[k] for k in keys]).flatten()[0]
733
-
734
- block._data = [np.array(kwargs[k], dtype=val.dtype) for k in keys]
735
- block._data = [np.array(row, order="F") for row in block._data]
736
- block._data = tuple(block._data)
737
- block.ndims = len(block._data)
738
- block.ngrids = block.ndims
739
- grids = [row.ctypes.data_as(ct.c_void_p) for row in block._data]
740
- block.grids = (ct.c_void_p * block.ngrids)(*grids)
741
- if block._data[0].ndim == 1:
742
- block.blocktype = SdfBlockType.SDF_BLOCKTYPE_PLAIN_MESH
743
- block.AddBlock = BlockPlainMesh
744
- for i in range(block.ndims):
745
- block.dims[i] = block._data[i].shape[0]
746
- else:
747
- block.blocktype = SdfBlockType.SDF_BLOCKTYPE_LAGRANGIAN_MESH
748
- block.AddBlock = BlockLagrangianMesh
749
- for i in range(block.ndims):
750
- block.dims[i] = block._data[0].shape[i]
751
- if isinstance(units, (list, tuple)):
752
- block.dim_units = self._create_id_array(units)
753
- if isinstance(labels, (list, tuple)):
754
- block.dim_labels = self._create_id_array(labels)
755
- if isinstance(geometry, str):
756
- if geometry == "rz":
757
- geometry = SdfGeometry.SDF_GEOMETRY_CYLINDRICAL
758
- if isinstance(geometry, int):
759
- block.geometry = geometry
760
-
761
- self._clib.sdf_set_defaults(self._handle, block)
762
- self._add_post(block)
763
-
764
- def add_block(self, name, value=None, id=None, **kwargs):
765
- if isinstance(value, dict):
766
- val = next(iter(value.values()), None)
767
- add_func = self._add_namevalue
768
- elif isinstance(value, (tuple, list, np.ndarray)):
769
- arr = np.array(value)
770
- if arr.ndim == 1:
771
- val = value[0]
772
- add_func = self._add_array
773
- else:
774
- val = arr.flatten()[0]
775
- add_func = self._add_plainvar
776
- elif value is not None:
777
- val = value
778
- add_func = self._add_constant
779
- else:
780
- keys = ["x", "y", "z"]
781
- keys = [k for k in keys if k in kwargs and kwargs[k] is not None]
782
- val = np.concatenate([kwargs[k] for k in keys]).flatten()[0]
783
- add_func = self._add_mesh
784
- if id is None:
785
- id = "grid"
786
-
787
- if id is None:
788
- id = name
789
- if id in self._block_ids:
790
- print(f'Unable to create block. ID duplicated: "{id}"')
791
- return
792
-
793
- datatype = None
794
- if isinstance(val, bool):
795
- datatype = SdfDataType.SDF_DATATYPE_LOGICAL
796
- elif isinstance(val, np.int32):
797
- datatype = SdfDataType.SDF_DATATYPE_INTEGER4
798
- elif isinstance(val, (int, np.int64)):
799
- datatype = SdfDataType.SDF_DATATYPE_INTEGER8
800
- elif isinstance(val, np.float32):
801
- datatype = SdfDataType.SDF_DATATYPE_REAL4
802
- elif isinstance(val, float):
803
- datatype = SdfDataType.SDF_DATATYPE_REAL8
804
- elif isinstance(val, str):
805
- datatype = SdfDataType.SDF_DATATYPE_CHARACTER
806
- else:
807
- add_func = None
808
-
809
- if add_func:
810
- add_func(name, value=value, id=id, datatype=datatype, **kwargs)
811
- else:
812
- print(f'Block "{id}", unsupported datatype: {type(value)}')
813
- return
680
+ def _create_string_array(self, values):
681
+ values = self._string_array_ctype(values)
682
+ res = self._clib.sdf_create_string_array(
683
+ self._handle, len(values), values
684
+ )
685
+ return res
814
686
 
815
687
  @property
816
688
  def name_dict(self):
@@ -831,25 +703,31 @@ class Block:
831
703
 
832
704
  def __init__(self, block):
833
705
  self._handle = block._handle
834
- self._id = block.id.decode()
835
- self._name = block.name.decode()
706
+ if block.id_orig:
707
+ self._id = block.id_orig.decode()
708
+ self._name = block.name_orig.decode()
709
+ else:
710
+ self._id = block.id.decode()
711
+ self._name = block.name.decode()
836
712
  self._datatype = _np_datatypes[block.datatype_out]
837
713
  self._data_length = block.data_length
838
714
  self._dims = tuple(block.dims[: block.ndims])
839
715
  self._contents = block
840
716
  self._blocklist = block._blocklist
717
+ self._in_file = block.in_file
841
718
  self._data = None
719
+ self._grid = None
842
720
 
843
721
  def _numpy_from_buffer(self, data, blen):
844
- buffer_from_memory = ct.pythonapi.PyMemoryView_FromMemory
845
- buffer_from_memory.restype = ct.py_object
722
+ buffer_from_memory = _c.pythonapi.PyMemoryView_FromMemory
723
+ buffer_from_memory.restype = _c.py_object
846
724
  dtype = self._datatype
847
- if dtype == np.byte:
848
- dtype = np.dtype("|S1")
725
+ if dtype == _np.byte:
726
+ dtype = _np.dtype("|S1")
849
727
  totype = _ct_datatypes[self._contents.datatype_out]
850
- cast = ct.cast(data, ct.POINTER(totype))
728
+ cast = _c.cast(data, _c.POINTER(totype))
851
729
  buf = buffer_from_memory(cast, blen)
852
- return np.frombuffer(buf, dtype)
730
+ return _np.frombuffer(buf, dtype)
853
731
 
854
732
  @property
855
733
  def blocklist(self):
@@ -887,6 +765,73 @@ class Block:
887
765
  return self._name
888
766
 
889
767
 
768
+ class BlockRunInfo(Block, dict):
769
+ """Run info block"""
770
+
771
+ def __init__(self, block, info=None):
772
+ import datetime
773
+ from datetime import datetime as dtm
774
+
775
+ if isinstance(block, Block):
776
+ block = block._contents
777
+
778
+ Block.__init__(self, block)
779
+
780
+ if info is not None:
781
+ self._run_info = self._build_info(info)
782
+ block.data = _c.cast(_c.byref(self._run_info), _c.c_void_p)
783
+
784
+ utc = datetime.timezone.utc
785
+
786
+ h = _c.cast(block.data, _c.POINTER(RunInfo)).contents
787
+
788
+ self._dict = {
789
+ "version": f"{h.version}.{h.revision}.{h.minor_rev}",
790
+ "commit_id": h.commit_id.decode(),
791
+ "sha1sum": h.sha1sum.decode(),
792
+ "compile_machine": h.compile_machine.decode(),
793
+ "compile_flags": h.compile_flags.decode(),
794
+ "compile_date": dtm.fromtimestamp(h.compile_date, utc).strftime(
795
+ "%c"
796
+ ),
797
+ "run_date": dtm.fromtimestamp(h.run_date, utc).strftime("%c"),
798
+ "io_date": dtm.fromtimestamp(h.io_date, utc).strftime("%c"),
799
+ }
800
+
801
+ dict.__init__(self, self._dict)
802
+
803
+ def _build_info(self, info):
804
+ import datetime as dtm
805
+ import dateutil.parser as dtp
806
+
807
+ run_info = RunInfo()
808
+ fields = [f[0] for f in run_info._fields_]
809
+ for f in run_info._fields_:
810
+ if f[1] == _c.c_char_p:
811
+ setattr(run_info, f[0], "".encode())
812
+ else:
813
+ setattr(run_info, f[0], 0)
814
+ k = "version"
815
+ if k in info and isinstance(info[k], str):
816
+ ver = [int(s) for s in info[k].split(".")]
817
+ info[k] = ver[0]
818
+ if len(ver) > 1:
819
+ info["revision"] = ver[1]
820
+ if len(ver) > 2:
821
+ info["minor_rev"] = ver[2]
822
+ for k, v in info.items():
823
+ if k.endswith("_date"):
824
+ if isinstance(v, str):
825
+ date = dtp.parse(v)
826
+ date = date.replace(tzinfo=dtm.timezone.utc)
827
+ v = int(date.timestamp())
828
+ elif isinstance(v, dtm.datetime):
829
+ v = int(v.timestamp())
830
+ if k in fields:
831
+ setattr(run_info, k, v)
832
+ return run_info
833
+
834
+
890
835
  class BlockConstant(Block):
891
836
  """Constant block"""
892
837
 
@@ -907,7 +852,7 @@ class BlockPlainVariable(Block):
907
852
  if self._data is None:
908
853
  clib = self._handle._clib
909
854
  clib.sdf_helper_read_data(self._handle, self._contents)
910
- blen = np.dtype(self._datatype).itemsize
855
+ blen = _np.dtype(self._datatype).itemsize
911
856
  for d in self.dims:
912
857
  blen *= d
913
858
  array = self._numpy_from_buffer(self._contents.data, blen)
@@ -964,6 +909,7 @@ class BlockPlainMesh(Block):
964
909
  self._id += "_mid"
965
910
  self._name += "_mid"
966
911
  self._dims = tuple([i - 1 for i in self._dims])
912
+ self._in_file = False
967
913
  if bool(block.dim_mults):
968
914
  self._mult = tuple(block.dim_mults[: block.ndims])
969
915
  if bool(block.extents):
@@ -977,7 +923,7 @@ class BlockPlainMesh(Block):
977
923
  clib.sdf_helper_read_data(self._handle, self._contents)
978
924
  grids = []
979
925
  for i, d in enumerate(self._bdims):
980
- blen = np.dtype(self._datatype).itemsize * d
926
+ blen = _np.dtype(self._datatype).itemsize * d
981
927
  array = self._numpy_from_buffer(self._contents.grids[i], blen)
982
928
  if self._mid:
983
929
  array = 0.5 * (array[1:] + array[:-1])
@@ -1020,7 +966,7 @@ class BlockLagrangianMesh(BlockPlainMesh):
1020
966
  if self._data is None:
1021
967
  clib = self._handle._clib
1022
968
  clib.sdf_helper_read_data(self._handle, self._contents)
1023
- blen = np.dtype(self._datatype).itemsize
969
+ blen = _np.dtype(self._datatype).itemsize
1024
970
  for d in self._bdims:
1025
971
  blen *= d
1026
972
  grids = []
@@ -1067,13 +1013,13 @@ class BlockNameValue(Block):
1067
1013
  vals = {}
1068
1014
  for n in range(block.ndims):
1069
1015
  val = None
1070
- if block.datatype == SdfDataType.SDF_DATATYPE_CHARACTER:
1071
- p = ct.cast(block.data, ct.POINTER(ct.c_char_p))
1016
+ if block.datatype == SdfDataType.CHARACTER:
1017
+ p = _c.cast(block.data, _c.POINTER(_c.c_char_p))
1072
1018
  val = p[n].decode()
1073
1019
  else:
1074
1020
  dt = _ct_datatypes[block.datatype]
1075
- val = ct.cast(block.data, ct.POINTER(dt))[n]
1076
- nid = get_member_name(block.material_names[n])
1021
+ val = _c.cast(block.data, _c.POINTER(dt))[n]
1022
+ nid = _get_member_name(block.material_names[n])
1077
1023
  vals[nid] = val
1078
1024
  self.__dict__[nid] = val
1079
1025
  self._data = vals
@@ -1088,7 +1034,7 @@ class BlockArray(Block):
1088
1034
  if self._data is None:
1089
1035
  clib = self._handle._clib
1090
1036
  clib.sdf_helper_read_data(self._handle, self._contents)
1091
- blen = np.dtype(self._datatype).itemsize
1037
+ blen = _np.dtype(self._datatype).itemsize
1092
1038
  for d in self.dims:
1093
1039
  blen *= d
1094
1040
  array = self._numpy_from_buffer(self._contents.data, blen)
@@ -1112,7 +1058,7 @@ class BlockData(Block):
1112
1058
  clib = self._handle._clib
1113
1059
  clib.sdf_helper_read_data(self._handle, self._contents)
1114
1060
  blen = self._contents.data_length
1115
- _data = ct.cast(self._contents.data, ct.POINTER(ct.c_char * blen))
1061
+ _data = _c.cast(self._contents.data, _c.POINTER(_c.c_char * blen))
1116
1062
  self._data = _data.contents[:]
1117
1063
  return self._data
1118
1064
 
@@ -1132,7 +1078,7 @@ class BlockData(Block):
1132
1078
  return self._mimetype
1133
1079
 
1134
1080
 
1135
- def BlockStation(block, name):
1081
+ def _BlockStation(block, name):
1136
1082
  """Station block"""
1137
1083
  sdict = dict(
1138
1084
  stations=None,
@@ -1173,9 +1119,24 @@ class BlockStitched(Block):
1173
1119
  vid = self._contents.variable_ids[i]
1174
1120
  if len(vid) > 0:
1175
1121
  vid = vid.decode()
1176
- self._data.append(self._blocklist._block_ids[vid])
1122
+ if vid in self._blocklist._block_ids:
1123
+ self._data.append(self._blocklist._block_ids[vid])
1124
+ else:
1125
+ self._data.append(None)
1126
+ else:
1127
+ self._data.append(None)
1177
1128
  return self._data
1178
1129
 
1130
+ @property
1131
+ def grid(self):
1132
+ """Associated mesh"""
1133
+ return self._grid
1134
+
1135
+ @property
1136
+ def grid_id(self):
1137
+ """Associated mesh id"""
1138
+ return self._contents.mesh_id.decode()
1139
+
1179
1140
 
1180
1141
  class BlockStitchedPath(BlockStitched):
1181
1142
  """Stitched path block"""
@@ -1186,19 +1147,40 @@ class BlockStitchedPath(BlockStitched):
1186
1147
  class BlockStitchedMaterial(BlockStitched):
1187
1148
  """Stitched material block"""
1188
1149
 
1189
- pass
1150
+ @property
1151
+ def material_names(self):
1152
+ """Material names"""
1153
+ b = self._contents
1154
+ return [b.material_names[i].decode() for i in range(b.ndims)]
1190
1155
 
1191
1156
 
1192
1157
  class BlockStitchedMatvar(BlockStitched):
1193
1158
  """Stitched material variable block"""
1194
1159
 
1195
- pass
1160
+ @property
1161
+ def material_id(self):
1162
+ """Material ID"""
1163
+ return self._contents.material_id.decode()
1196
1164
 
1197
1165
 
1198
1166
  class BlockStitchedSpecies(BlockStitched):
1199
1167
  """Stitched species block"""
1200
1168
 
1201
- pass
1169
+ @property
1170
+ def material_id(self):
1171
+ """Material ID"""
1172
+ return self._contents.material_id.decode()
1173
+
1174
+ @property
1175
+ def material_name(self):
1176
+ """Material name"""
1177
+ return self._contents.material_name.decode()
1178
+
1179
+ @property
1180
+ def material_names(self):
1181
+ """Species names"""
1182
+ b = self._contents
1183
+ return [b.material_names[i].decode() for i in range(b.ndims)]
1202
1184
 
1203
1185
 
1204
1186
  class BlockStitchedTensor(BlockStitched):
@@ -1207,63 +1189,63 @@ class BlockStitchedTensor(BlockStitched):
1207
1189
  pass
1208
1190
 
1209
1191
 
1210
- def get_header(h):
1211
- d = {}
1212
- if h.filename:
1213
- d["filename"] = h.filename.decode()
1214
- d["file_version"] = h.file_version
1215
- d["file_revision"] = h.file_revision
1216
- if h.code_name:
1217
- d["code_name"] = h.code_name.decode()
1218
- d["step"] = h.step
1219
- d["time"] = h.time
1220
- d["jobid1"] = h.jobid1
1221
- d["jobid2"] = h.jobid2
1222
- d["code_io_version"] = h.code_io_version
1223
- d["restart_flag"] = h.restart_flag
1224
- d["other_domains"] = h.other_domains
1225
- d["station_file"] = h.station_file
1226
- return d
1227
-
1228
-
1229
- def get_run_info(block):
1230
- import datetime
1231
- from datetime import datetime as dtm
1232
-
1233
- utc = datetime.timezone.utc
1234
-
1235
- h = ct.cast(block.data, ct.POINTER(RunInfo)).contents
1236
- d = {}
1237
- d["version"] = f"{h.version}.{h.revision}.{h.minor_rev}"
1238
- d["commit_id"] = h.commit_id.decode()
1239
- d["sha1sum"] = h.sha1sum.decode()
1240
- d["compile_machine"] = h.compile_machine.decode()
1241
- d["compile_flags"] = h.compile_flags.decode()
1242
- d["compile_date"] = dtm.fromtimestamp(h.compile_date, utc).strftime("%c")
1243
- d["run_date"] = dtm.fromtimestamp(h.run_date, utc).strftime("%c")
1244
- d["io_data"] = dtm.fromtimestamp(h.io_date, utc).strftime("%c")
1245
- return d
1246
-
1247
-
1248
- def get_member_name(name):
1192
+ class BlockCpuSplit(Block):
1193
+ """CPU split block"""
1194
+
1195
+ def __init__(self, block):
1196
+ super().__init__(block)
1197
+ nelements = 0
1198
+ if self._contents.geometry in (1, 4):
1199
+ nelements = sum(self.dims)
1200
+ elif self._contents.geometry == 2:
1201
+ nelements, adim = 0, []
1202
+ for dim in self.dims:
1203
+ adim.append(dim)
1204
+ nelements += _np.prod(adim)
1205
+ elif self._contents.geometry == 3:
1206
+ nelements = _np.prod(self.dims)
1207
+ else:
1208
+ raise Exception("CPU split geometry not supported")
1209
+ self._contents.nelements = nelements
1210
+
1211
+ @property
1212
+ def data(self):
1213
+ """Block data contents"""
1214
+ if self._data is None:
1215
+ clib = self._handle._clib
1216
+ clib.sdf_helper_read_data(self._handle, self._contents)
1217
+ nelements = self._contents.nelements
1218
+ blen = _np.dtype(self._datatype).itemsize * nelements
1219
+ array = self._numpy_from_buffer(self._contents.data, blen)
1220
+ if self._contents.geometry in (1, 4):
1221
+ d0, data = 0, []
1222
+ for dim in self.dims:
1223
+ d1 = d0 + dim
1224
+ data.append(array[d0:d1])
1225
+ d0 = d1
1226
+ self._data = tuple(data)
1227
+ elif self._contents.geometry == 2:
1228
+ d0, data, adim = 0, [], []
1229
+ for dim in self.dims:
1230
+ adim.append(dim)
1231
+ d1 = d0 + _np.prod(adim)
1232
+ data.append(array[d0:d1].reshape(adim, order="F"))
1233
+ d0 = d1
1234
+ self._data = tuple(data)
1235
+ elif self._contents.geometry == 3:
1236
+ self._data = array.reshape(self.dims, order="F")
1237
+ return self._data
1238
+
1239
+
1240
+ _re_pattern = _re.compile(r"[^a-zA-Z0-9]")
1241
+
1242
+
1243
+ def _get_member_name(name):
1249
1244
  sname = name.decode()
1250
- return "".join(
1251
- [
1252
- (
1253
- i
1254
- if (
1255
- (i >= "a" and i <= "z")
1256
- or (i >= "A" and i <= "Z")
1257
- or (i >= "0" and i <= "9")
1258
- )
1259
- else "_"
1260
- )
1261
- for i in sname
1262
- ]
1263
- )
1245
+ return _re_pattern.sub("_", sname)
1264
1246
 
1265
1247
 
1266
- def read(file=None, convert=False, mmap=0, dict=False, derived=True):
1248
+ def _read(file=None, convert=False, mmap=0, dict=False, derived=True):
1267
1249
  """Reads the SDF data and returns a dictionary of NumPy arrays.
1268
1250
 
1269
1251
  Parameters
@@ -1297,7 +1279,7 @@ def read(file=None, convert=False, mmap=0, dict=False, derived=True):
1297
1279
  return blocklist
1298
1280
 
1299
1281
 
1300
- def new(dict=False, code_name="sdfr", restart=False):
1282
+ def _new(dict=False, code_name="sdfr", restart=False):
1301
1283
  """Creates a new SDF blocklist and returns a dictionary of NumPy arrays.
1302
1284
 
1303
1285
  Parameters
@@ -1306,7 +1288,9 @@ def new(dict=False, code_name="sdfr", restart=False):
1306
1288
  Return file contents as a dictionary rather than member names.
1307
1289
  """
1308
1290
 
1309
- blocklist = BlockList(mode=SDF_WRITE, code_name=code_name, restart=restart)
1291
+ blocklist = BlockList(
1292
+ mode=SdfMode.WRITE, code_name=code_name, restart=restart
1293
+ )
1310
1294
 
1311
1295
  if isinstance(dict, str):
1312
1296
  if dict == "id" or dict == "ids":
@@ -1315,3 +1299,701 @@ def new(dict=False, code_name="sdfr", restart=False):
1315
1299
  return blocklist._block_names
1316
1300
 
1317
1301
  return blocklist
1302
+
1303
+
1304
+ def _get_md5(data):
1305
+ return _hashlib.md5(data).hexdigest()
1306
+
1307
+
1308
+ def _get_sha(data):
1309
+ sha = _hashlib.sha256()
1310
+ try:
1311
+ with _io.BytesIO(data) as buf:
1312
+ with _tarfile.open(mode="r:*", fileobj=buf) as file:
1313
+ for name in sorted(file.getnames()):
1314
+ fd = file.extractfile(name)
1315
+ if fd:
1316
+ sha.update(fd.read())
1317
+ fd.close()
1318
+ except Exception:
1319
+ try:
1320
+ sha.update(_gzip.decompress(data))
1321
+ except Exception:
1322
+ sha.update(data)
1323
+ return sha.hexdigest()
1324
+
1325
+
1326
+ def _get_tarfile_data(source=None):
1327
+ if not source or not _os.path.exists(source):
1328
+ return source
1329
+ if _os.path.isdir(source):
1330
+ buf = _io.BytesIO()
1331
+ with _tarfile.open("out", "w:gz", fileobj=buf) as tar:
1332
+ tar.add(source)
1333
+ buf.seek(0)
1334
+ return buf.read()
1335
+ else:
1336
+ with open(source, "rb") as fd:
1337
+ return fd.read()
1338
+
1339
+
1340
+ def _get_mimetype(data):
1341
+ try:
1342
+ _ = _gzip.decompress(data)
1343
+ return "application/gzip"
1344
+ except Exception:
1345
+ pass
1346
+ try:
1347
+ buf = _io.BytesIO(data)
1348
+ _ = _tarfile.open(mode="r:*", fileobj=buf)
1349
+ return "application/tar"
1350
+ except Exception:
1351
+ return "text/plain"
1352
+
1353
+
1354
+ def _get_checksum_info(value=None, checksum_type=None):
1355
+ if not value:
1356
+ return None, None, None, value
1357
+ data = _get_tarfile_data(value)
1358
+ mimetype = _get_mimetype(data)
1359
+ if checksum_type is None:
1360
+ if mimetype == "text/plain":
1361
+ checksum_type = "md5"
1362
+ else:
1363
+ checksum_type = "sha256"
1364
+ if checksum_type == "md5":
1365
+ checksum = _get_md5(data)
1366
+ else:
1367
+ checksum = _get_sha(data)
1368
+
1369
+ return checksum, checksum_type, mimetype, data
1370
+
1371
+
1372
+ def _add_preamble(blocklist, id, name, datatype):
1373
+ blocklist._clib.sdf_get_next_block(blocklist._handle)
1374
+ h = blocklist._handle.contents
1375
+ h.nblocks += 1
1376
+ h.nblocks_file += 1
1377
+ block = h.current_block.contents
1378
+ block._handle = blocklist._handle
1379
+ block._blocklist = h.blocklist
1380
+ block._data = None
1381
+ block.datatype = datatype
1382
+ block.in_file = 1
1383
+ block.AddBlock = None
1384
+ blocklist._set_block_name(id, name)
1385
+ return h, block
1386
+
1387
+
1388
+ def _add_post(blocklist, block, extra=None):
1389
+ if block.AddBlock:
1390
+ if extra is None:
1391
+ newblock = block.AddBlock(block)
1392
+ else:
1393
+ newblock = block.AddBlock(block, extra)
1394
+ else:
1395
+ return
1396
+
1397
+ id = block.id.decode()
1398
+ name = block.name.decode()
1399
+ if not block.dont_display:
1400
+ blocklist.__dict__[name] = newblock
1401
+ if block._data is not None:
1402
+ newblock._data = block._data
1403
+ blocklist._block_ids.update({id: newblock})
1404
+ blocklist._block_names.update({name: newblock})
1405
+
1406
+
1407
+ def _add_constant(blocklist, name, value=0, datatype=None, id=None):
1408
+ h, block = _add_preamble(blocklist, id, name, datatype)
1409
+ block.blocktype = SdfBlockType.CONSTANT
1410
+ block.AddBlock = BlockConstant
1411
+
1412
+ const_value = _struct.pack(_st_datatypes[block.datatype], value)
1413
+ _c.memmove(block.const_value, const_value, 16)
1414
+
1415
+ _add_post(blocklist, block)
1416
+
1417
+
1418
+ def _add_namevalue(blocklist, name, value={}, datatype=None, id=None):
1419
+ h, block = _add_preamble(blocklist, id, name, datatype)
1420
+ block.blocktype = SdfBlockType.NAMEVALUE
1421
+ block.AddBlock = BlockNameValue
1422
+
1423
+ nvalue = len(value)
1424
+ block.ndims = nvalue
1425
+ ctype = _ct_datatypes[block.datatype]
1426
+ if block.datatype == SdfDataType.CHARACTER:
1427
+ vals = blocklist._string_array_ctype(value.values())
1428
+ else:
1429
+ vals = (ctype * nvalue)(*value.values())
1430
+ names = blocklist._string_array_ctype(value.keys())
1431
+ vals = _c.cast(vals, _c.POINTER(_c.c_void_p))
1432
+ blocklist._clib.sdf_set_namevalue(block, names, vals)
1433
+
1434
+ _add_post(blocklist, block)
1435
+
1436
+
1437
+ def _add_array(blocklist, name, value=(), datatype=None, id=None):
1438
+ h, block = _add_preamble(blocklist, id, name, datatype)
1439
+ block.blocktype = SdfBlockType.ARRAY
1440
+ block.AddBlock = BlockArray
1441
+
1442
+ block._data = _np.array(value)
1443
+ block.ndims = block._data.ndim
1444
+ for i in range(block.ndims):
1445
+ block.dims[i] = block._data.shape[i]
1446
+ block.data = block._data.ctypes.data_as(_c.c_void_p)
1447
+
1448
+ _add_post(blocklist, block)
1449
+
1450
+
1451
+ def _add_cpu_split(
1452
+ blocklist, name, value=(), id=None, datatype=None, geometry=1
1453
+ ):
1454
+ from itertools import chain
1455
+
1456
+ if not isinstance(blocklist, BlockList):
1457
+ print("ERROR: first argument must be of type BlockList")
1458
+ return
1459
+ if id is None:
1460
+ id = name
1461
+ if datatype is None:
1462
+ if geometry == 4:
1463
+ datatype = SdfDataType.INTEGER8
1464
+ else:
1465
+ datatype = SdfDataType.INTEGER4
1466
+ h, block = _add_preamble(blocklist, id, name, datatype)
1467
+ block.blocktype = SdfBlockType.CPU_SPLIT
1468
+ block.AddBlock = BlockCpuSplit
1469
+
1470
+ dtype = _np_datatypes[datatype]
1471
+ block._data = _np.asarray(list(chain.from_iterable(value)), dtype=dtype)
1472
+ block.ndims = len(value)
1473
+ block.geometry = geometry
1474
+ dims = []
1475
+ for i in range(block.ndims):
1476
+ dims.append(len(value[i]))
1477
+ block.dims[i] = len(value[i])
1478
+
1479
+ block.data = block._data.ctypes.data_as(_c.c_void_p)
1480
+
1481
+ _add_post(blocklist, block)
1482
+
1483
+
1484
+ def _add_datablock(
1485
+ blocklist,
1486
+ name,
1487
+ value=(),
1488
+ id=None,
1489
+ checksum=None,
1490
+ checksum_type=None,
1491
+ mimetype=None,
1492
+ datatype=None,
1493
+ ):
1494
+ datatype = SdfDataType.CHARACTER
1495
+ h, block = _add_preamble(blocklist, id, name, datatype)
1496
+ block.blocktype = SdfBlockType.DATABLOCK
1497
+ block.AddBlock = BlockData
1498
+
1499
+ if not checksum:
1500
+ checksum, checksum_type, mimetype, value = _get_checksum_info(
1501
+ value, checksum_type
1502
+ )
1503
+
1504
+ if isinstance(checksum, str):
1505
+ block.checksum = blocklist._create_string(checksum)
1506
+ if isinstance(checksum_type, str):
1507
+ block.checksum_type = blocklist._create_id(checksum_type)
1508
+ if isinstance(mimetype, str):
1509
+ block.mimetype = blocklist._create_id(mimetype)
1510
+
1511
+ block._data = _np.array(value)
1512
+ block.ndims = 0
1513
+ block.nelements = len(value)
1514
+ block.data = block._data.ctypes.data_as(_c.c_void_p)
1515
+
1516
+ _add_post(blocklist, block)
1517
+
1518
+
1519
+ def _add_plainvar(
1520
+ blocklist,
1521
+ name,
1522
+ value=(),
1523
+ datatype=None,
1524
+ id=None,
1525
+ mult=None,
1526
+ units=None,
1527
+ mesh_id=None,
1528
+ stagger=None,
1529
+ species=None,
1530
+ ):
1531
+ try:
1532
+ mult = float(mult)
1533
+ except Exception:
1534
+ if mult is not None:
1535
+ print(f"ERROR: unable to use mult parameter, {mult}")
1536
+ return
1537
+ try:
1538
+ stagger = SdfStagger(stagger)
1539
+ except Exception:
1540
+ if stagger is not None:
1541
+ print(f"ERROR: unable to use stagger parameter, {stagger}")
1542
+ return
1543
+ if units is not None and not isinstance(units, str):
1544
+ print(f"ERROR: unable to use units parameter, {units}")
1545
+ return
1546
+ if mesh_id is not None and not isinstance(mesh_id, str):
1547
+ print(f"ERROR: unable to use mesh_id parameter, {mesh_id}")
1548
+ return
1549
+
1550
+ h, block = _add_preamble(blocklist, id, name, datatype)
1551
+
1552
+ block._data = _np.array(value, order="F")
1553
+ block.ndims = block._data.ndim
1554
+
1555
+ if block.ndims == 1 and isinstance(species, str):
1556
+ block.blocktype = SdfBlockType.POINT_VARIABLE
1557
+ block.AddBlock = BlockPointVariable
1558
+ block.material_id = blocklist._create_id(species)
1559
+ else:
1560
+ block.blocktype = SdfBlockType.PLAIN_VARIABLE
1561
+ block.AddBlock = BlockPlainVariable
1562
+
1563
+ for i in range(block.ndims):
1564
+ block.dims[i] = block._data.shape[i]
1565
+ block.data = block._data.ctypes.data_as(_c.c_void_p)
1566
+ if mult is not None:
1567
+ block.mult = mult
1568
+ if isinstance(units, str):
1569
+ block.units = blocklist._create_id(units)
1570
+ if isinstance(mesh_id, str):
1571
+ block.mesh_id = blocklist._create_id(mesh_id)
1572
+ if stagger:
1573
+ block.stagger = stagger
1574
+
1575
+ blocklist._clib.sdf_set_defaults(blocklist._handle, block)
1576
+ _add_post(blocklist, block)
1577
+
1578
+
1579
+ def _add_mesh(
1580
+ blocklist,
1581
+ name,
1582
+ value=None,
1583
+ datatype=None,
1584
+ id=None,
1585
+ units=None,
1586
+ labels=None,
1587
+ geometry=None,
1588
+ species=None,
1589
+ **kwargs,
1590
+ ):
1591
+ h, block = _add_preamble(blocklist, id, name, datatype)
1592
+
1593
+ keys = ["x", "y", "z"]
1594
+ keys = [k for k in keys if k in kwargs and kwargs[k] is not None]
1595
+ val = _np.concatenate([kwargs[k] for k in keys]).flatten()[0]
1596
+
1597
+ block._data = [_np.array(kwargs[k], dtype=val.dtype) for k in keys]
1598
+ block._data = [_np.array(row, order="F") for row in block._data]
1599
+ block._data = tuple(block._data)
1600
+ block.ndims = len(block._data)
1601
+ block.ngrids = block.ndims
1602
+ grids = [row.ctypes.data_as(_c.c_void_p) for row in block._data]
1603
+ block.grids = (_c.c_void_p * block.ngrids)(*grids)
1604
+ if block._data[0].ndim == 1:
1605
+ block.blocktype = SdfBlockType.PLAIN_MESH
1606
+ block.AddBlock = BlockPlainMesh
1607
+ for i in range(block.ndims):
1608
+ block.dims[i] = block._data[i].shape[0]
1609
+ if isinstance(species, str):
1610
+ block.blocktype = SdfBlockType.POINT_MESH
1611
+ block.AddBlock = BlockPointMesh
1612
+ block.material_id = blocklist._create_id(species)
1613
+ else:
1614
+ block.blocktype = SdfBlockType.LAGRANGIAN_MESH
1615
+ block.AddBlock = BlockLagrangianMesh
1616
+ for i in range(block.ndims):
1617
+ block.dims[i] = block._data[0].shape[i]
1618
+ if isinstance(units, str):
1619
+ units = (units,)
1620
+ if isinstance(units, (list, tuple)):
1621
+ block.dim_units = blocklist._create_id_array(units)
1622
+ if isinstance(labels, str):
1623
+ labels = (labels,)
1624
+ if isinstance(labels, (list, tuple)):
1625
+ block.dim_labels = blocklist._create_id_array(labels)
1626
+ if isinstance(geometry, str):
1627
+ if geometry == "rz":
1628
+ geometry = SdfGeometry.CYLINDRICAL
1629
+ if isinstance(geometry, int):
1630
+ block.geometry = geometry
1631
+
1632
+ blocklist._clib.sdf_set_defaults(blocklist._handle, block)
1633
+ _add_post(blocklist, block)
1634
+
1635
+
1636
+ def _add_stitched(
1637
+ blocklist,
1638
+ name,
1639
+ value={},
1640
+ id=None,
1641
+ mesh_id=None,
1642
+ btype=None,
1643
+ datatype=None,
1644
+ stagger=SdfStagger.HIDDEN0,
1645
+ material_id=None,
1646
+ material_name=None,
1647
+ material_names=None,
1648
+ ):
1649
+ if not isinstance(blocklist, BlockList):
1650
+ print("ERROR: first argument must be of type BlockList")
1651
+ return
1652
+ if not isinstance(value, (list, tuple)):
1653
+ print("ERROR: invalid value supplied for stitched block")
1654
+ return
1655
+ if not isinstance(mesh_id, str):
1656
+ found_mesh = None
1657
+ warn = True
1658
+ for val in value:
1659
+ if val in blocklist._block_ids:
1660
+ tmp = blocklist._block_ids[val]._contents.mesh_id
1661
+ if isinstance(tmp, bytes):
1662
+ tmp = tmp.decode()
1663
+ if warn and found_mesh is not None and found_mesh != tmp:
1664
+ print("WARNING: stitched blocks on different meshes")
1665
+ warn = False
1666
+ found_mesh = tmp
1667
+ else:
1668
+ print(f'WARNING: stitched id "{val}" not found in blocklist')
1669
+ if found_mesh is not None:
1670
+ mesh_id = found_mesh
1671
+ else:
1672
+ print("ERROR: no mesh_id supplied for stitched block")
1673
+ return
1674
+ if id is None:
1675
+ id = name
1676
+ if datatype is None:
1677
+ datatype = SdfDataType.NULL
1678
+ h, block = _add_preamble(blocklist, id, name, datatype)
1679
+
1680
+ if btype is None:
1681
+ btype = SdfBlockType.STITCHED
1682
+ block.blocktype = btype
1683
+
1684
+ if btype in (
1685
+ SdfBlockType.CONTIGUOUS_TENSOR,
1686
+ SdfBlockType.STITCHED_TENSOR,
1687
+ ):
1688
+ block.AddBlock = BlockStitchedTensor
1689
+ elif btype in (
1690
+ SdfBlockType.CONTIGUOUS_MATERIAL,
1691
+ SdfBlockType.STITCHED_MATERIAL,
1692
+ ):
1693
+ block.AddBlock = BlockStitchedMaterial
1694
+ block.material_names = blocklist._create_string_array(material_names)
1695
+ elif btype in (
1696
+ SdfBlockType.CONTIGUOUS_MATVAR,
1697
+ SdfBlockType.STITCHED_MATVAR,
1698
+ ):
1699
+ block.AddBlock = BlockStitchedMatvar
1700
+ block.material_id = blocklist._create_id(material_id)
1701
+ elif btype in (
1702
+ SdfBlockType.CONTIGUOUS_SPECIES,
1703
+ SdfBlockType.STITCHED_SPECIES,
1704
+ ):
1705
+ block.AddBlock = BlockStitchedSpecies
1706
+ block.material_id = blocklist._create_id(material_id)
1707
+ block.material_name = blocklist._create_string(material_name)
1708
+ block.material_names = blocklist._create_id_array(material_names)
1709
+ else:
1710
+ if stagger in (SdfStagger.HIDDEN0, SdfStagger.HIDDEN2):
1711
+ block.AddBlock = BlockStitchedPath
1712
+ else:
1713
+ block.AddBlock = BlockStitched
1714
+
1715
+ block.stagger = stagger
1716
+ nvalue = len(value)
1717
+ block.ndims = nvalue
1718
+ block.mesh_id = blocklist._create_id(mesh_id)
1719
+ block.variable_ids = blocklist._create_id_array(value)
1720
+ block._blocklist._block_ids = blocklist._block_ids
1721
+
1722
+ _add_post(blocklist, block)
1723
+
1724
+
1725
+ def _add_stitched_vector(blocklist, name, value={}, id=None, mesh_id=None):
1726
+ return _add_stitched(
1727
+ blocklist,
1728
+ name,
1729
+ value,
1730
+ id,
1731
+ mesh_id,
1732
+ btype=SdfBlockType.STITCHED_TENSOR,
1733
+ )
1734
+
1735
+
1736
+ def _add_stitched_material(
1737
+ blocklist, name, value={}, id=None, mesh_id=None, material_names=None
1738
+ ):
1739
+ return _add_stitched(
1740
+ blocklist,
1741
+ name,
1742
+ value,
1743
+ id,
1744
+ mesh_id,
1745
+ material_names=material_names,
1746
+ btype=SdfBlockType.STITCHED_MATERIAL,
1747
+ )
1748
+
1749
+
1750
+ def _add_stitched_matvar(
1751
+ blocklist, name, value={}, id=None, mesh_id=None, material_id=None
1752
+ ):
1753
+ return _add_stitched(
1754
+ blocklist,
1755
+ name,
1756
+ value,
1757
+ id,
1758
+ mesh_id,
1759
+ material_id=material_id,
1760
+ btype=SdfBlockType.STITCHED_MATVAR,
1761
+ )
1762
+
1763
+
1764
+ def _add_stitched_species(
1765
+ blocklist,
1766
+ name,
1767
+ value={},
1768
+ id=None,
1769
+ mesh_id=None,
1770
+ material_id=None,
1771
+ material_name=None,
1772
+ material_names=None,
1773
+ ):
1774
+ return _add_stitched(
1775
+ blocklist,
1776
+ name,
1777
+ value,
1778
+ id,
1779
+ mesh_id,
1780
+ material_id=material_id,
1781
+ material_name=material_name,
1782
+ material_names=material_names,
1783
+ btype=SdfBlockType.STITCHED_SPECIES,
1784
+ )
1785
+
1786
+
1787
+ def _add_runinfo(blocklist, name, value=None, **kwargs):
1788
+ if not isinstance(blocklist, BlockList):
1789
+ print("ERROR: first argument must be of type BlockList")
1790
+ return
1791
+ id = None
1792
+ args = None
1793
+ data = None
1794
+ if isinstance(value, Block):
1795
+ id = value.id
1796
+ name = value.name
1797
+ data = value._contents.data
1798
+ elif isinstance(name, dict) and value is None:
1799
+ args = name
1800
+ name = None
1801
+ else:
1802
+ args = value
1803
+
1804
+ if "id" in kwargs:
1805
+ id = kwargs["id"]
1806
+
1807
+ if name is None:
1808
+ name = "Run_info"
1809
+ if id is None:
1810
+ id = name.lower()
1811
+
1812
+ datatype = SdfDataType.CHARACTER
1813
+ h, block = _add_preamble(blocklist, id, name, datatype)
1814
+ block.blocktype = SdfBlockType.RUN_INFO
1815
+ block.AddBlock = BlockRunInfo
1816
+
1817
+ block.data = data
1818
+
1819
+ _add_post(blocklist, block, args)
1820
+
1821
+
1822
+ def _copy_block(blocklist, block=None, **kwargs):
1823
+ if not block._in_file:
1824
+ return
1825
+
1826
+ _ = block.data
1827
+ kwargs["value"] = block.data
1828
+ kwargs["id"] = block.id
1829
+ kwargs["name"] = block.name
1830
+ kwargs["datatype"] = SdfDataType(block._contents.datatype)
1831
+
1832
+ if isinstance(block, BlockConstant):
1833
+ _add_constant(blocklist, **kwargs)
1834
+ elif isinstance(block, BlockNameValue):
1835
+ _add_namevalue(blocklist, **kwargs)
1836
+ elif isinstance(block, BlockArray):
1837
+ _add_array(blocklist, **kwargs)
1838
+ elif isinstance(block, BlockRunInfo):
1839
+ kwargs["value"] = block
1840
+ _add_runinfo(blocklist, **kwargs)
1841
+ elif isinstance(block, BlockData):
1842
+ kwargs["checksum"] = block.checksum
1843
+ kwargs["checksum_type"] = block.checksum_type
1844
+ kwargs["mimetype"] = block.mimetype
1845
+ del kwargs["datatype"]
1846
+ _add_datablock(blocklist, **kwargs)
1847
+ elif isinstance(block, BlockPlainVariable):
1848
+ kwargs["mult"] = block.mult
1849
+ kwargs["units"] = block.units
1850
+ kwargs["mesh_id"] = block.grid_id
1851
+ kwargs["stagger"] = block.stagger
1852
+ if hasattr(block, "species_id"):
1853
+ kwargs["species"] = block.species_id
1854
+ _add_plainvar(blocklist, **kwargs)
1855
+ elif isinstance(block, BlockPlainMesh):
1856
+ if len(block.data) > 0:
1857
+ kwargs["x"] = block.data[0]
1858
+ if len(block.data) > 1:
1859
+ kwargs["y"] = block.data[1]
1860
+ if len(block.data) > 2:
1861
+ kwargs["z"] = block.data[2]
1862
+ if hasattr(block, "species_id"):
1863
+ kwargs["species"] = block.species_id
1864
+ kwargs["units"] = block.units
1865
+ kwargs["labels"] = block.labels
1866
+ kwargs["geometry"] = block.geometry
1867
+ _add_mesh(blocklist, **kwargs)
1868
+ elif isinstance(block, BlockStitched):
1869
+ b = block._contents
1870
+ btype = b.blocktype
1871
+ kwargs["mesh_id"] = b.mesh_id.decode()
1872
+ kwargs["value"] = [d.id if d else "" for d in block.data]
1873
+ kwargs["stagger"] = b.stagger
1874
+ kwargs["btype"] = btype
1875
+
1876
+ if btype in (
1877
+ SdfBlockType.CONTIGUOUS_MATERIAL,
1878
+ SdfBlockType.STITCHED_MATERIAL,
1879
+ ):
1880
+ kwargs["material_names"] = [
1881
+ b.material_names[i].decode() for i in range(b.ndims)
1882
+ ]
1883
+ elif btype in (
1884
+ SdfBlockType.CONTIGUOUS_MATVAR,
1885
+ SdfBlockType.STITCHED_MATVAR,
1886
+ ):
1887
+ kwargs["material_id"] = b.material_id.decode()
1888
+ elif btype in (
1889
+ SdfBlockType.CONTIGUOUS_SPECIES,
1890
+ SdfBlockType.STITCHED_SPECIES,
1891
+ ):
1892
+ kwargs["material_id"] = b.material_id.decode()
1893
+ kwargs["material_name"] = b.material_name.decode()
1894
+ kwargs["material_names"] = [
1895
+ b.material_names[i].decode() for i in range(b.ndims)
1896
+ ]
1897
+
1898
+ _add_stitched(blocklist, **kwargs)
1899
+ elif isinstance(block, BlockCpuSplit):
1900
+ kwargs["geometry"] = block._contents.geometry
1901
+ _add_cpu_split(blocklist, **kwargs)
1902
+ else:
1903
+ print(
1904
+ f'WARNING: block id "{block.id}" of type '
1905
+ f'"{type(block).__name__}" not supported'
1906
+ )
1907
+ return
1908
+
1909
+
1910
+ def _add_block(blocklist, name=None, value=None, id=None, **kwargs):
1911
+ if not isinstance(blocklist, BlockList):
1912
+ print("ERROR: first argument must be of type BlockList")
1913
+ return
1914
+ if isinstance(name, Block):
1915
+ return _copy_block(blocklist, block=name, value=value, id=id, **kwargs)
1916
+
1917
+ add_func = None
1918
+ if isinstance(value, dict):
1919
+ val = next(iter(value.values()), None)
1920
+ add_func = _add_namevalue
1921
+ elif isinstance(value, (tuple, list, _np.ndarray)):
1922
+ arr = _np.array(value)
1923
+ if arr.ndim == 1:
1924
+ val = value[0]
1925
+ if isinstance(arr[0], str):
1926
+ add_func = _add_stitched
1927
+ elif "species" in kwargs or "mesh_id" in kwargs:
1928
+ add_func = _add_plainvar
1929
+ else:
1930
+ add_func = _add_array
1931
+ else:
1932
+ val = arr.flatten()[0]
1933
+ add_func = _add_plainvar
1934
+ elif isinstance(value, (str, bytes)):
1935
+ val = value
1936
+ add_func = _add_datablock
1937
+ elif value is not None:
1938
+ val = value
1939
+ add_func = _add_constant
1940
+ else:
1941
+ keys = ["x", "y", "z"]
1942
+ keys = [k for k in keys if k in kwargs and kwargs[k] is not None]
1943
+ if len(keys) > 0:
1944
+ val = _np.concatenate([kwargs[k] for k in keys]).flatten()[0]
1945
+ add_func = _add_mesh
1946
+ if id is None:
1947
+ k = "species"
1948
+ if k in kwargs:
1949
+ id = f"grid/{kwargs[k]}"
1950
+ else:
1951
+ id = "grid"
1952
+
1953
+ if id is None:
1954
+ id = name
1955
+ if id in blocklist._block_ids:
1956
+ print(f'Unable to create block. ID duplicated: "{id}"')
1957
+ return
1958
+
1959
+ datatype = None
1960
+ if isinstance(val, (bool, _np.bool)):
1961
+ datatype = SdfDataType.LOGICAL
1962
+ elif isinstance(val, _np.int32):
1963
+ datatype = SdfDataType.INTEGER4
1964
+ elif isinstance(val, (int, _np.int64)):
1965
+ datatype = SdfDataType.INTEGER8
1966
+ elif isinstance(val, _np.float32):
1967
+ datatype = SdfDataType.REAL4
1968
+ elif isinstance(val, float):
1969
+ datatype = SdfDataType.REAL8
1970
+ elif isinstance(val, str) or isinstance(val, bytes):
1971
+ datatype = SdfDataType.CHARACTER
1972
+ if add_func not in (
1973
+ _add_namevalue,
1974
+ _add_datablock,
1975
+ _add_stitched,
1976
+ ):
1977
+ add_func = None
1978
+ else:
1979
+ add_func = None
1980
+
1981
+ if add_func:
1982
+ add_func(
1983
+ blocklist, name, value=value, id=id, datatype=datatype, **kwargs
1984
+ )
1985
+ else:
1986
+ print(f'Block "{id}", unsupported datatype: {type(value)}')
1987
+ return
1988
+
1989
+
1990
+ def _write(blocklist, filename):
1991
+ if not isinstance(blocklist, BlockList):
1992
+ print("ERROR: first argument must be of type BlockList")
1993
+ return
1994
+ if not blocklist._handle:
1995
+ return
1996
+ for k, b in blocklist._block_ids.items():
1997
+ if isinstance(b, Block) and b._contents.in_file:
1998
+ _ = b.data
1999
+ blocklist._clib.sdf_write(blocklist._handle, filename.encode())