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.
Files changed (39) hide show
  1. pyadps/Home_Page.py +11 -5
  2. pyadps/pages/01_Read_File.py +623 -215
  3. pyadps/pages/02_View_Raw_Data.py +97 -41
  4. pyadps/pages/03_Download_Raw_File.py +200 -67
  5. pyadps/pages/04_Sensor_Health.py +905 -0
  6. pyadps/pages/05_QC_Test.py +493 -0
  7. pyadps/pages/06_Profile_Test.py +971 -0
  8. pyadps/pages/07_Velocity_Test.py +600 -0
  9. pyadps/pages/08_Write_File.py +623 -0
  10. pyadps/pages/09_Add-Ons.py +168 -0
  11. pyadps/utils/__init__.py +5 -3
  12. pyadps/utils/autoprocess.py +371 -80
  13. pyadps/utils/logging_utils.py +269 -0
  14. pyadps/utils/metadata/config.ini +22 -4
  15. pyadps/utils/metadata/demo.000 +0 -0
  16. pyadps/utils/metadata/flmeta.json +420 -420
  17. pyadps/utils/metadata/vlmeta.json +611 -565
  18. pyadps/utils/multifile.py +292 -0
  19. pyadps/utils/plotgen.py +505 -3
  20. pyadps/utils/profile_test.py +720 -125
  21. pyadps/utils/pyreadrdi.py +164 -92
  22. pyadps/utils/readrdi.py +436 -186
  23. pyadps/utils/script.py +197 -147
  24. pyadps/utils/sensor_health.py +120 -0
  25. pyadps/utils/signal_quality.py +472 -68
  26. pyadps/utils/velocity_test.py +79 -31
  27. pyadps/utils/writenc.py +222 -39
  28. {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/METADATA +13 -14
  29. pyadps-0.3.0.dist-info/RECORD +35 -0
  30. {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/WHEEL +1 -1
  31. {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/entry_points.txt +1 -0
  32. pyadps/pages/04_QC_Test.py +0 -334
  33. pyadps/pages/05_Profile_Test.py +0 -575
  34. pyadps/pages/06_Velocity_Test.py +0 -341
  35. pyadps/pages/07_Write_File.py +0 -452
  36. pyadps/utils/cutbin.py +0 -413
  37. pyadps/utils/regrid.py +0 -279
  38. pyadps-0.2.1b0.dist-info/RECORD +0 -31
  39. {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/LICENSE +0 -0
pyadps/utils/script.py CHANGED
@@ -1,155 +1,205 @@
1
- import sys
2
-
1
+ import os
3
2
  import matplotlib.pyplot as plt
4
3
  import numpy as np
5
4
  import pyadps.utils.readrdi as rd
6
- from pyadps.utils.cutbin import CutBins
7
- from pyadps.utils.plotgen import plotmask, plotvar
5
+ from pyadps.utils.plotgen import CutBins
8
6
  from pyadps.utils.profile_test import side_lobe_beam_angle, trim_ends
9
- from pyadps.utils.regrid import regrid2d, regrid3d
10
- from pyadps.utils.signal_quality import (default_mask, ev_check, false_target,
11
- pg_check, qc_check, qc_prompt)
12
- from pyadps.utils.velocity_test import (despike, flatline,
13
- magnetic_declination, velocity_cutoff)
7
+ from pyadps.utils.profile_test import regrid2d, regrid3d
8
+ from pyadps.utils.signal_quality import (
9
+ default_mask,
10
+ ev_check,
11
+ false_target,
12
+ pg_check,
13
+ correlation_check,
14
+ echo_check,
15
+ qc_prompt,
16
+ )
17
+ from pyadps.utils.velocity_test import (
18
+ despike,
19
+ flatline,
20
+ velocity_modifier,
21
+ wmm2020api,
22
+ velocity_cutoff,
23
+ )
24
+
25
+ import pyadps.utils.writenc as wr
14
26
 
15
27
  plt.style.use("seaborn-v0_8-darkgrid")
16
28
 
17
29
 
18
- # Read data
19
- filename = "/home/amol/Desktop/BGS11000.000"
20
- ds = rd.ReadFile(filename)
21
- fl = ds.fixedleader
22
- vl = ds.variableleader
23
- vel = ds.velocity.data
24
- echo = ds.echo.data
25
- cor = ds.correlation.data
26
- pgood = ds.percentgood.data
27
-
28
- # Data pressure = vl.vleader["Pressure"]
29
- beam_angle = int(fl.system_configuration()["Beam Angle"])
30
- cell_size = fl.field()["Depth Cell Len"]
31
- blank_size = fl.field()["Blank Transmit"]
32
- cells = fl.field()["Cells"]
33
-
34
- # sys.exit()
35
-
36
- # Original mask created from velocity
37
- mask = default_mask(fl, vel)
38
- orig_mask = np.copy(mask)
39
-
40
- # Default threshold
41
- ct = fl.field()["Correlation Thresh"]
42
- et = 0
43
- pgt = fl.field()["Percent Good Min"]
44
- evt = fl.field()["Error Velocity Thresh"]
45
- ft = fl.field()["False Target Thresh"]
46
-
47
- print(ct, et, pgt, evt, ft)
48
-
49
- # Get the threshold values
50
- ct = qc_prompt(fl, "Correlation Thresh")
51
- evt = qc_prompt(fl, "Error Velocity Thresh")
52
- pgt = qc_prompt(fl, "Percent Good Min")
53
- et = qc_prompt(fl, "Echo Intensity Thresh", echo)
54
- ft = qc_prompt(fl, "False Target Thresh")
55
-
56
- # Apply threshold
57
- values, counts = np.unique(mask, return_counts=True)
58
- print(values, counts, np.round(counts * 100 / np.sum(counts)))
59
- mask = pg_check(pgood, mask, pgt)
60
- mask = qc_check(cor, mask, ct)
61
- mask = qc_check(echo, mask, et)
62
- mask = ev_check(vel[3, :, :], mask, evt)
63
- mask = false_target(echo, mask, ft, threebeam=True)
64
-
65
-
66
- ########## PROFILE TEST #########
67
-
68
- affirm = input("Would you like to trim the ends? [y/n]: ")
69
- if affirm.lower() == "y":
70
- mask = trim_ends(vl, mask)
71
-
72
- affirm = input("Would you remove the surface backscatter bins? [y/n]: ")
73
- if affirm.lower() == "y":
74
- mask = side_lobe_beam_angle(fl, vl, mask)
75
-
76
- affirm = input("Would you like to manually select and mask data?")
77
- if affirm.lower() == "y":
78
- manual = CutBins(echo[0, :, :], mask)
79
- plt.show()
80
- mask = manual.mask()
81
-
82
- affirm = input("Regrid the data based on pressure sensor? [y/n]:")
83
- if affirm.lower() == "y":
84
- z, vel = regrid3d(fl, vl, vel, -32768)
85
- z, echo_reg = regrid3d(fl, vl, echo, -32768)
86
- z, correlation_reg = regrid3d(fl, vl, cor, -32768)
87
- z, percentgood_reg = regrid3d(fl, vl, pgood, -32768)
88
- z, mask = regrid2d(fl, vl, mask, -32768)
89
-
90
- # affirm = input("Display original and revised mask files? [y/n]:")
91
- # if affirm.lower() == "y":
92
- # plotmask(orig_mask, mask)
93
-
94
-
95
- ########## VELOCITY TEST ##########
96
- affirm = input("Apply correction for magnetic declination? [y/n]:")
97
- if affirm.lower() == "y":
98
- lat = input("Enter Latitude: ")
99
- lat = float(lat)
100
-
101
- lon = input("Enter Longitude: ")
102
- lon = float(lon)
103
-
104
- depth = input("Enter Depth (m): ")
105
- depth = float(depth)
106
-
107
- year = input("Year: ")
108
- year = int(year)
109
-
110
- velocity = magnetic_declination(vel, lat, lon, depth, year)
111
-
112
- affirm = input("Apply velocity thresholds [y/n]: ")
113
- if affirm.lower() == "y":
114
- maxuvel = input("Enter maximum zonal velocity: ")
115
- maxuvel = float(maxuvel)
116
-
117
- maxvvel = input("Enter maximum meridional velocity: ")
118
- maxvvel = float(maxvvel)
119
-
120
- maxwvel = input("Enter maximum vertical velocity: ")
121
- maxwvel = float(maxwvel)
122
- mask = velocity_cutoff(vel[0, :, :], mask, cutoff=maxuvel)
123
- mask = velocity_cutoff(vel[1, :, :], mask, cutoff=maxvvel)
124
- mask = velocity_cutoff(vel[2, :, :], mask, cutoff=maxwvel)
125
-
126
- affirm = input("Despike the data? [y/n]: ")
127
- if affirm.lower() == "y":
128
- despike_kernal = input("Enter despike kernal size:")
129
- despike_kernal = int(despike_kernal)
130
-
131
- despike_cutoff = input("Enter despike cutoff (mm/s): ")
132
- despike_cutoff = float(despike_cutoff)
133
-
134
- mask = despike(
135
- vel[0, :, :], mask, kernal_size=despike_kernal, cutoff=despike_cutoff
136
- )
137
- mask = despike(
138
- vel[1, :, :], mask, kernal_size=despike_kernal, cutoff=despike_cutoff
139
- )
140
-
141
- affirm = input("Remove flatlines? [y/n]: ")
142
- if affirm.lower() == "y":
143
- flatline_kernal = input("Enter despike kernal size:")
144
- flatline_kernal = int(flatline_kernal)
145
- flatline_cutoff = input("Enter Flatline deviation: [y/n]")
146
- flatlineL_cutoff = int(flatline_cutoff)
147
- mask = flatline(
148
- velocity[0, :, :], mask, kernal_size=flatline_kernal, cutoff=flatline_cutoff
149
- )
150
- mask = flatline(
151
- velocity[1, :, :], mask, kernal_size=flatline_kernal, cutoff=flatline_cutoff
152
- )
153
- mask = flatline(
154
- velocity[2, :, :], mask, kernal_size=flatline_kernal, cutoff=flatline_cutoff
155
- )
30
+ def main():
31
+ # Get the config file
32
+ try:
33
+ filepath = input("Enter file name: ")
34
+ if os.path.exists(filepath):
35
+ run_script(filepath)
36
+ else:
37
+ print("File not found!")
38
+ except Exception as e:
39
+ import traceback
40
+
41
+ print("Error: Unable to process the data.")
42
+ traceback.print_exc()
43
+
44
+
45
+ # filename = "./metadata/demo.000"
46
+
47
+
48
+ def run_script(filename):
49
+ ds = rd.ReadFile(filename)
50
+ fl = ds.fixedleader
51
+ vl = ds.variableleader
52
+ vel = ds.velocity.data
53
+ echo = ds.echo.data
54
+ cor = ds.correlation.data
55
+ pgood = ds.percentgood.data
56
+ time = ds.time
57
+ beamdir = ds.fixedleader.system_configuration()["Beam Direction"]
58
+
59
+ # Data pressure = vl.vleader["Pressure"]
60
+ # beam_angle = int(fl.system_configuration()["Beam Angle"])
61
+ # blank_size = fl.field()["Blank Transmit"]
62
+ cell_size = fl.field()["Depth Cell Len"] / 100
63
+ cells = fl.field()["Cells"]
64
+ bin1dist = fl.field()["Bin 1 Dist"] / 100
65
+
66
+ mean_depth = np.mean(ds.variableleader.depth_of_transducer.data) / 10
67
+ mean_depth = np.trunc(mean_depth)
68
+ if beamdir.lower() == "up":
69
+ sgn = -1
70
+ else:
71
+ sgn = 1
72
+
73
+ first_depth = mean_depth + sgn * bin1dist
74
+ last_depth = first_depth + sgn * cells * cell_size
75
+ z = np.arange(first_depth, last_depth, sgn * cell_size)
76
+
77
+ # Original mask created from velocity
78
+ mask = default_mask(ds)
79
+ orig_mask = np.copy(mask)
80
+
81
+ # Default threshold
82
+ ct = fl.field()["Correlation Thresh"]
83
+ et = 0
84
+ pgt = fl.field()["Percent Good Min"]
85
+ evt = fl.field()["Error Velocity Thresh"]
86
+ ft = fl.field()["False Target Thresh"]
87
+
88
+ # Get the threshold values
89
+ ct = qc_prompt(ds, "Correlation Thresh")
90
+ evt = qc_prompt(ds, "Error Velocity Thresh")
91
+ pgt = qc_prompt(ds, "Percent Good Min")
92
+ et = qc_prompt(ds, "Echo Intensity Thresh", echo)
93
+ ft = qc_prompt(ds, "False Target Thresh")
94
+
95
+ # Apply threshold
96
+ # values, counts = np.unique(mask, return_counts=True)
97
+ # print(values, counts, np.round(counts * 100 / np.sum(counts)))
98
+ print("Applying Thresholds")
99
+ mask = pg_check(ds, mask, pgt)
100
+ mask = correlation_check(ds, mask, ct)
101
+ mask = echo_check(ds, mask, et)
102
+ mask = ev_check(ds, mask, evt)
103
+ mask = false_target(ds, mask, ft, threebeam=True)
104
+
105
+ ########## PROFILE TEST #########
106
+
107
+ affirm = input("Would you like to trim the ends? [y/n]: ")
108
+ if affirm.lower() == "y":
109
+ mask = trim_ends(ds, mask)
110
+
111
+ affirm = input("Would you remove the surface backscatter bins? [y/n]: ")
112
+ if affirm.lower() == "y":
113
+ mask = side_lobe_beam_angle(ds, mask)
114
+
115
+ affirm = input("Would you like to manually select and mask data? [y/n]: ")
116
+ if affirm.lower() == "y":
117
+ manual = CutBins(echo[0, :, :], mask)
118
+ plt.show()
119
+ mask = manual.mask()
120
+
121
+ affirm = input("Regrid the data based on pressure sensor? [y/n]:")
122
+ if affirm.lower() == "y":
123
+ z, vel = regrid3d(ds, vel, -32768)
124
+ z, echo_reg = regrid3d(ds, echo, -32768)
125
+ z, correlation_reg = regrid3d(ds, cor, -32768)
126
+ z, percentgood_reg = regrid3d(ds, pgood, -32768)
127
+ z, mask = regrid2d(ds, mask, -32768)
128
+
129
+ ########## VELOCITY TEST ##########
130
+ affirm = input("Apply correction for magnetic declination? [y/n]:")
131
+ if affirm.lower() == "y":
132
+ lat = input("Enter Latitude: ")
133
+ lat = float(lat)
134
+
135
+ lon = input("Enter Longitude: ")
136
+ lon = float(lon)
137
+
138
+ depth = input("Enter Depth (m): ")
139
+ depth = float(depth)
140
+
141
+ year = input("Year: ")
142
+ year = int(year)
143
+
144
+ mag = wmm2020api(lat, lon, year)
145
+ vel = velocity_modifier(vel, mag)
146
+
147
+ affirm = input("Apply velocity thresholds [y/n]: ")
148
+ if affirm.lower() == "y":
149
+ maxuvel = input("Enter maximum zonal velocity: ")
150
+ maxuvel = float(maxuvel)
151
+
152
+ maxvvel = input("Enter maximum meridional velocity: ")
153
+ maxvvel = float(maxvvel)
154
+
155
+ maxwvel = input("Enter maximum vertical velocity: ")
156
+ maxwvel = float(maxwvel)
157
+ mask = velocity_cutoff(vel[0, :, :], mask, cutoff=maxuvel)
158
+ mask = velocity_cutoff(vel[1, :, :], mask, cutoff=maxvvel)
159
+ mask = velocity_cutoff(vel[2, :, :], mask, cutoff=maxwvel)
160
+
161
+ affirm = input("Despike the data? [y/n]: ")
162
+ if affirm.lower() == "y":
163
+ despike_kernel = input("Enter despike kernel size:")
164
+ despike_kernel = int(despike_kernel)
165
+
166
+ despike_cutoff = input("Enter despike cutoff (mm/s): ")
167
+ despike_cutoff = float(despike_cutoff)
168
+
169
+ mask = despike(
170
+ vel[0, :, :], mask, kernel_size=despike_kernel, cutoff=despike_cutoff
171
+ )
172
+ mask = despike(
173
+ vel[1, :, :], mask, kernel_size=despike_kernel, cutoff=despike_cutoff
174
+ )
175
+
176
+ affirm = input("Remove flatlines? [y/n]: ")
177
+ if affirm.lower() == "y":
178
+ flatline_kernel = input("Enter despike kernel size:")
179
+ flatline_kernel = int(flatline_kernel)
180
+ flatline_cutoff = input("Enter Flatline deviation: [y/n]")
181
+ flatlineL_cutoff = int(flatline_cutoff)
182
+ mask = flatline(
183
+ vel[0, :, :], mask, kernel_size=flatline_kernel, cutoff=flatline_cutoff
184
+ )
185
+ mask = flatline(
186
+ vel[1, :, :], mask, kernel_size=flatline_kernel, cutoff=flatline_cutoff
187
+ )
188
+ mask = flatline(
189
+ vel[2, :, :], mask, kernel_size=flatline_kernel, cutoff=flatline_cutoff
190
+ )
191
+ apply_mask = input("Apply mask? [y/n]: ")
192
+ if apply_mask.lower() == "y":
193
+ for i in range(4):
194
+ vel[i, :, :] = np.where(mask == 0, vel[i, :, :], -32768)
195
+
196
+ outfilepath = input("Enter output file name (*nc): ")
197
+ if os.path.exists(outfilepath):
198
+ if os.path.isfile(outfilepath):
199
+ print(f"The file already exists: {outfilepath}")
200
+ else:
201
+ wr.finalnc(outfilepath, z, mask, time, vel)
202
+
203
+
204
+ if __name__ == "__main__":
205
+ main()
@@ -0,0 +1,120 @@
1
+ import numpy as np
2
+
3
+
4
+ def sound_speed_correction(
5
+ velocity: np.ndarray,
6
+ sound_speed: np.ndarray,
7
+ temperature: np.ndarray,
8
+ salinity: np.ndarray,
9
+ depth: np.ndarray,
10
+ horizontal: bool = True,
11
+ ) -> np.ndarray:
12
+ """
13
+ Corrects velocity measurements for variations in sound speed.
14
+
15
+ The function calculates the corrected sound speed based on temperature,
16
+ salinity, and depth using empirical equations. It then adjusts the velocity
17
+ measurements for the u and v components using the ratio of the original
18
+ and corrected sound speeds, while leaving the w component unchanged by default.
19
+
20
+ Parameter:
21
+ ----------
22
+ velocity (numpy.ndarray): 4D array of velocity measurements in m/s with
23
+ components (u, v, w, error) along depth and time axes. Missing values
24
+ should be represented by -32768.
25
+ sound_speed (numpy.ndarray): 1D array of measured sound speed in m/s as a function of time.
26
+ temperature (numpy.ndarray): 1D array of temperature in degrees Celsius as a function of time.
27
+ salinity (numpy.ndarray): 1D array of salinity in PSU (Practical Salinity Units) as a function of time.
28
+ depth (numpy.ndarray): 1D array of transducer depth in meters as a function of time.
29
+ horizontal (bool): By default only horizontal velocities are corrected.
30
+
31
+ Returns:
32
+ --------
33
+ numpy.ndarray: 3D array of corrected velocity measurements as 32-bit integers.
34
+ The w component remains unchanged. Missing values (-32768) remain unchanged.
35
+
36
+ Notes:
37
+ ------
38
+ The sound speed correction formula is derived empirically using the
39
+ equation (Urick, 1983).
40
+ """
41
+ # Calculate corrected sound speed
42
+ sound_speed_corrected = (
43
+ 1449.2
44
+ + 4.6 * temperature
45
+ - 0.055 * temperature**2
46
+ + 0.00029 * temperature**3
47
+ + (1.34 - 0.01 * temperature) * (salinity - 35)
48
+ + 0.016 * depth
49
+ )
50
+
51
+ sound_speed = sound_speed
52
+ sound_speed_corrected = sound_speed_corrected
53
+ # Separate u, v, and w components
54
+ u = velocity[0, :, :]
55
+ v = velocity[1, :, :]
56
+ w = velocity[2, :, :]
57
+ e = velocity[3, :, :]
58
+
59
+ # Correct u and v components
60
+ u_corrected = np.where(
61
+ u == -32768,
62
+ -32768.0,
63
+ u * sound_speed[np.newaxis, :] / sound_speed_corrected[np.newaxis, :],
64
+ )
65
+
66
+ v_corrected = np.where(
67
+ v == -32768,
68
+ -32768.0,
69
+ v * sound_speed[np.newaxis, :] / sound_speed_corrected[np.newaxis, :],
70
+ )
71
+
72
+ if not horizontal:
73
+ w_corrected = np.where(
74
+ w == -32768,
75
+ -32768.0,
76
+ w * sound_speed[np.newaxis, :] / sound_speed_corrected[np.newaxis, :],
77
+ )
78
+ else:
79
+ w_corrected = w
80
+
81
+ # Combine corrected components back into a 4D array
82
+ velocity_corrected = np.stack(
83
+ [
84
+ u_corrected.astype(np.int32),
85
+ v_corrected.astype(np.int32),
86
+ w_corrected.astype(np.int32),
87
+ e.astype(np.int32),
88
+ ],
89
+ axis=0,
90
+ )
91
+
92
+ return velocity_corrected
93
+
94
+
95
+ def tilt_sensor_check(
96
+ tilt: np.ndarray, mask: np.ndarray, cutoff: int = 15
97
+ ) -> np.ndarray:
98
+ """
99
+ Updates the given 2D mask array based on the tilt sensor readings. If the tilt value in
100
+ the 1D tilt array exceeds the specified cutoff, the corresponding values in the mask are
101
+ set to 1.
102
+
103
+ Parameters
104
+ ----------
105
+ tilt : np.ndarray
106
+ A 1D array of tilt sensor readings.
107
+ mask : np.ndarray
108
+ A 2D array where the tilt values are checked against the cutoff.
109
+ cutoff : int, optional
110
+ The tilt value threshold. Default is 15. If a tilt value exceeds this threshold,
111
+ the corresponding mask value is updated to 1.
112
+
113
+ Returns
114
+ -------
115
+ np.ndarray
116
+ A 2D array with updated mask values where tilt exceeds the cutoff.
117
+ """
118
+ tilt = tilt * 0.01
119
+ updated_mask = np.where(tilt[:, np.newaxis] > cutoff, 1, mask.T)
120
+ return updated_mask.T