pyadps 0.2.0b0__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 -211
  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.0b0.dist-info → pyadps-0.3.0.dist-info}/METADATA +63 -33
  29. pyadps-0.3.0.dist-info/RECORD +35 -0
  30. {pyadps-0.2.0b0.dist-info → pyadps-0.3.0.dist-info}/WHEEL +1 -1
  31. {pyadps-0.2.0b0.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.0b0.dist-info/RECORD +0 -31
  39. {pyadps-0.2.0b0.dist-info → pyadps-0.3.0.dist-info}/LICENSE +0 -0
@@ -1,9 +1,24 @@
1
1
  from itertools import groupby
2
+ from pygeomag import GeoMag
2
3
 
3
4
  import requests
4
5
  import numpy as np
5
6
  import scipy as sp
6
7
 
8
+
9
+ def magdec(glat, glon, alt, time):
10
+ # Selecting COF file According to given year
11
+ if time >= 2010 and time < 2030:
12
+ var = 2010 + (int(time) - 2010) // 5 * 5
13
+ file_name = "wmm/WMM_{}.COF".format(str(var))
14
+ geo_mag = GeoMag(coefficients_file=file_name)
15
+ else:
16
+ geo_mag = GeoMag("wmm/WMM_2025.COF")
17
+ result = geo_mag.calculate(glat=glat, glon=glon, alt=alt, time=time)
18
+
19
+ return [[result.d]]
20
+
21
+
7
22
  def wmm2020api(lat1, lon1, year):
8
23
  """
9
24
  This function uses the WMM2020 API to retrieve the magnetic field values at a given location
@@ -18,37 +33,60 @@ def wmm2020api(lat1, lon1, year):
18
33
  Returns:
19
34
  mag -> magnetic declination at the given location in degree.
20
35
  """
21
- baseurl = "https://www.ngdc.noaa.gov/geomag-web/calculators/calculateDeclination?"
36
+ baseurl_wmm = (
37
+ "https://www.ngdc.noaa.gov/geomag-web/calculators/calculateDeclination?"
38
+ )
39
+ baseurl_igrf = (
40
+ "https://www.ngdc.noaa.gov/geomag-web/calculators/calculateDeclination?"
41
+ )
42
+ baseurl_emm = "https://emmcalc.geomag.info/?magneticcomponent=d&"
22
43
  key = "zNEw7"
23
- resultFormat="json"
24
- url = "{}lat1={}&lon1={}&key={}&startYear{}&resultFormat={}".format(baseurl, lat1, lon1, key, year, resultFormat)
44
+ resultFormat = "json"
45
+ if year >= 2025:
46
+ baseurl = baseurl_wmm
47
+ model = "WMM"
48
+ elif year >= 2019:
49
+ baseurl = baseurl_wmm
50
+ model = "IGRF"
51
+ elif year >= 2000:
52
+ baseurl = baseurl_emm
53
+ model = "EMM"
54
+ elif year >= 1590:
55
+ baseurl = baseurl_igrf
56
+ model = "IGRF"
57
+ url = "{}model={}&lat1={}&lon1={}&key={}&startYear={}&resultFormat={}".format(
58
+ baseurl, model, lat1, lon1, key, year, resultFormat
59
+ )
25
60
  response = requests.get(url)
26
61
  data = response.json()
27
62
  results = data["result"][0]
28
63
  mag = [[results["declination"]]]
29
-
64
+
30
65
  return mag
31
66
 
32
- def magnetic_declination(lat, lon, depth, year):
33
- """
34
- The function calculates the magnetic declination at a given location and depth.
35
- using a local installation of wmm2020 model.
36
67
 
68
+ # Commentin magnetic_declination model since the method is no longer using.
69
+ # def magnetic_declination(lat, lon, depth, year):
70
+ # """
71
+ # The function calculates the magnetic declination at a given location and depth.
72
+ # using a local installation of wmm2020 model.
37
73
 
38
- Args:
39
- lat (parameter, float): Latitude in decimals
40
- lon (parameter, float): Longitude in decimals
41
- depth (parameter, float): depth in m
42
- year (parameter, integer): Year
43
74
 
44
- Returns:
45
- mag: Magnetic declination (degrees)
46
- """
47
- import wmm2020
48
- mag = wmm2020.wmm(lat, lon, depth, year)
49
- mag = mag.decl.data
75
+ # Args:
76
+ # lat (parameter, float): Latitude in decimals
77
+ # lon (parameter, float): Longitude in decimals
78
+ # depth (parameter, float): depth in m
79
+ # year (parameter, integer): Year
80
+
81
+ # Returns:
82
+ # mag: Magnetic declination (degrees)
83
+ # """
84
+ # import wmm2020
85
+ # mag = wmm2020.wmm(lat, lon, depth, year)
86
+ # mag = mag.decl.data
87
+
88
+ # return mag
50
89
 
51
- return mag
52
90
 
53
91
  def velocity_modifier(velocity, mag):
54
92
  """
@@ -64,12 +102,17 @@ def velocity_modifier(velocity, mag):
64
102
  """
65
103
  mag = np.deg2rad(mag[0][0])
66
104
  velocity = np.where(velocity == -32768, np.nan, velocity)
67
- velocity[0, :, :] = velocity[0, :, :] * np.cos(mag) + velocity[1, :, :] * np.sin(mag)
68
- velocity[1, :, :] = -1 * velocity[0, :, :] * np.sin(mag) + velocity[1, :, :] * np.cos(mag)
105
+ velocity[0, :, :] = velocity[0, :, :] * np.cos(mag) + velocity[1, :, :] * np.sin(
106
+ mag
107
+ )
108
+ velocity[1, :, :] = -1 * velocity[0, :, :] * np.sin(mag) + velocity[
109
+ 1, :, :
110
+ ] * np.cos(mag)
69
111
  velocity = np.where(velocity == np.nan, -32768, velocity)
70
112
 
71
113
  return velocity
72
114
 
115
+
73
116
  def velocity_cutoff(velocity, mask, cutoff=250):
74
117
  """
75
118
  Masks all velocities above a cutoff. Note that
@@ -89,7 +132,7 @@ def velocity_cutoff(velocity, mask, cutoff=250):
89
132
  return mask
90
133
 
91
134
 
92
- def despike(velocity, mask, kernal_size=13, cutoff=150):
135
+ def despike(velocity, mask, kernel_size=13, cutoff=3):
93
136
  """
94
137
  Function to remove anomalous spikes in the data over a period of time.
95
138
  A median filter is used to despike the data.
@@ -97,26 +140,31 @@ def despike(velocity, mask, kernal_size=13, cutoff=150):
97
140
  Args:
98
141
  velocity (numpy array, integer): Velocity(depth, time) in mm/s
99
142
  mask (numpy array, integer): Mask file
100
- kernal_size (paramater, integer): Number of ensembles over which the spike has to be checked
101
- cutoff (parameter, integer): [TODO:description]
143
+ kernel_size (paramater, integer): Window size for rolling median filter
144
+ cutoff (parameter, integer): Number of standard deviations to identify spikes
102
145
 
103
146
  Returns:
104
147
  mask
105
148
  """
106
- cutoff = cutoff * 10
107
149
  velocity = np.where(velocity == -32768, np.nan, velocity)
108
150
  shape = np.shape(velocity)
109
151
  for j in range(shape[0]):
110
- filt = sp.signal.medfilt(velocity[j, :], kernal_size)
152
+ # Apply median filter
153
+ filt = sp.signal.medfilt(velocity[j, :], kernel_size)
154
+ # Calculate absolute deviation from the rolling median
111
155
  diff = np.abs(velocity[j, :] - filt)
112
- mask[j, :] = np.where(diff < cutoff, mask[j, :], 1)
156
+ # Calculate threshold for spikes based on standard deviation
157
+ std_dev = np.nanstd(diff)
158
+ spike_threshold = cutoff * std_dev
159
+ # Apply mask after identifying spikes
160
+ mask[j, :] = np.where(diff < spike_threshold, mask[j, :], 1)
113
161
  return mask
114
162
 
115
163
 
116
164
  def flatline(
117
165
  velocity,
118
166
  mask,
119
- kernal_size=4,
167
+ kernel_size=4,
120
168
  cutoff=1,
121
169
  ):
122
170
  """
@@ -126,7 +174,7 @@ def flatline(
126
174
  Args:
127
175
  velocity (numpy arrray, integer): Velocity (depth, time)
128
176
  mask (numpy array, integer): Mask file
129
- kernal_size (parameter, integer): No. of ensembles over which flatline has to be detected
177
+ kernel_size (parameter, integer): No. of ensembles over which flatline has to be detected
130
178
  cutoff (parameter, integer): Permitted deviation in velocity
131
179
 
132
180
  Returns:
@@ -143,7 +191,7 @@ def flatline(
143
191
  for k, g in groupby(dummymask):
144
192
  # subset_size = sum(1 for i in g)
145
193
  subset_size = len(list(g))
146
- if k == 1 and subset_size >= kernal_size:
194
+ if k == 1 and subset_size >= kernel_size:
147
195
  mask[j, index : index + subset_size] = 1
148
196
  index = index + subset_size
149
197
  dummymask = np.zeros(shape[1])
pyadps/utils/writenc.py CHANGED
@@ -17,7 +17,6 @@ from netCDF4 import date2num
17
17
  from pyadps.utils import readrdi as rd
18
18
 
19
19
 
20
-
21
20
  def pd2nctime(time, t0="hours since 2000-01-01"):
22
21
  """
23
22
  Function to convert pandas datetime format to netcdf datetime format.
@@ -68,7 +67,14 @@ def flead_ncatt(fl_obj, ncfile_id, ens=0):
68
67
  setattr(ncfile_id, format_key, format(value))
69
68
 
70
69
 
71
- def rawnc(infile, outfile, time, axis_option=None, attributes=None, t0="hours since 2000-01-01"):
70
+ def rawnc(
71
+ infile,
72
+ outfile,
73
+ axis_option="time",
74
+ fixensemble=True,
75
+ attributes=None,
76
+ t0="hours since 2000-01-01",
77
+ ):
72
78
  """
73
79
  rawnc is a function to create netcdf file. Stores 3-D data types like
74
80
  velocity, echo, correlation, and percent good.
@@ -85,7 +91,12 @@ def rawnc(infile, outfile, time, axis_option=None, attributes=None, t0="hours si
85
91
 
86
92
  outnc = nc4.Dataset(outfile, "w", format="NETCDF4")
87
93
 
88
- flead = rd.FixedLeader(infile)
94
+ ds = rd.ReadFile(infile)
95
+ if fixensemble and not ds.isFixedEnsemble:
96
+ ds.fixensemble()
97
+
98
+ head = ds.fileheader
99
+ flead = ds.fixedleader
89
100
  cell_list = flead.fleader["Cells"]
90
101
  beam_list = flead.fleader["Beams"]
91
102
 
@@ -96,8 +107,11 @@ def rawnc(infile, outfile, time, axis_option=None, attributes=None, t0="hours si
96
107
  primary_axis = "ensemble"
97
108
  ensemble = outnc.createVariable("ensemble", "i4", ("ensemble",))
98
109
  ensemble.axis = "T"
110
+ # Add ensemble
111
+ total_ensembles = ds.ensembles
112
+ ensemble = np.arange(1, total_ensembles + 1, 1)
99
113
  elif axis_option == "time":
100
- tsize = len(time)
114
+ tsize = ds.ensembles
101
115
  outnc.createDimension("time", tsize)
102
116
  primary_axis = "time"
103
117
  time_var = outnc.createVariable("time", "i4", ("time",))
@@ -106,6 +120,7 @@ def rawnc(infile, outfile, time, axis_option=None, attributes=None, t0="hours si
106
120
  time_var.long_name = "time"
107
121
 
108
122
  # Convert time_data to numerical format
123
+ time = ds.time
109
124
  nctime = pd2nctime(time, t0)
110
125
  time_var[:] = nctime
111
126
 
@@ -128,7 +143,7 @@ def rawnc(infile, outfile, time, axis_option=None, attributes=None, t0="hours si
128
143
  cell[:] = np.arange(1, max(cell_list) + 1, 1)
129
144
  beam[:] = np.arange(1, max(beam_list) + 1, 1)
130
145
 
131
- varlist = rd.FileHeader(infile).data_types(1)
146
+ varlist = head.data_types(1)
132
147
  varlist.remove("Fixed Leader")
133
148
  varlist.remove("Variable Leader")
134
149
 
@@ -139,10 +154,8 @@ def rawnc(infile, outfile, time, axis_option=None, attributes=None, t0="hours si
139
154
  varid[i] = outnc.createVariable(
140
155
  item, "i2", (primary_axis, "cell", "beam"), fill_value=-32768
141
156
  )
142
- # varid[i].missing_value = -32768
143
- vel = getattr(rd, item)
144
- var = vel(infile).data
145
- # var = rd.variables(infile, item)
157
+ vel = getattr(ds, item.lower())
158
+ var = vel.data
146
159
 
147
160
  else:
148
161
  # Unsigned integers might be assigned for future netcdf versions
@@ -150,34 +163,34 @@ def rawnc(infile, outfile, time, axis_option=None, attributes=None, t0="hours si
150
163
  varid[i] = outnc.createVariable(
151
164
  format_item, "i2", (primary_axis, "cell", "beam")
152
165
  )
153
- datatype = getattr(rd, format_item)
154
- var = np.array(datatype(infile).data, dtype="int16")
155
- # var = np.array(rd.variables(infile, item), dtype="int16")
166
+ datatype = getattr(ds, format_item.lower())
167
+ var = np.array(datatype.data, dtype="int16")
156
168
 
157
169
  vshape = var.T.shape
158
- if i == 0:
159
- if primary_axis == "time":
160
- time[:] = np.arange(1, vshape[0] + 1, 1)
161
- elif primary_axis == "ensemble":
162
- ensemble[:] = np.arange(1, vshape[0] + 1, 1)
163
- else:
164
- raise ValueError(f"Invalid axis_option: {axis_option}.")
165
170
 
166
171
  varid[i][0 : vshape[0], 0 : vshape[1], 0 : vshape[2]] = var.T
167
-
172
+
168
173
  # Add global attributes if provided
169
174
  if attributes:
170
175
  for key, value in attributes.items():
171
- setattr(outnc, key, str(value)) # Convert to string to store in NetCDF metadata
176
+ setattr(
177
+ outnc, key, str(value)
178
+ ) # Convert to string to store in NetCDF metadata
172
179
 
173
180
  # outnc.history = "Created " + time.ctime(time.time())
174
181
  flead_ncatt(flead, outnc)
175
-
176
182
 
177
183
  outnc.close()
178
184
 
179
185
 
180
- def vlead_nc(infile, outfile, time, axis_option=None, attributes=None, t0="hours since 2000-01-01"):
186
+ def flead_nc(
187
+ infile,
188
+ outfile,
189
+ axis_option="time",
190
+ fixensemble=True,
191
+ attributes=None,
192
+ t0="hours since 2000-01-01",
193
+ ):
181
194
  """
182
195
  Function to create ncfile containing Variable Leader.
183
196
 
@@ -187,6 +200,11 @@ def vlead_nc(infile, outfile, time, axis_option=None, attributes=None, t0="hours
187
200
  """
188
201
  outnc = nc4.Dataset(outfile, "w", format="NETCDF4")
189
202
 
203
+ # Read Binary File
204
+ ds = rd.ReadFile(infile)
205
+ if fixensemble:
206
+ ds.fixensemble()
207
+ flead = ds.fixedleader
190
208
  # Dimensions
191
209
  # Define the primary axis based on axis_option
192
210
  if axis_option == "ensemble":
@@ -194,8 +212,12 @@ def vlead_nc(infile, outfile, time, axis_option=None, attributes=None, t0="hours
194
212
  primary_axis = "ensemble"
195
213
  ensemble = outnc.createVariable("ensemble", "i4", ("ensemble",))
196
214
  ensemble.axis = "T"
215
+ # Add ensemble
216
+ total_ensembles = ds.ensembles
217
+ ensemble = np.arange(1, total_ensembles + 1, 1)
218
+
197
219
  elif axis_option == "time":
198
- tsize = len(time)
220
+ tsize = ds.ensembles
199
221
  outnc.createDimension("time", tsize)
200
222
  primary_axis = "time"
201
223
  time_var = outnc.createVariable("time", "i4", ("time",))
@@ -204,6 +226,7 @@ def vlead_nc(infile, outfile, time, axis_option=None, attributes=None, t0="hours
204
226
  time_var.long_name = "time"
205
227
 
206
228
  # Convert time_data to numerical format
229
+ time = ds.time
207
230
  nctime = pd2nctime(time, t0)
208
231
  time_var[:] = nctime
209
232
 
@@ -211,8 +234,81 @@ def vlead_nc(infile, outfile, time, axis_option=None, attributes=None, t0="hours
211
234
  raise ValueError(f"Invalid axis_option: {axis_option}.")
212
235
 
213
236
  # Variables
237
+ fdict = flead.fleader
238
+ varid = [0] * len(fdict)
239
+
240
+ i = 0
241
+
242
+ for key, values in fdict.items():
243
+ format_item = key.replace(" ", "_")
244
+ varid[i] = outnc.createVariable(
245
+ format_item, "i4", primary_axis, fill_value=-32768
246
+ )
247
+ var = values
248
+ vshape = var.shape
249
+
250
+ varid[i][0 : vshape[0]] = var
251
+ i += 1
214
252
 
215
- vlead = rd.VariableLeader(infile)
253
+ # Add global attributes if provided
254
+ if attributes:
255
+ for key, value in attributes.items():
256
+ setattr(outnc, key, str(value)) # Store attributes as strings
257
+
258
+ outnc.close()
259
+
260
+
261
+ def vlead_nc(
262
+ infile,
263
+ outfile,
264
+ axis_option="time",
265
+ fixensemble=True,
266
+ attributes=None,
267
+ t0="hours since 2000-01-01",
268
+ ):
269
+ """
270
+ Function to create ncfile containing Variable Leader.
271
+
272
+ Args:
273
+ infile (string): Input file path including filename
274
+ outfile (string): Output file path including filename
275
+ """
276
+ # Create output NetCDF File
277
+ outnc = nc4.Dataset(outfile, "w", format="NETCDF4")
278
+
279
+ # Read Binary File
280
+ ds = rd.ReadFile(infile)
281
+ if fixensemble:
282
+ ds.fixensemble()
283
+ vlead = ds.variableleader
284
+ # Dimensions
285
+ # Define the primary axis based on axis_option
286
+ if axis_option == "ensemble":
287
+ outnc.createDimension("ensemble", None)
288
+ primary_axis = "ensemble"
289
+ ensemble = outnc.createVariable("ensemble", "i4", ("ensemble",))
290
+ ensemble.axis = "T"
291
+ # Add ensemble
292
+ total_ensembles = ds.ensembles
293
+ ensemble = np.arange(1, total_ensembles + 1, 1)
294
+ elif axis_option == "time":
295
+ tsize = ds.ensembles
296
+ outnc.createDimension("time", tsize)
297
+ primary_axis = "time"
298
+ time_var = outnc.createVariable("time", "i4", ("time",))
299
+ time_var.axis = "T"
300
+ time_var.units = t0
301
+ time_var.long_name = "time"
302
+
303
+ # Convert time_data to numerical format
304
+ time = ds.time
305
+ nctime = pd2nctime(time, t0)
306
+ time_var[:] = nctime
307
+
308
+ else:
309
+ raise ValueError(f"Invalid axis_option: {axis_option}.")
310
+
311
+ # Read Data
216
312
  vdict = vlead.vleader
217
313
  varid = [0] * len(vdict)
218
314
 
@@ -224,18 +320,12 @@ def vlead_nc(infile, outfile, time, axis_option=None, attributes=None, t0="hours
224
320
  format_item, "i4", primary_axis, fill_value=-32768
225
321
  )
226
322
  var = values
227
- vshape = var.shape
228
- if i == 0:
229
- if primary_axis == "time":
230
- time[:] = np.arange(1, vshape[0] + 1, 1)
231
- elif primary_axis == "ensemble":
232
- ensemble[:] = np.arange(1, vshape[0] + 1, 1)
233
- else:
234
- raise ValueError(f"Invalid axis_option: {axis_option}.")
323
+ # vshape = var.shape
235
324
 
236
- varid[i][0 : vshape[0]] = var
325
+ varid[i][0 : ds.ensembles] = var
326
+ # varid[i][0 : vshape[0]] = var
237
327
  i += 1
238
-
328
+
239
329
  # Add global attributes if provided
240
330
  if attributes:
241
331
  for key, value in attributes.items():
@@ -244,7 +334,18 @@ def vlead_nc(infile, outfile, time, axis_option=None, attributes=None, t0="hours
244
334
  outnc.close()
245
335
 
246
336
 
247
- def finalnc(outfile, depth, time, data, t0="hours since 2000-01-01", attributes=None):
337
+ def finalnc(
338
+ outfile,
339
+ depth,
340
+ final_mask,
341
+ final_echo,
342
+ final_corr,
343
+ final_pgood,
344
+ time,
345
+ data,
346
+ t0="hours since 2000-01-01",
347
+ attributes=None,
348
+ ):
248
349
  """
249
350
  Function to create the processed NetCDF file.
250
351
 
@@ -259,15 +360,19 @@ def finalnc(outfile, depth, time, data, t0="hours since 2000-01-01", attributes=
259
360
 
260
361
  # Change velocity to cm/s
261
362
  data = data.astype(np.float64)
262
- data[data > fill] /= 10
363
+ data[data > fill] /= 10
263
364
 
264
365
  # Change depth to positive
265
- depth = abs(depth)
366
+ # depth = abs(depth)
266
367
 
267
368
  # Reverse the arrays if depth in descending order
268
369
  if np.all(depth[:-1] >= depth[1:]):
269
370
  depth = depth[::-1]
270
371
  data = data[:, ::-1, :]
372
+ final_mask = final_mask[::-1, :]
373
+ final_echo = final_echo[:, ::-1, :]
374
+ final_corr = final_corr[:, ::-1, :]
375
+ final_pgood = final_pgood[:, ::-1, :]
271
376
 
272
377
  ncfile = nc4.Dataset(outfile, mode="w", format="NETCDF4")
273
378
  # Check if depth is scalar or array
@@ -307,6 +412,69 @@ def finalnc(outfile, depth, time, data, t0="hours since 2000-01-01", attributes=
307
412
  evel.units = "cm/s"
308
413
  evel.long_name = "error_velocity"
309
414
 
415
+ mvel = ncfile.createVariable("mask", np.float32, ("time", "depth"), fill_value=fill)
416
+ mvel.long_name = "Velocity Mask (1: bad value, 0: good value)"
417
+
418
+ echo1 = ncfile.createVariable(
419
+ "echo1", np.float32, ("time", "depth"), fill_value=-32768
420
+ )
421
+ echo1.long_name = "Echo intensity Beam 1"
422
+
423
+ echo2 = ncfile.createVariable(
424
+ "echo2", np.float32, ("time", "depth"), fill_value=-32768
425
+ )
426
+ echo2.long_name = "Echo intensity Beam 2"
427
+
428
+ echo3 = ncfile.createVariable(
429
+ "echo3", np.float32, ("time", "depth"), fill_value=-32768
430
+ )
431
+ echo3.long_name = "Echo intensity Beam 3"
432
+
433
+ echo4 = ncfile.createVariable(
434
+ "echo4", np.float32, ("time", "depth"), fill_value=-32768
435
+ )
436
+ echo4.long_name = "Echo intensity Beam 4"
437
+
438
+ corr1 = ncfile.createVariable(
439
+ "corr1", np.float32, ("time", "depth"), fill_value=-32768
440
+ )
441
+ corr1.long_name = "Beam 1 correlation"
442
+
443
+ corr2 = ncfile.createVariable(
444
+ "corr2", np.float32, ("time", "depth"), fill_value=-32768
445
+ )
446
+ corr2.long_name = "Beam 2 correlation"
447
+
448
+ corr3 = ncfile.createVariable(
449
+ "corr3", np.float32, ("time", "depth"), fill_value=-32768
450
+ )
451
+ corr3.long_name = "Beam 3 correlation"
452
+
453
+ corr4 = ncfile.createVariable(
454
+ "corr4", np.float32, ("time", "depth"), fill_value=-32768
455
+ )
456
+ corr4.long_name = "Beam 4 correlation"
457
+
458
+ pgd1 = ncfile.createVariable(
459
+ "pgd1", np.float32, ("time", "depth"), fill_value=-32768
460
+ )
461
+ pgd1.long_name = "Percent Good Beam 1"
462
+
463
+ pgd2 = ncfile.createVariable(
464
+ "pgd2", np.float32, ("time", "depth"), fill_value=-32768
465
+ )
466
+ pgd2.long_name = "Percent Good Beam 2"
467
+
468
+ pgd3 = ncfile.createVariable(
469
+ "pgd3", np.float32, ("time", "depth"), fill_value=-32768
470
+ )
471
+ pgd3.long_name = "Percent Good Beam 3"
472
+
473
+ pgd4 = ncfile.createVariable(
474
+ "pgd4", np.float32, ("time", "depth"), fill_value=-32768
475
+ )
476
+ pgd4.long_name = "Percent Good Beam 4"
477
+
310
478
  nctime = pd2nctime(time, t0)
311
479
  # write data
312
480
  z[:] = depth
@@ -315,10 +483,25 @@ def finalnc(outfile, depth, time, data, t0="hours since 2000-01-01", attributes=
315
483
  vvel[:, :] = data[1, :, :].T
316
484
  wvel[:, :] = data[2, :, :].T
317
485
  evel[:, :] = data[3, :, :].T
318
-
486
+ mvel[:, :] = final_mask.T
487
+ echo1[:, :] = final_echo[0, :, :].T
488
+ echo2[:, :] = final_echo[1, :, :].T
489
+ echo3[:, :] = final_echo[2, :, :].T
490
+ echo4[:, :] = final_echo[3, :, :].T
491
+ corr1[:, :] = final_corr[0, :, :].T
492
+ corr2[:, :] = final_corr[1, :, :].T
493
+ corr3[:, :] = final_corr[2, :, :].T
494
+ corr4[:, :] = final_corr[3, :, :].T
495
+ pgd1[:, :] = final_pgood[0, :, :].T
496
+ pgd2[:, :] = final_pgood[1, :, :].T
497
+ pgd3[:, :] = final_pgood[2, :, :].T
498
+ pgd4[:, :] = final_pgood[3, :, :].T
499
+
319
500
  # Add global attributes if provided
320
501
  if attributes:
321
502
  for key, value in attributes.items():
322
503
  setattr(ncfile, key, str(value)) # Store attributes as strings
323
504
 
505
+ ncfile.mask_applied = "True"
506
+
324
507
  ncfile.close()