def test_cannon(self, cannon_2015_rvs): ref, hist, sim = cannon_2015_rvs(15000) DQM = DetrendedQuantileMapping(kind="*", group="time") DQM.train(ref, hist) p = DQM.adjust(sim) np.testing.assert_almost_equal(p.mean(), 41.6, 0) np.testing.assert_almost_equal(p.std(), 15.0, 0)
def test_mon_U(self, mon_series, series, mon_triangular, kind, name, spatial_dims): """ Train on hist: U ref: U + monthly cycle Predict on hist to get ref """ n = 10000 u = np.random.rand(n) # Define distributions xd = uniform(loc=2, scale=0.1) yd = uniform(loc=4, scale=0.1) noise = uniform(loc=0, scale=1e-7) # Generate random numbers x = xd.ppf(u) y = yd.ppf(u) + noise.ppf(u) # Test train hist, ref = series(x, name), mon_series(y, name) trend = np.linspace(-0.2, 0.2, n) + int(kind == MULTIPLICATIVE) ref_t = mon_series(apply_correction(y, trend, kind), name) sim = series(apply_correction(x, trend, kind), name) if spatial_dims: hist = hist.expand_dims(**spatial_dims) ref = ref.expand_dims(**spatial_dims) sim = sim.expand_dims(**spatial_dims) ref_t = ref_t.expand_dims(**spatial_dims) DQM = DetrendedQuantileMapping(kind=kind, group="time.month", nquantiles=5) DQM.train(ref, hist) mqm = DQM.ds.af.mean(dim="quantiles") p = DQM.adjust(sim) if spatial_dims: mqm = mqm.isel({crd: 0 for crd in spatial_dims.keys()}) np.testing.assert_array_almost_equal(mqm, int(kind == MULTIPLICATIVE), 1) np.testing.assert_array_almost_equal(p, ref_t, 1)
def test_quantiles(self, series, kind, name): """Train on hist: U ref: Normal Predict on hist to get ref """ ns = 10000 u = np.random.rand(ns) # Define distributions xd = uniform(loc=10, scale=1) yd = norm(loc=12, scale=1) # Generate random numbers with u so we get exact results for comparison x = xd.ppf(u) y = yd.ppf(u) # Test train hist = sim = series(x, name) ref = series(y, name) DQM = DetrendedQuantileMapping(kind=kind, group="time", nquantiles=50, interp="linear") DQM.train(ref, hist) p = DQM.adjust(sim) q = DQM.ds.quantiles ex = apply_correction(xd.ppf(q), invert(xd.mean(), kind), kind) ey = apply_correction(yd.ppf(q), invert(yd.mean(), kind), kind) expected = get_correction(ex, ey, kind) # Results are not so good at the endpoints np.testing.assert_array_almost_equal(DQM.ds.af[2:-2], expected[2:-2], 1) # Test predict # Accept discrepancies near extremes middle = (x > 1e-2) * (x < 0.99) np.testing.assert_array_almost_equal(p[middle], ref[middle], 1) # Test with simure not equal to hist ff = series(np.ones(ns) * 1.1, name) sim2 = apply_correction(sim, ff, kind) ref2 = apply_correction(ref, ff, kind) p2 = DQM.adjust(sim2) np.testing.assert_array_almost_equal(p2[middle], ref2[middle], 1) # Test with actual trend in sim trend = series( np.linspace(-0.2, 0.2, ns) + (1 if kind == MULTIPLICATIVE else 0), name) sim3 = apply_correction(sim, trend, kind) ref3 = apply_correction(ref, trend, kind) p3 = DQM.adjust(sim3) np.testing.assert_array_almost_equal(p3[middle], ref3[middle], 1)
def test_cannon_and_from_ds(self, cannon_2015_rvs, tmp_path): ref, hist, sim = cannon_2015_rvs(15000) DQM = DetrendedQuantileMapping.train(ref, hist, kind="*", group="time") p = DQM.adjust(sim) np.testing.assert_almost_equal(p.mean(), 41.6, 0) np.testing.assert_almost_equal(p.std(), 15.0, 0) file = tmp_path / "test_dqm.nc" DQM.ds.to_netcdf(file) ds = xr.open_dataset(file) DQM2 = DetrendedQuantileMapping.from_dataset(ds) xr.testing.assert_equal(DQM.ds, DQM2.ds) p2 = DQM2.adjust(sim) np.testing.assert_array_equal(p, p2)
def test_mon_U(self, mon_series, series, kind, name, add_dims): """ Train on hist: U ref: U + monthly cycle Predict on hist to get ref """ n = 5000 u = np.random.rand(n) # Define distributions xd = uniform(loc=2, scale=0.1) yd = uniform(loc=4, scale=0.1) noise = uniform(loc=0, scale=1e-7) # Generate random numbers x = xd.ppf(u) y = yd.ppf(u) + noise.ppf(u) # Test train hist, ref = series(x, name), mon_series(y, name) trend = np.linspace(-0.2, 0.2, n) + int(kind == MULTIPLICATIVE) ref_t = mon_series(apply_correction(y, trend, kind), name) sim = series(apply_correction(x, trend, kind), name) if add_dims: ref = ref.expand_dims(lat=[0, 1, 2]).chunk({"lat": 1}) hist = hist.expand_dims(lat=[0, 1, 2]).chunk({"lat": 1}) sim = sim.expand_dims(lat=[0, 1, 2]).chunk({"lat": 1}) ref_t = ref_t.expand_dims(lat=[0, 1, 2]) DQM = DetrendedQuantileMapping.train(ref, hist, kind=kind, group="time.month", nquantiles=5) mqm = DQM.ds.af.mean(dim="quantiles") p = DQM.adjust(sim) if add_dims: mqm = mqm.isel(lat=0) np.testing.assert_array_almost_equal(mqm, int(kind == MULTIPLICATIVE), 1) np.testing.assert_allclose(p.transpose(..., "time"), ref_t, rtol=0.1, atol=0.5)
def cannon_2015_figure_2(): n = 10000 ref, hist, sim = tu.cannon_2015_rvs(n, random=False) QM = EmpiricalQuantileMapping(kind="*", group="time", interp="linear") QM.train(ref, hist) sim_eqm = QM.predict(sim) DQM = DetrendedQuantileMapping(kind="*", group="time", interp="linear") DQM.train(ref, hist) sim_dqm = DQM.predict(sim, degree=0) QDM = QuantileDeltaMapping(kind="*", group="time", interp="linear") QDM.train(ref, hist) sim_qdm = QDM.predict(sim) fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4)) x = np.linspace(0, 105, 50) ax1.plot(x, gaussian_kde(ref)(x), color="r", label="Obs hist") ax1.plot(x, gaussian_kde(hist)(x), color="k", label="GCM hist") ax1.plot(x, gaussian_kde(sim)(x), color="blue", label="GCM simure") ax1.plot(x, gaussian_kde(sim_qdm)(x), color="lime", label="QDM future") ax1.plot(x, gaussian_kde(sim_eqm)(x), color="darkgreen", ls="--", label="QM future") ax1.plot(x, gaussian_kde(sim_dqm)(x), color="lime", ls=":", label="DQM future") ax1.legend(frameon=False) ax1.set_xlabel("Value") ax1.set_ylabel("Density") tau = np.array([0.25, 0.5, 0.75, 0.95, 0.99]) * 100 bc_gcm = (scoreatpercentile(sim, tau) - scoreatpercentile(hist, tau)) / scoreatpercentile(hist, tau) bc_qdm = (scoreatpercentile(sim_qdm, tau) - scoreatpercentile(ref, tau)) / scoreatpercentile(ref, tau) bc_eqm = (scoreatpercentile(sim_eqm, tau) - scoreatpercentile(ref, tau)) / scoreatpercentile(ref, tau) bc_dqm = (scoreatpercentile(sim_dqm, tau) - scoreatpercentile(ref, tau)) / scoreatpercentile(ref, tau) ax2.plot([0, 1], [0, 1], ls=":", color="blue") ax2.plot(bc_gcm, bc_gcm, "-", color="blue", label="GCM") ax2.plot(bc_gcm, bc_qdm, marker="o", mfc="lime", label="QDM") ax2.plot( bc_gcm, bc_eqm, marker="o", mfc="darkgreen", ls=":", color="darkgreen", label="QM", ) ax2.plot( bc_gcm, bc_dqm, marker="s", mec="lime", mfc="w", ls="--", color="lime", label="DQM", ) for i, s in enumerate(tau / 100): ax2.text(bc_gcm[i], bc_eqm[i], f"{s} ", ha="right", va="center", fontsize=9) ax2.set_xlabel("GCM relative change") ax2.set_ylabel("Bias adjusted relative change") ax2.legend(loc="upper left", frameon=False) ax2.set_aspect("equal") plt.tight_layout() return fig