From f275e7eeb387459580c37e749a83a0d226e12892 Mon Sep 17 00:00:00 2001 From: Nathan Collier Date: Thu, 1 Jun 2023 15:56:09 -0400 Subject: [PATCH 1/2] initial take at reimplementing ratios --- src/ILAMB/ConfRatio.py | 87 +++++++++++++++++++++++++++++++++++++++++ src/ILAMB/Scoreboard.py | 4 +- 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/ILAMB/ConfRatio.py diff --git a/src/ILAMB/ConfRatio.py b/src/ILAMB/ConfRatio.py new file mode 100644 index 00000000..6d2e10a8 --- /dev/null +++ b/src/ILAMB/ConfRatio.py @@ -0,0 +1,87 @@ +""".""" +import os + +import numpy as np + +from . import ilamblib as il +from .Confrontation import Confrontation +from .Variable import Variable + + +def variable_ratio(num: Variable, den: Variable): + """.""" + den.convert(num.unit) + years = np.asarray([num.time_bnds[::12, 0], num.time_bnds[11::12, 1]]).T + num = num.coarsenInTime(years) + den = den.coarsenInTime(years) + with np.errstate(under="ignore"): + ratio = num.data / den.data + ratio = Variable( + name="ratio", + unit="1", + data=ratio, + time=num.time, + time_bnds=num.time_bnds, + lat=num.lat, + lat_bnds=num.lat_bnds, + lon=num.lon, + lon_bnds=num.lon_bnds, + ) + return ratio + + +class ConfRatio(Confrontation): + """.""" + + def __init__(self, **keywords): + required_keys = [ + "numerator_source", + "numerator_variable", + "denominator_source", + "denominator_variable", + ] + if set(required_keys).difference(keywords): + msg = f"This confrontation requires a different set of keywords: {','.join(required_keys)}" + raise il.MisplacedData(msg) + for key in ["numerator_source", "denominator_source"]: + keywords[key] = os.path.join(os.environ["ILAMB_ROOT"], keywords[key]) + keywords["source"] = keywords["numerator_source"] + keywords["skip_cycle"] = True + keywords["rmse_score_basis"] = "series" + self.source = keywords["numerator_source"] + super().__init__(**keywords) + + def stageData(self, m): + """.""" + # construct observation ratios + kwargs = self.keywords + num = Variable( + filename=kwargs["numerator_source"], + variable_name=kwargs["numerator_variable"], + ) + den = Variable( + filename=kwargs["denominator_source"], + variable_name=kwargs["denominator_variable"], + t0=num.time_bnds.min(), + tf=num.time_bnds.max(), + ) + num.trim(t=[den.time_bnds.min(), den.time_bnds.max()]) + obs = variable_ratio(num, den) + + # constructor model ratios + num = m.extractTimeSeries( + kwargs["numerator_variable"], + initial_time=obs.time_bnds[0, 0], + final_time=obs.time_bnds[-1, 1], + lats=None if obs.spatial else obs.lat, + lons=None if obs.spatial else obs.lon, + ) + den = m.extractTimeSeries( + kwargs["denominator_variable"], + initial_time=obs.time_bnds[0, 0], + final_time=obs.time_bnds[-1, 1], + lats=None if obs.spatial else obs.lat, + lons=None if obs.spatial else obs.lon, + ) + mod = variable_ratio(num, den) + return obs, mod diff --git a/src/ILAMB/Scoreboard.py b/src/ILAMB/Scoreboard.py index 5cdb3f3c..192a0500 100644 --- a/src/ILAMB/Scoreboard.py +++ b/src/ILAMB/Scoreboard.py @@ -13,6 +13,7 @@ from .ConfSoilCarbon import ConfSoilCarbon from .ConfUncertainty import ConfUncertainty from .ConfBurntArea import ConfBurntArea +from .ConfRatio import ConfRatio try: from .ConfUSGS import ConfUSGS except: @@ -328,7 +329,8 @@ def _loadScores(node): "ConfSoilCarbon" : ConfSoilCarbon, "ConfUncertainty" : ConfUncertainty, "ConfBurntArea" : ConfBurntArea, - "ConfUSGS" : ConfUSGS } + "ConfUSGS" : ConfUSGS, + "ConfRatio" : ConfRatio } class Scoreboard(): """ From 81d3c1be14b9087dc28275264e8641ccffc9072a Mon Sep 17 00:00:00 2001 From: Nathan Collier Date: Thu, 15 Jun 2023 13:58:26 -0400 Subject: [PATCH 2/2] added comments and also skip spatial distribution --- src/ILAMB/ConfRatio.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ILAMB/ConfRatio.py b/src/ILAMB/ConfRatio.py index 6d2e10a8..72e14543 100644 --- a/src/ILAMB/ConfRatio.py +++ b/src/ILAMB/ConfRatio.py @@ -31,7 +31,10 @@ def variable_ratio(num: Variable, den: Variable): class ConfRatio(Confrontation): - """.""" + """. + * over_regions, a list of regions overwhich to compute averages, could be basins here + * mask_lower_percentile = 0.05, would create a mask of the lower end of the denominator and intepolate the mask to the model + """ def __init__(self, **keywords): required_keys = [ @@ -47,6 +50,7 @@ def __init__(self, **keywords): keywords[key] = os.path.join(os.environ["ILAMB_ROOT"], keywords[key]) keywords["source"] = keywords["numerator_source"] keywords["skip_cycle"] = True + keywords["skip_sd"] = True keywords["rmse_score_basis"] = "series" self.source = keywords["numerator_source"] super().__init__(**keywords)