Skip to content

Commit

Permalink
401: tests for mode_2d_arearat mode_3d_ratio ctc
Browse files Browse the repository at this point in the history
  • Loading branch information
John-Sharples committed Jan 14, 2025
1 parent 210fb30 commit 09b2567
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 8 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)


# TODO: 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
70 changes: 70 additions & 0 deletions test/test_mode_2d_arearat_statistics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import pytest
from unittest.mock import patch
import numpy as np
import metcalcpy.util.mode_2d_arearat_statistics as m2as

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

0 comments on commit 09b2567

Please sign in to comment.