pyadps 0.3.3b0__py3-none-any.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.
- pyadps/Home_Page.py +42 -0
- pyadps/__init__.py +8 -0
- pyadps/__main__.py +15 -0
- pyadps/pages/01_Read_File.py +458 -0
- pyadps/pages/02_View_Raw_Data.py +164 -0
- pyadps/pages/03_Download_Raw_File.py +298 -0
- pyadps/pages/04_Sensor_Health.py +905 -0
- pyadps/pages/05_QC_Test.py +476 -0
- pyadps/pages/06_Profile_Test.py +970 -0
- pyadps/pages/07_Velocity_Test.py +600 -0
- pyadps/pages/08_Write_File.py +574 -0
- pyadps/pages/09_Auto_process.py +62 -0
- pyadps/pages/__init__.py +0 -0
- pyadps/utils/__init__.py +12 -0
- pyadps/utils/autoprocess.py +530 -0
- pyadps/utils/metadata/config.ini +99 -0
- pyadps/utils/metadata/demo.000 +0 -0
- pyadps/utils/metadata/flmeta.json +422 -0
- pyadps/utils/metadata/vlmeta.json +567 -0
- pyadps/utils/plotgen.py +728 -0
- pyadps/utils/profile_test.py +556 -0
- pyadps/utils/pyreadrdi.py +969 -0
- pyadps/utils/readrdi.py +1610 -0
- pyadps/utils/script.py +201 -0
- pyadps/utils/sensor_health.py +120 -0
- pyadps/utils/signal_quality.py +455 -0
- pyadps/utils/velocity_test.py +200 -0
- pyadps/utils/writenc.py +339 -0
- pyadps-0.3.3b0.dist-info/LICENSE +8 -0
- pyadps-0.3.3b0.dist-info/METADATA +172 -0
- pyadps-0.3.3b0.dist-info/RECORD +33 -0
- pyadps-0.3.3b0.dist-info/WHEEL +4 -0
- pyadps-0.3.3b0.dist-info/entry_points.txt +5 -0
@@ -0,0 +1,969 @@
|
|
1
|
+
"""
|
2
|
+
pyreadrdi.py
|
3
|
+
|
4
|
+
Module Overview
|
5
|
+
---------------
|
6
|
+
This module provides functionalities to read and parse RDI ADCP files.
|
7
|
+
It includes functions for reading file headers, fixed and variable leaders,
|
8
|
+
and data types like velocity, correlation, echo intensity, and percent good.
|
9
|
+
Currently reads only PD0 format.
|
10
|
+
|
11
|
+
Modules
|
12
|
+
-------------------
|
13
|
+
- fileheader: Function to read and parse the file header information.
|
14
|
+
- fixedleader: Function to read and parse the fixed leader section of an RDI file.
|
15
|
+
- variableleader: Function to read and parse the variable leader section of an RDI file.
|
16
|
+
- datatype: Function to read and parse 3D data types.
|
17
|
+
- ErrorCode: Enum class to define and manage error codes for file operations.
|
18
|
+
|
19
|
+
Creation Date
|
20
|
+
--------------
|
21
|
+
2024-09-01
|
22
|
+
|
23
|
+
Last Modified Date
|
24
|
+
--------------
|
25
|
+
2024-09-01
|
26
|
+
|
27
|
+
Version
|
28
|
+
-------
|
29
|
+
0.2.0
|
30
|
+
|
31
|
+
Author
|
32
|
+
------
|
33
|
+
[P. Amol] <your.email@example.com>
|
34
|
+
|
35
|
+
License
|
36
|
+
-------
|
37
|
+
This module is licensed under the MIT License. See LICENSE file for details.
|
38
|
+
|
39
|
+
Dependencies
|
40
|
+
------------
|
41
|
+
- numpy: Required for handling array operations.
|
42
|
+
- struct: Required for unpacking binary data.
|
43
|
+
- io: Provides file handling capabilities, including file-like object support.
|
44
|
+
- enum: Provides support for creating enumerations, used for defining error codes.
|
45
|
+
|
46
|
+
Usage
|
47
|
+
-----
|
48
|
+
To use this module, import the necessary functions as follows:
|
49
|
+
|
50
|
+
>>> from readrdi import fileheader, fixedleader, variableleader, datatype
|
51
|
+
|
52
|
+
Examples
|
53
|
+
--------
|
54
|
+
>>> header_data = fileheader('example.rdi')
|
55
|
+
>>> fixed_data, ensemble, error_code = fixedleader('example.rdi')
|
56
|
+
>>> var_data = variableleader('example.rdi')
|
57
|
+
>>> vel_data = datatype('example.rdi', "velocity")
|
58
|
+
>>> vel_data = datatype('example.rdi', "echo", beam=4, cell=20)
|
59
|
+
|
60
|
+
Other add-on functions and classes inlcude bcolors, safe_open, and ErrorCode.
|
61
|
+
Examples (add-on)
|
62
|
+
-------------------
|
63
|
+
>>> error = ErrorCode.FILE_NOT_FOUND
|
64
|
+
|
65
|
+
"""
|
66
|
+
|
67
|
+
import io
|
68
|
+
import os
|
69
|
+
import sys
|
70
|
+
from enum import Enum
|
71
|
+
from struct import error as StructError
|
72
|
+
from struct import unpack
|
73
|
+
|
74
|
+
import numpy as np
|
75
|
+
|
76
|
+
|
77
|
+
class bcolors:
|
78
|
+
"""
|
79
|
+
Terminal color codes for styling console output.
|
80
|
+
|
81
|
+
This class provides a set of color codes and text formatting options for styling
|
82
|
+
terminal or console output. The codes can be used to change the text color and style
|
83
|
+
in a terminal that supports ANSI escape sequences.
|
84
|
+
|
85
|
+
Attributes
|
86
|
+
----------
|
87
|
+
HEADER : str
|
88
|
+
Color code for magenta text, typically used for headers.
|
89
|
+
OKBLUE : str
|
90
|
+
Color code for blue text, typically used for general information.
|
91
|
+
OKCYAN : str
|
92
|
+
Color code for cyan text, used for informational messages.
|
93
|
+
OKGREEN : str
|
94
|
+
Color code for green text, typically used for success messages.
|
95
|
+
WARNING : str
|
96
|
+
Color code for yellow text, used for warnings.
|
97
|
+
FAIL : str
|
98
|
+
Color code for red text, used for errors or failures.
|
99
|
+
ENDC : str
|
100
|
+
Reset color code to default. Resets the color and formatting.
|
101
|
+
BOLD : str
|
102
|
+
Bold text formatting code. Makes text bold.
|
103
|
+
UNDERLINE : str
|
104
|
+
Underlined text formatting code. Underlines the text.
|
105
|
+
|
106
|
+
Usage
|
107
|
+
-----
|
108
|
+
To use these color codes, prepend them to your string and append `bcolors.ENDC`
|
109
|
+
to reset the formatting. For example:
|
110
|
+
|
111
|
+
>>> print(f"{bcolors.OKGREEN}Success{bcolors.ENDC}")
|
112
|
+
>>> print(f"{bcolors.WARNING}Warning: This is a warning.{bcolors.ENDC}")
|
113
|
+
|
114
|
+
Examples
|
115
|
+
--------
|
116
|
+
>>> print(f"{bcolors.OKBLUE}This text is blue.{bcolors.ENDC}")
|
117
|
+
>>> print(f"{bcolors.FAIL}This text is red and indicates an error.{bcolors.ENDC}")
|
118
|
+
>>> print(f"{bcolors.BOLD}{bcolors.UNDERLINE}Bold and underlined text.{bcolors.ENDC}")
|
119
|
+
|
120
|
+
Notes
|
121
|
+
-----
|
122
|
+
These color codes use ANSI escape sequences and may not be supported in all terminal
|
123
|
+
environments. The appearance may vary depending on the terminal emulator used.
|
124
|
+
"""
|
125
|
+
|
126
|
+
HEADER = "\033[95m"
|
127
|
+
OKBLUE = "\033[94m"
|
128
|
+
OKCYAN = "\033[96m"
|
129
|
+
OKGREEN = "\033[92m"
|
130
|
+
WARNING = "\033[93m"
|
131
|
+
FAIL = "\033[91m"
|
132
|
+
ENDC = "\033[0m"
|
133
|
+
BOLD = "\033[1m"
|
134
|
+
UNDERLINE = "\033[4m"
|
135
|
+
|
136
|
+
# HEADER = "[95m"
|
137
|
+
# OKBLUE = "[94m"
|
138
|
+
# OKCYAN = "[96m"
|
139
|
+
# OKGREEN = "[92m"
|
140
|
+
# WARNING = "[93m"
|
141
|
+
# FAIL = "[91m"
|
142
|
+
# ENDC = "[0m"
|
143
|
+
# BOLD = "[1m"
|
144
|
+
# UNDERLINE = "[4m"
|
145
|
+
|
146
|
+
|
147
|
+
class ErrorCode(Enum):
|
148
|
+
"""
|
149
|
+
Enumeration for error codes with associated messages.
|
150
|
+
This enum provides a set of error codes and their corresponding descriptive messages.
|
151
|
+
It is used to standardize error reporting and handling within the application.
|
152
|
+
Attributes
|
153
|
+
----------
|
154
|
+
SUCCESS : tuple
|
155
|
+
Represents a successful operation.
|
156
|
+
FILE_NOT_FOUND : tuple
|
157
|
+
Error code for when a file is not found.
|
158
|
+
PERMISSION_DENIED : tuple
|
159
|
+
Error code for when access to a resource is denied.
|
160
|
+
IO_ERROR: tuple
|
161
|
+
Error Code for when the file fails to open.
|
162
|
+
OUT_OF_MEMORY : tuple
|
163
|
+
Error code for when the system runs out of memory.
|
164
|
+
WRONG_RDIFILE_TYPE : tuple
|
165
|
+
Error code for when a file type is not supported by RDI or incorrect.
|
166
|
+
ID_NOT_FOUND: tuple
|
167
|
+
Error code for when RDI file is found but the data type ID does not match.
|
168
|
+
FILE_CORRUPTED : tuple
|
169
|
+
Error code for when a file is corrupted and cannot be read.
|
170
|
+
DATATYPE_MISMATCH: tuple
|
171
|
+
Error code for when the data type is not same as the previous ensemble.
|
172
|
+
VALUE_ERROR: tuple
|
173
|
+
Error code for incorrect argument.
|
174
|
+
UNKNOWN_ERROR : tuple
|
175
|
+
Error code for an unspecified or unknown error.
|
176
|
+
|
177
|
+
Methods
|
178
|
+
-------
|
179
|
+
get_message(code)
|
180
|
+
Retrieves the descriptive message corresponding to a given error code.
|
181
|
+
|
182
|
+
Parameters
|
183
|
+
----------
|
184
|
+
code : int
|
185
|
+
The error code for which the message is to be retrieved.
|
186
|
+
|
187
|
+
Returns
|
188
|
+
-------
|
189
|
+
str
|
190
|
+
The descriptive message associated with the provided error code. If the code
|
191
|
+
is not valid, returns \"Error: Invalid error code.\"
|
192
|
+
"""
|
193
|
+
|
194
|
+
SUCCESS = (0, "Success")
|
195
|
+
FILE_NOT_FOUND = (1, "Error: File not found.")
|
196
|
+
PERMISSION_DENIED = (2, "Error: Permission denied.")
|
197
|
+
IO_ERROR = (3, "IO Error: Unable to open file.")
|
198
|
+
OUT_OF_MEMORY = (4, "Error: Out of memory.")
|
199
|
+
WRONG_RDIFILE_TYPE = (5, "Error: Wrong RDI File Type.")
|
200
|
+
ID_NOT_FOUND = (6, "Error: Data type ID not found.")
|
201
|
+
DATATYPE_MISMATCH = (7, "Warning: Data type mismatch.")
|
202
|
+
FILE_CORRUPTED = (8, "Warning: File Corrupted.")
|
203
|
+
VALUE_ERROR = (9, "Value Error for incorrect argument.")
|
204
|
+
UNKNOWN_ERROR = (99, "Unknown error.")
|
205
|
+
|
206
|
+
def __init__(self, code, message):
|
207
|
+
self.code = code
|
208
|
+
self.message = message
|
209
|
+
|
210
|
+
@classmethod
|
211
|
+
def get_message(cls, code):
|
212
|
+
for error in cls:
|
213
|
+
if error.code == code:
|
214
|
+
return error.message
|
215
|
+
else: # inserted
|
216
|
+
return "Error: Invalid error code."
|
217
|
+
|
218
|
+
|
219
|
+
def safe_open(filename, mode="rb"):
|
220
|
+
"""
|
221
|
+
Safely open a file, handling common file-related errors.
|
222
|
+
|
223
|
+
This function attempts to open a file and handles exceptions that may occur,
|
224
|
+
such as the file not being found or a lack of necessary permissions.
|
225
|
+
It returns the file object if successful, or an appropriate error message.
|
226
|
+
|
227
|
+
Parameters
|
228
|
+
----------
|
229
|
+
filepath : str
|
230
|
+
The path to the file that you want to open.
|
231
|
+
mode : str, optional
|
232
|
+
The mode in which to open the file (e.g., 'r' for reading, 'w' for writing).
|
233
|
+
Defaults to 'r'.
|
234
|
+
|
235
|
+
Returns
|
236
|
+
-------
|
237
|
+
file object or None
|
238
|
+
If the file is successfully opened, the file object is returned.
|
239
|
+
If an error occurs, None is returned and an error message is printed.
|
240
|
+
|
241
|
+
Raises
|
242
|
+
------
|
243
|
+
FileNotFoundError
|
244
|
+
If the file does not exist.
|
245
|
+
PermissionError
|
246
|
+
If the file cannot be opened due to insufficient permissions.
|
247
|
+
IOError
|
248
|
+
If an I/O error occurs during the opening of the file.
|
249
|
+
MemoryError
|
250
|
+
If required memory cannot be allocated by Python.
|
251
|
+
Exception
|
252
|
+
If an unexpected error occurs
|
253
|
+
|
254
|
+
|
255
|
+
|
256
|
+
Examples
|
257
|
+
--------
|
258
|
+
>>> f = safe_open('existing_file.txt')
|
259
|
+
>>> if f:
|
260
|
+
... content = f.read()
|
261
|
+
... f.close()
|
262
|
+
|
263
|
+
>>> safe_open('nonexistent_file.txt')
|
264
|
+
Error: File not found.
|
265
|
+
|
266
|
+
>>> safe_open('/restricted_access_file.txt')
|
267
|
+
Error: Permission denied.
|
268
|
+
"""
|
269
|
+
try:
|
270
|
+
filename = os.path.abspath(filename)
|
271
|
+
file = open(filename, mode)
|
272
|
+
return (file, ErrorCode.SUCCESS)
|
273
|
+
except FileNotFoundError as e:
|
274
|
+
print(f"FileNotFoundError: The file '{filename}' was not found: {e}")
|
275
|
+
return (None, ErrorCode.FILE_NOT_FOUND)
|
276
|
+
except PermissionError as e:
|
277
|
+
print(f"PermissionError: Permission denied for '{filename}': {e}")
|
278
|
+
return (None, ErrorCode.PERMISSION_DENIED)
|
279
|
+
except IOError as e:
|
280
|
+
print(f"IOError: An error occurred trying to open '{filename}': {e}")
|
281
|
+
return (None, ErrorCode.IO_ERROR)
|
282
|
+
except MemoryError as e:
|
283
|
+
print(f"MemoryError: Out of memory '{filename}':{e}")
|
284
|
+
return (None, ErrorCode.OUT_OF_MEMORY)
|
285
|
+
except Exception as e:
|
286
|
+
print(f"An unexpected error occurred: {e}")
|
287
|
+
return (None, ErrorCode.UNKNOWN_ERROR)
|
288
|
+
|
289
|
+
|
290
|
+
def safe_read(bfile, num_bytes):
|
291
|
+
"""
|
292
|
+
Safely read a specified number of bytes from a binary file.
|
293
|
+
|
294
|
+
This function attempts to read `num_bytes` from the provided binary file object.
|
295
|
+
It includes error handling for I/O errors, unexpected end-of-file, and other potential issues.
|
296
|
+
|
297
|
+
Parameters
|
298
|
+
----------
|
299
|
+
bfile : file object
|
300
|
+
A binary file object opened for reading.
|
301
|
+
num_bytes : int
|
302
|
+
The number of bytes to read from the file.
|
303
|
+
|
304
|
+
Returns
|
305
|
+
-------
|
306
|
+
bytes or None
|
307
|
+
The bytes read from the file, or None if an error occurred.
|
308
|
+
|
309
|
+
Raises
|
310
|
+
------
|
311
|
+
IOError
|
312
|
+
If an I/O error occurs during the file read operation.
|
313
|
+
OSError
|
314
|
+
If an operating system-related error occurs.
|
315
|
+
ValueError
|
316
|
+
If fewer than `num_bytes` are read from the file, indicating an unexpected end of file.
|
317
|
+
"""
|
318
|
+
try:
|
319
|
+
readbytes = bfile.read(num_bytes)
|
320
|
+
|
321
|
+
if len(readbytes) != num_bytes:
|
322
|
+
print(f"Unexpected end of file: fewer than {num_bytes} bytes were read.")
|
323
|
+
return (None, ErrorCode.FILE_CORRUPTED)
|
324
|
+
else:
|
325
|
+
return (readbytes, ErrorCode.SUCCESS)
|
326
|
+
|
327
|
+
except (IOError, OSError) as e:
|
328
|
+
print(f"File read error: {e}")
|
329
|
+
return (None, ErrorCode.IO_ERROR)
|
330
|
+
except ValueError as e:
|
331
|
+
print(f"Value error: {e}")
|
332
|
+
return (None, ErrorCode.VALUE_ERROR)
|
333
|
+
|
334
|
+
|
335
|
+
def fileheader(rdi_file):
|
336
|
+
"""
|
337
|
+
Parse the binary RDI ADCP file and extract header information.
|
338
|
+
|
339
|
+
This function reads a binary file and extracts several fields from its header,
|
340
|
+
returning them as numpy arrays and integers.
|
341
|
+
|
342
|
+
Parameters
|
343
|
+
----------
|
344
|
+
filename : str
|
345
|
+
The path to the binary file to be read.
|
346
|
+
|
347
|
+
Returns
|
348
|
+
-------
|
349
|
+
datatype : numpy.ndarray
|
350
|
+
A 1D numpy array of type `int16` representing the data type field from the file header.
|
351
|
+
byte : numpy.ndarray
|
352
|
+
A 1D numpy array of type `int16` representing the byte information from the file header.
|
353
|
+
byteskip : numpy.ndarray
|
354
|
+
A 1D numpy array of type `int32` indicating how many bytes to skip in the file.
|
355
|
+
address_offset : numpy.ndarray
|
356
|
+
A 2D numpy array of type `int` representing the address offsets within the file.
|
357
|
+
dataid : numpy.ndarray
|
358
|
+
A 2D numpy array of type `int` representing the data IDs extracted from the file header.
|
359
|
+
ensemble : int
|
360
|
+
An integer representing the ensemble information from the file header.
|
361
|
+
error_code : int
|
362
|
+
An integer representing the error code, where 0 typically indicates success.
|
363
|
+
|
364
|
+
Raises
|
365
|
+
------
|
366
|
+
IOError
|
367
|
+
If there is an issue opening or reading from the file.
|
368
|
+
ValueError
|
369
|
+
If the file does not contain the expected structure or the data cannot be parsed correctly.
|
370
|
+
|
371
|
+
Notes
|
372
|
+
-----
|
373
|
+
This function assumes that the file is in a specific RDI binary format and may not work correctly
|
374
|
+
if the file format differs.
|
375
|
+
|
376
|
+
Examples
|
377
|
+
--------
|
378
|
+
>>> datatype, byte, byteskip, address_offset, dataid, ensemble, error_code = fileheader("data.bin")
|
379
|
+
>>> if error_code == 0:
|
380
|
+
... print("File header read successfully.")
|
381
|
+
... else:
|
382
|
+
... print(f"Error code: {error_code}")
|
383
|
+
"""
|
384
|
+
|
385
|
+
filename = rdi_file
|
386
|
+
headerid = np.array([], dtype="int8")
|
387
|
+
sourceid = np.array([], dtype="int8")
|
388
|
+
byte = np.array([], dtype="int16")
|
389
|
+
spare = np.array([], dtype="int8")
|
390
|
+
datatype = np.array([], dtype="int16")
|
391
|
+
address_offset = []
|
392
|
+
ensemble = 0
|
393
|
+
error_code = 0
|
394
|
+
dataid = []
|
395
|
+
byteskip = np.array([], dtype="int32")
|
396
|
+
dummytuple = ([], [], [], [], [], ensemble, error_code)
|
397
|
+
|
398
|
+
bfile, error = safe_open(filename, mode="rb")
|
399
|
+
if bfile is None:
|
400
|
+
error_code = error.code
|
401
|
+
dummytuple = ([], [], [], [], [], ensemble, error_code)
|
402
|
+
return dummytuple
|
403
|
+
bfile.seek(0, 0)
|
404
|
+
bskip = i = 0
|
405
|
+
hid = [None] * 5
|
406
|
+
while byt := bfile.read(6):
|
407
|
+
hid[0], hid[1], hid[2], hid[3], hid[4] = unpack("<BBHBB", byt)
|
408
|
+
headerid = np.append(headerid, np.int8(hid[0]))
|
409
|
+
sourceid = np.append(sourceid, np.int16(hid[1]))
|
410
|
+
byte = np.append(byte, np.int16(hid[2]))
|
411
|
+
spare = np.append(spare, np.int16(hid[3]))
|
412
|
+
datatype = np.append(datatype, np.int16(hid[4]))
|
413
|
+
|
414
|
+
# dbyte = bfile.read(2 * datatype[i])
|
415
|
+
dbyte, error = safe_read(bfile, 2 * datatype[i])
|
416
|
+
if dbyte is None:
|
417
|
+
if i == 0:
|
418
|
+
error_code = error.code
|
419
|
+
dummytuple = ([], [], [], [], [], ensemble, error_code)
|
420
|
+
return dummytuple
|
421
|
+
else:
|
422
|
+
break
|
423
|
+
|
424
|
+
# Check for id and datatype errors
|
425
|
+
if i == 0:
|
426
|
+
if headerid[0] != 127 or sourceid[0] != 127:
|
427
|
+
error = ErrorCode.WRONG_RDIFILE_TYPE
|
428
|
+
print(bcolors.FAIL + error.message + bcolors.ENDC)
|
429
|
+
error_code = error.code
|
430
|
+
dummytuple = ([], [], [], [], [], ensemble, error_code)
|
431
|
+
return dummytuple
|
432
|
+
else:
|
433
|
+
if headerid[i] != 127 or sourceid[i] != 127:
|
434
|
+
error = ErrorCode.ID_NOT_FOUND
|
435
|
+
print(bcolors.FAIL + error.message + bcolors.ENDC)
|
436
|
+
break
|
437
|
+
|
438
|
+
if datatype[i] != datatype[i - 1]:
|
439
|
+
error = ErrorCode.DATATYPE_MISMATCH
|
440
|
+
print(bcolors.FAIL + error.message)
|
441
|
+
print(f"Data Types for ensemble {i} is {datatype[i - 1]}.")
|
442
|
+
print(f"Data Types for ensemble {i + 1} is {datatype[i]}.")
|
443
|
+
print(f"Ensembles reset to {i}" + bcolors.ENDC)
|
444
|
+
break
|
445
|
+
|
446
|
+
try:
|
447
|
+
data = unpack("H" * datatype[i], dbyte)
|
448
|
+
address_offset.append(data)
|
449
|
+
except:
|
450
|
+
error = ErrorCode.FILE_CORRUPTED
|
451
|
+
error_code = error.code
|
452
|
+
dummytuple = ([], [], [], [], [], ensemble, error_code)
|
453
|
+
return dummytuple
|
454
|
+
|
455
|
+
skip_array = [None] * datatype[i]
|
456
|
+
for dtype in range(datatype[i]):
|
457
|
+
bseek = int(bskip) + int(address_offset[i][dtype])
|
458
|
+
bfile.seek(bseek, 0)
|
459
|
+
readbyte = bfile.read(2)
|
460
|
+
skip_array[dtype] = int.from_bytes(
|
461
|
+
readbyte, byteorder="little", signed=False
|
462
|
+
)
|
463
|
+
|
464
|
+
dataid.append(skip_array)
|
465
|
+
# bytekip is the number of bytes to skip to reach
|
466
|
+
# an ensemble from beginning of file.
|
467
|
+
# ?? Should byteskip be from current position ??
|
468
|
+
bskip = int(bskip) + int(byte[i]) + 2
|
469
|
+
bfile.seek(bskip, 0)
|
470
|
+
byteskip = np.append(byteskip, np.int32(bskip))
|
471
|
+
i += 1
|
472
|
+
|
473
|
+
ensemble = i
|
474
|
+
bfile.close()
|
475
|
+
address_offset = np.array(address_offset)
|
476
|
+
dataid = np.array(dataid)
|
477
|
+
datatype = datatype[0:ensemble]
|
478
|
+
byte = byte[0:ensemble]
|
479
|
+
byteskip = byteskip[0:ensemble]
|
480
|
+
error_code = error.code
|
481
|
+
return (datatype, byte, byteskip, address_offset, dataid, ensemble, error_code)
|
482
|
+
|
483
|
+
|
484
|
+
def fixedleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=0):
|
485
|
+
"""
|
486
|
+
Parse the fixed leader data from binary RDI ADCP file.
|
487
|
+
|
488
|
+
This function extracts the fixed leader section of an RDI file. It uses
|
489
|
+
optional parameters that can be obtained from the `fileheader` function. The function
|
490
|
+
returns data extracted from the file, the ensemble number, and an error code indicating
|
491
|
+
the status of the operation.
|
492
|
+
|
493
|
+
Parameters
|
494
|
+
----------
|
495
|
+
rdi_file : str
|
496
|
+
The path to the RDI binary file from which to read the fixed leader section.
|
497
|
+
byteskip : numpy.ndarray, optional
|
498
|
+
Number of bytes to skip before reading the fixed leader section. If not provided,
|
499
|
+
defaults to None. Can be obtained from the `fileheader` function.
|
500
|
+
offset : numpy.ndarray, optional
|
501
|
+
Offset in bytes from the start of the file to the fixed leader section. If not provided,
|
502
|
+
defaults to None. Can be obtained from the `fileheader` function.
|
503
|
+
idarray : numpy.ndarray, optional
|
504
|
+
An optional list of IDs to be processed. If not provided, defaults to None. Can be obtained
|
505
|
+
from the `fileheader` function.
|
506
|
+
ensemble : int, optional
|
507
|
+
The ensemble number to be used or processed. If not provided, defaults to 0. Can be obtained
|
508
|
+
from the `fileheader` function.
|
509
|
+
|
510
|
+
Returns
|
511
|
+
-------
|
512
|
+
data : numpy.ndarray
|
513
|
+
Extracted data from the fixed leader section of the file. The type of `data` depends on the
|
514
|
+
implementation and file structure.
|
515
|
+
ensemble : int
|
516
|
+
The ensemble number processed or retrieved from the file.
|
517
|
+
error_code : int
|
518
|
+
An error code indicating the status of the operation.
|
519
|
+
|
520
|
+
Raises
|
521
|
+
------
|
522
|
+
FileNotFoundError
|
523
|
+
If the RDI file cannot be found.
|
524
|
+
PermissionError
|
525
|
+
If the file cannot be accessed due to permission issues.
|
526
|
+
ValueError
|
527
|
+
If provided parameters are of incorrect type or value.
|
528
|
+
|
529
|
+
Examples
|
530
|
+
--------
|
531
|
+
>>> data, ensemble, error_code = fixedleader('data.rdi', byteskip=10, offset=50)
|
532
|
+
>>> print(data, ensemble, error_code)
|
533
|
+
(data_from_file, 0, 0)
|
534
|
+
|
535
|
+
>>> data, ensemble, error_code = fixedleader('data.rdi', idarray=[1, 2, 3])
|
536
|
+
>>> print(data, ensemble, error_code)
|
537
|
+
(data_from_file, 0, 0)
|
538
|
+
"""
|
539
|
+
|
540
|
+
filename = rdi_file
|
541
|
+
error_code = 0
|
542
|
+
|
543
|
+
if (
|
544
|
+
not all((isinstance(v, np.ndarray) for v in (byteskip, offset, idarray)))
|
545
|
+
or ensemble == 0
|
546
|
+
):
|
547
|
+
_, _, byteskip, offset, idarray, ensemble, error_code = fileheader(filename)
|
548
|
+
|
549
|
+
fid = [[0] * ensemble for _ in range(36)]
|
550
|
+
|
551
|
+
bfile, error = safe_open(filename, "rb")
|
552
|
+
if bfile is None:
|
553
|
+
return (fid, ensemble, error.code)
|
554
|
+
if error.code == 0 and error_code != 0:
|
555
|
+
error.code = error_code
|
556
|
+
error.message = error.get_message(error.code)
|
557
|
+
|
558
|
+
bfile.seek(0, 0)
|
559
|
+
for i in range(ensemble):
|
560
|
+
fbyteskip = None
|
561
|
+
for count, item in enumerate(idarray[i]):
|
562
|
+
if item in (0, 1):
|
563
|
+
fbyteskip = offset[0][count]
|
564
|
+
if fbyteskip == None:
|
565
|
+
error = ErrorCode.ID_NOT_FOUND
|
566
|
+
ensemble = i
|
567
|
+
print(bcolors.WARNING + error.message)
|
568
|
+
print(f"Total ensembles reset to {i}." + bcolors.ENDC)
|
569
|
+
break
|
570
|
+
else: # inserted
|
571
|
+
try:
|
572
|
+
bfile.seek(fbyteskip, 1)
|
573
|
+
bdata = bfile.read(59)
|
574
|
+
# Fixed Leader ID, CPU Version no. & Revision no.
|
575
|
+
(fid[0][i], fid[1][i], fid[2][i]) = unpack("<HBB", bdata[0:4])
|
576
|
+
if fid[0][i] not in (0, 1):
|
577
|
+
error = ErrorCode.ID_NOT_FOUND
|
578
|
+
ensemble = i
|
579
|
+
print(bcolors.WARNING + error.message)
|
580
|
+
print(f"Total ensembles reset to {i}." + bcolors.ENDC)
|
581
|
+
break
|
582
|
+
# System configuration & Real/Slim flag
|
583
|
+
(fid[3][i], fid[4][i]) = unpack("<HB", bdata[4:7])
|
584
|
+
# Lag Length, number of beams & Number of cells
|
585
|
+
(fid[5][i], fid[6][i], fid[7][i]) = unpack("<BBB", bdata[7:10])
|
586
|
+
# Pings per Ensemble, Depth cell length & Blank after transmit
|
587
|
+
(fid[8][i], fid[9][i], fid[10][i]) = unpack("<HHH", bdata[10:16])
|
588
|
+
# Signal Processing mode, Low correlation threshold & No. of
|
589
|
+
# code repetition
|
590
|
+
(fid[11][i], fid[12][i], fid[13][i]) = unpack("<BBB", bdata[16:19])
|
591
|
+
# Percent good minimum & Error velocity threshold
|
592
|
+
(fid[14][i], fid[15][i]) = unpack("<BH", bdata[19:22])
|
593
|
+
# Time between ping groups (TP command)
|
594
|
+
# Minute, Second, Hundredth
|
595
|
+
(fid[16][i], fid[17][i], fid[18][i]) = unpack("<BBB", bdata[22:25])
|
596
|
+
# Coordinate transform, Heading alignment & Heading bias
|
597
|
+
(fid[19][i], fid[20][i], fid[21][i]) = unpack("<BHH", bdata[25:30])
|
598
|
+
# Sensor source & Sensor available
|
599
|
+
(fid[22][i], fid[23][i]) = unpack("<BB", bdata[30:32])
|
600
|
+
# Bin 1 distance, Transmit pulse length & Reference layer ave
|
601
|
+
(fid[24][i], fid[25][i], fid[26][i]) = unpack("<HHH", bdata[32:38])
|
602
|
+
# False target threshold, Spare & Transmit lag distance
|
603
|
+
(fid[27][i], fid[28][i], fid[29][i]) = unpack("<BBH", bdata[38:42])
|
604
|
+
# CPU board serial number (Big Endian)
|
605
|
+
(fid[30][i]) = unpack(">Q", bdata[42:50])[0]
|
606
|
+
# (fid[30][i], fid[31][i])= struct.unpack('>II', packed_data)
|
607
|
+
# fid[30][i] = int.from_bytes(bdata[42:50], byteorder="big", signed=False)
|
608
|
+
# System bandwidth, system power & Spare
|
609
|
+
(fid[31][i], fid[32][i], fid[33][i]) = unpack("<HBB", bdata[50:54])
|
610
|
+
# Instrument serial number & Beam angle
|
611
|
+
(fid[34][i], fid[35][i]) = unpack("<LB", bdata[54:59])
|
612
|
+
|
613
|
+
bfile.seek(byteskip[i], 0)
|
614
|
+
|
615
|
+
except (ValueError, StructError) as e:
|
616
|
+
print(bcolors.WARNING + "WARNING: The file is broken.")
|
617
|
+
print(
|
618
|
+
f"Function `fixedleader` unable to extract data for ensemble {i + 1}. Total ensembles reset to {i}."
|
619
|
+
)
|
620
|
+
print("Details from struct function:")
|
621
|
+
print(f"An error occurred: {e}" + bcolors.ENDC)
|
622
|
+
error = ErrorCode.FILE_CORRUPTED
|
623
|
+
ensemble = i
|
624
|
+
|
625
|
+
except (OSError, io.UnsupportedOperation) as e:
|
626
|
+
print(bcolors.WARNING + "WARNING: The file is broken.")
|
627
|
+
print(
|
628
|
+
f"Function `fixedleader` unable to extract data for ensemble {i + 1}. Total ensembles reset to {i}."
|
629
|
+
)
|
630
|
+
print(f"File seeking error at iteration {i}: {e}" + bcolors.ENDC)
|
631
|
+
error = ErrorCode.FILE_CORRUPTED
|
632
|
+
ensemble = i
|
633
|
+
bfile.close()
|
634
|
+
error_code = error.code
|
635
|
+
fid = np.array(fid)
|
636
|
+
data = fid[:, :ensemble]
|
637
|
+
return (data, ensemble, error_code)
|
638
|
+
|
639
|
+
|
640
|
+
def variableleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=0):
|
641
|
+
"""
|
642
|
+
Parse the variable leader data from binary RDI ADCP file.
|
643
|
+
|
644
|
+
This function extracts the variable leader section of an RDI file. It uses
|
645
|
+
optional parameters that can be obtained from the `fileheader` function. The function
|
646
|
+
returns data extracted from the file, the ensemble number, and an error code indicating
|
647
|
+
the status of the operation.
|
648
|
+
|
649
|
+
Parameters
|
650
|
+
----------
|
651
|
+
rdi_file : str
|
652
|
+
The path to the RDI binary file from which to read the fixed leader section.
|
653
|
+
byteskip : numpy.ndarray, optional
|
654
|
+
Number of bytes to skip before reading the fixed leader section. If not provided,
|
655
|
+
defaults to None. Can be obtained from the `fileheader` function.
|
656
|
+
offset : numpy.ndarray, optional
|
657
|
+
Offset in bytes from the start of the file to the fixed leader section. If not provided,
|
658
|
+
defaults to None. Can be obtained from the `fileheader` function.
|
659
|
+
idarray : numpy.ndarray, optional
|
660
|
+
An optional list of IDs to be processed. If not provided, defaults to None. Can be obtained
|
661
|
+
from the `fileheader` function.
|
662
|
+
ensemble : int, optional
|
663
|
+
The ensemble number to be used or processed. If not provided, defaults to 0. Can be obtained
|
664
|
+
from the `fileheader` function.
|
665
|
+
|
666
|
+
Returns
|
667
|
+
-------
|
668
|
+
data : numpy.ndarray
|
669
|
+
Extracted data from the variable leader section of the file.
|
670
|
+
ensemble : int
|
671
|
+
The ensemble number processed or retrieved from the file.
|
672
|
+
error_code : int
|
673
|
+
An error code indicating the status of the operation.
|
674
|
+
|
675
|
+
Raises
|
676
|
+
------
|
677
|
+
FileNotFoundError
|
678
|
+
If the RDI file cannot be found.
|
679
|
+
PermissionError
|
680
|
+
If the file cannot be accessed due to permission issues.
|
681
|
+
ValueError
|
682
|
+
|
683
|
+
If provided parameters are of incorrect type or value.
|
684
|
+
Examples
|
685
|
+
--------
|
686
|
+
>>> data, ensemble, error_code = fixedleader('data.rdi', byteskip=10, offset=50)
|
687
|
+
>>> print(data, ensemble, error_code)
|
688
|
+
(data_from_file, 0, 0)
|
689
|
+
|
690
|
+
>>> data, ensemble, error_code = fixedleader('data.rdi', idarray=[1, 2, 3])
|
691
|
+
>>> print(data, ensemble, error_code)
|
692
|
+
"""
|
693
|
+
|
694
|
+
filename = rdi_file
|
695
|
+
error_code = 0
|
696
|
+
if (
|
697
|
+
not all((isinstance(v, np.ndarray) for v in (byteskip, offset, idarray)))
|
698
|
+
or ensemble == 0
|
699
|
+
):
|
700
|
+
_, _, byteskip, offset, idarray, ensemble, error_code = fileheader(filename)
|
701
|
+
vid = [[0] * ensemble for _ in range(48)]
|
702
|
+
bfile, error = safe_open(filename, "rb")
|
703
|
+
if bfile is None:
|
704
|
+
return (vid, ensemble, error.code)
|
705
|
+
if error.code == 0 and error_code != 0:
|
706
|
+
error.code = error_code
|
707
|
+
error.message = error.get_message(error.code)
|
708
|
+
bfile.seek(0, 0)
|
709
|
+
for i in range(ensemble):
|
710
|
+
fbyteskip = None
|
711
|
+
for count, item in enumerate(idarray[i]):
|
712
|
+
if item in (128, 129):
|
713
|
+
fbyteskip = offset[0][count]
|
714
|
+
if fbyteskip == None:
|
715
|
+
error = ErrorCode.ID_NOT_FOUND
|
716
|
+
ensemble = i
|
717
|
+
print(bcolors.WARNING + error.message)
|
718
|
+
print(f"Total ensembles reset to {i}." + bcolors.ENDC)
|
719
|
+
break
|
720
|
+
else:
|
721
|
+
try:
|
722
|
+
bfile.seek(fbyteskip, 1)
|
723
|
+
bdata = bfile.read(65)
|
724
|
+
vid[0][i], vid[1][i] = unpack("<HH", bdata[0:4])
|
725
|
+
if vid[0][i] not in (128, 129):
|
726
|
+
error = ErrorCode.ID_NOT_FOUND
|
727
|
+
ensemble = i
|
728
|
+
print(bcolors.WARNING + error.message)
|
729
|
+
print(f"Total ensembles reset to {i}." + bcolors.ENDC)
|
730
|
+
break
|
731
|
+
sys.exit(f"Variable Leader not found for Ensemble {i}")
|
732
|
+
# Extract WorkHorse ADCP’s real-time clock (RTC)
|
733
|
+
# Year, Month, Day, Hour, Minute, Second & Hundredth
|
734
|
+
(
|
735
|
+
vid[2][i],
|
736
|
+
vid[3][i],
|
737
|
+
vid[4][i],
|
738
|
+
vid[5][i],
|
739
|
+
vid[6][i],
|
740
|
+
vid[7][i],
|
741
|
+
vid[8][i],
|
742
|
+
) = unpack("<BBBBBBB", bdata[4:11])
|
743
|
+
# Extract Ensemble # MSB & BIT Result
|
744
|
+
(vid[9][i], vid[10][i]) = unpack("<BH", bdata[11:14])
|
745
|
+
# Extract sensor variables (directly or derived):
|
746
|
+
# Sound Speed, Transducer Depth, Heading,
|
747
|
+
# Pitch, Roll, Temperature & Salinity
|
748
|
+
(
|
749
|
+
vid[11][i],
|
750
|
+
vid[12][i],
|
751
|
+
vid[13][i],
|
752
|
+
vid[14][i],
|
753
|
+
vid[15][i],
|
754
|
+
vid[16][i],
|
755
|
+
vid[17][i],
|
756
|
+
) = unpack("<HHHhhHh", bdata[14:28])
|
757
|
+
# Extract [M]inimum Pre-[P]ing Wait [T]ime between ping groups
|
758
|
+
# MPT minutes, MPT seconds & MPT hundredth
|
759
|
+
(vid[18][i], vid[19][i], vid[20][i]) = unpack("<BBB", bdata[28:31])
|
760
|
+
# Extract standard deviation of motion sensors:
|
761
|
+
# Heading, Pitch, & Roll
|
762
|
+
(vid[21][i], vid[22][i], vid[23][i]) = unpack("<BBB", bdata[31:34])
|
763
|
+
# Extract ADC Channels (8)
|
764
|
+
(
|
765
|
+
vid[24][i],
|
766
|
+
vid[25][i],
|
767
|
+
vid[26][i],
|
768
|
+
vid[27][i],
|
769
|
+
vid[28][i],
|
770
|
+
vid[29][i],
|
771
|
+
vid[30][i],
|
772
|
+
vid[31][i],
|
773
|
+
) = unpack("<BBBBBBBB", bdata[34:42])
|
774
|
+
# Extract error status word (4)
|
775
|
+
(vid[32][i], vid[33][i], vid[34][i], vid[35][i]) = unpack(
|
776
|
+
"<BBBB", bdata[42:46]
|
777
|
+
)
|
778
|
+
# Extract Reserved, Pressure, Pressure Variance & Spare
|
779
|
+
(vid[36][i], vid[37][i], vid[38][i], vid[39][i]) = unpack(
|
780
|
+
"<HiiB", bdata[46:57]
|
781
|
+
)
|
782
|
+
# Extract Y2K time
|
783
|
+
# Century, Year, Month, Day, Hour, Minute, Second, Hundredth
|
784
|
+
(
|
785
|
+
vid[40][i],
|
786
|
+
vid[41][i],
|
787
|
+
vid[42][i],
|
788
|
+
vid[43][i],
|
789
|
+
vid[44][i],
|
790
|
+
vid[45][i],
|
791
|
+
vid[46][i],
|
792
|
+
vid[47][i],
|
793
|
+
) = unpack("<BBBBBBBB", bdata[57:65])
|
794
|
+
|
795
|
+
bfile.seek(byteskip[i], 0)
|
796
|
+
|
797
|
+
except (ValueError, StructError) as e:
|
798
|
+
print(bcolors.WARNING + "WARNING: The file is broken.")
|
799
|
+
print(
|
800
|
+
f"Function `variableleader` unable to extract data for ensemble {i + 1}. Total ensembles reset to {i}."
|
801
|
+
)
|
802
|
+
print("Details from struct function:")
|
803
|
+
print(f"An error occurred: {e}" + bcolors.ENDC)
|
804
|
+
error = ErrorCode.FILE_CORRUPTED
|
805
|
+
ensemble = i
|
806
|
+
|
807
|
+
except (OSError, io.UnsupportedOperation) as e:
|
808
|
+
print(bcolors.WARNING + "WARNING: The file is broken.")
|
809
|
+
print(
|
810
|
+
f"Function `variableleader` unable to extract data for ensemble {i + 1}. Total ensembles reset to {i}."
|
811
|
+
)
|
812
|
+
print(f"File seeking error at iteration {i}: {e}" + bcolors.ENDC)
|
813
|
+
error = ErrorCode.FILE_CORRUPTED
|
814
|
+
ensemble = i
|
815
|
+
|
816
|
+
bfile.close()
|
817
|
+
error_code = error.code
|
818
|
+
vid = np.array(vid, dtype="int32")
|
819
|
+
data = vid[:, :ensemble]
|
820
|
+
return (data, ensemble, error_code)
|
821
|
+
|
822
|
+
|
823
|
+
def datatype(
|
824
|
+
filename,
|
825
|
+
var_name,
|
826
|
+
cell=0,
|
827
|
+
beam=0,
|
828
|
+
byteskip=None,
|
829
|
+
offset=None,
|
830
|
+
idarray=None,
|
831
|
+
ensemble=0,
|
832
|
+
):
|
833
|
+
"""
|
834
|
+
Parse 3D data from binary RDI ADCP file.
|
835
|
+
|
836
|
+
This function extracts 3D data like velocity, echo intensity,
|
837
|
+
correlation, percent good, and status from the binary RDI file.
|
838
|
+
It uses optional parameters can be obtained from the
|
839
|
+
`fileheader` function and `variableleader` functions. The function
|
840
|
+
returns data of shape (beam, cell, ensemble). The number of beams,
|
841
|
+
cells and ensembles along with error code are also returned.
|
842
|
+
|
843
|
+
Parameters
|
844
|
+
----------
|
845
|
+
filename : TYPE STRING
|
846
|
+
RDI ADCP binary file. The function can currently extract Workhorse,
|
847
|
+
Ocean Surveyor, and DVS files.
|
848
|
+
|
849
|
+
var_name : TYPE STRING
|
850
|
+
Extracts RDI variables that are functions of beam and cells.
|
851
|
+
List of permissible variable names: 'velocity', 'correlation',
|
852
|
+
'echo', 'percent good', 'status'
|
853
|
+
|
854
|
+
Returns
|
855
|
+
-------
|
856
|
+
data : numpy.ndarray
|
857
|
+
Returns a 3-D array of size (beam, cell, ensemble) for the var_name.
|
858
|
+
beam: int
|
859
|
+
Returns number of beams.
|
860
|
+
cell: int
|
861
|
+
Returns number of cells.
|
862
|
+
ensemble: int
|
863
|
+
Returns number of ensembles.
|
864
|
+
|
865
|
+
"""
|
866
|
+
|
867
|
+
varid = dict()
|
868
|
+
|
869
|
+
# Define file ids:
|
870
|
+
varid = {
|
871
|
+
"velocity": (256, 257),
|
872
|
+
"correlation": (512, 513),
|
873
|
+
"echo": (768, 769),
|
874
|
+
"percent good": (1024, 1025),
|
875
|
+
"status": (1280, 1281),
|
876
|
+
}
|
877
|
+
error_code = 0
|
878
|
+
|
879
|
+
# Check for optional arguments.
|
880
|
+
# -----------------------------
|
881
|
+
# These arguments are outputs of fileheader function.
|
882
|
+
# Makes the code faster if the fileheader function is already executed.
|
883
|
+
if (
|
884
|
+
not all((isinstance(v, np.ndarray) for v in (byteskip, offset, idarray)))
|
885
|
+
or ensemble == 0
|
886
|
+
):
|
887
|
+
_, _, byteskip, offset, idarray, ensemble, error_code = fileheader(filename)
|
888
|
+
if error_code > 0 and error_code < 6:
|
889
|
+
return ([], error_code)
|
890
|
+
|
891
|
+
# These arguments are outputs of fixedleader function.
|
892
|
+
# Makes the code faster if the fixedheader function is already executed.
|
893
|
+
if cell == 0 or beam == 0:
|
894
|
+
flead, ensemble, fl_error_code = fixedleader(
|
895
|
+
filename,
|
896
|
+
byteskip=byteskip,
|
897
|
+
offset=offset,
|
898
|
+
idarray=idarray,
|
899
|
+
ensemble=ensemble,
|
900
|
+
)
|
901
|
+
cell = int(flead[7][0])
|
902
|
+
beam = int(flead[6][0])
|
903
|
+
if fl_error_code != 0:
|
904
|
+
error_code = fl_error_code
|
905
|
+
else:
|
906
|
+
cell = int(cell)
|
907
|
+
beam = int(beam)
|
908
|
+
|
909
|
+
# Velocity is 16 bits and all others are 8 bits.
|
910
|
+
# Create empty array for the chosen variable name.
|
911
|
+
if var_name == "velocity":
|
912
|
+
var_array = np.zeros((beam, cell, ensemble), dtype="int16")
|
913
|
+
bitstr = "<h"
|
914
|
+
bitint = 2
|
915
|
+
else: # inserted
|
916
|
+
var_array = np.zeros((beam, cell, ensemble), dtype="uint8")
|
917
|
+
bitstr = "<B"
|
918
|
+
bitint = 1
|
919
|
+
# -----------------------------
|
920
|
+
|
921
|
+
# Read the file in safe mode.
|
922
|
+
bfile, error = safe_open(filename, "rb")
|
923
|
+
if bfile is None:
|
924
|
+
return (var_array, ensemble, error.code)
|
925
|
+
if error.code == 0 and error_code != 0:
|
926
|
+
error.code = error_code
|
927
|
+
error.message = error.get_message(error.code)
|
928
|
+
|
929
|
+
bfile.seek(0, 0)
|
930
|
+
vid = varid.get(var_name)
|
931
|
+
# Print error if the variable id is not found.
|
932
|
+
if not vid:
|
933
|
+
print(
|
934
|
+
bcolors.FAIL
|
935
|
+
+ "ValueError: Invalid variable name. List of permissible variable names: 'velocity', 'correlation', 'echo', 'percent good', 'status'"
|
936
|
+
+ bcolors.ENDC
|
937
|
+
)
|
938
|
+
error = ErrorCode.VALUE_ERROR
|
939
|
+
return (var_array, error.code)
|
940
|
+
|
941
|
+
# Checks if variable id is found in address offset
|
942
|
+
fbyteskip = None
|
943
|
+
for count, item in enumerate(idarray[0][:]):
|
944
|
+
if item in vid:
|
945
|
+
fbyteskip = offset[0][count]
|
946
|
+
break
|
947
|
+
if fbyteskip is None:
|
948
|
+
print(
|
949
|
+
bcolors.FAIL
|
950
|
+
+ "ERROR: Variable ID not found in address offset."
|
951
|
+
+ bcolors.ENDC
|
952
|
+
)
|
953
|
+
error = ErrorCode.ID_NOT_FOUND
|
954
|
+
return (var_array, error.code)
|
955
|
+
|
956
|
+
# READ DATA
|
957
|
+
for i in range(ensemble):
|
958
|
+
bfile.seek(fbyteskip, 1)
|
959
|
+
bdata = bfile.read(2)
|
960
|
+
for cno in range(cell):
|
961
|
+
for bno in range(beam):
|
962
|
+
bdata = bfile.read(bitint)
|
963
|
+
varunpack = unpack(bitstr, bdata)
|
964
|
+
var_array[bno][cno][i] = varunpack[0]
|
965
|
+
bfile.seek(byteskip[i], 0)
|
966
|
+
bfile.close()
|
967
|
+
|
968
|
+
data = var_array
|
969
|
+
return (data, ensemble, cell, beam, error_code)
|