Skip to content

Commit 99c0b49

Browse files
authored
Merge pull request #5 from cchdo/cnv_sn
Skip CNV generation attempt if the hdr temperature/conductivity sensr…r serial number does not match the first serial number of that sensor type in the xmlcon
2 parents 78b4cde + 570e3fe commit 99c0b49

File tree

4 files changed

+94
-51
lines changed

4 files changed

+94
-51
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## v2025.09.1 (2025-09-??)
4+
* Skip CNV generation attempt if the hdr temperature/conductivity sensor serial number does not match the first serial number of that sensor type in the xmlcon.
5+
36
## v2025.09.0 (2025-09-02)
47
* Added a timeout to the SBEBatch.exe container wine command, this attempts to work around a issue where the wine process would never exit even though work had finished.
58
Right now the timeout is 5 minutes and fixed.

src/r2r_ctd/accessors.py

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
check_time_valid,
3838
)
3939
from r2r_ctd.derived import (
40+
get_con_report_sn,
41+
get_hdr_sn,
4042
get_latitude,
4143
get_longitude,
4244
get_time,
@@ -119,15 +121,79 @@ def con_report(self) -> str | None:
119121
return None
120122

121123
@cached_property
122-
def cnv_24hz(self) -> str | None:
123-
"""Caching wrapper around :py:func:`~r2r_ctd.derived.make_cnvs`
124+
def con_temp_sn(self) -> str | None:
125+
"""Finds the first temperature sensor serial number in the xmlcon"""
126+
if self.con_report is None:
127+
return None
128+
sns = get_con_report_sn(self.con_report, "Temperature")
129+
return sns[0]
124130

125-
Will generate the :py:meth:`cnv_1db` as a side effect if not already done.
126-
"""
131+
@cached_property
132+
def hdr_temp_sn(self) -> str | None:
133+
"""Finds the temperature sensor serial number in the hdr file"""
134+
if "hdr" not in self._obj:
135+
return None
136+
return get_hdr_sn(self._obj.hdr.item(), "Temperature")
137+
138+
@cached_property
139+
def con_cond_sn(self) -> str | None:
140+
"""Finds the first conductivity sensor serial number in the xmlcon"""
127141
if self.con_report is None:
128142
return None
143+
sns = get_con_report_sn(self.con_report, "Conductivity")
144+
return sns[0]
145+
146+
@cached_property
147+
def hdr_cond_sn(self) -> str | None:
148+
"""Finds the conductivity sensor serial number in the hdr file"""
149+
if "hdr" not in self._obj:
150+
return None
151+
return get_hdr_sn(self._obj.hdr.item(), "Conductivity")
152+
153+
@property
154+
def can_make_cnv(self) -> bool:
155+
"""Test if cnv conversion is likely to succeed
156+
157+
CNV conversion will be skipped if any of the following are true:
158+
159+
* missing conreport
160+
* missing "all three files"
161+
* the hdr temperature serial number is not the same as the first temperature SN in the xmlcon
162+
* the hdr conductivity serial number is not the same as the first conductivity SN in the xmlcon
163+
"""
164+
if self.con_report is None:
165+
logger.error(
166+
f"{self.name}: Unable to make cnv file due to missing conreport"
167+
)
168+
return False
129169

130170
if self.all_three_files is False:
171+
logger.error(
172+
f"{self.name}: Unable to make cnv file due to missing all three files"
173+
)
174+
return False
175+
176+
if self.con_temp_sn != self.hdr_temp_sn:
177+
logger.error(
178+
f"{self.name}: Unable to make cnv file due to xmlcon vs hdr Temperature SN mismatch: {self.con_temp_sn} vs {self.hdr_temp_sn}"
179+
)
180+
return False
181+
182+
if self.con_cond_sn != self.hdr_cond_sn:
183+
logger.error(
184+
f"{self.name}: Unable to make cnv file due to xmlcon vs hdr Conductivity SN mismatch: {self.con_cond_sn} vs {self.hdr_cond_sn}"
185+
)
186+
return False
187+
188+
return True
189+
190+
@cached_property
191+
def cnv_24hz(self) -> str | None:
192+
"""Caching wrapper around :py:func:`~r2r_ctd.derived.make_cnvs`
193+
194+
Will generate the :py:meth:`cnv_1db` as a side effect if not already done.
195+
"""
196+
if not self.can_make_cnv:
131197
return None
132198

133199
cnv_24hz = get_or_write_derived_file(self._obj, "cnv_24hz", make_cnvs)
@@ -142,10 +208,7 @@ def cnv_1db(self) -> str | None:
142208
143209
Will generate the :py:meth:`cnv_24hz` as a side effect if not already done.
144210
"""
145-
if self.con_report is None:
146-
return None
147-
148-
if self.all_three_files is False:
211+
if not self.can_make_cnv:
149212
return None
150213

151214
cnv_1db = get_or_write_derived_file(self._obj, "cnv_1db", make_cnvs)

src/r2r_ctd/derived.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ def _con_report_extract_sensors(con_report: str) -> list[str]:
207207
return sensors
208208

209209

210-
def get_con_report_sn(con_report: str, instrument: str) -> set[str]:
210+
def get_con_report_sn(con_report: str, instrument: str) -> list[str]:
211211
"""Get the serial numbers for instruments from the configuration report (XMLCON)."""
212212
title = ""
213213
sns = []
@@ -228,10 +228,10 @@ def get_con_report_sn(con_report: str, instrument: str) -> set[str]:
228228
key = key.strip().lower()
229229
value = value.strip()
230230

231-
if key == "serial number":
231+
if key == "serial number" and value not in sns:
232232
sns.append(value)
233233

234-
return set(sns)
234+
return sns
235235

236236

237237
def get_hdr_sn(hdr: str, instrument: str) -> str | None:

src/r2r_ctd/reporting.py

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,14 @@
1212
from functools import cached_property
1313
from importlib.metadata import metadata, version
1414
from statistics import mean
15-
from typing import Literal
15+
from typing import Literal, cast
1616

1717
from lxml.builder import ElementMaker
1818
from lxml.etree import _Element
1919

2020
import r2r_ctd.accessors # noqa: F401
2121
from r2r_ctd.breakout import Breakout
2222
from r2r_ctd.derived import (
23-
get_con_report_sn,
24-
get_hdr_sn,
2523
get_latitude,
2624
get_longitude,
2725
get_model,
@@ -529,32 +527,17 @@ def info_casts_with_dock_deck_test_in_file_name(self):
529527
@cached_property
530528
def info_casts_with_temp_sensor_sn_problems(self):
531529
"""List of casts where the serial number in the data header does not
532-
match any serial numbers in the xmlcon.
530+
match the first serial number for a temperature sensor in the xmlcon.
533531
534-
.. admonition:: WHOI Divergence
535-
:class: warning
536-
537-
There can be more than one temperature sensor and they will have different serial numbers.
538-
The datafile would only have one serial number, but the xmlcon will list all the sensors.
539-
The original WHOI code would only check one of the serial numbers found in the xmlcon.
540-
541-
I'm not sure the exact cause, but there are a lot of false problems in the breakouts I was given
542-
to test with, for example: 156405 reports that all the casts have SN problems, but a manual examination
543-
and this code, show that there are no mismatches.
544-
545-
This code checks the serial number in the header file against all the serial numbers in the xmlcon of the
546-
same instrument type (e.g. all temperature sensor serial numbers)
532+
The seabird software throws an error if the above is not the case, this will prevent the creation of a cnv product
533+
even if the serial number is in the secondary channel.
547534
"""
548535
problem_casts = []
549-
for station in self.breakout.stations_hex_paths:
550-
data = self.breakout[station]
551-
con_report = data.r2r.con_report
552-
if con_report is None:
553-
continue
554-
models = get_con_report_sn(con_report, "Temperature")
555-
sn = get_hdr_sn(data.hdr.item(), "Temperature")
556-
if sn not in models:
557-
problem_casts.append(station.stem)
536+
for station in self.breakout:
537+
con_sn = station.r2r.con_temp_sn
538+
hdr_sn = station.r2r.hdr_temp_sn
539+
if con_sn != hdr_sn or None in (con_sn, hdr_sn):
540+
problem_casts.append(cast(str, station.r2r.name))
558541
return Info(
559542
" ".join(problem_casts),
560543
name="Casts with temp. sensor serial number problem",
@@ -564,23 +547,17 @@ def info_casts_with_temp_sensor_sn_problems(self):
564547
@cached_property
565548
def info_casts_with_cond_sensor_sn_problems(self):
566549
"""List of casts where the serial number in the data header does not
567-
match any serial numbers in the xmlcon.
568-
569-
.. admonition:: WHOI Divergence
570-
:class: warning
550+
match the first Conductivity sensor serial numbers in the xmlcon.
571551
572-
See the info_casts_with_temp_sensor_sn_problems divergence note
552+
The seabird software throws an error if the above is not the case, this will prevent the creation of a cnv product
553+
even if the serial number is in the secondary channel.
573554
"""
574555
problem_casts = []
575-
for station in self.breakout.stations_hex_paths:
576-
data = self.breakout[station]
577-
con_report = data.r2r.con_report
578-
if con_report is None:
579-
continue
580-
models = get_con_report_sn(con_report, "Conductivity")
581-
sn = get_hdr_sn(data.hdr.item(), "Conductivity")
582-
if sn not in models:
583-
problem_casts.append(station.stem)
556+
for station in self.breakout:
557+
con_sn = station.r2r.con_cond_sn
558+
hdr_sn = station.r2r.hdr_cond_sn
559+
if con_sn != hdr_sn or None in (con_sn, hdr_sn):
560+
problem_casts.append(cast(str, station.r2r.name))
584561
return Info(
585562
" ".join(problem_casts),
586563
name="Casts with cond. sensor serial number problem",

0 commit comments

Comments
 (0)