diff --git a/swmmanywhere/metric_utilities.py b/swmmanywhere/metric_utilities.py index 0a3b0617..e0207f6c 100644 --- a/swmmanywhere/metric_utilities.py +++ b/swmmanywhere/metric_utilities.py @@ -153,7 +153,7 @@ def restriction_on_scale(scale: str, variable: str): """Restriction on scale. - Restrict the design variables to the outlet scale if the metric is 'pbias'. + Restrict the design variables to the outlet scale if the metric is 'relerror'. Args: scale (str): The scale of the metric. @@ -169,15 +169,15 @@ def restriction_on_metric(scale: str, variable: str): """Restriction on metric. - Restrict the variable to 'flow' if the metric is 'pbias'. + Restrict the variable to 'flow' if the metric is 'relerror'. Args: scale (str): The scale of the metric. metric (str): The metric. variable (str): The variable. """ - if variable in ('length', 'nmanholes', 'npipes') and metric != 'pbias': - raise ValueError(f"Variable {variable} only valid with pbias metric") + if variable in ('length', 'nmanholes', 'npipes') and metric != 'relerror': + raise ValueError(f"Variable {variable} only valid with relerror metric") # Coefficient Registry @@ -209,15 +209,15 @@ def register_coef(coef_func: Callable): return coef_func @register_coef -def pbias(y: np.ndarray, +def relerror(y: np.ndarray, yhat: np.ndarray) -> float: - r"""Percentage bias, PBIAS. + r"""Relative error, relerror. - Calculate the percent bias: + Calculate the relative error: .. math:: - pbias = \\frac{{\mean(synthetic) - \mean(real)}}{{\mean(real)}} + relerror = \\frac{{\mean(synthetic) - \mean(real)}}{{\mean(real)}} where: - :math:`synthetic` is the synthetic data, @@ -228,7 +228,7 @@ def pbias(y: np.ndarray, yhat (np.ndarray): The synthetic data. Returns: - float: The PBIAS value. + float: The relerror value. """ total_observed = y.mean() if total_observed == 0: @@ -870,24 +870,24 @@ def new_metric(**kwargs): metrics.register(metric_factory('outlet_nse_flow')) metrics.register(metric_factory('outlet_kge_flow')) -metrics.register(metric_factory('outlet_pbias_flow')) +metrics.register(metric_factory('outlet_relerror_flow')) -metrics.register(metric_factory('outlet_pbias_length')) -metrics.register(metric_factory('outlet_pbias_npipes')) -metrics.register(metric_factory('outlet_pbias_nmanholes')) -metrics.register(metric_factory('outlet_pbias_diameter')) +metrics.register(metric_factory('outlet_relerror_length')) +metrics.register(metric_factory('outlet_relerror_npipes')) +metrics.register(metric_factory('outlet_relerror_nmanholes')) +metrics.register(metric_factory('outlet_relerror_diameter')) metrics.register(metric_factory('outlet_nse_flooding')) metrics.register(metric_factory('outlet_kge_flooding')) -metrics.register(metric_factory('outlet_pbias_flooding')) +metrics.register(metric_factory('outlet_relerror_flooding')) metrics.register(metric_factory('grid_nse_flooding')) metrics.register(metric_factory('grid_kge_flooding')) -metrics.register(metric_factory('grid_pbias_flooding')) +metrics.register(metric_factory('grid_relerror_flooding')) metrics.register(metric_factory('subcatchment_nse_flooding')) metrics.register(metric_factory('subcatchment_kge_flooding')) -metrics.register(metric_factory('subcatchment_pbias_flooding')) +metrics.register(metric_factory('subcatchment_relerror_flooding')) @metrics.register def nc_deltacon0(synthetic_G: nx.Graph, diff --git a/swmmanywhere/paper/plotting.py b/swmmanywhere/paper/plotting.py index 473cea84..98f4724a 100644 --- a/swmmanywhere/paper/plotting.py +++ b/swmmanywhere/paper/plotting.py @@ -20,16 +20,16 @@ def create_behavioral_indices(df: pd.DataFrame) -> tuple[pd.Series, pd.Series]: Returns: tuple[pd.Series, pd.Series]: A tuple of two series, the first is the behavioural indices for 'strict' objectives (KGE/NSE), the second - is the behavioural indices for less strict objectives (PBIAS). + is the behavioural indices for less strict objectives (relerror). """ behavioural_ind_nse = ((df.loc[:, df.columns.str.contains('nse')] > 0) & \ (df.loc[:, df.columns.str.contains('nse')] < 1)).any(axis=1) behavioural_ind_kge = ((df.loc[:, df.columns.str.contains('kge')] > -0.41) &\ (df.loc[:, df.columns.str.contains('kge')] < 1)).any(axis=1) - behavioural_ind_bias = (df.loc[:, - df.columns.str.contains('bias')].abs() < 0.1 + behavioural_ind_relerror = (df.loc[:, + df.columns.str.contains('relerror')].abs() < 0.1 ).any(axis=1) - return behavioural_ind_nse | behavioural_ind_kge, behavioural_ind_bias + return behavioural_ind_nse | behavioural_ind_kge, behavioural_ind_relerror def plot_objectives(df: pd.DataFrame, parameters: list[str], @@ -99,7 +99,7 @@ def add_threshold_lines(ax, objective, xmin, xmax): xmax (float): The maximum x value. """ thresholds = { - 'bias': [-0.1, 0.1], + 'relerror': [-0.1, 0.1], 'nse': [0], 'kge': [-0.41] } diff --git a/tests/test_data/demo_config.yml b/tests/test_data/demo_config.yml index 0be3ac96..7ea3e8df 100644 --- a/tests/test_data/demo_config.yml +++ b/tests/test_data/demo_config.yml @@ -39,19 +39,19 @@ graphfcn_list: metric_list: - outlet_nse_flow - outlet_kge_flow - - outlet_pbias_flow - - outlet_pbias_length - - outlet_pbias_npipes - - outlet_pbias_nmanholes + - outlet_relerror_flow + - outlet_relerror_length + - outlet_relerror_npipes + - outlet_relerror_nmanholes - outlet_nse_flooding - outlet_kge_flooding - - outlet_pbias_flooding + - outlet_relerror_flooding - grid_nse_flooding - grid_kge_flooding - - grid_pbias_flooding + - grid_relerror_flooding - subcatchment_nse_flooding - subcatchment_kge_flooding - - subcatchment_pbias_flooding + - subcatchment_relerror_flooding - nc_deltacon0 - nc_laplacian_dist - nc_laplacian_norm_dist diff --git a/tests/test_metric_utilities.py b/tests/test_metric_utilities.py index 45096d55..1a8a8fa3 100644 --- a/tests/test_metric_utilities.py +++ b/tests/test_metric_utilities.py @@ -200,13 +200,13 @@ def test_inf(): yhat = np.array([1,2,3,4,5])) assert val == np.inf - val = mu.pbias(y = np.array([-3,-3,0,3,3]), + val = mu.relerror(y = np.array([-3,-3,0,3,3]), yhat = np.array([1,2,3,4,5])) assert val == np.inf -def test_pbias_different_length(): - """Test the pbias metric with different length arrays.""" - val = mu.pbias(y = np.array([1,2,3,4,5,6]), +def test_relerror_different_length(): + """Test the relerror metric with different length arrays.""" + val = mu.relerror(y = np.array([1,2,3,4,5,6]), yhat = np.array([1])) assert_close(val, (1 - 3.5)/3.5) @@ -400,10 +400,10 @@ def test_design_params(): # Target results design_results = {'outlet_kstest_diameters' : 0.0625, - 'outlet_pbias_diameter': 0.0625, - 'outlet_pbias_length' : -0.15088965, - 'outlet_pbias_nmanholes' : -0.05, - 'outlet_pbias_npipes' : -0.15789473} + 'outlet_relerror_diameter': 0.0625, + 'outlet_relerror_length' : -0.15088965, + 'outlet_relerror_nmanholes' : -0.05, + 'outlet_relerror_npipes' : -0.15789473} # Iterate for G = G, i.e., perfect results metrics = mu.iterate_metrics(synthetic_G = G, @@ -533,7 +533,7 @@ def test_restirctions(): """Test the restriction register by generating an invalid metric.""" # Invalid because length can't be calculated at grid scale with pytest.raises(ValueError): - mu.metric_factory('grid_pbias_length') + mu.metric_factory('grid_relerror_length') # Invalid because nmanholes can't be evaluated with nse with pytest.raises(ValueError): diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 910d46c8..4fc14fd3 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -16,8 +16,8 @@ def test_create_behavioural_indices(): 'nse2': [-1, 0, 0.5, 1, -2], 'kge1': [-2, -0.4, 0, 0.5, 1], 'kge2': [-0.41, -0.5, 0, 0.5, 1], - 'bias1': [-0.2, -0.09, 0, 0.1, 0.2], - 'bias2': [-0.2, -0.1, 0, 0.1, 0.2], + 'relerror1': [-0.2, -0.09, 0, 0.1, 0.2], + 'relerror2': [-0.2, -0.1, 0, 0.1, 0.2], } df = pd.DataFrame(data)