Skip to content

Commit 41084bd

Browse files
authored
Merge pull request #290 from jmcvey3/online
Skip junk headers in AD2CP files
2 parents f282687 + e6e27a6 commit 41084bd

File tree

3 files changed

+60
-79
lines changed

3 files changed

+60
-79
lines changed

mhkit/dolfyn/io/nortek.py

+23-73
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,8 @@ def read_nortek(
5656

5757
userdata = _find_userdata(filename, userdata)
5858

59-
with _NortekReader(
60-
filename, debug=debug, do_checksum=do_checksum, nens=nens
61-
) as rdr:
62-
rdr.readfile()
59+
rdr = _NortekReader(filename, debug=debug, do_checksum=do_checksum, nens=nens)
60+
rdr.readfile()
6361
rdr.dat2sci()
6462
dat = rdr.data
6563

@@ -300,14 +298,10 @@ def filesize(
300298
return self._filesz
301299

302300
@property
303-
def pos(
304-
self,
305-
):
301+
def pos(self):
306302
return self.f.tell()
307303

308-
def init_ADV(
309-
self,
310-
):
304+
def init_ADV(self):
311305
dat = self.data = {
312306
"data_vars": {},
313307
"coords": {},
@@ -335,9 +329,7 @@ def init_ADV(
335329
self.n_samp_guess = int(self.filesize / dlta + 1)
336330
self.n_samp_guess *= int(self.config["fs"])
337331

338-
def init_AWAC(
339-
self,
340-
):
332+
def init_AWAC(self):
341333
dat = self.data = {
342334
"data_vars": {},
343335
"coords": {},
@@ -392,9 +384,7 @@ def findnext(self, do_cs=True):
392384
sum += cs
393385
cs = val
394386

395-
def read_id(
396-
self,
397-
):
387+
def read_id(self):
398388
"""Read the next 'ID' from the file."""
399389
self._thisid_bytes = bts = self.read(2)
400390
tmp = unpack(self.endian + "BB", bts)
@@ -414,9 +404,7 @@ def read_id(
414404
return val
415405
return tmp[1]
416406

417-
def readnext(
418-
self,
419-
):
407+
def readnext(self):
420408
id = "0x%02x" % self.read_id()
421409
if id in self.fun_map:
422410
func_name = self.fun_map[id]
@@ -503,9 +491,7 @@ def checksum(self, byts):
503491
else:
504492
self.f.seek(2, 1)
505493

506-
def read_user_cfg(
507-
self,
508-
):
494+
def read_user_cfg(self):
509495
# ID: '0x00 = 00
510496
if self.debug:
511497
logging.info(
@@ -607,9 +593,7 @@ def read_user_cfg(
607593
int(Mode1[2])
608594
] # noqa
609595

610-
def read_head_cfg(
611-
self,
612-
):
596+
def read_head_cfg(self):
613597
# ID: '0x04 = 04
614598
if self.debug:
615599
logging.info(
@@ -631,9 +615,7 @@ def read_head_cfg(
631615
)
632616
self.checksum(byts)
633617

634-
def read_hw_cfg(
635-
self,
636-
):
618+
def read_hw_cfg(self):
637619
# ID 0x05 = 05
638620
if self.debug:
639621
logging.info(
@@ -700,9 +682,7 @@ def _init_data(self, vardict):
700682
if va.standard_name:
701683
self.data["standard_name"][nm] = va.standard_name
702684

703-
def read_vec_data(
704-
self,
705-
):
685+
def read_vec_data(self):
706686
# ID: 0x10 = 16
707687
c = self.c
708688
dat = self.data
@@ -741,9 +721,7 @@ def read_vec_data(
741721
self.checksum(byts)
742722
self.c += 1
743723

744-
def read_vec_checkdata(
745-
self,
746-
):
724+
def read_vec_checkdata(self):
747725
# ID: 0x07 = 07
748726
if self.debug:
749727
logging.info(
@@ -794,9 +772,7 @@ def _sci_data(self, vardict):
794772
if retval is not None:
795773
dat[nm] = retval
796774

797-
def sci_vec_data(
798-
self,
799-
):
775+
def sci_vec_data(self):
800776
self._sci_data(nortek_defs.vec_data)
801777
dat = self.data
802778

@@ -814,9 +790,7 @@ def sci_vec_data(
814790
# Apply velocity scaling (1 or 0.1)
815791
dat["data_vars"]["vel"] *= self.config["vel_scale_mm"]
816792

817-
def read_vec_hdr(
818-
self,
819-
):
793+
def read_vec_hdr(self):
820794
# ID: '0x12 = 18
821795
if self.debug:
822796
logging.info(
@@ -846,9 +820,7 @@ def read_vec_hdr(
846820
self.config["data_header"] = [self.config["data_header"]]
847821
self.config["data_header"] += [hdrnow]
848822

849-
def read_vec_sysdata(
850-
self,
851-
):
823+
def read_vec_sysdata(self):
852824
# ID: 0x11 = 17
853825
c = self.c
854826
if self.debug:
@@ -884,9 +856,7 @@ def read_vec_sysdata(
884856
) = unpack(self.endian + "2H3hH2BH", byts[8:])
885857
self.checksum(byts)
886858

887-
def sci_vec_sysdata(
888-
self,
889-
):
859+
def sci_vec_sysdata(self):
890860
"""Translate the data in the vec_sysdata structure into
891861
scientific units.
892862
"""
@@ -937,9 +907,7 @@ def sci_vec_sysdata(
937907
tbx.interpgaps(dv["roll"], t)
938908
tbx.interpgaps(dv["temp"], t)
939909

940-
def read_microstrain(
941-
self,
942-
):
910+
def read_microstrain(self):
943911
"""Read ADV microstrain sensor (IMU) data"""
944912

945913
def update_defs(dat, mag=False, orientmat=False):
@@ -1058,9 +1026,7 @@ def update_defs(dat, mag=False, orientmat=False):
10581026
self.checksum(byts0 + byts)
10591027
self.c += 1 # reset the increment
10601028

1061-
def sci_microstrain(
1062-
self,
1063-
):
1029+
def sci_microstrain(self):
10641030
"""Rotate orientation data into ADV coordinate system."""
10651031
# MS = MicroStrain
10661032
dv = self.data["data_vars"]
@@ -1085,9 +1051,7 @@ def sci_microstrain(
10851051
dv["angrt"] *= self.config["fs"]
10861052
dv["accel"] *= self.config["fs"]
10871053

1088-
def read_awac_profile(
1089-
self,
1090-
):
1054+
def read_awac_profile(self):
10911055
# ID: '0x20' = 32
10921056
dat = self.data
10931057
if self.debug:
@@ -1135,9 +1099,7 @@ def read_awac_profile(
11351099
self.checksum(byts)
11361100
self.c += 1
11371101

1138-
def sci_awac_profile(
1139-
self,
1140-
):
1102+
def sci_awac_profile(self):
11411103
self._sci_data(nortek_defs.awac_profile)
11421104
# Calculate the ranges.
11431105
cs_coefs = {2000: 0.0239, 1000: 0.0478, 600: 0.0797, 400: 0.1195}
@@ -1158,9 +1120,7 @@ def sci_awac_profile(
11581120
self.data["attrs"]["cell_size"] = cs
11591121
self.data["attrs"]["blank_dist"] = bd
11601122

1161-
def read_awac_waves_hdr(
1162-
self,
1163-
):
1123+
def read_awac_waves_hdr(self):
11641124
# ID: '0x31'
11651125
c = self.c
11661126
if self.debug:
@@ -1205,9 +1165,7 @@ def read_awac_waves_hdr(
12051165
self.config["data_header"] = [self.config["data_header"]]
12061166
self.config["data_header"] += [hdrnow]
12071167

1208-
def read_awac_waves(
1209-
self,
1210-
):
1168+
def read_awac_waves(self):
12111169
"""Read awac wave and suv data"""
12121170
# IDs: 0x30 & 0x36
12131171
c = self.c
@@ -1244,21 +1202,13 @@ def read_awac_waves(
12441202
self.checksum(byts)
12451203
self.c += 1
12461204

1247-
def dat2sci(
1248-
self,
1249-
):
1205+
def dat2sci(self):
12501206
for nm in self._dtypes:
12511207
getattr(self, "sci_" + nm)()
12521208
for nm in ["data_header", "checkdata"]:
12531209
if nm in self.config and isinstance(self.config[nm], list):
12541210
self.config[nm] = _recatenate(self.config[nm])
12551211

1256-
def __exit__(self, type, value, trace):
1257-
self.close()
1258-
1259-
def __enter__(self):
1260-
return self
1261-
12621212

12631213
def _crop_data(obj, range, n_lastdim):
12641214
for nm, dat in obj.items():

mhkit/dolfyn/io/nortek2.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ def __init__(
132132
self._check_nortek(endian)
133133
self.f.seek(0, 2) # Seek to end
134134
self._eof = self.f.tell()
135-
self._index = lib.get_index(fname, reload=rebuild_index, debug=debug)
135+
self.start_pos = self._check_header()
136+
self._index = lib.get_index(
137+
fname, pos=self.start_pos, eof=self._eof, reload=rebuild_index, debug=debug
138+
)
136139
self._reopen(bufsize)
137140
self.filehead_config = self._read_filehead_config_string()
138141
self._ens_pos = self._index["pos"][
@@ -168,6 +171,24 @@ def _check_nortek(self, endian):
168171
)
169172
self.endian = endian
170173

174+
def _check_header(self):
175+
def find_all(s, c):
176+
idx = s.find(c)
177+
while idx != -1:
178+
yield idx
179+
idx = s.find(c, idx + 1)
180+
181+
# Open the entire file
182+
self._reopen(self._eof)
183+
pk = self.f.peek(1)
184+
# Search for multiple saved headers
185+
found = [i for i in find_all(pk, b"GETCLOCKSTR")]
186+
if len(found) < 2:
187+
return 0
188+
else:
189+
start_idx = found[-1] - 11
190+
return start_idx
191+
171192
def _reopen(self, bufsize=None):
172193
if bufsize is None:
173194
bufsize = 1000000

mhkit/dolfyn/io/nortek2_lib.py

+15-5
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def _calc_time(year, month, day, hour, minute, second, usec, zero_is_bad=True):
107107
return dt
108108

109109

110-
def _create_index(infile, outfile, N_ens, debug):
110+
def _create_index(infile, outfile, init_pos, eof, debug):
111111
logging = getLogger()
112112
print("Indexing {}...".format(infile), end="")
113113
fin = open(_abspath(infile), "rb")
@@ -135,15 +135,21 @@ def _create_index(infile, outfile, N_ens, debug):
135135
35: 40,
136136
36: 40,
137137
}
138-
while N[21] < N_ens: # Will fail if velocity ping isn't saved first
138+
pos = 0
139+
while pos <= eof:
139140
pos = fin.tell()
141+
if init_pos and not pos:
142+
fin.seek(init_pos, 1)
140143
try:
141144
dat = _hdr.unpack(fin.read(_hdr.size))
142145
except:
143146
break
144147
if dat[2] in ids:
145148
idk = dat[2]
146149
d_ver, d_off, config = struct.unpack("<BBH", fin.read(4))
150+
if d_ver not in [1, 3]:
151+
# 1 for bottom track, 3 for all others
152+
continue
147153
fin.seek(4, 1)
148154
yr, mo, dy, h, m, s, u = struct.unpack("6BH", fin.read(8))
149155
fin.seek(14, 1)
@@ -181,7 +187,7 @@ def _create_index(infile, outfile, N_ens, debug):
181187
fin.seek(dat[4] - (36 + seek_2ens[idk]), 1)
182188
last_ens[idk] = ens[idk]
183189

184-
if debug and N[idk] < 5:
190+
if debug:
185191
# hex: [18, 15, 1C, 17] = [vel_b5, vel, echo, bt]
186192
logging.info(
187193
"%10d: %02X, %d, %02X, %d, %d, %d, %d\n"
@@ -197,6 +203,10 @@ def _create_index(infile, outfile, N_ens, debug):
197203
)
198204
)
199205
else:
206+
if dat[4] < 0:
207+
if debug:
208+
logging.info("Invalid skip byte at pos: %10d\n" % (pos))
209+
break
200210
fin.seek(dat[4], 1)
201211
fin.close()
202212
fout.close()
@@ -254,7 +264,7 @@ def _boolarray_firstensemble_ping(index):
254264
return dens
255265

256266

257-
def get_index(infile, reload=False, debug=False):
267+
def get_index(infile, pos=0, eof=2**32, reload=False, debug=False):
258268
"""
259269
This function reads ad2cp.index files
260270
@@ -275,7 +285,7 @@ def get_index(infile, reload=False, debug=False):
275285

276286
index_file = infile + ".index"
277287
if not path.isfile(index_file) or reload:
278-
_create_index(infile, index_file, 2**32, debug)
288+
_create_index(infile, index_file, pos, eof, debug)
279289
f = open(_abspath(index_file), "rb")
280290
file_head = f.read(12)
281291
if file_head[:10] == b"Index Ver:":

0 commit comments

Comments
 (0)