pyadps 0.2.1b0__py3-none-any.whl → 0.3.0__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 +11 -5
- pyadps/pages/01_Read_File.py +623 -215
- pyadps/pages/02_View_Raw_Data.py +97 -41
- pyadps/pages/03_Download_Raw_File.py +200 -67
- pyadps/pages/04_Sensor_Health.py +905 -0
- pyadps/pages/05_QC_Test.py +493 -0
- pyadps/pages/06_Profile_Test.py +971 -0
- pyadps/pages/07_Velocity_Test.py +600 -0
- pyadps/pages/08_Write_File.py +623 -0
- pyadps/pages/09_Add-Ons.py +168 -0
- pyadps/utils/__init__.py +5 -3
- pyadps/utils/autoprocess.py +371 -80
- pyadps/utils/logging_utils.py +269 -0
- pyadps/utils/metadata/config.ini +22 -4
- pyadps/utils/metadata/demo.000 +0 -0
- pyadps/utils/metadata/flmeta.json +420 -420
- pyadps/utils/metadata/vlmeta.json +611 -565
- pyadps/utils/multifile.py +292 -0
- pyadps/utils/plotgen.py +505 -3
- pyadps/utils/profile_test.py +720 -125
- pyadps/utils/pyreadrdi.py +164 -92
- pyadps/utils/readrdi.py +436 -186
- pyadps/utils/script.py +197 -147
- pyadps/utils/sensor_health.py +120 -0
- pyadps/utils/signal_quality.py +472 -68
- pyadps/utils/velocity_test.py +79 -31
- pyadps/utils/writenc.py +222 -39
- {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/METADATA +13 -14
- pyadps-0.3.0.dist-info/RECORD +35 -0
- {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/WHEEL +1 -1
- {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/entry_points.txt +1 -0
- pyadps/pages/04_QC_Test.py +0 -334
- pyadps/pages/05_Profile_Test.py +0 -575
- pyadps/pages/06_Velocity_Test.py +0 -341
- pyadps/pages/07_Write_File.py +0 -452
- pyadps/utils/cutbin.py +0 -413
- pyadps/utils/regrid.py +0 -279
- pyadps-0.2.1b0.dist-info/RECORD +0 -31
- {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/LICENSE +0 -0
pyadps/utils/pyreadrdi.py
CHANGED
@@ -3,17 +3,17 @@ pyreadrdi.py
|
|
3
3
|
|
4
4
|
Module Overview
|
5
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,
|
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
8
|
and data types like velocity, correlation, echo intensity, and percent good.
|
9
|
-
Currently reads only PD0 format.
|
9
|
+
Currently reads only PD0 format.
|
10
10
|
|
11
11
|
Modules
|
12
12
|
-------------------
|
13
13
|
- fileheader: Function to read and parse the file header information.
|
14
14
|
- fixedleader: Function to read and parse the fixed leader section of an RDI file.
|
15
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.
|
16
|
+
- datatype: Function to read and parse 3D data types.
|
17
17
|
- ErrorCode: Enum class to define and manage error codes for file operations.
|
18
18
|
|
19
19
|
Creation Date
|
@@ -22,15 +22,15 @@ Creation Date
|
|
22
22
|
|
23
23
|
Last Modified Date
|
24
24
|
--------------
|
25
|
-
|
25
|
+
2025-10-01
|
26
26
|
|
27
27
|
Version
|
28
28
|
-------
|
29
|
-
0.
|
29
|
+
0.3.0
|
30
30
|
|
31
31
|
Author
|
32
32
|
------
|
33
|
-
[P. Amol] <
|
33
|
+
[P. Amol] <prakashamol@gmail.com>
|
34
34
|
|
35
35
|
License
|
36
36
|
-------
|
@@ -57,7 +57,7 @@ Examples
|
|
57
57
|
>>> vel_data = datatype('example.rdi', "velocity")
|
58
58
|
>>> vel_data = datatype('example.rdi', "echo", beam=4, cell=20)
|
59
59
|
|
60
|
-
Other add-on functions and classes inlcude bcolors, safe_open, and ErrorCode.
|
60
|
+
Other add-on functions and classes inlcude bcolors, safe_open, and ErrorCode.
|
61
61
|
Examples (add-on)
|
62
62
|
-------------------
|
63
63
|
>>> error = ErrorCode.FILE_NOT_FOUND
|
@@ -320,7 +320,7 @@ def safe_read(bfile, num_bytes):
|
|
320
320
|
|
321
321
|
if len(readbytes) != num_bytes:
|
322
322
|
print(f"Unexpected end of file: fewer than {num_bytes} bytes were read.")
|
323
|
-
return (
|
323
|
+
return (None, ErrorCode.FILE_CORRUPTED)
|
324
324
|
else:
|
325
325
|
return (readbytes, ErrorCode.SUCCESS)
|
326
326
|
|
@@ -403,65 +403,85 @@ def fileheader(rdi_file):
|
|
403
403
|
bfile.seek(0, 0)
|
404
404
|
bskip = i = 0
|
405
405
|
hid = [None] * 5
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
406
|
+
try:
|
407
|
+
while byt := bfile.read(6):
|
408
|
+
hid[0], hid[1], hid[2], hid[3], hid[4] = unpack("<BBHBB", byt)
|
409
|
+
headerid = np.append(headerid, np.int8(hid[0]))
|
410
|
+
sourceid = np.append(sourceid, np.int16(hid[1]))
|
411
|
+
byte = np.append(byte, np.int16(hid[2]))
|
412
|
+
spare = np.append(spare, np.int16(hid[3]))
|
413
|
+
datatype = np.append(datatype, np.int16(hid[4]))
|
414
|
+
|
415
|
+
# dbyte = bfile.read(2 * datatype[i])
|
416
|
+
dbyte, error = safe_read(bfile, 2 * datatype[i])
|
417
|
+
if dbyte is None:
|
418
|
+
if i == 0:
|
419
|
+
error_code = error.code
|
420
|
+
dummytuple = ([], [], [], [], [], ensemble, error_code)
|
421
|
+
return dummytuple
|
422
|
+
else:
|
423
|
+
break
|
424
|
+
|
425
|
+
# Check for id and datatype errors
|
417
426
|
if i == 0:
|
418
|
-
|
419
|
-
|
420
|
-
|
427
|
+
if headerid[0] != 127 or sourceid[0] != 127:
|
428
|
+
error = ErrorCode.WRONG_RDIFILE_TYPE
|
429
|
+
print(bcolors.FAIL + error.message + bcolors.ENDC)
|
430
|
+
error_code = error.code
|
431
|
+
dummytuple = ([], [], [], [], [], ensemble, error_code)
|
432
|
+
return dummytuple
|
421
433
|
else:
|
422
|
-
|
434
|
+
if headerid[i] != 127 or sourceid[i] != 127:
|
435
|
+
error = ErrorCode.ID_NOT_FOUND
|
436
|
+
print(bcolors.FAIL + error.message)
|
437
|
+
print(f"Ensembles reset to {i}" + bcolors.ENDC)
|
438
|
+
break
|
423
439
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
440
|
+
if datatype[i] != datatype[i - 1]:
|
441
|
+
error = ErrorCode.DATATYPE_MISMATCH
|
442
|
+
print(bcolors.FAIL + error.message)
|
443
|
+
print(f"Data Types for ensemble {i} is {datatype[i - 1]}.")
|
444
|
+
print(f"Data Types for ensemble {i + 1} is {datatype[i]}.")
|
445
|
+
print(f"Ensembles reset to {i}" + bcolors.ENDC)
|
446
|
+
break
|
447
|
+
|
448
|
+
try:
|
449
|
+
data = unpack("H" * datatype[i], dbyte)
|
450
|
+
address_offset.append(data)
|
451
|
+
except:
|
452
|
+
error = ErrorCode.FILE_CORRUPTED
|
429
453
|
error_code = error.code
|
454
|
+
dummytuple = ([], [], [], [], [], ensemble, error_code)
|
430
455
|
return dummytuple
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
# ?? Should byteskip be from current position ??
|
461
|
-
bskip = int(bskip) + int(byte[i]) + 2
|
462
|
-
bfile.seek(bskip, 0)
|
463
|
-
byteskip = np.append(byteskip, np.int32(bskip))
|
464
|
-
i += 1
|
456
|
+
|
457
|
+
skip_array = [None] * datatype[i]
|
458
|
+
for dtype in range(datatype[i]):
|
459
|
+
bseek = int(bskip) + int(address_offset[i][dtype])
|
460
|
+
bfile.seek(bseek, 0)
|
461
|
+
readbyte = bfile.read(2)
|
462
|
+
skip_array[dtype] = int.from_bytes(
|
463
|
+
readbyte, byteorder="little", signed=False
|
464
|
+
)
|
465
|
+
|
466
|
+
dataid.append(skip_array)
|
467
|
+
# bytekip is the number of bytes to skip to reach
|
468
|
+
# an ensemble from beginning of file.
|
469
|
+
# ?? Should byteskip be from current position ??
|
470
|
+
bskip = int(bskip) + int(byte[i]) + 2
|
471
|
+
bfile.seek(bskip, 0)
|
472
|
+
byteskip = np.append(byteskip, np.int32(bskip))
|
473
|
+
i += 1
|
474
|
+
except (ValueError, StructError, OverflowError) as e:
|
475
|
+
# except:
|
476
|
+
print(bcolors.WARNING + "WARNING: The file is broken.")
|
477
|
+
print(
|
478
|
+
f"Function `fileheader` unable to extract data for ensemble {i + 1}. Total ensembles reset to {i}."
|
479
|
+
)
|
480
|
+
print(bcolors.UNDERLINE + "Details from struct function" + bcolors.ENDC)
|
481
|
+
print(f" Error Type: {type(e).__name__}")
|
482
|
+
print(f" Error Details: {e}")
|
483
|
+
error = ErrorCode.FILE_CORRUPTED
|
484
|
+
ensemble = i
|
465
485
|
|
466
486
|
ensemble = i
|
467
487
|
bfile.close()
|
@@ -548,13 +568,24 @@ def fixedleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=0):
|
|
548
568
|
error.code = error_code
|
549
569
|
error.message = error.get_message(error.code)
|
550
570
|
|
571
|
+
# Note: When processing data from ADCPs with older firmware,
|
572
|
+
# the instrument serial number may be missing. As a result,
|
573
|
+
# garbage value is recorded, which sometimes is too large for a standard 64-bit integer.
|
574
|
+
# The following variables are defined to replace garbage value with a missing value.
|
575
|
+
# Flag to track if a missing serial number is detected
|
576
|
+
is_serial_missing = False
|
577
|
+
# Define the maximum value for a standard signed int64
|
578
|
+
INT64_MAX = 2**63 - 1
|
579
|
+
# Define a missing value flag (0 is a safe unsigned integer choice)
|
580
|
+
MISSING_VALUE_FLAG = 0
|
581
|
+
|
551
582
|
bfile.seek(0, 0)
|
552
583
|
for i in range(ensemble):
|
553
584
|
fbyteskip = None
|
554
585
|
for count, item in enumerate(idarray[i]):
|
555
586
|
if item in (0, 1):
|
556
|
-
fbyteskip = offset[
|
557
|
-
if fbyteskip
|
587
|
+
fbyteskip = offset[0][count]
|
588
|
+
if fbyteskip is None:
|
558
589
|
error = ErrorCode.ID_NOT_FOUND
|
559
590
|
ensemble = i
|
560
591
|
print(bcolors.WARNING + error.message)
|
@@ -596,6 +627,14 @@ def fixedleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=0):
|
|
596
627
|
(fid[27][i], fid[28][i], fid[29][i]) = unpack("<BBH", bdata[38:42])
|
597
628
|
# CPU board serial number (Big Endian)
|
598
629
|
(fid[30][i]) = unpack(">Q", bdata[42:50])[0]
|
630
|
+
# Check for overflow only once to set the flag
|
631
|
+
if not is_serial_missing and fid[30][i] > INT64_MAX:
|
632
|
+
print(
|
633
|
+
bcolors.WARNING
|
634
|
+
+ "WARNING: Missing serial number detected (old firmware). Flagging for replacement."
|
635
|
+
+ bcolors.ENDC
|
636
|
+
)
|
637
|
+
is_serial_missing = True
|
599
638
|
# (fid[30][i], fid[31][i])= struct.unpack('>II', packed_data)
|
600
639
|
# fid[30][i] = int.from_bytes(bdata[42:50], byteorder="big", signed=False)
|
601
640
|
# System bandwidth, system power & Spare
|
@@ -605,13 +644,14 @@ def fixedleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=0):
|
|
605
644
|
|
606
645
|
bfile.seek(byteskip[i], 0)
|
607
646
|
|
608
|
-
except (ValueError, StructError) as e:
|
647
|
+
except (ValueError, StructError, OverflowError) as e:
|
609
648
|
print(bcolors.WARNING + "WARNING: The file is broken.")
|
610
649
|
print(
|
611
650
|
f"Function `fixedleader` unable to extract data for ensemble {i + 1}. Total ensembles reset to {i}."
|
612
651
|
)
|
613
|
-
print("Details from struct function
|
614
|
-
print(f"
|
652
|
+
print(bcolors.UNDERLINE + "Details from struct function" + bcolors.ENDC)
|
653
|
+
print(f" Error Type: {type(e).__name__}")
|
654
|
+
print(f" Error Details: {e}")
|
615
655
|
error = ErrorCode.FILE_CORRUPTED
|
616
656
|
ensemble = i
|
617
657
|
|
@@ -625,6 +665,20 @@ def fixedleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=0):
|
|
625
665
|
ensemble = i
|
626
666
|
bfile.close()
|
627
667
|
error_code = error.code
|
668
|
+
|
669
|
+
if is_serial_missing:
|
670
|
+
print(
|
671
|
+
bcolors.OKBLUE
|
672
|
+
+ "INFO: Replacing entire serial number array with missing value flag."
|
673
|
+
+ bcolors.ENDC
|
674
|
+
)
|
675
|
+
# If Serial No. is missing, flag all data after Serial No.
|
676
|
+
fid[30] = [MISSING_VALUE_FLAG] * ensemble # Serial No.
|
677
|
+
fid[31] = [MISSING_VALUE_FLAG] * ensemble # System Bandwidth
|
678
|
+
fid[32] = [MISSING_VALUE_FLAG] * ensemble # System Power
|
679
|
+
fid[33] = [MISSING_VALUE_FLAG] * ensemble # Spare 2
|
680
|
+
fid[34] = [MISSING_VALUE_FLAG] * ensemble # Instrument No
|
681
|
+
fid[35] = [MISSING_VALUE_FLAG] * ensemble # Beam Angle
|
628
682
|
fid = np.array(fid)
|
629
683
|
data = fid[:, :ensemble]
|
630
684
|
return (data, ensemble, error_code)
|
@@ -703,7 +757,7 @@ def variableleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=
|
|
703
757
|
fbyteskip = None
|
704
758
|
for count, item in enumerate(idarray[i]):
|
705
759
|
if item in (128, 129):
|
706
|
-
fbyteskip = offset[
|
760
|
+
fbyteskip = offset[0][count]
|
707
761
|
if fbyteskip == None:
|
708
762
|
error = ErrorCode.ID_NOT_FOUND
|
709
763
|
ensemble = i
|
@@ -787,13 +841,14 @@ def variableleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=
|
|
787
841
|
|
788
842
|
bfile.seek(byteskip[i], 0)
|
789
843
|
|
790
|
-
except (ValueError, StructError) as e:
|
844
|
+
except (ValueError, StructError, OverflowError) as e:
|
791
845
|
print(bcolors.WARNING + "WARNING: The file is broken.")
|
792
846
|
print(
|
793
847
|
f"Function `variableleader` unable to extract data for ensemble {i + 1}. Total ensembles reset to {i}."
|
794
848
|
)
|
795
|
-
print("Details from struct function
|
796
|
-
print(f"
|
849
|
+
print(bcolors.UNDERLINE + "Details from struct function" + bcolors.ENDC)
|
850
|
+
print(f" Error Type: {type(e).__name__}")
|
851
|
+
print(f" Error Details: {e}")
|
797
852
|
error = ErrorCode.FILE_CORRUPTED
|
798
853
|
ensemble = i
|
799
854
|
|
@@ -883,7 +938,7 @@ def datatype(
|
|
883
938
|
|
884
939
|
# These arguments are outputs of fixedleader function.
|
885
940
|
# Makes the code faster if the fixedheader function is already executed.
|
886
|
-
if cell
|
941
|
+
if isinstance(cell, (np.integer, int)) or isinstance(beam, (np.integer, int)):
|
887
942
|
flead, ensemble, fl_error_code = fixedleader(
|
888
943
|
filename,
|
889
944
|
byteskip=byteskip,
|
@@ -891,22 +946,25 @@ def datatype(
|
|
891
946
|
idarray=idarray,
|
892
947
|
ensemble=ensemble,
|
893
948
|
)
|
894
|
-
cell =
|
895
|
-
beam =
|
949
|
+
cell = []
|
950
|
+
beam = []
|
951
|
+
cell = flead[7][:]
|
952
|
+
beam = flead[6][:]
|
896
953
|
if fl_error_code != 0:
|
897
954
|
error_code = fl_error_code
|
898
955
|
else:
|
899
|
-
cell =
|
900
|
-
beam =
|
901
|
-
|
956
|
+
cell = cell
|
957
|
+
beam = beam
|
902
958
|
# Velocity is 16 bits and all others are 8 bits.
|
903
959
|
# Create empty array for the chosen variable name.
|
904
960
|
if var_name == "velocity":
|
905
|
-
var_array = np.
|
961
|
+
var_array = np.full(
|
962
|
+
(int(max(beam)), int(max(cell)), ensemble), -32768, dtype="int16"
|
963
|
+
)
|
906
964
|
bitstr = "<h"
|
907
965
|
bitint = 2
|
908
966
|
else: # inserted
|
909
|
-
var_array = np.zeros((beam, cell, ensemble), dtype="uint8")
|
967
|
+
var_array = np.zeros((int(max(beam)), int(max(cell)), ensemble), dtype="uint8")
|
910
968
|
bitstr = "<B"
|
911
969
|
bitint = 1
|
912
970
|
# -----------------------------
|
@@ -935,7 +993,9 @@ def datatype(
|
|
935
993
|
fbyteskip = None
|
936
994
|
for count, item in enumerate(idarray[0][:]):
|
937
995
|
if item in vid:
|
938
|
-
fbyteskip =
|
996
|
+
fbyteskip = []
|
997
|
+
for i in range(ensemble):
|
998
|
+
fbyteskip.append(int(offset[i][count]))
|
939
999
|
break
|
940
1000
|
if fbyteskip is None:
|
941
1001
|
print(
|
@@ -947,16 +1007,28 @@ def datatype(
|
|
947
1007
|
return (var_array, error.code)
|
948
1008
|
|
949
1009
|
# READ DATA
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
1010
|
+
i = 0
|
1011
|
+
try:
|
1012
|
+
for i in range(ensemble):
|
1013
|
+
bfile.seek(fbyteskip[i], 1)
|
1014
|
+
bdata = bfile.read(2)
|
1015
|
+
for cno in range(int(cell[i])):
|
1016
|
+
for bno in range(int(beam[i])):
|
1017
|
+
bdata = bfile.read(bitint)
|
1018
|
+
varunpack = unpack(bitstr, bdata)
|
1019
|
+
var_array[bno][cno][i] = varunpack[0]
|
1020
|
+
bfile.seek(byteskip[i], 0)
|
1021
|
+
bfile.close()
|
1022
|
+
except (ValueError, StructError, OverflowError) as e:
|
1023
|
+
print(bcolors.WARNING + "WARNING: The file is broken.")
|
1024
|
+
print(
|
1025
|
+
f"Function `datatype` unable to extract {var_name} for ensemble {i + 1}. Total ensembles reset to {i}."
|
1026
|
+
)
|
1027
|
+
print(bcolors.UNDERLINE + "Details from struct function" + bcolors.ENDC)
|
1028
|
+
print(f" Error Type: {type(e).__name__}")
|
1029
|
+
print(f" Error Details: {e}")
|
1030
|
+
error = ErrorCode.FILE_CORRUPTED
|
1031
|
+
ensemble = i
|
960
1032
|
|
961
|
-
data = var_array
|
1033
|
+
data = var_array[:, :, :ensemble]
|
962
1034
|
return (data, ensemble, cell, beam, error_code)
|