pyadps 0.1.0__py3-none-any.whl → 0.1.0b0__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/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 (None, ErrorCode.FILE_CORRUPTED)
323
+ return (readbytes, ErrorCode.FILE_CORRUPTED)
324
324
  else:
325
325
  return (readbytes, ErrorCode.SUCCESS)
326
326
 
@@ -427,7 +427,6 @@ 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)
431
430
  return dummytuple
432
431
  else:
433
432
  if headerid[i] != 127 or sourceid[i] != 127:
@@ -443,14 +442,8 @@ def fileheader(rdi_file):
443
442
  print(f"Ensembles reset to {i}" + bcolors.ENDC)
444
443
  break
445
444
 
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
445
+ data = unpack("H" * datatype[i], dbyte)
446
+ address_offset.append(data)
454
447
 
455
448
  skip_array = [None] * datatype[i]
456
449
  for dtype in range(datatype[i]):
@@ -560,7 +553,7 @@ def fixedleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=0):
560
553
  fbyteskip = None
561
554
  for count, item in enumerate(idarray[i]):
562
555
  if item in (0, 1):
563
- fbyteskip = offset[0][count]
556
+ fbyteskip = offset[1][count]
564
557
  if fbyteskip == None:
565
558
  error = ErrorCode.ID_NOT_FOUND
566
559
  ensemble = i
