diff --git a/oceanstream/L2_calibrated_data/noise_masks.py b/oceanstream/L2_calibrated_data/noise_masks.py index 8b53c63..4486b17 100644 --- a/oceanstream/L2_calibrated_data/noise_masks.py +++ b/oceanstream/L2_calibrated_data/noise_masks.py @@ -19,6 +19,186 @@ from oceanstream.utils import add_metadata_to_mask, attach_masks_to_dataset, dict_to_formatted_list +RAPIDKRILL_MASK_PARAMETERS = { + "transient": { + "method": "ryan", + "params": { + "m": 5, + "n": 20, + # "n": 5, + "thr": 20, + "excludeabove": 250, + "operation": "percentile15", + }, + }, + "attenuation": { + "method": "ryan", + "params": { + "r0": 180, + "r1": 280, + "n": 30, + "m": None, + "thr": -6, + "start": 0, + "offset": 0, + }, + }, + "impulse": {"method": "ryan", "params": {"thr": 10, "m": 5, "n": 1}}, + "seabed": { + "method": "ariza", + "params": { + "r0": 10, + "r1": 1000, + "roff": 0, + "thr": -40, + "ec": 1, + "ek": (1, 3), + "dc": 10, + "dk": (3, 7), + }, + }, + "false_seabed": { + "method": "blackwell", + "params": { + "theta": None, + "phi": None, + "r0": 10, + "r1": 1000, + "tSv": -75, + "ttheta": 702, + "tphi": 282, + "wtheta": 28, + "wphi": 52, + }, + }, +} + + +OCEANSTREAM_MASK_PARAMETERS = { + "transient": { + "method": "ryan", + "params": { + "m": 5, + "n": 20, + # "n": 5, + "thr": 20, + "excludeabove": 250, + "operation": "percentile15", + }, + }, + "attenuation": { + "method": "ryan", + "params": { + "r0": 180, + "r1": 280, + "n": 5, + "m": None, + "thr": -5, + "start": 0, + "offset": 0, + }, + }, + "impulse": {"method": "ryan", "params": {"thr": 3, "m": 3, "n": 1}}, + "seabed": { + "method": "ariza", + "params": { + "r0": 10, + "r1": 1000, + "roff": 0, + "thr": -35, + "ec": 15, + "ek": (1, 3), + "dc": 150, + "dk": (1, 3), + }, + }, + "false_seabed": { + "method": "blackwell_mod", + "params": { + "theta": None, + "phi": None, + "r0": 10, + "r1": 1000, + "tSv": -75, + "ttheta": 702, + "tphi": 282, + "wtheta": 28, + "wphi": 52, + "rlog": None, + "tpi": None, + "freq": None, + "rank": 50, + }, + }, +} + +TEST_MASK_PARAMETERS = { + "transient": { + "method": "ryan", + "params": { + "m": 5, + "n": 5, + "thr": 20, + "excludeabove": 250, + "operation": "mean", + }, + }, + "attenuation": { + "method": "ryan", + "params": { + "r0": 180, + "r1": 280, + "n": 5, + "m": None, + "thr": -5, + "start": 0, + "offset": 0, + }, + }, + "impulse": {"method": "ryan", "params": {"thr": 3, "m": 3, "n": 1}}, + "seabed": { + "method": "ariza", + "params": { + "r0": 10, + "r1": 1000, + "roff": 0, + "thr": -40, + "ec": 1, + "ek": (1, 3), + "dc": 10, + "dk": (3, 7), + }, + }, + "false_seabed": { + "method": "blackwell", + "params": { + "theta": None, + "phi": None, + "r0": 10, + "r1": 1000, + "tSv": -75, + "ttheta": 702, + "tphi": 282, + "wtheta": 28, + "wphi": 52, + }, + }, +} + + +OCEANSTREAM_NOISE_MASK_PARAMETERS = { + k: OCEANSTREAM_MASK_PARAMETERS[k] for k in ["transient", "attenuation", "impulse"] +} +OCEANSTREAM_SEABED_MASK_PARAMETERS = { + k: OCEANSTREAM_MASK_PARAMETERS[k] for k in ["seabed", "false_seabed"] +} + + +MASK_PARAMETERS = { + "method": "ryan", + "params": {"thr": 3, "m": 3, "n": 1}, +} + def create_transient_mask( Sv: Union[xr.Dataset, str, pathlib.Path], parameters: dict, method: str = "ryan" @@ -127,13 +307,47 @@ def create_seabed_mask(Sv, parameters, method): return mask -def create_noise_masks_rapidkrill(source_Sv: xarray.Dataset): +def create_mask(source_Sv: xarray.Dataset, mask_type="impulse", params=MASK_PARAMETERS): """ - A function that creates noise masks for a given Sv dataset according to - rapidkrill processing needs + A function that creates a single noise mask for a given dataset + + Parameters: + - source_Sv (xarray.Dataset): the dataset to which the masks will be attached. + - mask type (str): type of mask + - params (dict): a dictionary of mask parameters containing type and + + Returns: + - xarray.DataArray: the required mask + """ + mask_map = { + "transient": create_transient_mask, + "impulse": create_impulse_mask, + "attenuation": create_attenuation_mask, + "seabed": create_seabed_mask, + "false_seabed": create_seabed_mask, + } + method = params["method"] + parameters = params["params"] + + mask = mask_map[mask_type](source_Sv, parameters=parameters, method=method) + mask = add_metadata_to_mask( + mask, + metadata={ + "mask_type": mask_type, + "method": "method", + "parameters": dict_to_formatted_list(parameters), + }, + ) + return mask + + +def create_multiple_masks(source_Sv: xarray.Dataset, params=TEST_MASK_PARAMETERS): + """ + A function that creates multiple noise masks for a given Sv dataset Parameters: - source_Sv (xarray.Dataset): the dataset to which the masks will be attached. + - params (dict): a dict of dictionaries of mask parameters Returns: - xarray.Dataset: a dataset with the same dimensions as the original, @@ -147,114 +361,38 @@ def create_noise_masks_rapidkrill(source_Sv: xarray.Dataset): both the `angle_alongship` and `angle_athwartship` variables. Absence of these variables leads to errors . """ - rapidkrill_transient_mask_params = { - "m": 5, - "n": 20, - "thr": 20, - "excludeabove": 250, - "operation": "percentile15", - } - transient_mask = create_transient_mask( - source_Sv, parameters=rapidkrill_transient_mask_params, method="ryan" - ) - transient_mask = add_metadata_to_mask( - mask=transient_mask, - metadata={ - "mask_type": "transient", - "method": "ryan", - "parameters": dict_to_formatted_list(rapidkrill_transient_mask_params), - }, - ) + masks = [create_mask(source_Sv, mask_type=k, params=params[k]) for k in params.keys()] + Sv_mask = attach_masks_to_dataset(source_Sv, masks) + return Sv_mask - rapidkrill_attenuation_mask_params = { - "r0": 180, - "r1": 280, - "n": 30, - "m": None, - "thr": -6, - "start": 0, - "offset": 0, - } - attenuation_mask = create_attenuation_mask( - source_Sv, parameters=rapidkrill_attenuation_mask_params, method="ryan" - ) - attenuation_mask = add_metadata_to_mask( - mask=attenuation_mask, - metadata={ - "mask_type": "attenuation", - "method": "ryan", - "parameters": dict_to_formatted_list(rapidkrill_attenuation_mask_params), - }, - ) - rapidkrill_impulse_mask_param = {"thr": 10, "m": 5, "n": 1} - impulse_mask = create_impulse_mask( - source_Sv, parameters=rapidkrill_impulse_mask_param, method="ryan" - ) - impulse_mask = add_metadata_to_mask( - mask=impulse_mask, - metadata={ - "mask_type": "impulse", - "method": "ryan", - "parameters": dict_to_formatted_list(rapidkrill_impulse_mask_param), - }, - ) +def create_noise_masks_rapidkrill(source_Sv: xarray.Dataset, params=RAPIDKRILL_MASK_PARAMETERS): + """ + A function that creates noise masks for a given Sv dataset according to + rapidkrill processing needs - rapidkrill_seabed_mask_params = { - "r0": 10, - "r1": 1000, - "roff": 0, - "thr": -40, - "ec": 1, - "ek": (1, 3), - "dc": 10, - "dk": (3, 7), - } - seabed_mask = create_seabed_mask( - source_Sv, - method="ariza", - parameters=rapidkrill_seabed_mask_params, - ) - seabed_mask = add_metadata_to_mask( - mask=seabed_mask, - metadata={ - "mask_type": "seabed", - "method": "ariza", - "parameters": dict_to_formatted_list(rapidkrill_seabed_mask_params), - }, - ) + Parameters: + - source_Sv (xarray.Dataset): the dataset to which the masks will be attached. - rapidkrill_seabed_echo_mask_params = { - "theta": None, - "phi": None, - "r0": 10, - "r1": 1000, - "tSv": -75, - "ttheta": 702, - "tphi": 282, - "wtheta": 28, - "wphi": 52, - } - seabed_echo_mask = create_seabed_mask( - source_Sv, - method="blackwell", - parameters=rapidkrill_seabed_echo_mask_params, - ) - seabed_echo_mask = add_metadata_to_mask( - mask=seabed_echo_mask, - metadata={ - "mask_type": "false_seabed", - "method": "blackwell", - "parameters": dict_to_formatted_list(rapidkrill_seabed_echo_mask_params), - }, - ) + Returns: + - xarray.Dataset: a dataset with the same dimensions as the original, + containing the original data and five masks: mask_transient, mask_impulse, + mask_attenuated, mask_seabed, mask_false_seabed - masks = [transient_mask, impulse_mask, attenuation_mask, seabed_mask, seabed_echo_mask] - Sv_mask = attach_masks_to_dataset(source_Sv, masks) + Notes: + - To effectively utilize the `blackwell` method for seabed detection, + it's essential that the `source_Sv` dataset includes the `split-beam angle` parameters. + Specifically, ensure that your input `source_Sv` contains + both the `angle_alongship` and `angle_athwartship` variables. + Absence of these variables leads to errors . + """ + Sv_mask = create_multiple_masks(source_Sv, params) return Sv_mask -def create_default_noise_masks_oceanstream(source_Sv: xarray.Dataset): +def create_default_noise_masks_oceanstream( + source_Sv: xarray.Dataset, params=OCEANSTREAM_MASK_PARAMETERS +): """ A function that creates noise masks for a given Sv dataset using default methods for oceanstream @@ -273,129 +411,32 @@ def create_default_noise_masks_oceanstream(source_Sv: xarray.Dataset): both the `angle_alongship` and `angle_athwartship` variables. Absence of these variables leads to errors . """ - oceanstream_transient_mask_params = { - "m": 5, - "n": 20, - "thr": 20, - "excludeabove": 250, - "operation": "percentile15", - } - transient_mask = create_transient_mask( - source_Sv, parameters=oceanstream_transient_mask_params, method="ryan" - ) - transient_mask = add_metadata_to_mask( - mask=transient_mask, - metadata={ - "mask_type": "transient", - "method": "ryan", - "parameters": dict_to_formatted_list(oceanstream_transient_mask_params), - }, - ) + Sv_mask = create_multiple_masks(source_Sv, params) + return Sv_mask - oceanstream_attenuation_mask_params = { - "r0": 180, - "r1": 280, - "n": 30, - "m": None, - "thr": -6, - "start": 0, - "offset": 0, - } - attenuation_mask = create_attenuation_mask( - source_Sv, parameters=oceanstream_attenuation_mask_params, method="ryan" - ) - attenuation_mask = add_metadata_to_mask( - mask=attenuation_mask, - metadata={ - "mask_type": "attenuation", - "method": "ryan", - "parameters": dict_to_formatted_list(oceanstream_attenuation_mask_params), - }, - ) - oceanstream_impulse_mask_param = {"thr": 10, "m": 5, "n": 1} - impulse_mask = create_impulse_mask( - source_Sv, parameters=oceanstream_impulse_mask_param, method="ryan" - ) - impulse_mask = add_metadata_to_mask( - mask=impulse_mask, - metadata={ - "mask_type": "impulse", - "method": "ryan", - "parameters": dict_to_formatted_list(oceanstream_impulse_mask_param), - }, - ) +def create_seabed_masks_oceanstream( + source_Sv: xarray.Dataset, params=OCEANSTREAM_SEABED_MASK_PARAMETERS +): + """ + A function that creates seabed masks for a given Sv dataset using default methods for oceanstream - oceanstream_seabed_echo_mask_params = { - "theta": None, - "phi": None, - "r0": 10, - "r1": 1000, - "tSv": -75, - "ttheta": 702, - "tphi": 282, - "wtheta": 28, - "wphi": 52, - "rlog": None, - "tpi": None, - "freq": None, - "rank": 50, - } - seabed_echo_mask = create_seabed_mask( - source_Sv, - method="blackwell_mod", - parameters=oceanstream_seabed_echo_mask_params, - ) - seabed_echo_mask = add_metadata_to_mask( - mask=seabed_echo_mask, - metadata={ - "mask_type": "false_seabed", - "method": "blackwell_mod", - "parameters": dict_to_formatted_list(oceanstream_seabed_echo_mask_params), - }, - ) + Parameters: + - source_Sv (xarray.Dataset): the dataset to which the masks will be attached. - # initial "ariza" parameters - # oceanstream_seabed_mask_params = { - # "r0": 10, - # "r1": 1000, - # "roff": 0, - # "thr": -40, - # "ec": 1, - # "ek": (1, 3), - # "dc": 10, - # "dk": (3, 7), - # } - oceanstream_seabed_mask_params = { - "r0": 10, - "r1": 1000, - "roff": 0, - "thr": -35, - "ec": 15, - "ek": (1, 3), - "dc": 150, - "dk": (1, 3), - } - seabed_mask = create_seabed_mask( - source_Sv, - method="ariza", - parameters=oceanstream_seabed_mask_params, - ) - seabed_mask = add_metadata_to_mask( - mask=seabed_mask, - metadata={ - "mask_type": "seabed", - "method": "ariza", - "parameters": dict_to_formatted_list(oceanstream_seabed_mask_params), - }, - ) + Returns: + - xarray.Dataset: a dataset with the same dimensions as the original, + containing the original data and five masks: mask_transient, mask_impulse, + mask_attenuated - masks = [transient_mask, impulse_mask, attenuation_mask, seabed_echo_mask, seabed_mask] - Sv_mask = attach_masks_to_dataset(source_Sv, masks) + """ + Sv_mask = create_multiple_masks(source_Sv, params) return Sv_mask -def create_noise_masks_oceanstream(source_Sv: xarray.Dataset): +def create_noise_masks_oceanstream( + source_Sv: xarray.Dataset, params=OCEANSTREAM_NOISE_MASK_PARAMETERS +): """ A function that creates noise masks for a given Sv dataset using default methods for oceanstream @@ -408,64 +449,5 @@ def create_noise_masks_oceanstream(source_Sv: xarray.Dataset): mask_attenuated """ - oceanstream_transient_mask_params = { - "r0": 200, - "r1": 1000, - "n": 5, - "thr": [2, 0], - "roff": 250, - "jumps": 5, - "maxts": -35, - "start": 0, - } - transient_mask = create_transient_mask( - source_Sv, parameters=oceanstream_transient_mask_params, method="fielding" - ) - - transient_mask = add_metadata_to_mask( - mask=transient_mask, - metadata={ - "mask_type": "transient", - "method": "ryan", - "parameters": dict_to_formatted_list(oceanstream_transient_mask_params), - }, - ) - - oceanstream_attenuation_mask_params = { - "r0": 180, - "r1": 280, - "n": 5, - "m": None, - "thr": -5, - "start": 0, - "offset": 0, - } - - attenuation_mask = create_attenuation_mask( - source_Sv, parameters=oceanstream_attenuation_mask_params, method="ryan" - ) - attenuation_mask = add_metadata_to_mask( - mask=attenuation_mask, - metadata={ - "mask_type": "attenuation", - "method": "ryan", - "parameters": dict_to_formatted_list(oceanstream_attenuation_mask_params), - }, - ) - - oceanstream_impulse_mask_param = {"thr": 3, "m": 3, "n": 1} - impulse_mask = create_impulse_mask( - source_Sv, parameters=oceanstream_impulse_mask_param, method="ryan" - ) - impulse_mask = add_metadata_to_mask( - mask=impulse_mask, - metadata={ - "mask_type": "impulse", - "method": "ryan", - "parameters": dict_to_formatted_list(oceanstream_impulse_mask_param), - }, - ) - - masks = [transient_mask, impulse_mask, attenuation_mask] - Sv_mask = attach_masks_to_dataset(source_Sv, masks) + Sv_mask = create_multiple_masks(source_Sv, params) return Sv_mask diff --git a/tests/test_noise_mask.py b/tests/test_noise_mask.py index db7e53a..5423d29 100644 --- a/tests/test_noise_mask.py +++ b/tests/test_noise_mask.py @@ -2,11 +2,12 @@ from oceanstream.L2_calibrated_data.noise_masks import ( create_attenuation_mask, - create_default_noise_masks_oceanstream, + # create_default_noise_masks_oceanstream, create_impulse_mask, - create_noise_masks_rapidkrill, + # create_noise_masks_rapidkrill, create_seabed_mask, create_transient_mask, + create_multiple_masks, ) @@ -17,22 +18,21 @@ def test_impulse(enriched_ek60_Sv): assert mask["channel"].shape == (3,) -def test_transient(sv_dataset_jr161): - source_Sv = sv_dataset_jr161 - FIELDING_DEFAULT_PARAMS = { - "r0": 200, - "r1": 1000, +def test_transient(enriched_ek60_Sv): + source_Sv = enriched_ek60_Sv + RYAN_DEFAULT_PARAMS = { + # "m": 5, + # "n": 20, + "m": 5, "n": 5, - "thr": [2, 0], - "roff": 250, - "jumps": 5, - "maxts": -35, - "start": 0, + "thr": 20, + "excludeabove": 250, + "operation": "mean", } - mask_fielding = create_transient_mask( - source_Sv, parameters=FIELDING_DEFAULT_PARAMS, method="fielding" + mask_ryan = create_transient_mask( + source_Sv, parameters=RYAN_DEFAULT_PARAMS, method="ryan" ) - assert mask_fielding["channel"].shape == (3,) + assert mask_ryan["channel"].shape == (3,) def test_attenuation(enriched_ek60_Sv): @@ -62,16 +62,8 @@ def test_seabed(enriched_ek60_Sv): assert mask["channel"].shape == (3,) -@pytest.mark.ignore -def test_add_masks_rapidkrill(enriched_ek60_Sv): +def test_create_masks(enriched_ek60_Sv): enriched_Sv = enriched_ek60_Sv - Sv_mask = create_noise_masks_rapidkrill(enriched_Sv) + Sv_mask = create_multiple_masks(enriched_Sv) assert Sv_mask["mask_seabed"].attrs["mask_type"] == "seabed" - - -# @pytest.mark.ignore -def test_add_masks_default_oceanstream(enriched_ek60_Sv): - enriched_Sv = enriched_ek60_Sv - Sv_mask = create_default_noise_masks_oceanstream(enriched_Sv) - assert Sv_mask["mask_false_seabed"].attrs["mask_type"] == "false_seabed" assert Sv_mask["mask_impulse"].attrs["parameters"] == ["thr=10", "m=5", "n=1"]