From 898bac4fb27fbb4491dad756173ce6305da7b930 Mon Sep 17 00:00:00 2001 From: ssuttles-usgs Date: Wed, 15 May 2024 09:01:41 -0400 Subject: [PATCH 1/7] add avgd data type --- stglib/aqd/aqdutils.py | 4 + stglib/sig/cdf2nc.py | 86 ++++++++++++- stglib/sig/mat2cdf.py | 226 ++++++++++++++++++++++++++++++----- stglib/tests/test_scripts.py | 2 +- 4 files changed, 288 insertions(+), 30 deletions(-) diff --git a/stglib/aqd/aqdutils.py b/stglib/aqd/aqdutils.py index 02d55329..5ba956c4 100644 --- a/stglib/aqd/aqdutils.py +++ b/stglib/aqd/aqdutils.py @@ -835,6 +835,10 @@ def check_attrs(ds, waves=False, hr=False, inst_type="AQD"): ds.attrs["bin_size"] = ds.attrs["SIGBurstHR_CellSize"] elif ds.attrs["data_type"].upper() == "ECHO1": ds.attrs["bin_size"] = ds.attrs["SIGEchoSounder_CellSize"] + elif ds.attrs["data_type"].upper() == "AVERAGE": + ds.attrs["bin_size"] = ds.attrs["SIGAverage_CellSize"] + elif ds.attrs["data_type"].upper() == "ALT_AVERAGE": + ds.attrs["bin_size"] = ds.attrs["SIGAlt_Average_CellSize"] if ds.attrs["frequency"] == 1000 or ds.attrs["frequency"] == 500: ds.attrs["beam_angle"] = 25 diff --git a/stglib/sig/cdf2nc.py b/stglib/sig/cdf2nc.py index 1817841a..74c14e7d 100644 --- a/stglib/sig/cdf2nc.py +++ b/stglib/sig/cdf2nc.py @@ -1,3 +1,4 @@ +import re import time import numpy as np @@ -52,7 +53,12 @@ def cdf_to_nc(cdf_filename, atmpres=False): # Need to clip data after coord transform when using dolfyn ds = utils.clip_ds(ds) - if ds.attrs["data_type"] == "Burst" or ds.attrs["data_type"] == "BurstHR": + if ( + ds.attrs["data_type"] == "Burst" + or ds.attrs["data_type"] == "BurstHR" + or ds.attrs["data_type"] == "Average" + or ds.attrs["data_type"] == "Alt_Average" + ): # Create separate vel variables first ds["U"] = ds["VelEast"] ds["V"] = ds["VelNorth"] @@ -129,6 +135,22 @@ def cdf_to_nc(cdf_filename, atmpres=False): {"standard_name": "time", "axis": "T", "long_name": "time (UTC)"} ) """ + att2del = [] + for k in ds.attrs: + if re.search("_Beam2xyz$", k): + print(k) + att2del.append(k) + + for k in att2del: + del ds.attrs[k] + + for j in ds.data_vars: + for k in ds[j].attrs: + + if type(ds[j].attrs[k]) is np.ndarray: + shp = len(ds[j].attrs[k].shape) + print(f"{j},{k},{shp}") + # write out nc file by data_type if "prefix" in ds.attrs: nc_filename = ds.attrs["prefix"] + ds.attrs["filename"] @@ -159,6 +181,24 @@ def cdf_to_nc(cdf_filename, atmpres=False): delayed_obj.compute() print("Done writing netCDF file", nc_out) + elif ds.attrs["data_type"] == "Average": + nc_out = nc_filename + "avg-cal.nc" + print("writing Average (avg) data to netCDF nc file") + print(ds.attrs) + delayed_obj = ds.to_netcdf(nc_out, compute=False) + with ProgressBar(): + delayed_obj.compute() + print("Done writing netCDF file", nc_out) + + elif ds.attrs["data_type"] == "Alt_Average": + nc_out = nc_filename + "alt-cal.nc" + print("writing Alt_Average (avg) data to netCDF nc file") + print(ds.attrs) + delayed_obj = ds.to_netcdf(nc_out, compute=False) + with ProgressBar(): + delayed_obj.compute() + print("Done writing netCDF file", nc_out) + utils.check_compliance(nc_out, conventions=ds.attrs["Conventions"]) end_time = time.time() @@ -286,6 +326,10 @@ def ds_rename_sig(ds, waves=False): "AmpBeam5": "amp_b5", "CorBeam5": "corr_b5", "Echo": "echo_amp", + "Headingstd": "Hdg_std", + "Pitchstd": "Ptch_std", + "Rollstd": "Roll_std", + "Pressurestd": "Pres_std", } for v in varnames: @@ -695,6 +739,46 @@ def ds_add_attrs_sig(ds): } ) + if "Hdg_std" in ds: + ds["Hdg_std"].attrs.update( + { + "units": "degrees", + "long_name": "Instrument heading standard deviation", + "standard_name": "platform_orientation", + "cell_methods": "time: standard_deviation", + } + ) + + if "Ptch_std" in ds: + ds["Ptch_std"].attrs.update( + { + "units": "degrees", + "long_name": "Instrument pitch standard deviation", + "standard_name": "platform_pitch", + "cell_methods": "time: standard_deviation", + } + ) + + if "Roll_std" in ds: + ds["Roll_std"].attrs.update( + { + "units": "degrees", + "long_name": "Instrument roll standard deviation", + "standard_name": "platform_roll", + "cell_methods": "time: standard_deviation", + } + ) + + if "Pres_std" in ds: + ds["Pres_std"].attrs.update( + { + "units": "dbar", + "long_name": "Uncorrected pressure standard deviation", + "standard_name": "sea_water_pressure", + "cell_methods": "time: standard_deviation", + } + ) + return ds diff --git a/stglib/sig/mat2cdf.py b/stglib/sig/mat2cdf.py index 3be0fa6f..57cac9a4 100644 --- a/stglib/sig/mat2cdf.py +++ b/stglib/sig/mat2cdf.py @@ -52,6 +52,23 @@ def load_mat_file(filnam): * np.arange(mat["Config"]["EchoSounder_NCells"]) ) + if mat["Config"]["Plan_AverageEnabled"] == "True": + bindistAVG = ( + mat["Config"]["Average_BlankingDistance"] + + mat["Config"]["Average_CellSize"] / 2 + + mat["Config"]["Average_CellSize"] + * np.arange(mat["Config"]["Average_NCells"]) + ) + + if "Alt_Plan_AveargedEnabled" in mat["Config"]: + if mat["Config"]["Alt_Plan_AverageEnabled"] == "True": + bindistAltAVG = ( + mat["Config"]["Alt_Average_BlankingDistance"] + + mat["Config"]["Alt_Average_CellSize"] / 2 + + mat["Config"]["Alt_Average_CellSize"] + * np.arange(mat["Config"]["Alt_Average_NCells"]) + ) + ds_dict = {} # initialize dictionary for xarray datasets if ( mat["Config"]["Plan_BurstEnabled"] == "True" @@ -59,22 +76,26 @@ def load_mat_file(filnam): and mat["Config"]["Burst_Altimeter"] == "True" ): # BurstRawAltimeter - dsbra = xr.Dataset() - dsbra["time"] = xr.DataArray( - [matlab2datetime(x) for x in mat["Data"]["BurstRawAltimeter_Time"]], - dims="time", - ) - dsbra["time"] = pd.DatetimeIndex(dsbra["time"]) - dsbra["time"] = pd.DatetimeIndex(dsbra["time"]) - dsbra.attrs["data_type"] = "BurstRawAltimeter" - ds_dict["dsbra"] = dsbra + if "BurstRawAltimeter_Time" in mat["Data"]: + dsbra = xr.Dataset() + dsbra["time"] = xr.DataArray( + [matlab2datetime(x) for x in mat["Data"]["BurstRawAltimeter_Time"]], + dims="time", + ) + dsbra["time"] = pd.DatetimeIndex(dsbra["time"]) + dsbra["time"] = pd.DatetimeIndex(dsbra["time"]) + dsbra.attrs["data_type"] = "BurstRawAltimeter" + ds_dict["dsbra"] = dsbra if ( mat["Config"]["Plan_BurstEnabled"] == "True" and mat["Config"]["Burst_NBeams"] == 5 ): # IBurst - if mat["Config"]["Burst_HighResolution5"] == "True": + if ( + mat["Config"]["Burst_HighResolution5"] == "True" + and "IBurstHR_Time" in mat["Data"] + ): dsi = xr.Dataset() dsi["time"] = pd.DatetimeIndex( xr.DataArray( @@ -87,7 +108,7 @@ def load_mat_file(filnam): dsi.attrs["data_type"] = "IBurstHR" ds_dict["dsi"] = dsi - else: + elif "IBurst_Time" in mat["Data"]: dsi = xr.Dataset() dsi["time"] = pd.DatetimeIndex( xr.DataArray( @@ -102,7 +123,10 @@ def load_mat_file(filnam): if mat["Config"]["Plan_BurstEnabled"] == "True": # Burst - if mat["Config"]["Burst_HighResolution"] == "True": + if ( + mat["Config"]["Burst_HighResolution"] == "True" + and "BurstHR_Time" in mat["Data"] + ): dsb = xr.Dataset() dsb["time"] = pd.DatetimeIndex( xr.DataArray( @@ -115,7 +139,7 @@ def load_mat_file(filnam): dsb.attrs["data_type"] = "BurstHR" ds_dict["dsb"] = dsb - else: + elif "Burst_Time" in mat["Data"]: dsb = xr.Dataset() dsb["time"] = pd.DatetimeIndex( xr.DataArray( @@ -133,18 +157,54 @@ def load_mat_file(filnam): and mat["Config"]["Burst_EchoSounder"] == "True" ): # echo1 data - only handling echo1 data to start - freq1 = mat["Config"]["EchoSounder_Frequency1"] - dse1 = xr.Dataset() - dse1["time"] = pd.DatetimeIndex( - xr.DataArray( - [matlab2datetime(x) for x in mat["Data"][f"Echo1Bin1_{freq1}kHz_Time"]], - dims="time", + if "EchoSounder_Frequency1" in mat["Config"]: + freq1 = mat["Config"]["EchoSounder_Frequency1"] + if f"Echo1Bin1_{freq1}kHz_Time" in mat["Data"]: + dse1 = xr.Dataset() + dse1["time"] = pd.DatetimeIndex( + xr.DataArray( + [ + matlab2datetime(x) + for x in mat["Data"][f"Echo1Bin1_{freq1}kHz_Time"] + ], + dims="time", + ) + ) + dse1["time"] = pd.DatetimeIndex(dse1["time"]) + dse1["bindist"] = xr.DataArray(bindistECHO, dims="bindist") + dse1.attrs["data_type"] = "Echo1" + ds_dict["dse1"] = dse1 + + if mat["Config"]["Plan_AverageEnabled"] == "True": + if "Average_Time" in mat["Data"]: + # Average + dsa = xr.Dataset() + dsa["time"] = pd.DatetimeIndex( + xr.DataArray( + [matlab2datetime(x) for x in mat["Data"]["Average_Time"]], + dims="time", + ) ) - ) - dse1["time"] = pd.DatetimeIndex(dse1["time"]) - dse1["bindist"] = xr.DataArray(bindistECHO, dims="bindist") - dse1.attrs["data_type"] = "Echo1" - ds_dict["dse1"] = dse1 + dsa["time"] = pd.DatetimeIndex(dsa["time"]) + dsa["bindist"] = xr.DataArray(bindistAVG, dims="bindist") + dsa.attrs["data_type"] = "Average" + ds_dict["dsa"] = dsa + + if "Alt_Plan_AveargedEnabled" in mat["Config"]: + if mat["Config"]["Alt_Plan_AverageEnabled"] == "True": + if "Alt_Average_Time" in mat["Data"]: + # Alt Average + dsalt = xr.Dataset() + dsalt["time"] = pd.DatetimeIndex( + xr.DataArray( + [matlab2datetime(x) for x in mat["Data"]["Alt_Average_Time"]], + dims="time", + ) + ) + dsalt["time"] = pd.DatetimeIndex(dsalt["time"]) + dsalt["bindist"] = xr.DataArray(bindistAltAVG, dims="bindist") + dsalt.attrs["data_type"] = "Alt_Average" + ds_dict["dsalt"] = dsalt for k in mat["Data"]: if "BurstRawAltimeter" in k: @@ -253,6 +313,66 @@ def load_mat_file(filnam): else: print("still need to process", k, mat["Data"][k].shape) + + elif re.match("^Average_", k): + if "_Time" not in k: + if mat["Data"][k].ndim == 1: + dsa[k.split("_")[1]] = xr.DataArray(mat["Data"][k], dims="time") + elif mat["Data"][k].ndim == 2: + if "AHRSRotationMatrix" in k: + coords = {"dimRM": np.arange(9)} + dsa["AHRSRotationMatrix"] = xr.DataArray( + mat["Data"][k], dims=["time", "dimRM"] + ) + if "Magnetometer" in k: + coords = {"dimM": np.arange(3)} + dsa["Magnetometer"] = xr.DataArray( + mat["Data"][k], dims=["time", "dimM"] + ) + if "Accelerometer" in k: + coords = {"dimA": np.arange(3)} + dsa["Accelerometer"] = xr.DataArray( + mat["Data"][k], dims=["time", "dimA"] + ) + # only checks to see if cells match on first sample + elif dsa.attrs["data_type"] == "Average": + if mat["Data"][k].shape[1] == mat["Data"]["Average_NCells"][0]: + dsa[k.split("_")[1]] = xr.DataArray( + mat["Data"][k], dims=["time", "bindist"] + ) + + else: + print("still need to process", k, mat["Data"][k].shape) + + elif re.match("^Alt_Average_", k): + if "_Time" not in k: + if mat["Data"][k].ndim == 1: + dsalt[k.split("_")[2]] = xr.DataArray(mat["Data"][k], dims="time") + elif mat["Data"][k].ndim == 2: + if "AHRSRotationMatrix" in k: + coords = {"dimRM": np.arange(9)} + dsalt["AHRSRotationMatrix"] = xr.DataArray( + mat["Data"][k], dims=["time", "dimRM"] + ) + if "Magnetometer" in k: + coords = {"dimM": np.arange(3)} + dsalt["Magnetometer"] = xr.DataArray( + mat["Data"][k], dims=["time", "dimM"] + ) + if "Accelerometer" in k: + coords = {"dimA": np.arange(3)} + dsalt["Accelerometer"] = xr.DataArray( + mat["Data"][k], dims=["time", "dimA"] + ) + # only checks to see if cells match on first sample + elif dsalt.attrs["data_type"] == "Alt_Average": + if mat["Data"][k].shape[1] == mat["Data"]["Average_NCells"][0]: + dsalt[k.split("_")[2]] = xr.DataArray( + mat["Data"][k], dims=["time", "bindist"] + ) + + else: + print("still need to process", k, mat["Data"][k].shape) else: print("missing variable:", k) @@ -271,7 +391,7 @@ def load_mat_file(filnam): def read_config_mat(mat, ds): for k in mat["Config"]: - if k == "Burst_Beam2xyz": + if re.search("_Beam2xyz$", k): ds.attrs[f"SIG{k}"] = str(mat["Config"][k]) else: ds.attrs[f"SIG{k}"] = mat["Config"][k] @@ -295,8 +415,8 @@ def add_units(mat, ds): def add_transmatrix(mat, ds): for k in mat["Config"]: - if "Beam2xyz" in k: - var = k.split("_")[1] + if f"{ds.attrs['data_type']}_Beam2xyz" in k: + var = k.split("_")[-1] ds[var] = xr.DataArray(mat["Config"][k]) @@ -347,7 +467,11 @@ def loadpar(f): print(f"Finished writing data to {cdf_filename}") matfiles = glob.glob(f"{basefile}_*.mat") - Parallel(n_jobs=-1, verbose=10)(delayed(loadpar)(f) for f in matfiles) + print(matfiles) + if len(matfiles) > 1: + Parallel(n_jobs=-1, verbose=10)(delayed(loadpar)(f) for f in matfiles) + else: + loadpar(matfiles[0]) dsd = load_mat_file(matfiles[0]) # get minimal dsd file for below cdffiles = glob.glob(f"{prefix}{outdir}*-raw.cdf") @@ -453,6 +577,52 @@ def loadpar(f): f"Failed to read or write netCDF file(s) for data_type {dse1.attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" ) + if "dsa" in dsd: + dsa = dsd["dsa"] + fin = outdir + f"*-{dsa.attrs['data_type']}-*.cdf" + try: + ds = xr.open_mfdataset(fin, parallel=True, chunks=chunksizes) + ds = aqdutils.check_attrs(ds, inst_type="SIG") + if "Beam2xyz" in ds: + if "time" in ds["Beam2xyz"].dims: + ds["Beam2xyz"] = ds["Beam2xyz"].isel(time=0, drop=True) + # write out all into single -raw.cdf files per data_type + cdf_filename = prefix + ds.attrs["filename"] + "_avgd-raw.cdf" + print("writing Average to netcdf") + delayed_obj = ds.to_netcdf(cdf_filename, compute=False) + with ProgressBar(): + delayed_obj.compute() + + print(f"Finished writing data to {cdf_filename}") + + except ValueError as ve: + print( + f"Failed to read or write netCDF file(s) for data_type {dsa.attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" + ) + + if "dsalt" in dsd: + dsalt = dsd["dsalt"] + fin = outdir + f"*-{dsalt.attrs['data_type']}-*.cdf" + try: + ds = xr.open_mfdataset(fin, parallel=True, chunks=chunksizes) + ds = aqdutils.check_attrs(ds, inst_type="SIG") + if "Beam2xyz" in ds: + if "time" in ds["Beam2xyz"].dims: + ds["Beam2xyz"] = ds["Beam2xyz"].isel(time=0, drop=True) + # write out all into single -raw.cdf files per data_type + cdf_filename = prefix + ds.attrs["filename"] + "_altavgd-raw.cdf" + print("writing Average to netcdf") + delayed_obj = ds.to_netcdf(cdf_filename, compute=False) + with ProgressBar(): + delayed_obj.compute() + + print(f"Finished writing data to {cdf_filename}") + + except ValueError as ve: + print( + f"Failed to read or write netCDF file(s) for data_type {dsalt.attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" + ) + toc = time.time() etime = round(toc - tic, 0) print(f"elapsed time = {etime}") diff --git a/stglib/tests/test_scripts.py b/stglib/tests/test_scripts.py index 5c4bc254..087a2219 100644 --- a/stglib/tests/test_scripts.py +++ b/stglib/tests/test_scripts.py @@ -363,7 +363,7 @@ def sig_nc(nc_file): assert "Done writing netCDF file" in result.stdout.decode("utf8") -@pytest.mark.skip(reason="works locally but not on github built-in checks") +# @pytest.mark.skip(reason="works locally but not on github built-in checks") def test_sig(): sig_mat("glob_att1126_sig1.txt", "sig1126_config.yaml") print(os.listdir()) From 7c6cfba3eb9d4d73d7f71b1d01cc8f6189c730e4 Mon Sep 17 00:00:00 2001 From: ssuttles-usgs Date: Wed, 15 May 2024 10:19:45 -0400 Subject: [PATCH 2/7] check tests --- stglib/tests/test_scripts.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stglib/tests/test_scripts.py b/stglib/tests/test_scripts.py index 087a2219..759e5efc 100644 --- a/stglib/tests/test_scripts.py +++ b/stglib/tests/test_scripts.py @@ -363,7 +363,9 @@ def sig_nc(nc_file): assert "Done writing netCDF file" in result.stdout.decode("utf8") -# @pytest.mark.skip(reason="works locally but not on github built-in checks") +pytest.mark.skip(reason="works locally but not on github built-in checks") + + def test_sig(): sig_mat("glob_att1126_sig1.txt", "sig1126_config.yaml") print(os.listdir()) From 30ecb688848ddd4631f1528a46037d473cb6edfb Mon Sep 17 00:00:00 2001 From: ssuttles-usgs Date: Thu, 16 May 2024 19:03:57 -0400 Subject: [PATCH 3/7] add tmat + fixes --- stglib/core/utils.py | 2 +- stglib/sig/cdf2nc.py | 119 +++++++++++++++++++++++++++-------- stglib/sig/mat2cdf.py | 7 ++- stglib/tests/test_scripts.py | 4 +- 4 files changed, 98 insertions(+), 34 deletions(-) diff --git a/stglib/core/utils.py b/stglib/core/utils.py index 83e59f41..8d53095e 100644 --- a/stglib/core/utils.py +++ b/stglib/core/utils.py @@ -179,7 +179,7 @@ def add_min_max(ds, exclude_vars=None): exclude = list(ds.dims) [exclude.append(k) for k in ds.variables if "time" in k] - exclude.extend(["TIM", "TransMatrix", "orientmat"]) + exclude.extend(["TIM", "TransMatrix", "orientmat", "beam2xyz"]) if exclude_vars: exclude.extend(exclude_vars) diff --git a/stglib/sig/cdf2nc.py b/stglib/sig/cdf2nc.py index 74c14e7d..b41f1ea1 100644 --- a/stglib/sig/cdf2nc.py +++ b/stglib/sig/cdf2nc.py @@ -89,6 +89,8 @@ def cdf_to_nc(cdf_filename, atmpres=False): ds = aqdutils.make_bin_depth(ds) + ds = ds_make_tmat(ds) + ds = ds_make_magaccel_vars(ds) ds = ds_make_ahrs_vars(ds) @@ -107,11 +109,6 @@ def cdf_to_nc(cdf_filename, atmpres=False): ds = aqdutils.ds_add_attrs(ds, inst_type="SIG") # for common adcp vars ds = ds_add_attrs_sig(ds) # for signature vars - # Add min/max values - # if ds.attrs["data_type"] not in ["Echo1"]: - print("add max/min variable attributes") - ds = utils.add_min_max(ds) - # Add DELTA_T for EPIC compliance # ds = utils.add_delta_t(ds) @@ -123,33 +120,18 @@ def cdf_to_nc(cdf_filename, atmpres=False): ds = utils.add_standard_names(ds) # add common standard names - # ds = drop_unused_dims(ds) + ds = drop_unused_dims(ds) - # ds = fix_encoding(ds) + ds = fix_encoding(ds) ds = utils.ds_add_lat_lon(ds) ds = utils.ds_coord_no_fillvalue(ds) - """ - ds["time"].attrs.update( - {"standard_name": "time", "axis": "T", "long_name": "time (UTC)"} - ) - """ - att2del = [] - for k in ds.attrs: - if re.search("_Beam2xyz$", k): - print(k) - att2del.append(k) - for k in att2del: - del ds.attrs[k] + ds = drop_attrs(ds) - for j in ds.data_vars: - for k in ds[j].attrs: - - if type(ds[j].attrs[k]) is np.ndarray: - shp = len(ds[j].attrs[k].shape) - print(f"{j},{k},{shp}") + # Add min/max values + ds = utils.add_min_max(ds) # write out nc file by data_type if "prefix" in ds.attrs: @@ -173,7 +155,7 @@ def cdf_to_nc(cdf_filename, atmpres=False): delayed_obj.compute() print("Done writing netCDF file", nc_out) - elif ds.attrs["data_type"] == "Echo1": + elif ds.attrs["data_type"] == "EchoSounder": nc_out = nc_filename + "e1-cal.nc" print("writing Echo1 (echo1) data to netCDF nc file") delayed_obj = ds.to_netcdf(nc_out, compute=False) @@ -224,6 +206,50 @@ def drop_unused_dims(ds): return ds +def drop_attrs(ds): + """Drop some global attrs""" + att2del = [] + for k in ds.attrs: + if re.search("_Beam2xyz$", k): + att2del.append(k) + + for k in att2del: + del ds.attrs[k] + + # Get rid of some of the instrument header attributes for other data_types + dtlist = [ + "Burst", + "BurstHR", + "IBurst", + "IBurstHR", + "EchoSounder", + "Average", + "Alt_Average", + "Alt_Burst", + ] + if ds.attrs["data_type"] in dtlist: + dtlist.remove(ds.attrs["data_type"]) + + rm = [] # initialize list of attrs to be removed + for k in dtlist: + for j in ds.attrs: + if re.match(f"^SIG{k}_", j): + rm.append(j) + for k in rm: + del ds.attrs[k] + + """ + for j in ds.data_vars: + for k in ds[j].attrs: + + if type(ds[j].attrs[k]) is np.ndarray: + shp = len(ds[j].attrs[k].shape) + print(f"{j},{k},{shp}") + """ + + return ds + + def ds_drop(ds): """ Drop old DataArrays from Dataset that won't make it into the final .nc file @@ -254,7 +280,7 @@ def ds_drop(ds): "VelY", "VelZ1", "VelZ2", - "Beam2xyz", + # "Beam2xyz", "AHRSRotationMatrix", "AHRSGyroX", "AHRSGyroY", @@ -330,6 +356,7 @@ def ds_rename_sig(ds, waves=False): "Pitchstd": "Ptch_std", "Rollstd": "Roll_std", "Pressurestd": "Pres_std", + # "Beam2xyz": "TransMatrix", } for v in varnames: @@ -739,6 +766,14 @@ def ds_add_attrs_sig(ds): } ) + if "TransMatrix" in ds: + ds["TransMatrix"].attrs.update( + { + "units": "1", + "long_name": "Instrument Transformation Matrix", + } + ) + if "Hdg_std" in ds: ds["Hdg_std"].attrs.update( { @@ -848,3 +883,33 @@ def ds_make_ahrs_vars(ds): ) return ds + + +def ds_make_tmat(ds): + """ + add instrument Transformation Matrix to xarray Dataset + """ + # rename to TransMatrix + varnames = {"Beam2xyz": "TransMatrix"} + for v in varnames: + if v in ds: + ds = ds.rename({v: varnames[v]}) + + # swap dims in Tmat + if "TransMatrix" in ds.data_vars: + n = ds["TransMatrix"].shape[0] + if n == 4: + if "inst4" not in ds.dims: + ds["inst4"] = xr.DataArray(["X", "Y", "Z1", "Z2"], dims="inst4") + + if "beam" not in ds.dims: + ds["beam"] = xr.DataArray( + range(1, ds["NBeams"][0].values + 1), dims="beam" + ) + + v = "TransMatrix" + tdims = ds[v].dims + ds[v] = ds[v].swap_dims({tdims[0]: "inst4"}) + ds[v] = ds[v].swap_dims({tdims[1]: "beam"}) + + return ds diff --git a/stglib/sig/mat2cdf.py b/stglib/sig/mat2cdf.py index 57cac9a4..1a313654 100644 --- a/stglib/sig/mat2cdf.py +++ b/stglib/sig/mat2cdf.py @@ -60,7 +60,7 @@ def load_mat_file(filnam): * np.arange(mat["Config"]["Average_NCells"]) ) - if "Alt_Plan_AveargedEnabled" in mat["Config"]: + if "Alt_Plan_AverageEnabled" in mat["Config"]: if mat["Config"]["Alt_Plan_AverageEnabled"] == "True": bindistAltAVG = ( mat["Config"]["Alt_Average_BlankingDistance"] @@ -172,7 +172,7 @@ def load_mat_file(filnam): ) dse1["time"] = pd.DatetimeIndex(dse1["time"]) dse1["bindist"] = xr.DataArray(bindistECHO, dims="bindist") - dse1.attrs["data_type"] = "Echo1" + dse1.attrs["data_type"] = "EchoSounder" ds_dict["dse1"] = dse1 if mat["Config"]["Plan_AverageEnabled"] == "True": @@ -190,7 +190,7 @@ def load_mat_file(filnam): dsa.attrs["data_type"] = "Average" ds_dict["dsa"] = dsa - if "Alt_Plan_AveargedEnabled" in mat["Config"]: + if "Alt_Plan_AverageEnabled" in mat["Config"]: if mat["Config"]["Alt_Plan_AverageEnabled"] == "True": if "Alt_Average_Time" in mat["Data"]: # Alt Average @@ -580,6 +580,7 @@ def loadpar(f): if "dsa" in dsd: dsa = dsd["dsa"] fin = outdir + f"*-{dsa.attrs['data_type']}-*.cdf" + print(fin) try: ds = xr.open_mfdataset(fin, parallel=True, chunks=chunksizes) ds = aqdutils.check_attrs(ds, inst_type="SIG") diff --git a/stglib/tests/test_scripts.py b/stglib/tests/test_scripts.py index 759e5efc..087a2219 100644 --- a/stglib/tests/test_scripts.py +++ b/stglib/tests/test_scripts.py @@ -363,9 +363,7 @@ def sig_nc(nc_file): assert "Done writing netCDF file" in result.stdout.decode("utf8") -pytest.mark.skip(reason="works locally but not on github built-in checks") - - +# @pytest.mark.skip(reason="works locally but not on github built-in checks") def test_sig(): sig_mat("glob_att1126_sig1.txt", "sig1126_config.yaml") print(os.listdir()) From 6c8bd76f89731bddcf206819d4b8d71bf1bab8d6 Mon Sep 17 00:00:00 2001 From: ssuttles-usgs Date: Tue, 21 May 2024 13:34:58 -0400 Subject: [PATCH 4/7] add tests, clean-up code --- .gitattributes | 2 + stglib/sig/cdf2nc.py | 69 ++-- stglib/sig/mat2cdf.py | 147 ++------ stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt | 319 ++++++++++++++++++ stglib/tests/data/gatts_MIA23SH2_cf_rev.txt | 22 ++ .../data/mat3/MIA23Sig1000_0001_avgd.mat | 3 + .../data/mat3/MIA23Sig1000_0002_avgd.mat | 3 + .../data/mat3/MIA23Sig1000_0003_avgd.mat | 3 + .../data/mat3/MIA23Sig1000_0004_avgd.mat | 3 + .../data/mat3/MIA23Sig1000_0005_avgd.mat | 3 + .../data/mat3/MIA23Sig1000_0006_avgd.mat | 3 + .../data/mat3/MIA23Sig1000_0007_avgd.mat | 3 + .../data/mat3/MIA23Sig1000_0008_avgd.mat | 3 + .../data/mat3/MIA23Sig1000_0009_avgd.mat | 3 + .../data/mat3/MIA23Sig1000_0010_avgd.mat | 3 + stglib/tests/data/sig_avg_config.yaml | 17 + stglib/tests/test_scripts.py | 6 +- 17 files changed, 458 insertions(+), 154 deletions(-) create mode 100644 stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt create mode 100644 stglib/tests/data/gatts_MIA23SH2_cf_rev.txt create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0001_avgd.mat create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0002_avgd.mat create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0003_avgd.mat create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0004_avgd.mat create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0005_avgd.mat create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0006_avgd.mat create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0007_avgd.mat create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0008_avgd.mat create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0009_avgd.mat create mode 100644 stglib/tests/data/mat3/MIA23Sig1000_0010_avgd.mat create mode 100644 stglib/tests/data/sig_avg_config.yaml diff --git a/.gitattributes b/.gitattributes index 07b88009..dd01487a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,3 +4,5 @@ stglib/_version.py export-subst stglib/tests/data/055109_20220808_1605.zip filter=lfs diff=lfs merge=lfs -text stglib/tests/data/055109_20220808_1605_config.yaml filter=lfs diff=lfs merge=lfs -text stglib/tests/data/gatts_055109_20220808_1605.txt filter=lfs diff=lfs merge=lfs -text +stglib/tests/data/*.cdf filter=lfs diff=lfs merge=lfs -text +stglib/tests/data/mat3/* filter=lfs diff=lfs merge=lfs -text diff --git a/stglib/sig/cdf2nc.py b/stglib/sig/cdf2nc.py index b41f1ea1..bdfe4610 100644 --- a/stglib/sig/cdf2nc.py +++ b/stglib/sig/cdf2nc.py @@ -46,7 +46,6 @@ def cdf_to_nc(cdf_filename, atmpres=False): # print(ds) # create Z depending on orientation - # ds, T, T_orig = aqdutils.set_orientation(ds, ds["Burst_Beam2xyz"].values) ds = utils.create_z(ds) # Clip data to in/out water times or via good_ens @@ -109,6 +108,8 @@ def cdf_to_nc(cdf_filename, atmpres=False): ds = aqdutils.ds_add_attrs(ds, inst_type="SIG") # for common adcp vars ds = ds_add_attrs_sig(ds) # for signature vars + ds = fix_encoding(ds) + # Add DELTA_T for EPIC compliance # ds = utils.add_delta_t(ds) @@ -122,8 +123,6 @@ def cdf_to_nc(cdf_filename, atmpres=False): ds = drop_unused_dims(ds) - ds = fix_encoding(ds) - ds = utils.ds_add_lat_lon(ds) ds = utils.ds_coord_no_fillvalue(ds) @@ -166,7 +165,6 @@ def cdf_to_nc(cdf_filename, atmpres=False): elif ds.attrs["data_type"] == "Average": nc_out = nc_filename + "avg-cal.nc" print("writing Average (avg) data to netCDF nc file") - print(ds.attrs) delayed_obj = ds.to_netcdf(nc_out, compute=False) with ProgressBar(): delayed_obj.compute() @@ -175,7 +173,6 @@ def cdf_to_nc(cdf_filename, atmpres=False): elif ds.attrs["data_type"] == "Alt_Average": nc_out = nc_filename + "alt-cal.nc" print("writing Alt_Average (avg) data to netCDF nc file") - print(ds.attrs) delayed_obj = ds.to_netcdf(nc_out, compute=False) with ProgressBar(): delayed_obj.compute() @@ -238,15 +235,6 @@ def drop_attrs(ds): for k in rm: del ds.attrs[k] - """ - for j in ds.data_vars: - for k in ds[j].attrs: - - if type(ds[j].attrs[k]) is np.ndarray: - shp = len(ds[j].attrs[k].shape) - print(f"{j},{k},{shp}") - """ - return ds @@ -280,7 +268,6 @@ def ds_drop(ds): "VelY", "VelZ1", "VelZ2", - # "Beam2xyz", "AHRSRotationMatrix", "AHRSGyroX", "AHRSGyroY", @@ -356,7 +343,6 @@ def ds_rename_sig(ds, waves=False): "Pitchstd": "Ptch_std", "Rollstd": "Roll_std", "Pressurestd": "Pres_std", - # "Beam2xyz": "TransMatrix", } for v in varnames: @@ -384,19 +370,26 @@ def ds_rename_sig(ds, waves=False): def fix_encoding(ds): """ensure we don't set dtypes uint for CF compliance""" - if "sample" not in ds.dims: + if "units" in ds["time"].encoding: + ds["time"].encoding.pop("units") + + tstep = ds["time"][1] - ds["time"][0] + # if "sample" not in ds.dims: + if tstep < np.timedelta64(1, "m"): print( - "make time encoding to dtype double because no sample dimension, round to milliseconds first" + f"make time encoding to dtype double because tstep {tstep} seconds is < 1 minute, round to milliseconds first" ) ds["time"] = ds["time"].dt.round("ms") # round time to milliseconds first + print("make time encoding to dtype double because time step < 1 minute") ds["time"].encoding["dtype"] = "double" - """if ds[var].max() > 2**31 - 1 or ds[var].min() < -(2**31): - print( - f"warning {var} may be too big to fit in int32: min {ds[var].min().values}, max {ds[var].max().values} so make double" - ) - ds[var].encoding["dtype"] = "double" - """ + else: + print( + f"make time encoding int because tstep {tstep} seconds is >= 1 minute, round time to seconds first" + ) + ds["time"] = ds["time"].dt.round( + "s" + ) # round time to seconds if time interval >= 1 minute ds["time"].encoding["dtype"] = "i4" if "beam" in ds.dims: @@ -417,27 +410,39 @@ def ds_add_attrs_sig(ds): """ add attributes to xarray Dataset """ - """ - ds["time"].attrs.update( - {"standard_name": "time", "axis": "T", "long_name": "time (UTC)"} - ) - """ + if "earth" in ds: ds["earth"].attrs.update( { - "units": "1", + # "units": "1", "long_name": "Earth Reference Frame", } ) + if "earth4" in ds: + ds["earth4"].attrs.update( + { + # "units": "1", + "long_name": "Earth Reference Frame for 4 beam ADCP", + } + ) + if "inst" in ds: ds["inst"].attrs.update( { - "units": "1", + # "units": "1", "long_name": "Instrumnet Reference Frame", } ) + if "inst4" in ds: + ds["inst4"].attrs.update( + { + # "units": "1", + "long_name": "Instrumnet Reference Frame for 4 beam ADCP", + } + ) + if "beam" in ds: ds["beam"].attrs.update( { @@ -769,7 +774,7 @@ def ds_add_attrs_sig(ds): if "TransMatrix" in ds: ds["TransMatrix"].attrs.update( { - "units": "1", + # "units": "1", "long_name": "Instrument Transformation Matrix", } ) diff --git a/stglib/sig/mat2cdf.py b/stglib/sig/mat2cdf.py index 1a313654..6a1854ee 100644 --- a/stglib/sig/mat2cdf.py +++ b/stglib/sig/mat2cdf.py @@ -467,7 +467,7 @@ def loadpar(f): print(f"Finished writing data to {cdf_filename}") matfiles = glob.glob(f"{basefile}_*.mat") - print(matfiles) + # print(matfiles) if len(matfiles) > 1: Parallel(n_jobs=-1, verbose=10)(delayed(loadpar)(f) for f in matfiles) else: @@ -488,9 +488,10 @@ def loadpar(f): chunksizes = {"time": 200000, "bindist": 48} print(f"Using default chunksizes = {chunksizes}") - if "dsb" in dsd: - dsb = dsd["dsb"] - fin = outdir + f"*-{dsb.attrs['data_type']}-*.cdf" + for k in dsd: + # dsb = dsd["dsb"] + fin = outdir + f"*-{dsd[k].attrs['data_type']}-*.cdf" + print(k) try: ds = xr.open_mfdataset(fin, parallel=True, chunks=chunksizes) ds = aqdutils.check_attrs(ds, inst_type="SIG") @@ -498,8 +499,27 @@ def loadpar(f): if "time" in ds["Beam2xyz"].dims: ds["Beam2xyz"] = ds["Beam2xyz"].isel(time=0, drop=True) # write out all into single -raw.cdf files per data_type - cdf_filename = prefix + ds.attrs["filename"] + "_burst-raw.cdf" - print("writing Burst to netcdf") + if ( + ds.attrs["data_type"].lower() == "burst" + or ds.attrs["data_type"].lower() == "bursthr" + ): + ftype = "burst" + elif ( + ds.attrs["data_type"].lower() == "iburst" + or ds.attrs["data_type"].lower() == "ibursthr" + ): + ftype = "iburst" + elif ds.attrs["data_type"].lower() == "echosounder": + ftype = "echo1" + elif ds.attrs["data_type"].lower() == "burstrawaltimeter": + ftype = "burstrawalt" + elif ds.attrs["data_type"].lower() == "average": + ftype = "avgd" + elif ds.attrs["data_type"].lower() == "alt_average": + ftype = "altavgd" + + cdf_filename = prefix + ds.attrs["filename"] + f"_{ftype}-raw.cdf" + print(f"writing {ftype} to netcdf") delayed_obj = ds.to_netcdf(cdf_filename, compute=False) with ProgressBar(): delayed_obj.compute() @@ -508,120 +528,7 @@ def loadpar(f): except ValueError as ve: print( - f"Failed to read or write netCDF file(s) for data_type {dsb.attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" - ) - - if "dsi" in dsd: - dsi = dsd["dsi"] - fin = outdir + f"*-{dsi.attrs['data_type']}-*.cdf" - try: - ds = xr.open_mfdataset(fin, parallel=True, chunks=chunksizes) - ds = aqdutils.check_attrs(ds, inst_type="SIG") - if "Beam2xyz" in ds: - if "time" in ds["Beam2xyz"].dims: - ds["Beam2xyz"] = ds["Beam2xyz"].isel(time=0, drop=True) - # write out all into single -raw.cdf files per data_type - cdf_filename = prefix + ds.attrs["filename"] + "_iburst-raw.cdf" - print("writing IBurst to netcdf") - delayed_obj = ds.to_netcdf(cdf_filename, compute=False) - with ProgressBar(): - delayed_obj.compute() - - print(f"Finished writing data to {cdf_filename}") - - except ValueError as ve: - print( - f"Failed to read or write netCDF file(s) for data_type {dsi.attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" - ) - - if "dsbra" in dsd: - dsbra = dsd["dsbra"] - fin = outdir + f"*-{dsbra.attrs['data_type']}-*.cdf" - try: - ds = xr.open_mfdataset(fin, parallel=True, chunks=chunksizes) - ds = aqdutils.check_attrs(ds, inst_type="SIG") - # write out all into single -raw.cdf files per data_type - cdf_filename = prefix + ds.attrs["filename"] + "_burstrawalt-raw.cdf" - print("writing BurstRawAltimeter to netcdf") - delayed_obj = ds.to_netcdf(cdf_filename, compute=False) - with ProgressBar(): - delayed_obj.compute() - - print(f"Finished writing data to {cdf_filename}") - - except ValueError as ve: - print( - f"Failed to read or write netCDF file(s) for data_type {dsbra.attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" - ) - - if "dse1" in dsd: - dse1 = dsd["dse1"] - try: - fin = outdir + f"*-{dse1.attrs['data_type']}-*.cdf" - ds = xr.open_mfdataset(fin, parallel=True, chunks=chunksizes) - ds = aqdutils.check_attrs(ds, inst_type="SIG") - if "Beam2xyz" in ds: - if "time" in ds["Beam2xyz"].dims: - ds["Beam2xyz"] = ds["Beam2xyz"].isel(time=0, drop=True) - # write out all into single -raw.cdf files per data_type - cdf_filename = prefix + ds.attrs["filename"] + "_echo1-raw.cdf" - print("writing Echo1 to netcdf") - delayed_obj = ds.to_netcdf(cdf_filename, compute=False) - with ProgressBar(): - delayed_obj.compute() - - print(f"Finished writing data to {cdf_filename}") - - except ValueError as ve: - print( - f"Failed to read or write netCDF file(s) for data_type {dse1.attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" - ) - - if "dsa" in dsd: - dsa = dsd["dsa"] - fin = outdir + f"*-{dsa.attrs['data_type']}-*.cdf" - print(fin) - try: - ds = xr.open_mfdataset(fin, parallel=True, chunks=chunksizes) - ds = aqdutils.check_attrs(ds, inst_type="SIG") - if "Beam2xyz" in ds: - if "time" in ds["Beam2xyz"].dims: - ds["Beam2xyz"] = ds["Beam2xyz"].isel(time=0, drop=True) - # write out all into single -raw.cdf files per data_type - cdf_filename = prefix + ds.attrs["filename"] + "_avgd-raw.cdf" - print("writing Average to netcdf") - delayed_obj = ds.to_netcdf(cdf_filename, compute=False) - with ProgressBar(): - delayed_obj.compute() - - print(f"Finished writing data to {cdf_filename}") - - except ValueError as ve: - print( - f"Failed to read or write netCDF file(s) for data_type {dsa.attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" - ) - - if "dsalt" in dsd: - dsalt = dsd["dsalt"] - fin = outdir + f"*-{dsalt.attrs['data_type']}-*.cdf" - try: - ds = xr.open_mfdataset(fin, parallel=True, chunks=chunksizes) - ds = aqdutils.check_attrs(ds, inst_type="SIG") - if "Beam2xyz" in ds: - if "time" in ds["Beam2xyz"].dims: - ds["Beam2xyz"] = ds["Beam2xyz"].isel(time=0, drop=True) - # write out all into single -raw.cdf files per data_type - cdf_filename = prefix + ds.attrs["filename"] + "_altavgd-raw.cdf" - print("writing Average to netcdf") - delayed_obj = ds.to_netcdf(cdf_filename, compute=False) - with ProgressBar(): - delayed_obj.compute() - - print(f"Finished writing data to {cdf_filename}") - - except ValueError as ve: - print( - f"Failed to read or write netCDF file(s) for data_type {dsalt.attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" + f"Failed to read or write netCDF file(s) for data_type {dsd[k].attrs['data_type']} to make composite -raw.cdf file, due to Value Error: '{ve}'" ) toc = time.time() diff --git a/stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt b/stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt new file mode 100644 index 00000000..73989c7a --- /dev/null +++ b/stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt @@ -0,0 +1,319 @@ +netcdf MIAsigavg-cal { +dimensions: + time = 14921 ; + inst4 = 4 ; + beam = 4 ; + z = 15 ; + inst = 3 ; + latitude = 1 ; + longitude = 1 ; +variables: + int time(time) ; + time:standard_name = "time" ; + time:axis = "T" ; + time:long_name = "time (UTC)" ; + time:units = "seconds since 2023-06-23 16:00:00" ; + time:calendar = "proleptic_gregorian" ; + int status(time) ; + status:long_name = "Status Code" ; + status:units = "1" ; + status:minimum = 944504834U ; + status:maximum = 944505858U ; + int error(time) ; + error:long_name = "Error Code" ; + error:units = "1" ; + error:minimum = 0U ; + error:maximum = 0U ; + int sample(time) ; + sample:long_name = "sample number" ; + sample:units = "1" ; + sample:minimum = 1U ; + sample:maximum = 120U ; + float ambig_vel(time) ; + ambig_vel:_FillValue = NaNf ; + ambig_vel:units = "m s-1" ; + ambig_vel:long_name = "Ambiguity velocity" ; + ambig_vel:minimum = 10.725f ; + ambig_vel:maximum = 10.77105f ; + float Bat_106(time) ; + Bat_106:_FillValue = NaNf ; + Bat_106:long_name = "Battery voltage" ; + Bat_106:units = "V" ; + Bat_106:epic_code = 106 ; + Bat_106:minimum = 18.3f ; + Bat_106:maximum = 18.7f ; + float Hdg_1215(time) ; + Hdg_1215:_FillValue = NaNf ; + Hdg_1215:units = "degrees" ; + Hdg_1215:long_name = "Instrument Heading" ; + Hdg_1215:epic_code = 1215 ; + Hdg_1215:note = "Heading is degrees true. Converted from magnetic with magnetic variation of -7.250000." ; + Hdg_1215:standard_name = "platform_orientation" ; + Hdg_1215:minimum = 0.6727271f ; + Hdg_1215:maximum = 1.6725f ; + float Ptch_1216(time) ; + Ptch_1216:_FillValue = NaNf ; + Ptch_1216:long_name = "Instrument Pitch" ; + Ptch_1216:units = "degrees" ; + Ptch_1216:epic_code = 1216 ; + Ptch_1216:standard_name = "platform_pitch" ; + Ptch_1216:minimum = 3.86575f ; + Ptch_1216:maximum = 3.983917f ; + float Roll_1217(time) ; + Roll_1217:_FillValue = NaNf ; + Roll_1217:long_name = "Instrument Roll" ; + Roll_1217:units = "degrees" ; + Roll_1217:epic_code = 1217 ; + Roll_1217:standard_name = "platform_roll" ; + Roll_1217:minimum = 0.11f ; + Roll_1217:maximum = 0.2039166f ; + float Tx_1211(time) ; + Tx_1211:_FillValue = NaNf ; + Tx_1211:long_name = "Instrument Internal Temperature" ; + Tx_1211:units = "degree_C" ; + Tx_1211:epic_code = 1211 ; + Tx_1211:minimum = 29.3915f ; + Tx_1211:maximum = 32.70192f ; + float SV_80(time) ; + SV_80:_FillValue = NaNf ; + SV_80:units = "m s-1" ; + SV_80:epic_code = 80 ; + SV_80:long_name = "Speed of Sound" ; + SV_80:standard_name = "speed_of_sound_in_sea_water" ; + SV_80:minimum = 1544.4f ; + SV_80:maximum = 1551.037f ; + float P_1(time) ; + P_1:_FillValue = NaNf ; + P_1:long_name = "Uncorrected pressure" ; + P_1:units = "dbar" ; + P_1:epic_code = 1 ; + P_1:standard_name = "sea_water_pressure" ; + P_1:minimum = 2.794817f ; + P_1:maximum = 3.990317f ; + float xmit_energy(time) ; + xmit_energy:_FillValue = NaNf ; + xmit_energy:long_name = "Transmit Energy" ; + xmit_energy:units = "dB" ; + xmit_energy:minimum = 94.f ; + xmit_energy:maximum = 106.f ; + int corr_nominal(time) ; + corr_nominal:long_name = "Nominal Correlation" ; + corr_nominal:units = "percent" ; + corr_nominal:minimum = 60UB ; + corr_nominal:maximum = 60UB ; + float TransMatrix(inst4, beam) ; + TransMatrix:units = "1" ; + TransMatrix:long_name = "Instrument Transformation Matrix" ; + double z(z) ; + z:long_name = "height relative to sea bed" ; + z:positive = "up" ; + z:axis = "Z" ; + z:units = "m" ; + z:standard_name = "height" ; + float u_1205(time, z) ; + u_1205:_FillValue = NaNf ; + u_1205:long_name = "Eastward Velocity" ; + u_1205:epic_code = 1205 ; + u_1205:units = "m s-1" ; + u_1205:note = "Velocity bins trimmed if out of water or if side lobes intersect sea surface (with 3 additional surface bins removed)." ; + u_1205:standard_name = "eastward_sea_water_velocity" ; + u_1205:minimum = -0.3043381f ; + u_1205:maximum = 0.4729342f ; + float v_1206(time, z) ; + v_1206:_FillValue = NaNf ; + v_1206:long_name = "Northward Velocity" ; + v_1206:epic_code = 1206 ; + v_1206:units = "m s-1" ; + v_1206:note = "Velocity bins trimmed if out of water or if side lobes intersect sea surface (with 3 additional surface bins removed)." ; + v_1206:standard_name = "northward_sea_water_velocity" ; + v_1206:minimum = -0.5342383f ; + v_1206:maximum = 0.5213875f ; + float w_1204(time, z) ; + w_1204:_FillValue = NaNf ; + w_1204:long_name = "Vertical Velocity" ; + w_1204:epic_code = 1204 ; + w_1204:units = "m s-1" ; + w_1204:note = "Velocity bins trimmed if out of water or if side lobes intersect sea surface (with 3 additional surface bins removed)." ; + w_1204:standard_name = "upward_sea_water_velocity" ; + w_1204:minimum = -0.238696f ; + w_1204:maximum = 0.4404314f ; + float w2_1204(time, z) ; + w2_1204:_FillValue = NaNf ; + w2_1204:long_name = "Vertical Velocity (2nd)" ; + w2_1204:units = "m s-1" ; + w2_1204:note = "Velocity bins trimmed if out of water or if side lobes intersect sea surface (with 3 additional surface bins removed)." ; + w2_1204:minimum = -0.2421437f ; + w2_1204:maximum = 0.4456696f ; + int beam(beam) ; + beam:units = "1" ; + beam:long_name = "Beam Reference Frame" ; + float vel(beam, time, z) ; + vel:_FillValue = NaNf ; + vel:units = "m s-1" ; + vel:standard_name = "radial_sea_water_velocity_away_from_instrument" ; + vel:long_name = "Beam Velocity" ; + vel:minimum = -0.3223417f, -0.2583833f, -0.414f, -0.4104f ; + vel:maximum = 0.4921f, 0.3793f, 0.4010909f, 0.4465818f ; + float corr(beam, time, z) ; + corr:_FillValue = NaNf ; + corr:units = "percent" ; + corr:standard_name = "beam_consistency_indicator_from_multibeam_acoustic_doppler_velocity_profiler_in_sea_water" ; + corr:long_name = "Acoustic Signal Correlation" ; + corr:minimum = 18UB, 22UB, 27UB, 22UB ; + corr:maximum = 100UB, 100UB, 100UB, 100UB ; + float amp(beam, time, z) ; + amp:_FillValue = NaNf ; + amp:units = "dB" ; + amp:standard_name = "signal_intensity_from_multibeam_acoustic_doppler_velocity_sensor_in_sea_water" ; + amp:long_name = "Acoustic Signal Amplitude" ; + amp:minimum = 44.5f, 46.5f, 41.f, 46.f ; + amp:maximum = 85.5f, 85.5f, 85.5f, 85.5f ; + float bin_depth(time, z) ; + bin_depth:_FillValue = NaNf ; + bin_depth:units = "m" ; + bin_depth:long_name = "bin depth" ; + bin_depth:note = "Actual depth time series of velocity bins. Calculated as pressure (P_1) - bindist." ; + bin_depth:minimum = -0.205183312296867 ; + bin_depth:maximum = 3.79031686484814 ; + string inst4(inst4) ; + inst4:units = "1" ; + inst4:long_name = "Instrumnet Reference Frame for 4 beam ADCP" ; + string inst(inst) ; + inst:units = "1" ; + inst:long_name = "Instrumnet Reference Frame" ; + float mag(inst, time) ; + mag:_FillValue = NaNf ; + mag:units = "uT" ; + mag:long_name = "Magnetometer Data" ; + mag:minimum = 28.60167f, 4.251818f, -43.2275f ; + mag:maximum = 28.88334f, 4.851666f, -42.97417f ; + float accel(inst, time) ; + accel:_FillValue = NaNf ; + accel:units = "m s-2" ; + accel:long_name = "Vector Acceleration of Instrument" ; + accel:minimum = 0.6620033f, 0.01975891f, 9.775846f ; + accel:maximum = 0.6824808f, 0.03638933f, 9.784853f ; + double latitude(latitude) ; + latitude:units = "degree_north" ; + latitude:axis = "Y" ; + latitude:long_name = "Latitude" ; + latitude:standard_name = "latitude" ; + latitude:epic_code = 500 ; + double longitude(longitude) ; + longitude:units = "degree_east" ; + longitude:axis = "X" ; + longitude:long_name = "Longitude" ; + longitude:standard_name = "longitude" ; + longitude:epic_code = 502 ; + +// global attributes: + :data_type = "Average" ; + :SIGSerialNo = 101042 ; + :SIGInstrumentName = "Signature1000" ; + :SIGAnalogBoardRev = "F-1" ; + :SIGDigitalBoardRev = "I-3" ; + :SIGSensorBoardRev = "I-0" ; + :SIGInterfaceBoardRev = "H-2" ; + :SIGFPGAVersion = 185 ; + :SIGFWVersion = 2214 ; + :SIGComType = "RS232" ; + :SIGBaudrate = 9600. ; + :SIGLedEnabled = "ON24H" ; + :SIGOrientation = "AUTOZUPDOWN" ; + :SIGHeadFrequency = 1000. ; + :SIGHasAccelerometer = "True" ; + :SIGHasMagnetometer = "True" ; + :SIGHasPressure = "True" ; + :SIGHasTemperature = "True" ; + :SIGHasCompass = "True" ; + :SIGHx = 25. ; + :SIGHy = 15. ; + :SIGHz = 0. ; + :SIGPressureOffset = 10. ; + :SIGDeclination = 0. ; + :SIGPlan_BurstEnabled = "True" ; + :SIGPlan_AverageEnabled = "True" ; + :SIGPlan_Salinity = 35. ; + :SIGPlan_Filename = "MIA23Sig1000.ad2cp" ; + :SIGPlan_MaxVerticalVelocity = 10 ; + :SIGPlan_ProfileInterval = 120 ; + :SIGPlan_AverageDepthInterval = 0 ; + :SIGPlan_BurstInterval = 3600 ; + :SIGPlan_BurstDepthInterval = 0 ; + :SIGPlan_SoundVelocity = 0. ; + :SIGPlan_SerialOutputEnabled = "False" ; + :SIGAlt_Plan_BurstEnabled = "True" ; + :SIGAlt_Plan_AverageEnabled = "True" ; + :SIGAlt_Plan_Salinity = 35. ; + :SIGAlt_Plan_Filename = "MIA23Sig1000.ad2cp" ; + :SIGAlt_Plan_MaxVerticalVelocity = 10 ; + :SIGAlt_Plan_ProfileInterval = 120 ; + :SIGAlt_Plan_AverageDepthInterval = 0 ; + :SIGAlt_Plan_BurstInterval = 3600 ; + :SIGAlt_Plan_BurstDepthInterval = 0 ; + :SIGAlt_Plan_SoundVelocity = 0. ; + :SIGAlt_Plan_SerialOutputEnabled = "False" ; + :SIGAverage_Altimeter = "False" ; + :SIGAverage_IceTrack = "False" ; + :SIGAverage_AverageInterval = 120 ; + :SIGAverage_BlankingDistance = 0.100000001490116 ; + :SIGAverage_CellSize = 0.200000002980232 ; + :SIGAverage_NBeams = 4 ; + :SIGAverage_NCells = 32 ; + :SIGAverage_ChannelBeamSel = 0 ; + :SIGAverage_CoordSystem = "BEAM" ; + :SIGAverage_DataFormat = 3 ; + :SIGAverage_NPings = 480 ; + :SIGAverage_Bandwidth = "BROAD" ; + :SIGAverage_PowerLevel = 0. ; + :SIGAverage_VelocityPrecision = 0. ; + :SIGAverage_VelocityRange = 5. ; + :SIGAverage_BottomTrack = "False" ; + :MOORING = "MIA23SH2" ; + :PROGRAM = "Coastal and Marine Hazards and Resources Program" ; + :PROJECT = "Coral Reefs" ; + :EXPERIMENT = "Miami X-Reefs" ; + :Region = "Florida" ; + :CruiseID = "2023-623-FA" ; + :SciPi = "Curt Storlazzi, Olivia Cheriton, Kurt Rosenberger" ; + :Year = 2023. ; + :Site = "SH2" ; + :platform_type = "Artificial Reef Box" ; + :latitude = 25.866503 ; + :longitude = -80.116706 ; + :LatLonDatum = "WGS84" ; + :WATER_DEPTH = 5. ; + :Deployment_date = "2023-06-23 15:30" ; + :Recovery_date = "2024-01-17 10:00" ; + :OFAFunding = "" ; + :CollaboratingAgency = "University of Miami" ; + :DESCRIPTION = "Seahive structure" ; + :WATER_DEPTH_SOURCE = "pressure data" ; + :magnetic_variation = -7.25 ; + :Conventions = "CF-1.8" ; + :basefile = "mat3/MIA23Sig1000" ; + :outdir = "mat3/" ; + :filename = "MIAsig" ; + :ClockError = 0 ; + :orientation = "UP" ; + :head_rotation = "horizontal" ; + :initial_instrument_height = 1. ; + :initial_instrument_height_note = "From seabed" ; + :zeroed_pressure = "Yes" ; + :cutoff_ampl = 0 ; + :trim_method = "water level sl" ; + :trim_surf_bins = 3 ; + :history = "2024-05-21T16:26:54.999377+00:00: Processed using mat2cdf.py with stglib 0.15.0+31.g30ecb68.dirty, xarray 2024.2.0, NumPy 1.26.4, netCDF4 1.6.5, Python 3.11.8.\n2024-05-21T16:27:17.727304+00:00: Data clipped using Deployment_date of 2023-06-23 15:30 and Recovery_date of 2024-01-17 10:00.\n2024-05-21T16:27:17.738401+00:00: Rotating heading and horizontal velocities by -7.25 degrees.\n2024-05-21T16:27:17.761806+00:00: Trimmed velocity data using NON-atmospherically corrected pressure (water level) and sidelobes +(with 3 additional surface bins removed).\n2024-05-21T16:27:18.023571+00:00: Processed to CF-1.8 using runsigcdf2nc.py.\n" ; + :nominal_sensor_depth_note = "WATER_DEPTH - initial_instrument_height" ; + :nominal_sensor_depth = 4. ; + :transducer_offset_from_bottom = 1. ; + :serial_number = 101042 ; + :frequency = 1000. ; + :instrument_type = "Signature1000" ; + :bin_size = 0.200000002980232 ; + :beam_angle = 25 ; + :nominal_instrument_depth = 4. ; + :start_time = "2023-06-23T16:00:00.000000000" ; + :stop_time = "2023-08-04T02:08:00.000000000" ; +} \ No newline at end of file diff --git a/stglib/tests/data/gatts_MIA23SH2_cf_rev.txt b/stglib/tests/data/gatts_MIA23SH2_cf_rev.txt new file mode 100644 index 00000000..58750e4d --- /dev/null +++ b/stglib/tests/data/gatts_MIA23SH2_cf_rev.txt @@ -0,0 +1,22 @@ +MOORING; MIA23SH2 +PROGRAM; Coastal and Marine Hazards and Resources Program +PROJECT; Coral Reefs +EXPERIMENT; Miami X-Reefs +Region; Florida +CruiseID; 2023-623-FA +SciPi; Curt Storlazzi, Olivia Cheriton, Kurt Rosenberger +Year; 2023 +Site; SH2 +platform_type; Artificial Reef Box +latitude; 25.866503 +longitude; -80.116706 +LatLonDatum; WGS84 +WATER_DEPTH; 5 +Deployment_date; 2023-06-23 15:30 +Recovery_date; 2024-01-17 10:00 +OFAFunding; +CollaboratingAgency; University of Miami +DESCRIPTION; Seahive structure +WATER_DEPTH_SOURCE; pressure data +magnetic_variation; -7.25 +Conventions; CF-1.8 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0001_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0001_avgd.mat new file mode 100644 index 00000000..874a5a99 --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0001_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de6330ee07c2a5c9205807e78a60e16299bbbbc33daa29f7e50531765a04712b +size 8028264 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0002_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0002_avgd.mat new file mode 100644 index 00000000..4d35ad62 --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0002_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd3101c8cc862e691cfff949daad0872cf6cb025e662fec18e0efb4b5cd9df83 +size 8076984 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0003_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0003_avgd.mat new file mode 100644 index 00000000..a3ff1b93 --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0003_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6f897836370464d1e2a1e8b42a71df2efbd84da45087c70b94fa2acbee0f91f3 +size 8056432 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0004_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0004_avgd.mat new file mode 100644 index 00000000..d1c8644d --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0004_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b0813860f425c58df6921e8d16435008aa6e757a22b2cc7f3bd2d60e7e053df +size 8048648 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0005_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0005_avgd.mat new file mode 100644 index 00000000..8bb6e83a --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0005_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc3834b613d47bb330a9fbfd6a3ab249998c626cf7dd3624d7f588601873eef2 +size 8076984 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0006_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0006_avgd.mat new file mode 100644 index 00000000..b131568e --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0006_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0cd5e77f66bc8be87d84da2d7d058c6c6deb843d8d6281eafb51f06bf9ec407d +size 8051296 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0007_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0007_avgd.mat new file mode 100644 index 00000000..b51913b5 --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0007_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eb412d050e951070e11305a19b83ef3fe51f2f627432b1746f4513c46d76d99f +size 8053944 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0008_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0008_avgd.mat new file mode 100644 index 00000000..18fe89ad --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0008_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de51c763d5055cdca830cf75d72f9954c86c8e95b9a8e44ee992f240a80edafa +size 8076984 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0009_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0009_avgd.mat new file mode 100644 index 00000000..405501e6 --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0009_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:55742a7d938f4335c7eb59e9b256ab02798d1efedb670be4e20a785dbfa57401 +size 8046160 diff --git a/stglib/tests/data/mat3/MIA23Sig1000_0010_avgd.mat b/stglib/tests/data/mat3/MIA23Sig1000_0010_avgd.mat new file mode 100644 index 00000000..5bf02a39 --- /dev/null +++ b/stglib/tests/data/mat3/MIA23Sig1000_0010_avgd.mat @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:359f3f2eaf13fb2a0bde4224f8bbecfaffdfcefe5d893b0eef09399fbf1c0803 +size 8058920 diff --git a/stglib/tests/data/sig_avg_config.yaml b/stglib/tests/data/sig_avg_config.yaml new file mode 100644 index 00000000..c3e99c41 --- /dev/null +++ b/stglib/tests/data/sig_avg_config.yaml @@ -0,0 +1,17 @@ +basefile: 'mat3/MIA23Sig1000' +outdir: 'mat3/' +filename: 'MIAsig' +#basefile: 'mat/MIA23Sig1000' +#outdir: 'cdf2/' #directory to write out raw cdf files +#filename: 'MIAsig2' # name of output file, -raw.cdf or .nc will be appended to this +#LatLonDatum: 'NAD83' +ClockError: 0 #sec +#ClockDrift: 15 #sec < 60 s no need to apply correction +orientation: 'UP' # use this to identify orientation of profiler +head_rotation: 'horizontal' #will probably be 'horizontal' +initial_instrument_height: 1. # meters +initial_instrument_height_note: 'From seabed' +zeroed_pressure: 'Yes' # was pressure zeroed before deployment +cutoff_ampl: 0 # set to 0, otherwise it automatically specifies cutoff based on amplitude which is a weird thing to do +trim_method: 'water level sl' # Water Level SL trims bin if any part of bin or side lobe is out of water - works best when pressure is corrected for atmospheric +trim_surf_bins: 3 #trim add'l surface bins \ No newline at end of file diff --git a/stglib/tests/test_scripts.py b/stglib/tests/test_scripts.py index 087a2219..b92afdd3 100644 --- a/stglib/tests/test_scripts.py +++ b/stglib/tests/test_scripts.py @@ -363,14 +363,16 @@ def sig_nc(nc_file): assert "Done writing netCDF file" in result.stdout.decode("utf8") -# @pytest.mark.skip(reason="works locally but not on github built-in checks") +@pytest.mark.skip(reason="works locally but not on github built-in checks") def test_sig(): sig_mat("glob_att1126_sig1.txt", "sig1126_config.yaml") - print(os.listdir()) sig_nc("11261sig_burst-raw.cdf") sig_mat("glob_att1126_sig2.txt", "sig11262_config.yaml") sig_nc("11262sig_burst-raw.cdf") sig_nc("11262sig_echo1-raw.cdf") + sig_mat("gatts_MIA23SH2_cf_rev.txt", "sig_avg_config.yaml") + sig_nc("MIAsig_avgd-raw.cdf") + sig_nc("MIAsig_altavgd-raw.cdf") def hobo_raw(glob_att, config_yaml): From 61ec48584c96f6ee2f4c0c22d27a7602db72deb0 Mon Sep 17 00:00:00 2001 From: ssuttles-usgs Date: Wed, 22 May 2024 11:23:39 -0400 Subject: [PATCH 5/7] final clean-up and checks for PR --- stglib/core/utils.py | 2 +- stglib/sig/cdf2nc.py | 29 +- stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt | 319 ------------------ 3 files changed, 15 insertions(+), 335 deletions(-) delete mode 100644 stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt diff --git a/stglib/core/utils.py b/stglib/core/utils.py index 8d53095e..83e59f41 100644 --- a/stglib/core/utils.py +++ b/stglib/core/utils.py @@ -179,7 +179,7 @@ def add_min_max(ds, exclude_vars=None): exclude = list(ds.dims) [exclude.append(k) for k in ds.variables if "time" in k] - exclude.extend(["TIM", "TransMatrix", "orientmat", "beam2xyz"]) + exclude.extend(["TIM", "TransMatrix", "orientmat"]) if exclude_vars: exclude.extend(exclude_vars) diff --git a/stglib/sig/cdf2nc.py b/stglib/sig/cdf2nc.py index bdfe4610..6a1a4471 100644 --- a/stglib/sig/cdf2nc.py +++ b/stglib/sig/cdf2nc.py @@ -75,7 +75,7 @@ def cdf_to_nc(cdf_filename, atmpres=False): dim="beam", ) if "CorBeam1" in ds: - ds["corr"] = xr.concat( + ds["cor"] = xr.concat( [ds[f"CorBeam{i}"] for i in range(1, ds["NBeams"][0].values + 1)], dim="beam", ) @@ -334,10 +334,10 @@ def ds_rename_sig(ds, waves=False): "AltimeterQualityAST": "ast_quality", "AltimeterTimeOffsetAST": "ast_offset_time", "AltimeterPressure": "ast_pressure", - "NominalCorrelation": "corr_nominal", + "NominalCorrelation": "cor_nominal", "VelBeam5": "vel_b5", "AmpBeam5": "amp_b5", - "CorBeam5": "corr_b5", + "CorBeam5": "cor_b5", "Echo": "echo_amp", "Headingstd": "Hdg_std", "Pitchstd": "Ptch_std", @@ -373,14 +373,13 @@ def fix_encoding(ds): if "units" in ds["time"].encoding: ds["time"].encoding.pop("units") - tstep = ds["time"][1] - ds["time"][0] + tstep = ds["time"][1] - ds["time"][0] # use time step to select time encoding # if "sample" not in ds.dims: if tstep < np.timedelta64(1, "m"): print( f"make time encoding to dtype double because tstep {tstep} seconds is < 1 minute, round to milliseconds first" ) ds["time"] = ds["time"].dt.round("ms") # round time to milliseconds first - print("make time encoding to dtype double because time step < 1 minute") ds["time"].encoding["dtype"] = "double" else: @@ -398,7 +397,7 @@ def fix_encoding(ds): for var in ds.data_vars: if ds[var].dtype == "uint32" or ds[var].dtype == "uint8": ds[var].encoding["dtype"] = "int32" - if var in ["corr", "corr_b5"]: + if var in ["cor", "cor_b5"]: ds[var].encoding["dtype"] = "float32" if ds[var].dtype == "float64": ds[var].encoding["dtype"] = "float32" @@ -431,7 +430,7 @@ def ds_add_attrs_sig(ds): ds["inst"].attrs.update( { # "units": "1", - "long_name": "Instrumnet Reference Frame", + "long_name": "Instrument Reference Frame", } ) @@ -439,7 +438,7 @@ def ds_add_attrs_sig(ds): ds["inst4"].attrs.update( { # "units": "1", - "long_name": "Instrumnet Reference Frame for 4 beam ADCP", + "long_name": "Instrument Reference Frame for 4 beam ADCP", } ) @@ -560,8 +559,8 @@ def ds_add_attrs_sig(ds): } ) - if "corr" in ds: - ds["corr"].attrs.update( + if "cor" in ds: + ds["cor"].attrs.update( { "units": "percent", "standard_name": "beam_consistency_indicator_from_multibeam_acoustic_doppler_velocity_profiler_in_sea_water", @@ -569,8 +568,8 @@ def ds_add_attrs_sig(ds): } ) - if "corr_b5" in ds: - ds["corr_b5"].attrs.update( + if "cor_b5" in ds: + ds["cor_b5"].attrs.update( { "units": "percent", "standard_name": "beam_consistency_indicator_from_multibeam_acoustic_doppler_velocity_profiler_in_sea_water", @@ -578,8 +577,8 @@ def ds_add_attrs_sig(ds): } ) - if "corr_nominal" in ds: - ds["corr_nominal"].attrs.update( + if "cor_nominal" in ds: + ds["cor_nominal"].attrs.update( { "units": "percent", "long_name": "Nominal Correlation", @@ -625,7 +624,7 @@ def ds_add_attrs_sig(ds): ds["brangeAST"].attrs.update( { "units": "m", - # "standard_name": "altimeter_range", + "standard_name": "altimeter_range", "long_name": "Acoustic Surface Tracking (AST) Range", } ) diff --git a/stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt b/stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt deleted file mode 100644 index 73989c7a..00000000 --- a/stglib/tests/data/MIAsigavg-cal.nc_ncdump.txt +++ /dev/null @@ -1,319 +0,0 @@ -netcdf MIAsigavg-cal { -dimensions: - time = 14921 ; - inst4 = 4 ; - beam = 4 ; - z = 15 ; - inst = 3 ; - latitude = 1 ; - longitude = 1 ; -variables: - int time(time) ; - time:standard_name = "time" ; - time:axis = "T" ; - time:long_name = "time (UTC)" ; - time:units = "seconds since 2023-06-23 16:00:00" ; - time:calendar = "proleptic_gregorian" ; - int status(time) ; - status:long_name = "Status Code" ; - status:units = "1" ; - status:minimum = 944504834U ; - status:maximum = 944505858U ; - int error(time) ; - error:long_name = "Error Code" ; - error:units = "1" ; - error:minimum = 0U ; - error:maximum = 0U ; - int sample(time) ; - sample:long_name = "sample number" ; - sample:units = "1" ; - sample:minimum = 1U ; - sample:maximum = 120U ; - float ambig_vel(time) ; - ambig_vel:_FillValue = NaNf ; - ambig_vel:units = "m s-1" ; - ambig_vel:long_name = "Ambiguity velocity" ; - ambig_vel:minimum = 10.725f ; - ambig_vel:maximum = 10.77105f ; - float Bat_106(time) ; - Bat_106:_FillValue = NaNf ; - Bat_106:long_name = "Battery voltage" ; - Bat_106:units = "V" ; - Bat_106:epic_code = 106 ; - Bat_106:minimum = 18.3f ; - Bat_106:maximum = 18.7f ; - float Hdg_1215(time) ; - Hdg_1215:_FillValue = NaNf ; - Hdg_1215:units = "degrees" ; - Hdg_1215:long_name = "Instrument Heading" ; - Hdg_1215:epic_code = 1215 ; - Hdg_1215:note = "Heading is degrees true. Converted from magnetic with magnetic variation of -7.250000." ; - Hdg_1215:standard_name = "platform_orientation" ; - Hdg_1215:minimum = 0.6727271f ; - Hdg_1215:maximum = 1.6725f ; - float Ptch_1216(time) ; - Ptch_1216:_FillValue = NaNf ; - Ptch_1216:long_name = "Instrument Pitch" ; - Ptch_1216:units = "degrees" ; - Ptch_1216:epic_code = 1216 ; - Ptch_1216:standard_name = "platform_pitch" ; - Ptch_1216:minimum = 3.86575f ; - Ptch_1216:maximum = 3.983917f ; - float Roll_1217(time) ; - Roll_1217:_FillValue = NaNf ; - Roll_1217:long_name = "Instrument Roll" ; - Roll_1217:units = "degrees" ; - Roll_1217:epic_code = 1217 ; - Roll_1217:standard_name = "platform_roll" ; - Roll_1217:minimum = 0.11f ; - Roll_1217:maximum = 0.2039166f ; - float Tx_1211(time) ; - Tx_1211:_FillValue = NaNf ; - Tx_1211:long_name = "Instrument Internal Temperature" ; - Tx_1211:units = "degree_C" ; - Tx_1211:epic_code = 1211 ; - Tx_1211:minimum = 29.3915f ; - Tx_1211:maximum = 32.70192f ; - float SV_80(time) ; - SV_80:_FillValue = NaNf ; - SV_80:units = "m s-1" ; - SV_80:epic_code = 80 ; - SV_80:long_name = "Speed of Sound" ; - SV_80:standard_name = "speed_of_sound_in_sea_water" ; - SV_80:minimum = 1544.4f ; - SV_80:maximum = 1551.037f ; - float P_1(time) ; - P_1:_FillValue = NaNf ; - P_1:long_name = "Uncorrected pressure" ; - P_1:units = "dbar" ; - P_1:epic_code = 1 ; - P_1:standard_name = "sea_water_pressure" ; - P_1:minimum = 2.794817f ; - P_1:maximum = 3.990317f ; - float xmit_energy(time) ; - xmit_energy:_FillValue = NaNf ; - xmit_energy:long_name = "Transmit Energy" ; - xmit_energy:units = "dB" ; - xmit_energy:minimum = 94.f ; - xmit_energy:maximum = 106.f ; - int corr_nominal(time) ; - corr_nominal:long_name = "Nominal Correlation" ; - corr_nominal:units = "percent" ; - corr_nominal:minimum = 60UB ; - corr_nominal:maximum = 60UB ; - float TransMatrix(inst4, beam) ; - TransMatrix:units = "1" ; - TransMatrix:long_name = "Instrument Transformation Matrix" ; - double z(z) ; - z:long_name = "height relative to sea bed" ; - z:positive = "up" ; - z:axis = "Z" ; - z:units = "m" ; - z:standard_name = "height" ; - float u_1205(time, z) ; - u_1205:_FillValue = NaNf ; - u_1205:long_name = "Eastward Velocity" ; - u_1205:epic_code = 1205 ; - u_1205:units = "m s-1" ; - u_1205:note = "Velocity bins trimmed if out of water or if side lobes intersect sea surface (with 3 additional surface bins removed)." ; - u_1205:standard_name = "eastward_sea_water_velocity" ; - u_1205:minimum = -0.3043381f ; - u_1205:maximum = 0.4729342f ; - float v_1206(time, z) ; - v_1206:_FillValue = NaNf ; - v_1206:long_name = "Northward Velocity" ; - v_1206:epic_code = 1206 ; - v_1206:units = "m s-1" ; - v_1206:note = "Velocity bins trimmed if out of water or if side lobes intersect sea surface (with 3 additional surface bins removed)." ; - v_1206:standard_name = "northward_sea_water_velocity" ; - v_1206:minimum = -0.5342383f ; - v_1206:maximum = 0.5213875f ; - float w_1204(time, z) ; - w_1204:_FillValue = NaNf ; - w_1204:long_name = "Vertical Velocity" ; - w_1204:epic_code = 1204 ; - w_1204:units = "m s-1" ; - w_1204:note = "Velocity bins trimmed if out of water or if side lobes intersect sea surface (with 3 additional surface bins removed)." ; - w_1204:standard_name = "upward_sea_water_velocity" ; - w_1204:minimum = -0.238696f ; - w_1204:maximum = 0.4404314f ; - float w2_1204(time, z) ; - w2_1204:_FillValue = NaNf ; - w2_1204:long_name = "Vertical Velocity (2nd)" ; - w2_1204:units = "m s-1" ; - w2_1204:note = "Velocity bins trimmed if out of water or if side lobes intersect sea surface (with 3 additional surface bins removed)." ; - w2_1204:minimum = -0.2421437f ; - w2_1204:maximum = 0.4456696f ; - int beam(beam) ; - beam:units = "1" ; - beam:long_name = "Beam Reference Frame" ; - float vel(beam, time, z) ; - vel:_FillValue = NaNf ; - vel:units = "m s-1" ; - vel:standard_name = "radial_sea_water_velocity_away_from_instrument" ; - vel:long_name = "Beam Velocity" ; - vel:minimum = -0.3223417f, -0.2583833f, -0.414f, -0.4104f ; - vel:maximum = 0.4921f, 0.3793f, 0.4010909f, 0.4465818f ; - float corr(beam, time, z) ; - corr:_FillValue = NaNf ; - corr:units = "percent" ; - corr:standard_name = "beam_consistency_indicator_from_multibeam_acoustic_doppler_velocity_profiler_in_sea_water" ; - corr:long_name = "Acoustic Signal Correlation" ; - corr:minimum = 18UB, 22UB, 27UB, 22UB ; - corr:maximum = 100UB, 100UB, 100UB, 100UB ; - float amp(beam, time, z) ; - amp:_FillValue = NaNf ; - amp:units = "dB" ; - amp:standard_name = "signal_intensity_from_multibeam_acoustic_doppler_velocity_sensor_in_sea_water" ; - amp:long_name = "Acoustic Signal Amplitude" ; - amp:minimum = 44.5f, 46.5f, 41.f, 46.f ; - amp:maximum = 85.5f, 85.5f, 85.5f, 85.5f ; - float bin_depth(time, z) ; - bin_depth:_FillValue = NaNf ; - bin_depth:units = "m" ; - bin_depth:long_name = "bin depth" ; - bin_depth:note = "Actual depth time series of velocity bins. Calculated as pressure (P_1) - bindist." ; - bin_depth:minimum = -0.205183312296867 ; - bin_depth:maximum = 3.79031686484814 ; - string inst4(inst4) ; - inst4:units = "1" ; - inst4:long_name = "Instrumnet Reference Frame for 4 beam ADCP" ; - string inst(inst) ; - inst:units = "1" ; - inst:long_name = "Instrumnet Reference Frame" ; - float mag(inst, time) ; - mag:_FillValue = NaNf ; - mag:units = "uT" ; - mag:long_name = "Magnetometer Data" ; - mag:minimum = 28.60167f, 4.251818f, -43.2275f ; - mag:maximum = 28.88334f, 4.851666f, -42.97417f ; - float accel(inst, time) ; - accel:_FillValue = NaNf ; - accel:units = "m s-2" ; - accel:long_name = "Vector Acceleration of Instrument" ; - accel:minimum = 0.6620033f, 0.01975891f, 9.775846f ; - accel:maximum = 0.6824808f, 0.03638933f, 9.784853f ; - double latitude(latitude) ; - latitude:units = "degree_north" ; - latitude:axis = "Y" ; - latitude:long_name = "Latitude" ; - latitude:standard_name = "latitude" ; - latitude:epic_code = 500 ; - double longitude(longitude) ; - longitude:units = "degree_east" ; - longitude:axis = "X" ; - longitude:long_name = "Longitude" ; - longitude:standard_name = "longitude" ; - longitude:epic_code = 502 ; - -// global attributes: - :data_type = "Average" ; - :SIGSerialNo = 101042 ; - :SIGInstrumentName = "Signature1000" ; - :SIGAnalogBoardRev = "F-1" ; - :SIGDigitalBoardRev = "I-3" ; - :SIGSensorBoardRev = "I-0" ; - :SIGInterfaceBoardRev = "H-2" ; - :SIGFPGAVersion = 185 ; - :SIGFWVersion = 2214 ; - :SIGComType = "RS232" ; - :SIGBaudrate = 9600. ; - :SIGLedEnabled = "ON24H" ; - :SIGOrientation = "AUTOZUPDOWN" ; - :SIGHeadFrequency = 1000. ; - :SIGHasAccelerometer = "True" ; - :SIGHasMagnetometer = "True" ; - :SIGHasPressure = "True" ; - :SIGHasTemperature = "True" ; - :SIGHasCompass = "True" ; - :SIGHx = 25. ; - :SIGHy = 15. ; - :SIGHz = 0. ; - :SIGPressureOffset = 10. ; - :SIGDeclination = 0. ; - :SIGPlan_BurstEnabled = "True" ; - :SIGPlan_AverageEnabled = "True" ; - :SIGPlan_Salinity = 35. ; - :SIGPlan_Filename = "MIA23Sig1000.ad2cp" ; - :SIGPlan_MaxVerticalVelocity = 10 ; - :SIGPlan_ProfileInterval = 120 ; - :SIGPlan_AverageDepthInterval = 0 ; - :SIGPlan_BurstInterval = 3600 ; - :SIGPlan_BurstDepthInterval = 0 ; - :SIGPlan_SoundVelocity = 0. ; - :SIGPlan_SerialOutputEnabled = "False" ; - :SIGAlt_Plan_BurstEnabled = "True" ; - :SIGAlt_Plan_AverageEnabled = "True" ; - :SIGAlt_Plan_Salinity = 35. ; - :SIGAlt_Plan_Filename = "MIA23Sig1000.ad2cp" ; - :SIGAlt_Plan_MaxVerticalVelocity = 10 ; - :SIGAlt_Plan_ProfileInterval = 120 ; - :SIGAlt_Plan_AverageDepthInterval = 0 ; - :SIGAlt_Plan_BurstInterval = 3600 ; - :SIGAlt_Plan_BurstDepthInterval = 0 ; - :SIGAlt_Plan_SoundVelocity = 0. ; - :SIGAlt_Plan_SerialOutputEnabled = "False" ; - :SIGAverage_Altimeter = "False" ; - :SIGAverage_IceTrack = "False" ; - :SIGAverage_AverageInterval = 120 ; - :SIGAverage_BlankingDistance = 0.100000001490116 ; - :SIGAverage_CellSize = 0.200000002980232 ; - :SIGAverage_NBeams = 4 ; - :SIGAverage_NCells = 32 ; - :SIGAverage_ChannelBeamSel = 0 ; - :SIGAverage_CoordSystem = "BEAM" ; - :SIGAverage_DataFormat = 3 ; - :SIGAverage_NPings = 480 ; - :SIGAverage_Bandwidth = "BROAD" ; - :SIGAverage_PowerLevel = 0. ; - :SIGAverage_VelocityPrecision = 0. ; - :SIGAverage_VelocityRange = 5. ; - :SIGAverage_BottomTrack = "False" ; - :MOORING = "MIA23SH2" ; - :PROGRAM = "Coastal and Marine Hazards and Resources Program" ; - :PROJECT = "Coral Reefs" ; - :EXPERIMENT = "Miami X-Reefs" ; - :Region = "Florida" ; - :CruiseID = "2023-623-FA" ; - :SciPi = "Curt Storlazzi, Olivia Cheriton, Kurt Rosenberger" ; - :Year = 2023. ; - :Site = "SH2" ; - :platform_type = "Artificial Reef Box" ; - :latitude = 25.866503 ; - :longitude = -80.116706 ; - :LatLonDatum = "WGS84" ; - :WATER_DEPTH = 5. ; - :Deployment_date = "2023-06-23 15:30" ; - :Recovery_date = "2024-01-17 10:00" ; - :OFAFunding = "" ; - :CollaboratingAgency = "University of Miami" ; - :DESCRIPTION = "Seahive structure" ; - :WATER_DEPTH_SOURCE = "pressure data" ; - :magnetic_variation = -7.25 ; - :Conventions = "CF-1.8" ; - :basefile = "mat3/MIA23Sig1000" ; - :outdir = "mat3/" ; - :filename = "MIAsig" ; - :ClockError = 0 ; - :orientation = "UP" ; - :head_rotation = "horizontal" ; - :initial_instrument_height = 1. ; - :initial_instrument_height_note = "From seabed" ; - :zeroed_pressure = "Yes" ; - :cutoff_ampl = 0 ; - :trim_method = "water level sl" ; - :trim_surf_bins = 3 ; - :history = "2024-05-21T16:26:54.999377+00:00: Processed using mat2cdf.py with stglib 0.15.0+31.g30ecb68.dirty, xarray 2024.2.0, NumPy 1.26.4, netCDF4 1.6.5, Python 3.11.8.\n2024-05-21T16:27:17.727304+00:00: Data clipped using Deployment_date of 2023-06-23 15:30 and Recovery_date of 2024-01-17 10:00.\n2024-05-21T16:27:17.738401+00:00: Rotating heading and horizontal velocities by -7.25 degrees.\n2024-05-21T16:27:17.761806+00:00: Trimmed velocity data using NON-atmospherically corrected pressure (water level) and sidelobes -(with 3 additional surface bins removed).\n2024-05-21T16:27:18.023571+00:00: Processed to CF-1.8 using runsigcdf2nc.py.\n" ; - :nominal_sensor_depth_note = "WATER_DEPTH - initial_instrument_height" ; - :nominal_sensor_depth = 4. ; - :transducer_offset_from_bottom = 1. ; - :serial_number = 101042 ; - :frequency = 1000. ; - :instrument_type = "Signature1000" ; - :bin_size = 0.200000002980232 ; - :beam_angle = 25 ; - :nominal_instrument_depth = 4. ; - :start_time = "2023-06-23T16:00:00.000000000" ; - :stop_time = "2023-08-04T02:08:00.000000000" ; -} \ No newline at end of file From b1a6c698f7767e2780e70bf088135a7f03008e9d Mon Sep 17 00:00:00 2001 From: ssuttles-usgs Date: Thu, 23 May 2024 11:54:50 -0400 Subject: [PATCH 6/7] reslove issues in PR --- .gitattributes | 7 +------ stglib/core/utils.py | 27 ++++++++++++++++++++------- stglib/sig/cdf2nc.py | 30 ++++++++++++++++++------------ stglib/tests/data/.gitattributes | 5 +++++ 4 files changed, 44 insertions(+), 25 deletions(-) diff --git a/.gitattributes b/.gitattributes index dd01487a..bdc578e9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,3 @@ *.ipynb filter=nbstripout *.ipynb diff=ipynb -stglib/_version.py export-subst -stglib/tests/data/055109_20220808_1605.zip filter=lfs diff=lfs merge=lfs -text -stglib/tests/data/055109_20220808_1605_config.yaml filter=lfs diff=lfs merge=lfs -text -stglib/tests/data/gatts_055109_20220808_1605.txt filter=lfs diff=lfs merge=lfs -text -stglib/tests/data/*.cdf filter=lfs diff=lfs merge=lfs -text -stglib/tests/data/mat3/* filter=lfs diff=lfs merge=lfs -text +stglib/_version.py export-subst \ No newline at end of file diff --git a/stglib/core/utils.py b/stglib/core/utils.py index 83e59f41..04142ed8 100644 --- a/stglib/core/utils.py +++ b/stglib/core/utils.py @@ -1301,14 +1301,27 @@ def spcon_from_salinity(S): ) -def check_fits_in_int32(ds, var): - if np.nanmax(np.abs(ds[var])) > (2**31 - 1): - warnings.warn( - f"32-bit integer overflow on {var}; setting encoding to i4 will fail" - ) - return False +def check_fits_in_int32(ds, var, units="s"): + # check to see if var is time and if so handle it differently + if var == "time": + tmax = (ds["time"][-1].values - ds["time"][0].values) / np.timedelta64(1, units) + + if np.abs(tmax) > (2**31 - 1): + warnings.warn( + f"32-bit integer overflow on {var} with units of '{units}'; setting encoding to i4 will fail" + ) + return False + + else: + return True else: - return True + if np.nanmax(np.abs(ds[var])) > (2**31 - 1): + warnings.warn( + f"32-bit integer overflow on {var}; setting encoding to i4 will fail" + ) + return False + else: + return True def check_time_fits_in_int32(ds, var): diff --git a/stglib/sig/cdf2nc.py b/stglib/sig/cdf2nc.py index 6a1a4471..cd4e5d9e 100644 --- a/stglib/sig/cdf2nc.py +++ b/stglib/sig/cdf2nc.py @@ -373,22 +373,28 @@ def fix_encoding(ds): if "units" in ds["time"].encoding: ds["time"].encoding.pop("units") - tstep = ds["time"][1] - ds["time"][0] # use time step to select time encoding - # if "sample" not in ds.dims: + # use time step to select time encoding + tstep = ds["time"][1] - ds["time"][0] + if tstep < np.timedelta64(1, "m"): - print( - f"make time encoding to dtype double because tstep {tstep} seconds is < 1 minute, round to milliseconds first" - ) - ds["time"] = ds["time"].dt.round("ms") # round time to milliseconds first + + histtext = f"make time encoding to dtype double because tstep {tstep} seconds is < 1 minute, round to milliseconds first" + ds = utils.insert_history(ds, histtext) + + # round time to milliseconds first + ds["time"] = ds["time"].dt.round("ms") ds["time"].encoding["dtype"] = "double" else: - print( - f"make time encoding int because tstep {tstep} seconds is >= 1 minute, round time to seconds first" - ) - ds["time"] = ds["time"].dt.round( - "s" - ) # round time to seconds if time interval >= 1 minute + histtext = f"make time encoding int because tstep {tstep} seconds is >= 1 minute, round time to seconds first" + ds = utils.insert_history(ds, histtext) + + # round time to seconds if time interval >= 1 minute + ds["time"] = ds["time"].dt.round("s") + + # check time to make sure it fits in int32, assume seconds for time units + utils.check_fits_in_int32(ds, "time", "s") + ds["time"].encoding["dtype"] = "i4" if "beam" in ds.dims: diff --git a/stglib/tests/data/.gitattributes b/stglib/tests/data/.gitattributes index d4e14e5f..153ed4cd 100644 --- a/stglib/tests/data/.gitattributes +++ b/stglib/tests/data/.gitattributes @@ -97,3 +97,8 @@ BEL503.wad filter=lfs diff=lfs merge=lfs -text BEL503.whd filter=lfs diff=lfs merge=lfs -text BEL5C_wvsconfig.yaml filter=lfs diff=lfs merge=lfs -text atmpres-BEL5Cwvs.cdf filter=lfs diff=lfs merge=lfs -text +055109_20220808_1605.zip filter=lfs diff=lfs merge=lfs -text +055109_20220808_1605_config.yaml filter=lfs diff=lfs merge=lfs -text +gatts_055109_20220808_1605.txt filter=lfs diff=lfs merge=lfs -text +*.cdf filter=lfs diff=lfs merge=lfs -text +mat3/** filter=lfs diff=lfs merge=lfs -text From b7c6388d9032abd58ddb01e1f6bce9270b484079 Mon Sep 17 00:00:00 2001 From: ssuttles-usgs Date: Thu, 23 May 2024 13:24:06 -0400 Subject: [PATCH 7/7] v2 reslove issues in PR --- .gitattributes | 2 +- stglib/core/utils.py | 27 +++++++-------------------- stglib/sig/cdf2nc.py | 2 +- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/.gitattributes b/.gitattributes index bdc578e9..c7868c45 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,3 @@ *.ipynb filter=nbstripout *.ipynb diff=ipynb -stglib/_version.py export-subst \ No newline at end of file +stglib/_version.py export-subst diff --git a/stglib/core/utils.py b/stglib/core/utils.py index 04142ed8..83e59f41 100644 --- a/stglib/core/utils.py +++ b/stglib/core/utils.py @@ -1301,27 +1301,14 @@ def spcon_from_salinity(S): ) -def check_fits_in_int32(ds, var, units="s"): - # check to see if var is time and if so handle it differently - if var == "time": - tmax = (ds["time"][-1].values - ds["time"][0].values) / np.timedelta64(1, units) - - if np.abs(tmax) > (2**31 - 1): - warnings.warn( - f"32-bit integer overflow on {var} with units of '{units}'; setting encoding to i4 will fail" - ) - return False - - else: - return True +def check_fits_in_int32(ds, var): + if np.nanmax(np.abs(ds[var])) > (2**31 - 1): + warnings.warn( + f"32-bit integer overflow on {var}; setting encoding to i4 will fail" + ) + return False else: - if np.nanmax(np.abs(ds[var])) > (2**31 - 1): - warnings.warn( - f"32-bit integer overflow on {var}; setting encoding to i4 will fail" - ) - return False - else: - return True + return True def check_time_fits_in_int32(ds, var): diff --git a/stglib/sig/cdf2nc.py b/stglib/sig/cdf2nc.py index cd4e5d9e..5a964972 100644 --- a/stglib/sig/cdf2nc.py +++ b/stglib/sig/cdf2nc.py @@ -393,7 +393,7 @@ def fix_encoding(ds): ds["time"] = ds["time"].dt.round("s") # check time to make sure it fits in int32, assume seconds for time units - utils.check_fits_in_int32(ds, "time", "s") + utils.check_time_fits_in_int32(ds, "time") ds["time"].encoding["dtype"] = "i4"