@@ -710,7 +703,7 @@ def variableleader(rdi_file, byteskip=None, offset=None, idarray=None, ensemble=
710
703
  fbyteskip = None
711
704
  for count, item in enumerate(idarray[i]):
712
705
  if item in (128, 129):
713
- fbyteskip = offset[0][count]
706
+ fbyteskip = offset[1][count]
714
707
  if fbyteskip == None:
715
708
  error = ErrorCode.ID_NOT_FOUND
716
709
  ensemble = i
@@ -942,7 +935,7 @@ def datatype(
942
935
  fbyteskip = None
943
936
  for count, item in enumerate(idarray[0][:]):
944
937
  if item in vid:
945
- fbyteskip = offset[0][count]
938
+ fbyteskip = offset[1][count]
946
939
  break
947
940
  if fbyteskip is None:
948
941
  print(
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,7 +101,6 @@ import os
101
101
  import sys
102
102
 
103
103
  import numpy as np
104
- import pandas as pd
105
104
  from pyadps.utils import pyreadrdi
106
105
 
107
106
 
@@ -130,7 +129,9 @@ class DotDict:
130
129
  # with open(json_file_path, "r") as file:
131
130
  # dictionary = json.load(file)
132
131
  else:
133
- dictionary = {} # Initialize an empty dictionary if no JSON file is found
132
+ dictionary = (
133
+ {}
134
+ ) # Initialize an empty dictionary if no JSON file is found
134
135
  self._initialize_from_dict(dictionary)
135
136
 
136
137
  def _initialize_from_dict(self, dictionary):
@@ -325,7 +326,7 @@ class FileHeader:
325
326
  """
326
327
  file_stats = os.stat(self.filename)
327
328
  sys_file_size = file_stats.st_size
328
- cal_file_size = sum((self.bytes).astype(int)) + 2 * len(self.bytes)
329
+ cal_file_size = sum(self.bytes) + 2 * len(self.bytes)
329
330
 
330
331
  check = dict()
331
332
 
@@ -434,7 +435,7 @@ def flead_dict(fid, dim=2):
434
435
  "False Target Thresh": "int64",
435
436
  "Spare 1": "int64",
436
437
  "Transmit Lag Dist": "int64",
437
- "CPU Serial No": "int128",
438
+ "CPU Serial No": "int64",
438
439
  "System Bandwidth": "int64",
439
440
  "System Power": "int64",
440
441
  "Spare 2": "int64",
@@ -446,15 +447,9 @@ def flead_dict(fid, dim=2):
446
447
  counter = 1
447
448
  for key, value in fname.items():
448
449
  if dim == 2:
449
- if key == "CPU Serial No":
450
- flead[key] = np.uint64(fid[:][counter])
451
- else:
452
- flead[key] = np.int64(fid[:][counter])
450
+ flead[key] = getattr(np, value)(fid[:][counter])
453
451
  elif dim == 1:
454
- if key == "CPU Serial No":
455
- flead[key] = np.uint64(fid[counter])
456
- else:
457
- flead[key] = np.int64(fid[counter])
452
+ flead[key] = getattr(np, value)(fid[counter])
458
453
  else:
459
454
  print("ERROR: Higher dimensions not allowed")
460
455
  sys.exit()
@@ -510,7 +505,6 @@ class FixedLeader:
510
505
  )
511
506
  self.warning = pyreadrdi.ErrorCode.get_message(self.error)
512
507
 
513
- self.data = np.uint64(self.data)
514
508
  self.fleader = flead_dict(self.data)
515
509
  self._initialize_from_dict(DotDict(json_file_path="flmeta.json"))
516
510
 
@@ -806,8 +800,7 @@ def vlead_dict(vid):
806
800
 
807
801
  counter = 1
808
802
  for key, value in vname.items():
809
- # vlead[key] = getattr(np, value)(vid[:][counter])
810
- vlead[key] = vid[:][counter]
803
+ vlead[key] = getattr(np, value)(vid[:][counter])
811
804
  counter += 1
812
805
 
813
806
  return vlead
@@ -884,7 +877,7 @@ class VariableLeader:
884
877
  setattr(getattr(self, key), "data", self.data[i])
885
878
  i = i + 1
886
879
 
887
- def bitresult(self):
880
+ def bit_result(self):
888
881
  """
889
882
  Extracts Bit Results from Variable Leader (Byte 13 & 14)
890
883
  This field is part of the WorkHorse ADCP’s Built-in Test function.
@@ -963,6 +956,8 @@ class VariableLeader:
963
956
 
964
957
  scale_factor = scale_list.get(fixclass["Frequency"])
965
958
 
959
+ print(fixclass["Frequency"])
960
+
966
961
  channel["Xmit Voltage"] = adc1 * (scale_factor[0] / 1000000)
967
962
 
968
963
  channel["Xmit Current"] = adc0 * (scale_factor[1] / 1000000)
@@ -979,80 +974,6 @@ class VariableLeader:
979
974
 
980
975
  return channel
981
976
 
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
-
1056
977
 
1057
978
  class Velocity:
1058
979
  """
@@ -1106,7 +1027,7 @@ class Velocity:
1106
1027
  self.cells = cell
1107
1028
  self.beams = beam
1108
1029
 
1109
- self.unit = "mm/s"
1030
+ self.units = "mm/s"
1110
1031
  self.missing_value = "-32768"
1111
1032
  self.scale_factor = 1
1112
1033
  self.valid_min = -32768
@@ -1165,7 +1086,7 @@ class Correlation:
1165
1086
  self.cells = cell
1166
1087
  self.beams = beam
1167
1088
 
1168
- self.unit = ""
1089
+ self.units = ""
1169
1090
  self.scale_factor = 1
1170
1091
  self.valid_min = 0
1171
1092
  self.valid_max = 255
@@ -1224,7 +1145,7 @@ class Echo:
1224
1145
  self.cells = cell
1225
1146
  self.beams = beam
1226
1147
 
1227
- self.unit = "counts"
1148
+ self.units = "counts"
1228
1149
  self.scale_factor = "0.45"
1229
1150
  self.valid_min = 0
1230
1151
  self.valid_max = 255
@@ -1283,7 +1204,7 @@ class PercentGood:
1283
1204
  self.cells = cell
1284
1205
  self.beams = beam
1285
1206
 
1286
- self.unit = "percent"
1207
+ self.units = "percent"
1287
1208
  self.valid_min = 0
1288
1209
  self.valid_max = 100
1289
1210
  self.long_name = "Percent Good"
@@ -1341,7 +1262,7 @@ class Status:
1341
1262
  self.cells = cell
1342
1263
  self.beams = beam
1343
1264
 
1344
- self.unit = ""
1265
+ self.units = ""
1345
1266
  self.valid_min = 0
1346
1267
  self.valid_max = 1
1347
1268
  self.long_name = "Status Data Format"
@@ -1469,47 +1390,6 @@ class ReadFile:
1469
1390
  warning_array["Status"] = self.status.warning
1470
1391
  ensemble_array["Status"] = self.status.ensembles
1471
1392
 
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
1513
1393
  self.error_codes = error_array
1514
1394
  self.warnings = warning_array
1515
1395
  self.ensemble_array = ensemble_array
@@ -1525,33 +1405,6 @@ class ReadFile:
1525
1405
  else:
1526
1406
  self.isWarning = True
1527
1407
 
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
-
1555
1408
  def fixensemble(self, min_cutoff=0):
1556
1409
  """
1557
1410
  Fixes the ensemble size across all data types in the file if they differ.
pyadps/utils/regrid.py ADDED
@@ -0,0 +1,122 @@
1
+ import numpy as np
2
+ import scipy as sp
3
+
4
+ # import readrdi as rd
5
+
6
+
7
+ def regrid2d(
8
+ flobj,
9
+ vlobj,
10
+ data,
11
+ fill_value,
12
+ minimum_depth="cell",
13
+ trimends=None,
14
+ method="nearest",
15
+ ):
16
+ depth = vlobj.vleader["Depth of Transducer"] / 10
17
+ depth_interval = flobj.field()["Depth Cell Len"] / 100
18
+ bins = flobj.field()["Cells"]
19
+ ensembles = flobj.ensembles
20
+
21
+ # Create a regular grid
22
+ # Find the minimum depth.
23
+ if minimum_depth == "surface":
24
+ mindepth = depth_interval
25
+ elif minimum_depth == "cell":
26
+ if trimends is not None:
27
+ dm = np.min(depth[trimends[0] : trimends[1]])
28
+ else:
29
+ dm = np.min(depth)
30
+ mintransdepth = dm - bins * depth_interval
31
+ mindepth = mintransdepth - mintransdepth % depth_interval
32
+ mindepth = mindepth - depth_interval
33
+ # If mindepth is above surface choose surface
34
+ if mindepth < 0:
35
+ mindepth = depth_interval
36
+ else:
37
+ mindepth = depth_interval
38
+
39
+ maxbins = np.max(depth) // depth_interval + 1
40
+ # print(np.max(depth), np.max(depth) % depth_interval)
41
+ # if np.max(depth) % depth_interval > depth_interval / 2:
42
+ # maxbins = maxbins + 1
43
+
44
+ maxdepth = maxbins * depth_interval
45
+ z = np.arange(-1 * maxdepth, -1 * mindepth, depth_interval)
46
+ regbins = len(z)
47
+
48
+ # print(maxbins, bins, ensemble)
49
+ data_regrid = np.zeros((regbins, ensembles))
50
+
51
+ # Create original depth array
52
+ for i, d in enumerate(depth):
53
+ n = -1 * d + depth_interval * bins
54
+ depth_bins = np.arange(-1 * d, n, depth_interval)
55
+ f = sp.interpolate.interp1d(
56
+ depth_bins,
57
+ data[:, i],
58
+ kind=method,
59
+ fill_value=fill_value,
60
+ bounds_error=False,
61
+ )
62
+ gridz = f(z)
63
+
64
+ data_regrid[:, i] = gridz
65
+
66
+ return z, data_regrid
67
+
68
+
69
+ def regrid3d(
70
+ flobj,
71
+ vlobj,
72
+ data,
73
+ fill_value,
74
+ minimum_depth="cell",
75
+ trimends=None,
76
+ method="nearest",
77
+ ):
78
+ beams = flobj.field()["Beams"]
79
+ z, data_dummy = regrid2d(
80
+ flobj,
81
+ vlobj,
82
+ data[0, :, :],
83
+ fill_value,
84
+ minimum_depth=minimum_depth,
85
+ trimends=trimends,
86
+ method=method,
87
+ )
88
+
89
+ newshape = np.shape(data_dummy)
90
+ data_regrid = np.zeros((beams, newshape[0], newshape[1]))
91
+ data_regrid[0, :, :] = data_dummy
92
+
93
+ for i in range(beams - 1):
94
+ z, data_dummy = regrid2d(
95
+ flobj,
96
+ vlobj,
97
+ data[i + 1, :, :],
98
+ fill_value,
99
+ minimum_depth=minimum_depth,
100
+ trimends=trimends,
101
+ method=method,
102
+ )
103
+ data_regrid[i + 1, :, :] = data_dummy
104
+
105
+ return z, data_regrid
106
+
107
+
108
+ # # read data
109
+ # filename = "BGS11000.000"
110
+ # fl = rd.FixedLeader(filename, run="fortran")
111
+ # vl = rd.VariableLeader(filename, run="fortran")
112
+ # # echo = rd.echo(filename, run="fortran")
113
+ # vel = rd.velocity(filename, run="fortran")
114
+ # pressure = vl.vleader["Pressure"]
115
+ #
116
+ # shape = np.shape(vel[0, :, :])
117
+ # mask = np.zeros(shape)
118
+ # orig_mask = np.copy(mask)
119
+ #
120
+ # z, newvel = regrid2d(fl, vl, vel[0, :, :], fill_value=-32768)
121
+ # z, newmask = regrid(mask[:, :], pressure, depth_interval=4, fill_value=1)
122
+ # z, newvel3d = regrid3d(vel, pressure, depth_interval=4, fill_value=-32768)