Skip to content

Commit

Permalink
Add TS (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
simedroniraluca authored Nov 28, 2023
1 parent d6167e0 commit 7406e0d
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 19 deletions.
1 change: 1 addition & 0 deletions oceanstream/L2_calibrated_data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
from .sv_computation import compute_sv
from .sv_dataset_extension import enrich_sv_dataset
from .sv_interpolation import interpolate_sv
from .target_strength_computation import compute_target_strength
3 changes: 2 additions & 1 deletion oceanstream/L2_calibrated_data/sv_computation.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
- `ComputeSVParams`: Class to validate and structure the parameters passed
to the Sv computation function.
- `compute_sv`: Main function to calculate Sv given an EchoData object
and other optional parameters.
and other optional parameters. This function is based on the `echopype.calibrate.compute_Sv()` function.
Usage:
Expand Down Expand Up @@ -84,6 +84,7 @@ def compute_sv(echodata: EchoData, **kwargs) -> xr.Dataset:
- Uses the `ComputeSVParams` pydantic model to validate parameters.
- Checks if the computed Sv is empty.
- Returns Sv only if it is not empty.
- Is based on the `echopype.calibrate.compute_Sv()` function.
"""
# Validate parameters using the pydantic model
Expand Down
109 changes: 109 additions & 0 deletions oceanstream/L2_calibrated_data/target_strength_computation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"""
target_strength_computation.py
-------------------------------
Module for computing the target strength (TS) from raw data.
Supported Sonar Models:
- EK60
- AZFP
- EK80
Functions and Classes:
- `SupportedSonarModelsForTS`: An Enum containing the sonar models supported
for TS computation.
- `WaveformMode`: Enum specifying the waveform mode ("CW" or "BB").
- `EncodeMode`: Enum indicating the encoding mode ("complex" or "power").
- `ComputeTSParams`: Class to validate and structure the parameters passed
to the TS computation function.
- `compute_target_strength`: Main function to calculate TS given an EchoData object
and other optional parameters. This function is based on the `echopype.calibrate.compute_TS()` function.
Usage:
To compute TS for a given EchoData object, `ed`, simply call:
`compute_target_strength(ed)`
"""

from enum import Enum
from typing import Any, Optional

import echopype as ep
import xarray as xr
from echopype.echodata.echodata import EchoData
from pydantic import BaseModel, ValidationError, field_validator


class SupportedSonarModelsForTS(str, Enum):
EK60 = "EK60"
AZFP = "AZFP"
EK80 = "EK80"


class WaveformMode(str, Enum):
CW = "CW"
BB = "BB"


class EncodeMode(str, Enum):
COMPLEX = "complex"
POWER = "power"


class ComputeTSParams(BaseModel):
echodata: Any
env_params: Optional[dict] = None
cal_params: Optional[dict] = None
waveform_mode: Optional[WaveformMode] = None
encode_mode: Optional[EncodeMode] = None

@field_validator("echodata")
def check_echodata_type(cls, value):
if not isinstance(value, EchoData):
raise ValueError("Invalid type for echodata. Expected an instance of EchoData.")
return value


def compute_target_strength(echodata: EchoData, **kwargs) -> xr.Dataset:
"""
Compute target strength (TS) from raw data.
Parameters:
- echodata (EchoData): The EchoData object containing
sonar data for computation.
- **kwargs: Additional keyword arguments passed to the TS computation.
Returns:
- xr.Dataset: A Dataset containing the computed TS values.
Notes:
This function:
- Validates the `echodata`'s sonar model against supported models.
- Uses the `ComputeTSParams` pydantic model to validate parameters.
- Checks if the computed TS is empty.
- Returns TS only if it is not empty.
- Is based on the `echopype.calibrate.compute_TS()` function.
"""
# Validate parameters using the pydantic model
try:
ComputeTSParams(echodata=echodata, **kwargs)
except ValidationError as e:
raise ValueError(str(e))
# Check if the sonar model is supported
sonar_model = echodata.sonar_model
try:
SupportedSonarModelsForTS(sonar_model)
except ValueError:
raise ValueError(
f"Sonar model '{sonar_model}'\
is not supported for TS computation.\
Supported models are \
{list(SupportedSonarModelsForTS)}."
)
# Compute TS
TS = ep.calibrate.compute_TS(echodata, **kwargs)
# Check if the computed TS is empty
if TS["TS"].values.size == 0:
raise ValueError("Computed TS is empty!")
return TS
34 changes: 16 additions & 18 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@
import pytest
from xarray import Dataset

from oceanstream.L2_calibrated_data import create_default_noise_masks_oceanstream, sv_interpolation
from oceanstream.L2_calibrated_data.background_noise_remover import apply_remove_background_noise
from oceanstream.L2_calibrated_data.sv_computation import compute_sv
from oceanstream.L2_calibrated_data.sv_dataset_extension import enrich_sv_dataset
from oceanstream.L2_calibrated_data import sv_interpolation, \
create_default_noise_masks_oceanstream
from oceanstream.L3_regridded_data import applying_masks_handler, \
attach_shoal_mask_to_ds
from oceanstream.L3_regridded_data import applying_masks_handler, attach_shoal_mask_to_ds

current_directory = os.path.dirname(os.path.abspath(__file__))
TEST_DATA_FOLDER = os.path.join(current_directory, "..", "test_data")
Expand Down Expand Up @@ -199,16 +197,16 @@ def ed_ek_60_for_Sv():
local_path = os.path.join(TEST_DATA_FOLDER, filename)
if os.path.isfile(local_path):
ed = ep.open_raw(
local_path,
sonar_model="EK60",
)
local_path,
sonar_model="EK60",
)
else:
rawdirpath = base_path + filename
s3raw_fpath = f"s3://{bucket}/{rawdirpath}"
storage_opts = {"anon": True}
ed = ep.open_raw(
s3raw_fpath,
sonar_model="EK60",storage_options=storage_opts) # type: ignore
s3raw_fpath, sonar_model="EK60", storage_options=storage_opts
) # type: ignore
return ed


Expand All @@ -226,22 +224,22 @@ def enriched_ek60_Sv(ed_ek_60_for_Sv):
def ed_ek_80_for_Sv():
base_url = "noaa-wcsd-pds.s3.amazonaws.com/"
path = "data/raw/Sally_Ride/SR1611/EK80/"
filename = "D20161109-T163350.raw"
file_name = "D20161109-T163350.raw"

local_path = os.path.join(TEST_DATA_FOLDER, filename)
local_path = os.path.join(TEST_DATA_FOLDER, file_name)
if os.path.isfile(local_path):
ed_EK80 = ep.open_raw(
local_path,
sonar_model="EK80",
)
local_path,
sonar_model="EK80",
)
else:
raw_file_address = base_url + path + file_name
rf = raw_file_address # Path(raw_file_address)
ed_EK80 = ep.open_raw(
f"https://{rf}",
sonar_model="EK80",
)
f"https://{rf}",
sonar_model="EK80",
)

return ed_EK80


Expand Down
10 changes: 10 additions & 0 deletions tests/test_target_strength_computation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import numpy as np
import pytest

from oceanstream.L2_calibrated_data import target_strength_computation


def test_ctarget_strength_computation(ed_ek_60_for_Sv):
TS = target_strength_computation.compute_target_strength(ed_ek_60_for_Sv, encode_mode="power")
val = np.nanmean(TS["TS"].values)
assert val == pytest.approx(-68.06057158474684, 0.0001)

0 comments on commit 7406e0d

Please sign in to comment.