Skip to content

Commit

Permalink
401: tests for mode_2d_arearat mode_3d_ratio ctc (#421)
Browse files Browse the repository at this point in the history
* 401: tests for mode_2d_arearat mode_3d_ratio ctc

* 401: refactor to fix sonarqube issues
  • Loading branch information
John-Sharples authored Jan 19, 2025
1 parent 210fb30 commit 11b337d
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 23 deletions.
20 changes: 12 additions & 8 deletions metcalcpy/util/ctc_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def calculate_fbias(input_data, columns_names, logger=None):
result = oyn / oy
result = round_half_up(result, PRECISION)
safe_log(logger, "info", f"ACC calculation successful: {result}")
except (TypeError, ZeroDivisionError, Warning, ValueError):
except (TypeError, ZeroDivisionError, Warning, ValueError) as e:
safe_log(logger, "error", f"Error in ACC calculation: {e}")
result = None
warnings.filterwarnings('ignore')
Expand Down Expand Up @@ -150,7 +150,7 @@ def calculate_fmean(input_data, columns_names, logger=None):
result = oyn / total
result = round_half_up(result, PRECISION)
safe_log(logger, "info", f"FMEAN calculation successful: {result}")
except (TypeError, ZeroDivisionError, Warning, ValueError):
except (TypeError, ZeroDivisionError, Warning, ValueError) as e:
safe_log(logger, "error", f"Error in FMEAN calculation: {e}")
result = None
warnings.filterwarnings('ignore')
Expand Down Expand Up @@ -317,7 +317,7 @@ def calculate_podn(input_data, columns_names, logger=None):
return result


def calculate_far(input_data, column_names, logger=None):
def calculate_far(input_data, columns_names, logger=None):
"""Performs calculation of FAR - false alarms
Args:
Expand Down Expand Up @@ -941,11 +941,15 @@ def calculate_ctc_on(input_data, columns_names, logger=None):
calculated ON as float
or None if some data values are missing or invalid
"""
safe_log(logger, "debug", "Starting calculation of CTC ON.")
fy_on = sum_column_data_by_name(input_data, columns_names, 'fy_on')
fn_on = sum_column_data_by_name(input_data, columns_names, 'fn_on')
return round_half_up(fy_on + fn_on, PRECISION)

try:
safe_log(logger, "debug", "Starting calculation of CTC ON.")
fy_on = sum_column_data_by_name(input_data, columns_names, 'fy_on')
fn_on = sum_column_data_by_name(input_data, columns_names, 'fn_on')
result = round_half_up(fy_on + fn_on, PRECISION)
except (TypeError, ZeroDivisionError, Warning, ValueError) as e:
result = None
safe_log(logger, "error", f"Error in calculating CTC ON: {str(e)}")
return result

def calculate_ctc_fy(input_data, columns_names, logger=None):
"""Calculates the Total Number of forecast yes and observation no plus
Expand Down
60 changes: 60 additions & 0 deletions test/test_ctc_statistics.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import pytest
import pandas as pd
import numpy as np
import sys
import os
from unittest.mock import patch
from functools import cache
sys.path.append("../../")
from metcalcpy.util import ctc_statistics as ctc

Expand Down Expand Up @@ -139,6 +142,63 @@ def test_CTC_ROC_thresh():
# if we get here, then all elements matched in value and position
assert True

@cache
def ctc_data():
df = pd.read_csv(f"{cwd}/data/ROC_CTC.data", sep='\t', header='infer')
return df.to_numpy(), np.array(df.columns)


# Some of the functions here that
# are evaluating to None could be better
# tested with a different dataset. e.g. acc
# needs a 'total' column in the test data.
@pytest.mark.parametrize(
"func_name,expected",
[
("fbias", 0.8549794),
("acc", None),
("fmean", None),
("pody", 0.5603757),
("pofd", 0.0368738),
("podn", 0.9631262),
("far", 0.3445741),
("csi", 0.432855),
("gss", None),
("hk", 0.5235019),
("hss", None),
("odds", 33.2937647),
("lodds", 3.5053691),
("bagss", None),
("eclv", None),
("ctc_total", None),
("cts_total", None),
("ctc_fn_on", 44984491.0),
("ctc_fn_oy", 2570049.0),
("ctc_fy_on", 1722257.0),
("ctc_fy_oy", 3275963.0),
("ctc_oy", 5846012.0),
("ctc_on", 46706748.0),
("ctc_fy", 46706748.0),
("ctc_fn", 47554540.0),
("odds1", 33.2937647),
("orss", 0.9416803),
("sedi", 0.7397156),
("seds", None),
("edi", 0.7014241),
("eds", None),
]
)
def test_ctc_statistics(func_name, expected):
func_str = f"calculate_{func_name}"
func = getattr(ctc, func_str)
actual = func(*ctc_data())
assert actual == expected

# Check None is returned on Exception
with patch.object(ctc, "sum_column_data_by_name", side_effect=TypeError):
actual = func(*ctc_data())
assert actual == None



if __name__ == "__main__":
Expand Down
71 changes: 71 additions & 0 deletions test/test_mode_2d_arearat_statistics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import pytest
from unittest.mock import patch
import numpy as np
import metcalcpy.util.mode_2d_arearat_statistics as m2as
from test.utils import MODE_TEST_DATA as data

column_names = np.array(
["object_type", "area", "fcst_flag", "simple_flag", "matched_flag"]
)

data = np.array(
[
["2d", 100, 1, 1, 1],
["2d", 30, 0, 1, 1],
["2d", 120, 1, 1, 0],
["2d", 12, 0, 1, 1],
["2d", 1, 1, 0, 1],
["2d", 17, 0, 1, 1],
["2d", 200, 1, 1, 1],
["3d", 66, 0, 1, 0],
]
)

@pytest.mark.parametrize(
"func_name,data_values,expected",
[
("arearat_fsa_asa", data, 0.8768267),
("arearat_osa_asa", data, 0.1231733),
("arearat_asm_asa", data, 0.7494781),
("arearat_asu_asa", data, 0.2505219),
("arearat_fsm_fsa", data, 0.7142857),
("arearat_fsu_fsa", data, 0.2857143),
("arearat_osm_osa", data, 1.0),
("arearat_osu_osa", data, None),
("arearat_fsm_asm", data, 0.2857143),
("arearat_osm_asm", data, 0.1643454),
("arearat_osu_asu", data, None),
("arearat_fsa_aaa", data, 0.875),
("arearat_osa_aaa", data, 0.1229167),
("arearat_fsa_faa", data, 0.9976247),
("arearat_fca_faa", data, 0.0023753),
("arearat_osa_oaa", data, 1.0),
("arearat_oca_oaa", data, None),
("arearat_fca_aca", data, 1.0),
("arearat_oca_aca", data, None),
("arearat_fsa_osa", data, 7.1186441),
("arearat_osa_fsa", data, 1.0),
("arearat_aca_asa", data, 0.0020877),
("arearat_asa_aca", data, 479.0),
("arearat_fca_fsa", data, 0.002381),
("arearat_fsa_fca", data, 420.0),
("arearat_oca_osa", data, None),
("arearat_osa_oca", data, None),
("objahits", data, 179.5),
("objamisses", data, None),
("objafas", data, 120.0),
("objacsi", data, 0.5993322),
("objapody", data, None),
("objafar", data, 0.1431981),
],
)
def test_calculate_3d_ratio(func_name, data_values, expected):
func_str = f"calculate_2d_{func_name}"
func = getattr(m2as, func_str)
actual = func(data_values, column_names)
assert actual == expected

# Check None is returned on Exception
with patch.object(m2as, "column_data_by_name_value", side_effect=TypeError):
actual = func(data_values, column_names)
assert actual == None
69 changes: 69 additions & 0 deletions test/test_mode_3d_ratio_statistics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import pytest
from unittest.mock import patch
import numpy as np
import metcalcpy.util.mode_3d_ratio_statistics as m3rs

column_names = np.array(
["object_type", "volume", "fcst_flag", "simple_flag", "matched_flag"]
)

data = np.array(
[
["3d", 100, 1, 1, 1],
["3d", 30, 0, 1, 1],
["3d", 120, 1, 1, 0],
["3d", 12, 0, 1, 1],
["3d", 1, 1, 0, 1],
["3d", 17, 0, 1, 1],
["2d", 200, 1, 1, 1],
["3d", 66, 0, 1, 0],
]
)

@pytest.mark.parametrize(
"func_name,data_values,expected",
[
("ratio_fsa_asa", data, 0.3333333),
("ratio_osa_asa", data, 0.6666667),
("ratio_asm_asa", data, 0.6666667),
("ratio_asu_asa", data, 0.3333333),
("ratio_fsm_fsa", data, 1.0),
("ratio_fsu_fsa", data, 0.5),
("ratio_osm_osa", data, 0.75),
("ratio_osu_osa", data, 0.25),
("ratio_fsm_asm", data, 0.25),
("ratio_osm_asm", data, 0.25),
("ratio_fsu_asu", data, 0.5),
("ratio_osu_asu", data, 0.5),
("ratio_fsa_aaa", data, 0.2857143),
("ratio_osa_aaa", data, 0.5714286),
("ratio_fsa_faa", data, 0.6666667),
("ratio_fca_faa", data, 0.3333333),
("ratio_osa_oaa", data, 1.0),
("ratio_oca_oaa", data, 0.0),
("ratio_fca_aca", data, 1.0),
("ratio_fsa_osa", data, 0.5),
("ratio_osa_fsa", data, 2.0),
("ratio_asa_aca", data, 6.0),
("ratio_fca_fsa", data, 0.5),
("ratio_fsa_fca", data, 2.0),
("ratio_oca_osa", data, 0.0),
("ratio_osa_oca", data, None),
("objhits", data, 2.0),
("objmisses", data, 1.0),
("objfas", data, 1.0),
("objcsi", data, 0.5),
("objpody", data, 0.6666667),
("objfar", data, 0.3333333),
],
)
def test_calculate_3d_ratio(func_name, data_values, expected):
func_str = f"calculate_3d_{func_name}"
func = getattr(m3rs, func_str)
actual = func(data_values, column_names)
assert actual == expected

# Check None is returned on Exception
with patch.object(m3rs, "column_data_by_name_value", side_effect=TypeError):
actual = func(data_values, column_names)
assert actual == None
15 changes: 1 addition & 14 deletions test/test_mode_3d_volrat_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from unittest.mock import patch
import numpy as np
import metcalcpy.util.mode_3d_volrat_statistics as m3vs
from test.utils import MODE_TEST_DATA as data_complex

column_names = np.array(
["object_type", "volume", "fcst_flag", "simple_flag", "matched_flag"]
Expand All @@ -16,20 +17,6 @@
)


data_complex = np.array(
[
["3d", 100, 1, 1, 1],
["3d", 30, 0, 1, 1],
["3d", 120, 1, 1, 0],
["3d", 12, 0, 1, 1],
["3d", 1, 1, 0, 1],
["3d", 17, 0, 1, 1],
["2d", 200, 1, 1, 1],
["3d", 66, 0, 1, 0],
]
)


@pytest.mark.parametrize(
"func_name,data_values,expected",
[
Expand Down
16 changes: 15 additions & 1 deletion test/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
from pathlib import Path
import numpy as np

def abs_path(rel_path):
"""Turn a relative path into abs path"""
return str(Path(str(Path(__file__).parents[2])) / rel_path)

# Datafile access
AGG_STAT_AND_BOOT_DATA = abs_path("METcalcpy/test/data/agg_stat_and_boot_data.data")
AGG_STAT_AND_BOOT_DATA = abs_path("METcalcpy/test/data/agg_stat_and_boot_data.data")

MODE_TEST_DATA = np.array(
[
["3d", 100, 1, 1, 1],
["3d", 30, 0, 1, 1],
["3d", 120, 1, 1, 0],
["3d", 12, 0, 1, 1],
["3d", 1, 1, 0, 1],
["3d", 17, 0, 1, 1],
["2d", 200, 1, 1, 1],
["3d", 66, 0, 1, 0],
]
)

0 comments on commit 11b337d

Please sign in to comment.