def setUp(self): x, t = symbols('x t') B = Matrix(1, 1, [-1]) u = Matrix(1, 1, [1]) state_vector = Matrix(1, 1, [x]) srm = SmoothReservoirModel.from_B_u(state_vector, t, B, u) parameter_dict = {} start_values = np.array([1]) times = np.arange(0, 6, 1) smr = SmoothModelRun(srm, parameter_dict, start_values, times) self.alpha = 1 start_values_14C = start_values * self.alpha decay_rate = 1.0 def Fa_func(t): return self.alpha self.smr_14C = SmoothModelRun_14C(smr, start_values_14C, Fa_func, decay_rate) dmr_from_pwc = DMR.from_SmoothModelRun(smr) fake_net_Us = DMR.from_SmoothModelRun(self.smr_14C).net_Us # we cannot infer net_Us_14C coming from data, hence we use the # net_Us from the 14C model coming from the Smooth 14C model # this is of no use in pracitical situations tough since once # we have smr, we can use smr_14C immediately instead of going # through DMRs self.dmr_from_pwc_14C = DiscreteModelRun_14C(dmr_from_pwc, start_values_14C, fake_net_Us, decay_rate)
def compute_Bs_discrete(single_site_dict, time_step_in_days): mdo = _load_mdo(single_site_dict, time_step_in_days, check_units=False) out = mdo.load_xs_Us_Fs_Rs() xs, Us, Fs, Rs = out times = mdo.time_agg.data.filled() nr_pools = mdo.model_structure.nr_pools data = np.nan * np.ones((len(times), nr_pools, nr_pools)) try: Bs = DMR.reconstruct_Bs( xs.data.filled(), Fs.data.filled(), Rs.data.filled() ) data[:-1, ...] = Bs except (DMRError, ValueError, OverflowError) as e: error = str(e) print(error, flush=True) print( "lat", single_site_dict["lat"], "lon", single_site_dict["lon"], "prob", single_site_dict["prob"] ) info = tuple() return data, info
def pool_age_density_val( x0_c: np.ndarray, times: np.ndarray, age_bin_indices: np.ndarray, # integer B_c: np.ndarray, U_c: np.ndarray, start_age_densities_of_x0_and_a: Callable[[np.ndarray, float], np.ndarray], ): # Note that the chunksize is supposed to be one # We have only one startvector npools, _ = x0_c.shape it_max = len(times) print(it_max) x0 = x0_c[:, 0] # .reshape(9) Bs = [B_c[i, :, :, 0] + np.eye(9) for i in range(it_max)] Us = [U_c[i, :, 0] for i in range(it_max)] dmr = DMR.from_Bs_and_net_Us(x0, times, Bs, Us) def start_age_densities(a): return start_age_densities_of_x0_and_a(x0, a) start_age_densities_of_bin_index = ( hr.pool_wise_bin_densities_from_smooth_densities_and_index( start_age_densities, npools, dmr.dt)) # res = np.zeros((len(age_bin_indices), len(times), npools, 1)) p_dmr = dmr.pool_age_densities_func(start_age_densities_of_bin_index) pad = p_dmr(age_bin_indices) res[:, 1:, :, 0] = pad # sol=dmr.solve()[:-1,:].reshape(U_c.shape) #remove the last value # return sol return res
def test_DiscreteModelRun_14CFromFakeData(self): dmr_from_smr_14C = DiscreteModelRun.from_SmoothModelRun(self.smr_14C) dmr_14C = DiscreteModelRun_14C( DiscreteModelRun.from_SmoothModelRun(self.smr), self.start_values_14C, dmr_from_smr_14C.net_Us, self.decay_rate) meths = [ "solve", "acc_net_external_input_vector", "acc_net_external_output_vector", "acc_net_internal_flux_matrix" ] for meth in meths: with self.subTest(): self.assertTrue( np.allclose( getattr(self.smr_14C, meth)(), getattr(dmr_14C, meth)()))
def test_start_value_format(self): # create ReservoirModel C_1, C_2, C_3 = symbols('C_1 C_2 C_3') state_vector = Matrix(3, 1, [C_1, C_2, C_3]) t = symbols('t') B = Matrix([[-2, 0, 1], [2, -2, 0], [0, 2, -2]]) u = Matrix(3, 1, [1, 0, 0]) srm = SmoothReservoirModel.from_B_u(state_vector, t, B, u) # create ModelRun ss = (-B**(-1) * u) # start_values = np.array(ss).astype(np.float64).reshape((3,)) start_values = np.array(ss).astype(np.float64) times = np.linspace(1919, 2009, 901) parameter_dict = {} smr = SmoothModelRun(srm, parameter_dict, start_values, times) smr.initialize_state_transition_operator_cache(lru_maxsize=None) DMR.from_SmoothModelRun(smr)
def valid_trajectory(x0_c, times, B_c, U_c): # Note that the chunksize is supposed to be one # We have only one startvector it_max = len(times) x0 = x0_c[:, 0] # .reshape(9) Bs = [B_c[i, :, :, 0] + np.eye(9) for i in range(it_max)] Us = [U_c[i, :, 0] for i in range(it_max)] # dmr = DMR.from_Bs_and_net_Us(x0,times,Bs,Us) # sol=dmr.solve()[:-1,:].reshape(U_c.shape) #remove the last value dmr = DMR.from_Bs_and_net_Us(x0, times, Bs[:-1], Us[:-1]) # Holger sol = dmr.solve().reshape(U_c.shape) # Holger return sol
def aggregate_xs(xs, nr_days): # Note that the chunksize is supposed to be one # We have only one startvector print("###########") print(x0_c.shape, type(x0_c)) print(times.shape) # print(ages.shape) print(B_c.shape) print(U_c.shape) it_max = len(times) print(it_max) x0 = x0_c[:, 0] # .reshape(9) Bs = [B_c[i, :, :, 0] + np.eye(9) for i in range(it_max)] Us = [U_c[i, :, 0] for i in range(it_max)] # dmr = DMR.from_Bs_and_net_Us(x0,times,Bs,Us) # sol=dmr.solve()[:-1,:].reshape(U_c.shape) #remove the last value dmr = DMR.from_Bs_and_net_Us(x0, times, Bs[:-1], Us[:-1]) # Holger sol = dmr.solve().reshape(U_c.shape) # Holger return sol
us_cont = sub_ds_cont["us"] Bs_cont = sub_ds_cont["Bs"] pwc_mr = PWCModelRunFD.from_Bs_and_us(symbols("t"), data_times, start_values_cont.values, Bs_cont[:-1], us_cont[:-1], state_variables=sub_ds_cont.pool.values) # discrete mr start_values_disc = sub_ds_disc["start_values"] Us_disc = sub_ds_disc["Us"] Bs_disc = sub_ds_disc["Bs"] dmr = DMR.from_Bs_and_net_Us(start_values_disc.values, data_times, Bs_disc[:-1].values, Us_disc[:-1].values) # - fig, ax = plt.subplots(figsize=(8, 8)) pwc_mr.model.plot_pools_and_fluxes(ax, legend=False) _ = ax.set_title("CARDAMOM") # compute the solution #soln = pwc_mr.solve() soln_cont = sub_ds_cont["solution"].values soln_disc = sub_ds_disc["solution"].values # + fig, axes = plt.subplots(ncols=2, nrows=3, figsize=(18, 12))
us_y6 = sub_ds_y6["us"] Bs_y6 = sub_ds_y6["Bs"] pwc_mr_y6 = PWCModelRunFD.from_Bs_and_us(symbols("t"), data_times_y6, start_values_y6.values, Bs_y6[:-1], us_y6[:-1], state_variables=sub_ds_y6.pool.values) # monthly, discrete start_values_dmr = sub_ds_dmr["start_values"] Us = sub_ds_dmr["Us"] Bs_dmr = sub_ds_dmr["Bs"] dmr = DMR.from_Bs_and_net_Us(start_values_dmr.values, data_times_m, Bs_dmr[:-1].values, Us[:-1].values) # - fig, ax = plt.subplots(figsize=(8, 8)) pwc_mr_m.model.plot_pools_and_fluxes(ax, legend=False) _ = ax.set_title("CARDAMOM") # compute the solution #soln = pwc_mr.solve() soln_m = sub_ds_m["solution"].values soln_y0 = sub_ds_y0["solution"].values soln_y6 = sub_ds_y6["solution"].values soln_dmr = sub_ds_dmr["solution"].values # + fig, axes = plt.subplots(ncols=2, nrows=3, figsize=(18, 12))
def compute_global_btt_quantile(ds, name, q, nr_time_steps, time_step_in_days, nr_sites=None, sto_cache_size=None): # load and adapt area and landfrac datases ds_area_lf = xr.open_dataset(data_path.joinpath("LSFRAC2.nc")) ds_area_lf_adapted = ds_area_lf.sel(lat=ds.lat, lon=ds.lon) ds_area_lf_adapted.area_sphere.attrs["units"] = "m^2" ds_area_lf_adapted.coords["lat"] = np.float64( ds_area_lf_adapted.coords["lat"]) ds_area_lf_adapted.coords["lon"] = np.float64( ds_area_lf_adapted.coords["lon"]) for var_name, var in ds_area_lf_adapted.data_vars.items(): ds_area_lf_adapted[var_name].coords["lat"] = np.float64( var.coords["lat"]) ds_area_lf_adapted[var_name].coords["lon"] = np.float64( var.coords["lon"]) # collect all sites with useful data coords_linear = np.where( (~np.isnan(ds.start_values[:, :, 0])\ & (ds.start_values[:, :, 0] != -np.inf))\ & (~np.isnan(ds.Bs[:, :, 0, 0, 0]))\ ) coords_tuples = [(x, y) for x, y in zip(*coords_linear)] # print(len(coords_tuples), "sites available") if nr_sites is None: nr_sites = len(coords_tuples) nr_times = len(ds.time) F_btt_svs = [] weights = np.nan * np.ones((nr_sites, nr_times - 1)) total_outflux_C = np.zeros(nr_times - 1) total_Ras = np.zeros(nr_times - 1) times = np.arange(len(ds.time)) * time_step_in_days if nr_sites is None: nr_sites = len(coords_tuples) def func_maker(dmr): F0 = dmr.fake_cumulative_start_age_masses(nr_time_steps) F_sv = dmr.cumulative_pool_age_masses_single_value(F0) rho = 1 - dmr.Bs.sum(1) F_btt_sv = lambda ai, ti: (rho[ti] * F_sv(ai, ti)).sum() + dmr.Ras[ti] return F_btt_sv for nr_coord, coords in enumerate(tqdm(coords_tuples[:nr_sites])): lat_idx, lon_idx = coords sub_ds = ds.isel(lat=lat_idx, lon=lon_idx) # load DMR start_values = sub_ds["start_values"].values Bs = sub_ds["Bs"].values Us = sub_ds["Us"].values Ras = sub_ds["Ras"].values dmr = DMR.from_Bs_and_net_Us(start_values, times, Bs[:nr_times - 1], Us[:nr_times - 1]) Ras = Ras[:nr_times - 1] dmr.Ras = Ras # create cumulative BTT distribution single value F_btt_sv = func_maker(dmr) land_sub_ds = ds_area_lf_adapted.sel(lat=ds.lat[lat_idx], lon=ds.lon[lon_idx]) weight = np.float( land_sub_ds.area_sphere * land_sub_ds.landfrac) / 1e12 F_btt_svs.append(F_btt_sv) weights[nr_coord, :] = weight R = dmr.acc_net_external_output_vector() total_outflux_C += weight * R.sum(axis=1) total_Ras += weight * Ras # initialize a state transition operator cache for this dmr if sto_cache_size: dmr.initialize_state_transition_operator_matrix_cache( sto_cache_size) # the global quantile function is a weighted average of the local quantile functions # weights are the respective masses of outflux (area*landfrac*R.sum) in each time step @lru_cache() def F_btt_sv_global(ai, ti): res = np.sum( np.array([ weight * F_btt_sv(int(ai), ti) for weight, F_btt_sv in zip(weights[:, ti], F_btt_svs) ])) return res global_btt_quantiles = np.nan * np.ones(nr_times, dtype=np.float64) quantile_ai = 0 for ti in tqdm(range(len(times) - 1)): critical_value = q * (total_outflux_C[ti] + total_Ras[ti]) quantile_ai = generalized_inverse_CDF( lambda ai: F_btt_sv_global(ai, ti), critical_value, x1=quantile_ai) if F_btt_sv_global(quantile_ai, ti) > critical_value: if quantile_ai > 0: quantile_ai = quantile_ai - 1 # save result for timestep ti global_btt_quantiles[ti] = quantile_ai * time_step_in_days # prepare return dataset data_vars = dict() data_vars[name] = xr.DataArray(data=global_btt_quantiles, dims=["time"]) res_ds = xr.Dataset(data_vars=data_vars, coords={"time": ds.time.data}) # sub_ds.close() return res_ds
def test_from_SmoothModelRun(self): x_0, x_1, t, k, u = symbols("x_0 x_1 k t u") inputs = {0: u * (2 - 2 * sin(2 * t)), 1: u} outputs = {0: x_0 * k, 1: x_1**2 * k} internal_fluxes = {(0, 1): x_0, (1, 0): 0.5 * x_1} srm = SmoothReservoirModel([x_0, x_1], t, inputs, outputs, internal_fluxes) t_max = 2 * np.pi times = np.linspace(0, t_max, 21) times_fine = np.linspace(0, t_max, 81) x0 = np.float(10) start_values = np.array([x0, x0]) parameter_dict = {k: 0.012, u: 10.7} smr = SmoothModelRun(srm, parameter_dict, start_values, times) smr_fine = SmoothModelRun(srm, parameter_dict, start_values, times_fine) xs, net_Us, net_Fs, net_Rs = smr.fake_net_discretized_output(times) xs, gross_Us, gross_Fs, gross_Rs \ = smr.fake_gross_discretized_output(times) xs_fine, gross_Us_fine, gross_Fs_fine, gross_Rs_fine \ = smr_fine.fake_gross_discretized_output(times_fine) dmr_from_pwc = DMR.from_SmoothModelRun(smr) dmr_from_fake_net_data = DMR.reconstruct_from_fluxes_and_solution( times, xs, net_Fs, net_Rs) dmr_from_fake_gross_data_ffas \ = DMR.reconstruct_from_fluxes_and_solution( times, xs, gross_Fs, gross_Rs ) dmr_from_fake_gross_data_ff = DMR.from_fluxes(start_values, times, gross_Us, gross_Fs, gross_Rs) dmr_from_fake_gross_data_ff_fine = DMR.from_fluxes( start_values, times_fine, gross_Us_fine, gross_Fs_fine, gross_Rs_fine) self.assertTrue(np.allclose(smr.solve(), dmr_from_pwc.solve())) self.assertTrue( np.allclose(smr.solve(), dmr_from_fake_net_data.solve())) # very unexpectedly the solution # can be reconstructed from the right start_value # the WRONG inputs WRONG internal fluxes and # WRONG outputs self.assertTrue( np.allclose(smr.solve(), dmr_from_fake_gross_data_ff.solve(), rtol=1e-3)) # Here we also expect different results. # We again abuse the DiscreteModelRun class # but this time we give it the right solution # which will be reproduced self.assertTrue( np.allclose(smr.solve(), dmr_from_fake_gross_data_ffas.solve())) # but the net influxes will be wrong self.assertFalse( np.allclose(smr.acc_net_external_input_vector(), dmr_from_fake_gross_data_ffas.net_Us)) # plot_attributes( # [ # smr, # dmr_from_fake_net_data, # dmr_from_fake_gross_data_ff, # dmr_from_fake_gross_data_ffas # ], # 'plot.pdf' # ) plot_stocks_and_fluxes( [ smr, # dmr_from_fake_net_data, # dmr_from_pwc, dmr_from_fake_gross_data_ff, dmr_from_fake_gross_data_ff_fine ], 'stocks_and_fluxes.pdf')