pyadps 0.1.0b0__py3-none-any.whl → 0.1.2__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 +194 -18
- pyadps/pages/02_View_Raw_Data.py +69 -33
- pyadps/pages/03_Download_Raw_File.py +214 -66
- pyadps/pages/04_Sensor_Health.py +905 -0
- pyadps/pages/05_QC_Test.py +476 -0
- pyadps/pages/06_Profile_Test.py +971 -0
- pyadps/pages/07_Velocity_Test.py +600 -0
- pyadps/pages/08_Write_File.py +606 -0
- pyadps/pages/09_Auto_process.py +64 -0
- pyadps/utils/__init__.py +3 -3
- pyadps/utils/autoprocess.py +548 -0
- pyadps/utils/metadata/config.ini +99 -0
- pyadps/utils/metadata/demo.000 +0 -0
- pyadps/utils/plotgen.py +505 -3
- pyadps/utils/profile_test.py +752 -145
- pyadps/utils/pyreadrdi.py +27 -17
- pyadps/utils/readrdi.py +167 -20
- pyadps/utils/script.py +197 -147
- pyadps/utils/sensor_health.py +120 -0
- pyadps/utils/signal_quality.py +344 -24
- pyadps/utils/velocity_test.py +103 -20
- pyadps/utils/writenc.py +223 -27
- {pyadps-0.1.0b0.dist-info → pyadps-0.1.2.dist-info}/METADATA +56 -24
- pyadps-0.1.2.dist-info/RECORD +33 -0
- {pyadps-0.1.0b0.dist-info → pyadps-0.1.2.dist-info}/WHEEL +1 -1
- pyadps-0.1.2.dist-info/entry_points.txt +5 -0
- pyadps/pages/04_QC_Test.py +0 -283
- pyadps/pages/05_Profile_Test.py +0 -389
- pyadps/pages/06_Velocity_Test.py +0 -293
- pyadps/pages/07_Write_File.py +0 -367
- pyadps/utils/cutbin.py +0 -413
- pyadps/utils/regrid.py +0 -122
- pyadps-0.1.0b0.dist-info/RECORD +0 -29
- pyadps-0.1.0b0.dist-info/entry_points.txt +0 -3
- {pyadps-0.1.0b0.dist-info → pyadps-0.1.2.dist-info}/LICENSE +0 -0
pyadps/utils/pyreadrdi.py
CHANGED
@@ -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
|
|
@@ -427,6 +427,7 @@ def fileheader(rdi_file):
|
|
427
427
|
error = ErrorCode.WRONG_RDIFILE_TYPE
|
428
428
|
print(bcolors.FAIL + error.message + bcolors.ENDC)
|
429
429
|
error_code = error.code
|
430
|
+
dummytuple = ([], [], [], [], [], ensemble, error_code)
|
430
431
|
return dummytuple
|
431
432
|
else:
|
432
433
|
if headerid[i] != 127 or sourceid[i] != 127:
|
@@ -442,8 +443,14 @@ def fileheader(rdi_file):
|
|
442
443
|
print(f"Ensembles reset to {i}" + bcolors.ENDC)
|
443
444
|
break
|
444
445
|
|
445
|
-
|
446
|
-
|
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
|
447
454
|
|
448
455
|
skip_array = [None] * datatype[i]
|
449
456
|
for dtype in range(datatype[i]):
|
@@ -553,7 +560,7 @@ def fixedleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=0):
|
|
553
560
|
fbyteskip = None
|
554
561
|
for count, item in enumerate(idarray[i]):
|
555
562
|
if item in (0, 1):
|
556
|
-
fbyteskip = offset[
|
563
|
+
fbyteskip = offset[0][count]
|
557
564
|
if fbyteskip == None:
|
558
565
|
error = ErrorCode.ID_NOT_FOUND
|
559
566
|
ensemble = i
|
@@ -703,7 +710,7 @@ def variableleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=
|
|
703
710
|
fbyteskip = None
|
704
711
|
for count, item in enumerate(idarray[i]):
|
705
712
|
if item in (128, 129):
|
706
|
-
fbyteskip = offset[
|
713
|
+
fbyteskip = offset[0][count]
|
707
714
|
if fbyteskip == None:
|
708
715
|
error = ErrorCode.ID_NOT_FOUND
|
709
716
|
ensemble = i
|
@@ -883,7 +890,7 @@ def datatype(
|
|
883
890
|
|
884
891
|
# These arguments are outputs of fixedleader function.
|
885
892
|
# Makes the code faster if the fixedheader function is already executed.
|
886
|
-
if cell
|
893
|
+
if isinstance(cell, (np.integer, int)) or isinstance(beam, (np.integer, int)):
|
887
894
|
flead, ensemble, fl_error_code = fixedleader(
|
888
895
|
filename,
|
889
896
|
byteskip=byteskip,
|
@@ -891,22 +898,23 @@ def datatype(
|
|
891
898
|
idarray=idarray,
|
892
899
|
ensemble=ensemble,
|
893
900
|
)
|
894
|
-
cell =
|
895
|
-
beam =
|
901
|
+
cell = []
|
902
|
+
beam = []
|
903
|
+
cell = flead[7][:]
|
904
|
+
beam = flead[6][:]
|
896
905
|
if fl_error_code != 0:
|
897
906
|
error_code = fl_error_code
|
898
907
|
else:
|
899
|
-
cell =
|
900
|
-
beam =
|
901
|
-
|
908
|
+
cell = cell
|
909
|
+
beam = beam
|
902
910
|
# Velocity is 16 bits and all others are 8 bits.
|
903
911
|
# Create empty array for the chosen variable name.
|
904
912
|
if var_name == "velocity":
|
905
|
-
var_array = np.
|
913
|
+
var_array = np.full((int(max(beam)), int(max(cell)), ensemble), -32768, dtype="int16")
|
906
914
|
bitstr = "<h"
|
907
915
|
bitint = 2
|
908
916
|
else: # inserted
|
909
|
-
var_array = np.zeros((beam, cell, ensemble), dtype="uint8")
|
917
|
+
var_array = np.zeros((int(max(beam)), int(max(cell)), ensemble), dtype="uint8")
|
910
918
|
bitstr = "<B"
|
911
919
|
bitint = 1
|
912
920
|
# -----------------------------
|
@@ -935,7 +943,9 @@ def datatype(
|
|
935
943
|
fbyteskip = None
|
936
944
|
for count, item in enumerate(idarray[0][:]):
|
937
945
|
if item in vid:
|
938
|
-
fbyteskip =
|
946
|
+
fbyteskip = []
|
947
|
+
for i in range(ensemble):
|
948
|
+
fbyteskip.append(int(offset[i][count]))
|
939
949
|
break
|
940
950
|
if fbyteskip is None:
|
941
951
|
print(
|
@@ -948,10 +958,10 @@ def datatype(
|
|
948
958
|
|
949
959
|
# READ DATA
|
950
960
|
for i in range(ensemble):
|
951
|
-
bfile.seek(fbyteskip, 1)
|
961
|
+
bfile.seek(fbyteskip[i], 1)
|
952
962
|
bdata = bfile.read(2)
|
953
|
-
for cno in range(cell):
|
954
|
-
for bno in range(beam):
|
963
|
+
for cno in range(int(cell[i])):
|
964
|
+
for bno in range(int(beam[i])):
|
955
965
|
bdata = bfile.read(bitint)
|
956
966
|
varunpack = unpack(bitstr, bdata)
|
957
967
|
var_array[bno][cno][i] = varunpack[0]
|
pyadps/utils/readrdi.py
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
"""
|
4
4
|
RDI ADCP Binary File Reader
|
5
5
|
===========================
|
6
|
-
This module provides classes and functions to read and extract data from RDI Acoustic Doppler
|
7
|
-
Current Profiler (ADCP) binary files. The module supports Workhorse, Ocean Surveyor, and DVS ADCPs.
|
8
|
-
It allows for parsing of various data types such as Fixed Leader, Variable Leader, Velocity, Correlation,
|
6
|
+
This module provides classes and functions to read and extract data from RDI Acoustic Doppler
|
7
|
+
Current Profiler (ADCP) binary files. The module supports Workhorse, Ocean Surveyor, and DVS ADCPs.
|
8
|
+
It allows for parsing of various data types such as Fixed Leader, Variable Leader, Velocity, Correlation,
|
9
9
|
Echo Intensity, Percent Good, and Status data.
|
10
10
|
|
11
11
|
Classes
|
@@ -28,7 +28,7 @@ Status
|
|
28
28
|
Parses the status data from the ADCP.
|
29
29
|
ReadFile
|
30
30
|
Manages the entire data extraction process and unifies all data types.
|
31
|
-
|
31
|
+
|
32
32
|
Functions
|
33
33
|
---------
|
34
34
|
check_equal(array)
|
@@ -101,6 +101,7 @@ import os
|
|
101
101
|
import sys
|
102
102
|
|
103
103
|
import numpy as np
|
104
|
+
import pandas as pd
|
104
105
|
from pyadps.utils import pyreadrdi
|
105
106
|
|
106
107
|
|
@@ -129,9 +130,7 @@ class DotDict:
|
|
129
130
|
# with open(json_file_path, "r") as file:
|
130
131
|
# dictionary = json.load(file)
|
131
132
|
else:
|
132
|
-
dictionary =
|
133
|
-
{}
|
134
|
-
) # Initialize an empty dictionary if no JSON file is found
|
133
|
+
dictionary = {} # Initialize an empty dictionary if no JSON file is found
|
135
134
|
self._initialize_from_dict(dictionary)
|
136
135
|
|
137
136
|
def _initialize_from_dict(self, dictionary):
|
@@ -326,7 +325,7 @@ class FileHeader:
|
|
326
325
|
"""
|
327
326
|
file_stats = os.stat(self.filename)
|
328
327
|
sys_file_size = file_stats.st_size
|
329
|
-
cal_file_size = sum(self.bytes) + 2 * len(self.bytes)
|
328
|
+
cal_file_size = sum((self.bytes).astype(int)) + 2 * len(self.bytes)
|
330
329
|
|
331
330
|
check = dict()
|
332
331
|
|
@@ -435,7 +434,7 @@ def flead_dict(fid, dim=2):
|
|
435
434
|
"False Target Thresh": "int64",
|
436
435
|
"Spare 1": "int64",
|
437
436
|
"Transmit Lag Dist": "int64",
|
438
|
-
"CPU Serial No": "
|
437
|
+
"CPU Serial No": "int128",
|
439
438
|
"System Bandwidth": "int64",
|
440
439
|
"System Power": "int64",
|
441
440
|
"Spare 2": "int64",
|
@@ -447,9 +446,15 @@ def flead_dict(fid, dim=2):
|
|
447
446
|
counter = 1
|
448
447
|
for key, value in fname.items():
|
449
448
|
if dim == 2:
|
450
|
-
|
449
|
+
if key == "CPU Serial No":
|
450
|
+
flead[key] = np.uint64(fid[:][counter])
|
451
|
+
else:
|
452
|
+
flead[key] = np.int64(fid[:][counter])
|
451
453
|
elif dim == 1:
|
452
|
-
|
454
|
+
if key == "CPU Serial No":
|
455
|
+
flead[key] = np.uint64(fid[counter])
|
456
|
+
else:
|
457
|
+
flead[key] = np.int64(fid[counter])
|
453
458
|
else:
|
454
459
|
print("ERROR: Higher dimensions not allowed")
|
455
460
|
sys.exit()
|
@@ -505,6 +510,7 @@ class FixedLeader:
|
|
505
510
|
)
|
506
511
|
self.warning = pyreadrdi.ErrorCode.get_message(self.error)
|
507
512
|
|
513
|
+
self.data = np.uint64(self.data)
|
508
514
|
self.fleader = flead_dict(self.data)
|
509
515
|
self._initialize_from_dict(DotDict(json_file_path="flmeta.json"))
|
510
516
|
|
@@ -800,7 +806,8 @@ def vlead_dict(vid):
|
|
800
806
|
|
801
807
|
counter = 1
|
802
808
|
for key, value in vname.items():
|
803
|
-
vlead[key] = getattr(np, value)(vid[:][counter])
|
809
|
+
# vlead[key] = getattr(np, value)(vid[:][counter])
|
810
|
+
vlead[key] = vid[:][counter]
|
804
811
|
counter += 1
|
805
812
|
|
806
813
|
return vlead
|
@@ -877,7 +884,7 @@ class VariableLeader:
|
|
877
884
|
setattr(getattr(self, key), "data", self.data[i])
|
878
885
|
i = i + 1
|
879
886
|
|
880
|
-
def
|
887
|
+
def bitresult(self):
|
881
888
|
"""
|
882
889
|
Extracts Bit Results from Variable Leader (Byte 13 & 14)
|
883
890
|
This field is part of the WorkHorse ADCP’s Built-in Test function.
|
@@ -956,8 +963,6 @@ class VariableLeader:
|
|
956
963
|
|
957
964
|
scale_factor = scale_list.get(fixclass["Frequency"])
|
958
965
|
|
959
|
-
print(fixclass["Frequency"])
|
960
|
-
|
961
966
|
channel["Xmit Voltage"] = adc1 * (scale_factor[0] / 1000000)
|
962
967
|
|
963
968
|
channel["Xmit Current"] = adc0 * (scale_factor[1] / 1000000)
|
@@ -974,6 +979,80 @@ class VariableLeader:
|
|
974
979
|
|
975
980
|
return channel
|
976
981
|
|
982
|
+
def error_status_word(self, esw=1):
|
983
|
+
bitset1 = (
|
984
|
+
"Bus Error exception",
|
985
|
+
"Address Error exception",
|
986
|
+
"Zero Divide exception",
|
987
|
+
"Emulator exception",
|
988
|
+
"Unassigned exception",
|
989
|
+
"Watchdog restart occurred",
|
990
|
+
"Batter Saver Power",
|
991
|
+
)
|
992
|
+
|
993
|
+
bitset2 = (
|
994
|
+
"Pinging",
|
995
|
+
"Not Used 1",
|
996
|
+
"Not Used 2",
|
997
|
+
"Not Used 3",
|
998
|
+
"Not Used 4",
|
999
|
+
"Not Used 5",
|
1000
|
+
"Cold Wakeup occured",
|
1001
|
+
"Unknown Wakeup occured",
|
1002
|
+
)
|
1003
|
+
|
1004
|
+
bitset3 = (
|
1005
|
+
"Clock Read error occured",
|
1006
|
+
"Unexpected alarm",
|
1007
|
+
"Clock jump forward",
|
1008
|
+
"Clock jump backward",
|
1009
|
+
"Not Used 6",
|
1010
|
+
"Not Used 7",
|
1011
|
+
"Not Used 8",
|
1012
|
+
"Not Used 9",
|
1013
|
+
)
|
1014
|
+
|
1015
|
+
bitset4 = (
|
1016
|
+
"Not Used 10",
|
1017
|
+
"Not Used 11",
|
1018
|
+
"Not Used 12",
|
1019
|
+
"Power Fail Unrecorded",
|
1020
|
+
"Spurious level 4 intr DSP",
|
1021
|
+
"Spurious level 5 intr UART",
|
1022
|
+
"Spurious level 6 intr CLOCK",
|
1023
|
+
"Level 7 interrup occured",
|
1024
|
+
)
|
1025
|
+
|
1026
|
+
if esw == 1:
|
1027
|
+
bitset = bitset1
|
1028
|
+
errorarray = self.vleader["Error Status Word 1"]
|
1029
|
+
elif esw == 2:
|
1030
|
+
bitset = bitset2
|
1031
|
+
errorarray = self.vleader["Error Status Word 2"]
|
1032
|
+
elif esw == 3:
|
1033
|
+
bitset = bitset3
|
1034
|
+
errorarray = self.vleader["Error Status Word 3"]
|
1035
|
+
else:
|
1036
|
+
bitset = bitset4
|
1037
|
+
errorarray = self.vleader["Error Status Word 4"]
|
1038
|
+
|
1039
|
+
errorstatus = dict()
|
1040
|
+
# bitarray = np.zeros(32, dtype='str')
|
1041
|
+
|
1042
|
+
for item in bitset:
|
1043
|
+
errorstatus[item] = np.array([])
|
1044
|
+
|
1045
|
+
for data in errorarray:
|
1046
|
+
byte_split = format(data, "08b")
|
1047
|
+
bitposition = 0
|
1048
|
+
for item in bitset:
|
1049
|
+
errorstatus[item] = np.append(
|
1050
|
+
errorstatus[item], byte_split[bitposition]
|
1051
|
+
)
|
1052
|
+
bitposition += 1
|
1053
|
+
|
1054
|
+
return errorstatus
|
1055
|
+
|
977
1056
|
|
978
1057
|
class Velocity:
|
979
1058
|
"""
|
@@ -1027,7 +1106,7 @@ class Velocity:
|
|
1027
1106
|
self.cells = cell
|
1028
1107
|
self.beams = beam
|
1029
1108
|
|
1030
|
-
self.
|
1109
|
+
self.unit = "mm/s"
|
1031
1110
|
self.missing_value = "-32768"
|
1032
1111
|
self.scale_factor = 1
|
1033
1112
|
self.valid_min = -32768
|
@@ -1086,7 +1165,7 @@ class Correlation:
|
|
1086
1165
|
self.cells = cell
|
1087
1166
|
self.beams = beam
|
1088
1167
|
|
1089
|
-
self.
|
1168
|
+
self.unit = ""
|
1090
1169
|
self.scale_factor = 1
|
1091
1170
|
self.valid_min = 0
|
1092
1171
|
self.valid_max = 255
|
@@ -1145,7 +1224,7 @@ class Echo:
|
|
1145
1224
|
self.cells = cell
|
1146
1225
|
self.beams = beam
|
1147
1226
|
|
1148
|
-
self.
|
1227
|
+
self.unit = "counts"
|
1149
1228
|
self.scale_factor = "0.45"
|
1150
1229
|
self.valid_min = 0
|
1151
1230
|
self.valid_max = 255
|
@@ -1204,7 +1283,7 @@ class PercentGood:
|
|
1204
1283
|
self.cells = cell
|
1205
1284
|
self.beams = beam
|
1206
1285
|
|
1207
|
-
self.
|
1286
|
+
self.unit = "percent"
|
1208
1287
|
self.valid_min = 0
|
1209
1288
|
self.valid_max = 100
|
1210
1289
|
self.long_name = "Percent Good"
|
@@ -1262,7 +1341,7 @@ class Status:
|
|
1262
1341
|
self.cells = cell
|
1263
1342
|
self.beams = beam
|
1264
1343
|
|
1265
|
-
self.
|
1344
|
+
self.unit = ""
|
1266
1345
|
self.valid_min = 0
|
1267
1346
|
self.valid_max = 1
|
1268
1347
|
self.long_name = "Status Data Format"
|
@@ -1390,6 +1469,47 @@ class ReadFile:
|
|
1390
1469
|
warning_array["Status"] = self.status.warning
|
1391
1470
|
ensemble_array["Status"] = self.status.ensembles
|
1392
1471
|
|
1472
|
+
# Add Time Axis
|
1473
|
+
year = self.variableleader.vleader["RTC Year"]
|
1474
|
+
month = self.variableleader.vleader["RTC Month"]
|
1475
|
+
day = self.variableleader.vleader["RTC Day"]
|
1476
|
+
hour = self.variableleader.vleader["RTC Hour"]
|
1477
|
+
minute = self.variableleader.vleader["RTC Minute"]
|
1478
|
+
second = self.variableleader.vleader["RTC Second"]
|
1479
|
+
year = year + 2000
|
1480
|
+
date_df = pd.DataFrame(
|
1481
|
+
{
|
1482
|
+
"year": year,
|
1483
|
+
"month": month,
|
1484
|
+
"day": day,
|
1485
|
+
"hour": hour,
|
1486
|
+
"minute": minute,
|
1487
|
+
"second": second,
|
1488
|
+
}
|
1489
|
+
)
|
1490
|
+
self.time = pd.to_datetime(date_df)
|
1491
|
+
|
1492
|
+
# Depth
|
1493
|
+
# Create a depth axis with mean depth in 'm'
|
1494
|
+
cell1 = self.fixedleader.field()["Cells"]
|
1495
|
+
bin1dist1 = self.fixedleader.field()["Bin 1 Dist"] / 100
|
1496
|
+
depth_cell_len1 = self.fixedleader.field()["Depth Cell Len"] / 100
|
1497
|
+
beam_direction1 = self.fixedleader.system_configuration()["Beam Direction"]
|
1498
|
+
mean_depth = np.mean(self.variableleader.vleader["Depth of Transducer"]) / 10
|
1499
|
+
mean_depth = np.trunc(mean_depth)
|
1500
|
+
if beam_direction1.lower() == "up":
|
1501
|
+
sgn = -1
|
1502
|
+
else:
|
1503
|
+
sgn = 1
|
1504
|
+
first_depth = mean_depth + sgn * bin1dist1
|
1505
|
+
last_depth = first_depth + sgn * cell1 * depth_cell_len1
|
1506
|
+
z = np.arange(first_depth, last_depth, sgn * depth_cell_len1)
|
1507
|
+
self.depth = z
|
1508
|
+
|
1509
|
+
# Add all attributes/method/data from FixedLeader and VariableLeader
|
1510
|
+
self._copy_attributes_from_var()
|
1511
|
+
|
1512
|
+
# Error Codes and Warnings
|
1393
1513
|
self.error_codes = error_array
|
1394
1514
|
self.warnings = warning_array
|
1395
1515
|
self.ensemble_array = ensemble_array
|
@@ -1405,6 +1525,33 @@ class ReadFile:
|
|
1405
1525
|
else:
|
1406
1526
|
self.isWarning = True
|
1407
1527
|
|
1528
|
+
# Add additional attributes
|
1529
|
+
# Ensemble
|
1530
|
+
dtens = self.ensemble_value_array
|
1531
|
+
minens = np.min(dtens)
|
1532
|
+
self.ensembles = minens
|
1533
|
+
|
1534
|
+
# Add attribute that lists all variables/functions
|
1535
|
+
self.list_vars = list(vars(self).keys())
|
1536
|
+
|
1537
|
+
def _copy_attributes_from_var(self):
|
1538
|
+
for attr_name, attr_value in self.variableleader.__dict__.items():
|
1539
|
+
# Copy each attribute of var into self
|
1540
|
+
setattr(self, attr_name, attr_value)
|
1541
|
+
for attr_name, attr_value in self.fixedleader.__dict__.items():
|
1542
|
+
# Copy each attribute of var into self
|
1543
|
+
setattr(self, attr_name, attr_value)
|
1544
|
+
|
1545
|
+
def __getattr__(self, name):
|
1546
|
+
# Delegate attribute/method access to self.var if not found in self
|
1547
|
+
if hasattr(self.variableleader, name):
|
1548
|
+
return getattr(self.variableleader, name)
|
1549
|
+
if hasattr(self.fixedleader, name):
|
1550
|
+
return getattr(self.fixedleader, name)
|
1551
|
+
raise AttributeError(
|
1552
|
+
f"'{self.__class__.__name__}' object has no attribute '{name}'"
|
1553
|
+
)
|
1554
|
+
|
1408
1555
|
def fixensemble(self, min_cutoff=0):
|
1409
1556
|
"""
|
1410
1557
|
Fixes the ensemble size across all data types in the file if they differ.
|