Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

75 if calculating nse for two timeseries also do kge and bias #104

Merged

Conversation

barneydobson
Copy link
Collaborator

@barneydobson barneydobson commented Mar 19, 2024

Description

  • Introduce KGE
  • Separate bias
  • Refactor to create a metric factory, to generate the scale, variable and coefficient based on the metric name
  • Allow all coefficients (nse, kge, bias) for all sensible combinations. It is conceivable that the design parameters (e.g., nmanholes) could be calculated at other scales than outlet... but that's a fair bit more coding and it's late..

Fixes #75 #49

To do

  • Docstrings here need some tidying

@barneydobson barneydobson linked an issue Mar 19, 2024 that may be closed by this pull request
@barneydobson barneydobson self-assigned this Mar 19, 2024
@barneydobson barneydobson added the sa_paper Sensitivity analysis paper label Mar 19, 2024
@barneydobson barneydobson added refactor Refactoring existing code without significantly changing functionality and removed refactor Refactoring existing code without significantly changing functionality labels Apr 1, 2024
slight changes to docstrings
fix tests so that all metric functions use all correct args
swmmanywhere/metric_utilities.py Outdated Show resolved Hide resolved
swmmanywhere/metric_utilities.py Outdated Show resolved Hide resolved
swmmanywhere/metric_utilities.py Outdated Show resolved Hide resolved
swmmanywhere/metric_utilities.py Show resolved Hide resolved

if var == 'nmanholes':
# Calculate the coefficient based on the number of manholes
return coef(np.array(sg_real.number_of_nodes()),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't number_of_nodes() return a single value? I think instead of np.array you should use np.atleast_1d. I don't quite understand this part, since coef can be any of the functions, you're comparing two single values, for example, using KGE? The same goes for the npipes case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was to contain the design metrics (i.e., pbias in nmanholes, npipes, and length) in metric_factory. At the very least I guess I should validate these in metric_factory (as you're correct, KGE/NSE make no sense in this context) - now added.

swmmanywhere/metric_utilities.py Outdated Show resolved Hide resolved
swmmanywhere/metric_utilities.py Outdated Show resolved Hide resolved
tests/test_metric_utilities.py Show resolved Hide resolved
Dobson added 5 commits April 5, 2024 09:33
Use inf rather than None
rename coef->coef_func
Add some validation
tidy and validate in metric_factory
Dobson and others added 5 commits April 8, 2024 16:18
Copy link
Collaborator

@dalonsoa dalonsoa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the registration of metrics needs another pass to make it more flexible, clear and robust. As it is now, it is very confusing and hard to modify.

Also, I've the feeling you're copy-pasting code from other places without paying too much attention to updating the docstrings to follow the appropriate style and format.

swmmanywhere/metric_utilities.py Outdated Show resolved Hide resolved
swmmanywhere/metric_utilities.py Show resolved Hide resolved
swmmanywhere/metric_utilities.py Outdated Show resolved Hide resolved
swmmanywhere/metric_utilities.py Outdated Show resolved Hide resolved
swmmanywhere/metric_utilities.py Show resolved Hide resolved
swmmanywhere/metric_utilities.py Show resolved Hide resolved
swmmanywhere/metric_utilities.py Show resolved Hide resolved
swmmanywhere/metric_utilities.py Show resolved Hide resolved
Comment on lines 618 to 622
if variable in design_variables:
if scale != 'outlet':
raise ValueError(f"Variable {variable} only supported at the outlet scale")
if metric != 'pbias':
raise ValueError(f"Variable {variable} only valid with pbias metric")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes more sense to have this validation within each of the relevant functions, so if they get an invalid variable, they flag that. Otherwise, you might need to take into account a lot of special cases.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that makes sense, though this means it won't be validated until the function is evaluated - rather than created

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK coef/scale registry below probably solves this

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dalonsoa I've added the coef and scale registries, but I don't think these validations can be handled when a coef or scale is registered because it requires knowledge of the variable to know whether it is an invalid combination. The metric_factory and the scale function (when called) are the only bits of code that have the information required to assess validity - and surely it is preferrable to validate before any code is run than after a simulation and the scale function is called?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dalonsoa any further comment on this - otherwise will merge

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could implement such validation via restrictions. Something like:

@register_restriction
def restriction_on_scale(scale, metric, variable):
    if variable in ('length', 'nmanholes', 'npipes') and scale != 'outlet':
        raise ValueError(f"Variable {variable} only supported at the outlet scale")

@register_restriction
def restriction_on_metric(scale, metric, variable):
    if variable in ('length', 'nmanholes', 'npipes') and metric != 'pbias':
        raise ValueError(f"Variable {variable} only valid with pbias metric")

#  And within `metric_factory`:

    for restriction in RESTRICTIONS_REGISTRY:
        restriction(scale, metric, variable)

Or something along these lines.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah I see - yes this seems tidier

Copy link
Collaborator Author

@barneydobson barneydobson Apr 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK added and tested- @dalonsoa you happy?

swmmanywhere/metric_utilities.py Outdated Show resolved Hide resolved
@barneydobson barneydobson merged commit 43d238a into main Apr 11, 2024
10 checks passed
@barneydobson barneydobson deleted the 75-if-calculating-nse-for-two-timeseries-also-do-kge-and-bias branch April 11, 2024 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
sa_paper Sensitivity analysis paper
Projects
None yet
Development

Successfully merging this pull request may close these issues.

If calculating NSE for two timeseries, also do KGE and bias
3 participants