diff --git a/.coveragerc b/.coveragerc index dd6bea0d..2acbc5ae 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,5 +1,8 @@ [run] +source = metcalcpy relative_files = True omit = config.py config-3.py + metcalcpy/contributed/* + diff --git a/docs/Users_Guide/logging.rst b/docs/Users_Guide/logging.rst index dcd1784e..7e156a78 100644 --- a/docs/Users_Guide/logging.rst +++ b/docs/Users_Guide/logging.rst @@ -20,7 +20,11 @@ configurations. This approach ensures consistency and simplifies the maintenance settings across all modules within METcalcpy. +<<<<<<< HEAD * **Key Feature:** :code:`setup_logging` **Function** +======= +* Key Feature: :code:`setup_logging` function +>>>>>>> develop * The :code:`setup_logging` function is the core of **logging_config.py**. It initializes and configures the logger instance based on parameters specified in a YAML configuration @@ -51,11 +55,16 @@ YAML-Driven Configuration ------------------------- METcalcpy now allows users to customize logging behavior directly within +<<<<<<< HEAD the user's YAML configuration files, eliminating the need for hardcoding +======= +their YAML configuration files, eliminating the need for hardcoding +>>>>>>> develop logging settings in Python scripts. **Key Parameters in YAML Configuration:** +<<<<<<< HEAD | :code:`log_dir:` Specifies the directory where log files are stored. | :code:`log_filename:` Defines the name of the log file. | :code:`log_level:` Determines the verbosity of the log output. @@ -63,6 +72,18 @@ logging settings in Python scripts. | :code:`log_level:` By setting the appropriate log level in the YAML configuration file (e.g., log_level: WARNING), the user can control the verbosity of the log output, ensuring that only the necessary information is recorded. +======= +:code:`log_dir:` Specifies the directory where log files are stored. + +:code:`log_filename:` Defines the name of the log file. + +:code:`log_level:` Determines the verbosity of the log output. +Available levels are :code:`DEBUG, INFO, WARNING, and ERROR:`. + +:code:`log_level:` By setting the appropriate log level in your YAML configuration +file (e.g., log_level: WARNING), you can control the verbosity of the log output, +ensuring that only the necessary information is recorded. +>>>>>>> develop METcalcpy supports the following log levels: @@ -98,6 +119,7 @@ Informative Log Formatting Log messages in METcalcpy are meticulously formatted to include detailed information, improving readability and facilitating easier analysis of log data. +<<<<<<< HEAD **Standard Log Format Includes:** * **Timestamp (UTC):** Each log message is tagged with a UTC timestamp @@ -173,6 +195,13 @@ specified settings. **Example Log Entry:** :code:`2023-12-19 18:20:00 UTC | user123 | INFO | Data loading completed successfully.` +======= + + + + + +>>>>>>> develop diff --git a/metcalcpy/util/mode_2d_arearat_statistics.py b/metcalcpy/util/mode_2d_arearat_statistics.py index 888215a2..b57749d6 100644 --- a/metcalcpy/util/mode_2d_arearat_statistics.py +++ b/metcalcpy/util/mode_2d_arearat_statistics.py @@ -545,7 +545,8 @@ def calculate_2d_arearat_fsa_osa(input_data, columns_names, logger=None): calculated statistic or None if some of the data values are missing or invalid """ - try: + + try: safe_log(logger, "debug", "Filtering data based on TWO_D_DATA_FILTER.") filtered_data = column_data_by_name_value(input_data, columns_names, TWO_D_DATA_FILTER) diff --git a/metcalcpy/util/mode_3d_ratio_statistics.py b/metcalcpy/util/mode_3d_ratio_statistics.py index 22804441..6aac32d8 100644 --- a/metcalcpy/util/mode_3d_ratio_statistics.py +++ b/metcalcpy/util/mode_3d_ratio_statistics.py @@ -563,7 +563,8 @@ def calculate_3d_ratio_osa_fsa(input_data, columns_names, logger=None): calculated statistic as float or None if some of the data values are missing or invalid """ - try: + + try: safe_log(logger, "debug", "Filtering data based on THREE_D_DATA_FILTER.") filtered_data = column_data_by_name_value(input_data, columns_names, THREE_D_DATA_FILTER) diff --git a/test/test_mode_2d_statistics.py b/test/test_mode_2d_statistics.py new file mode 100644 index 00000000..42143693 --- /dev/null +++ b/test/test_mode_2d_statistics.py @@ -0,0 +1,157 @@ +import pytest +import numpy as np +import pandas as pd + +import metcalcpy.util.mode_2d_ratio_statistics as m2rs +import metcalcpy.util.mode_2d_arearat_statistics as m2as + +def prepare_data(obj_type = "2d"): + """ + Prepare some data for testing mode ara rations. + This uses an existing file in test/data. A more + robust approach would be to use a real MODE export + from METviewer. + """ + file_path = "test/data/ee_av_input.data" + df = pd.read_csv(file_path, sep="\t") + + df["object_type"] = obj_type + + cols = np.array(df.columns) + data = df.to_numpy() + return cols, data + + +# Expected values +# I suspect these could be simplified +# as ratios of each other. +FSA_ASA = 0.5858572 +ASM_ASA = 0.8955360 +FSM_FSA = 0.9069445 +OSM_OSA = 0.8793973 +FSM_ASM = 0.0930555 +OSM_ASM = 0.4066794 +OSU_ASU = 0.4781241 +OSA_AAA = 0.2184832 +FSA_AAA = 0.3090720 +FSA_FAA = 0.5243991 +OSA_OAA = 0.5320855 +OCA_ACA = 0.4066794 + +OBJ_HITS = 362487 +OBJ_OSU = 20217 +OBJ_FSU = 22067 + +@pytest.mark.parametrize( + "pair, expected", + [ + ("fsa_asa", FSA_ASA), + ("osa_asa", 1 - FSA_ASA), + ("asm_asa", ASM_ASA), + ("asu_asa", 1 - ASM_ASA), + ("fsm_fsa", FSM_FSA), + ("fsu_fsa", 1- FSM_FSA), + ("osm_osa", OSM_OSA), + ("osu_osa", 1 - OSM_OSA), + ("fsm_asm", FSM_ASM), + ("osm_asm", OSM_ASM), + ("osa_aaa", OSA_AAA), + ("osu_asu", OSU_ASU), + ("fsa_aaa", FSA_AAA), + ("fsa_faa", FSA_FAA), + ("fca_faa", 1 - FSA_FAA), + ("osa_oaa", OSA_OAA), + ("oca_oaa", 1 - OSA_OAA), + ("fca_aca", 1 - OSM_ASM), + ("oca_aca", OCA_ACA), + ("fsa_osa", FSA_AAA / OSA_AAA), + ("osa_fsa", 1), # Can this be right? + ("aca_asa", ASM_ASA), + ("asa_aca", 1/ASM_ASA), + ("fca_fsa", (1-FSA_FAA)/FSA_FAA), + ("fsa_fca", FSA_FAA/(1-FSA_FAA)), + ("oca_osa", OSM_OSA), + ("osa_oca", 1 / OSM_OSA), + ("objahits", OBJ_HITS / 2), + ("objamisses", OBJ_OSU), + ("objafas", OBJ_FSU), + # The values below should be derived from + # the FSU, OSU, and HITS. However, the + # formulas described in the doc strings + # do not appear to give these answers. + ("objacsi", 0.8108331), + ("objapody", 0.8996478), + ("objafar", 0.0295392), + ] +) +def test_m2as(pair, expected): + col_names, data = prepare_data() + if pair.startswith("obj"): + func_str = "calculate_2d_{}".format(pair) + else: + func_str = "calculate_2d_arearat_{}".format(pair) + + func = getattr(m2as, func_str) + actual = func(data, col_names) + np.testing.assert_almost_equal(actual, expected) + + +# Expected values for rations +rFSA_ASA = 0.4399575 +rASM_ASA = 0.5855473 +rFSM_FSA = 0.9541063 +rFSU_FSA = 0.5458937 +rOSM_OSA = 0.6166983 +rFSM_ASM = 0.3411978 +rOSM_ASM = 0.3666062 +rFSU_ASU = 0.4820513 +rFSA_AAA = 0.3236904 +rOSA_AAA = 0.4120407 +rFSA_FAA = 0.7101201 +rOSA_OAA = 0.7571839 +rFCA_ACA = 0.5 +rACA_ASA = 0.3591923 + +@pytest.mark.parametrize( + "pair, expected", + [ + ("fsa_asa", rFSA_ASA), + ("osa_asa", 1 - rFSA_ASA), + ("asm_asa", rASM_ASA), + ("asu_asa", 1 - rASM_ASA), + ("fsm_fsa", rFSM_FSA), + ("fsu_fsa", rFSU_FSA), + ("osm_osa", rOSM_OSA), + ("osu_osa", 1 - rOSM_OSA), + ("fsm_asm", rFSM_ASM), + ("osm_asm", rOSM_ASM), + ("fsu_asu", rFSU_ASU), + ("osu_asu", 1 - rFSU_ASU), + ("fsa_aaa", rFSA_AAA), + ("osa_aaa", rOSA_AAA), + ("fsa_faa", rFSA_FAA), + ("fca_faa", 1- rFSA_FAA), + ("osa_oaa", rOSA_OAA), + ("oca_oaa", rOSA_OAA), + ("fca_aca", rFCA_ACA), + ("oca_aca", 1 - rFCA_ACA), + ("fsa_osa", rFSA_AAA/rOSA_AAA), + ("osa_fsa", rOSA_AAA/rFSA_AAA), + ("aca_asa", rACA_ASA), + ("asa_aca", 1 / rACA_ASA), + ("fca_fsa", (1- rFSA_FAA)/rFSA_FAA), + ("fsa_fca", rFSA_FAA / (1- rFSA_FAA)), + ("oca_osa", (1 - rOSA_OAA) / rOSA_OAA), + ("osa_oca", rOSA_OAA / (1 - rOSA_OAA)), + ] +) +def test_m2rs(pair, expected): + col_names, data = prepare_data() + if pair.startswith("obj"): + func_str = "calculate_2d_{}".format(pair) + else: + func_str = "calculate_2d_ratio_{}".format(pair) + + func = getattr(m2rs, func_str) + actual = func(data, col_names) + np.testing.assert_almost_equal(actual, expected, 6)