def compare_Kunc(p1, p2, Kstr, io): """Compare uncertainty propagation from the equilibrium constant internal overrides vs Monte-Carlo simulations. """ mcsize = 10000 Kunc_pct = 0.05 co2d = pyco2.CO2SYS(np.full(mcsize, pars_true[p1]), pars_true[p2], partypes[p1], partypes[p2], *args, **kwargs) if io == "in": equilibria_in = { Kstr: np.random.normal( loc=co2d["{}{}put".format(Kstr, io)][0], scale=co2d["{}{}put".format(Kstr, io)][0] * Kunc_pct, size=mcsize, ) } co2d_mcsim = pyco2.CO2SYS(np.full(mcsize, pars_true[p1]), pars_true[p2], partypes[p1], partypes[p2], *args, **kwargs, equilibria_in=equilibria_in) elif io == "out": equilibria_out = { Kstr: np.random.normal( loc=co2d["{}{}put".format(Kstr, io)][0], scale=co2d["{}{}put".format(Kstr, io)][0] * Kunc_pct, size=mcsize, ) } co2d_mcsim = pyco2.CO2SYS(np.full(mcsize, pars_true[p1]), pars_true[p2], partypes[p1], partypes[p2], *args, **kwargs, equilibria_out=equilibria_out) testvar = "isoQ{}".format(io) testunc_Mcsim = np.std(co2d_mcsim[testvar]) uncertainties, components = pyco2.uncertainty.propagate( co2d, [testvar], { "{}{}put".format(Kstr, io): Kunc_pct * co2d["{}{}put".format(Kstr, io)][0] }, ) comparison = get_compare(testunc_Mcsim, uncertainties[testvar][0]) print(p1, p2, Kstr) if comparison > -1: print(testunc_Mcsim) print(uncertainties[testvar][0]) print(comparison) assert (comparison < 4) or (uncertainties[testvar][0] < 1e-9)
def compare_par1par2(i, fixedpartype, uncertainties_in): fixedpar = partypes == fixedpartype par1s_true = pars_true[~fixedpar] par1u_true = paru_true[~fixedpar] par1types = partypes[~fixedpar] par2s_true = np.full_like(par1s_true, pars_true[fixedpar][0]) par2u_true = np.full_like(par1u_true, paru_true[fixedpar][0]) par2types = np.full_like(par1types, partypes[fixedpar][0]) par1 = par1s_true[i] par1type = par1types[i] par2 = par2s_true[i] par2type = par2types[i] co2d = pyco2.CO2SYS(par1, par2, par1type, par2type, *args, **kwargs) # Propagate directly uncertainties_in = [uncertainties_in] uncertainties, components = pyco2.uncertainty.propagate( co2d, uncertainties_in, { "PAR1": par1u_true[i], "PAR2": par2u_true[i] }) # Estimate the same with Monte-Carlo simulation mcsize = (10000, ) par1sim = np.random.normal(size=mcsize, loc=par1, scale=par1u_true[i]) par2sim = np.random.normal(size=mcsize, loc=par2, scale=par2u_true[i]) co2d_par1sim = pyco2.CO2SYS(par1sim, par2, par1type, par2type, *args, **kwargs) co2d_par2sim = pyco2.CO2SYS(par1, par2sim, par1type, par2type, *args, **kwargs) co2d_bothsim = pyco2.CO2SYS(par1sim, par2sim, par1type, par2type, *args, **kwargs) umc1 = np.std(co2d_par1sim[uncertainties_in[0]]) umc2 = np.std(co2d_par2sim[uncertainties_in[0]]) umcBoth = np.std(co2d_bothsim[uncertainties_in[0]]) compare1 = get_compare(umc1, components[uncertainties_in[0]]["PAR1"]) compare2 = get_compare(umc2, components[uncertainties_in[0]]["PAR2"]) compareBoth = get_compare(umcBoth, uncertainties[uncertainties_in[0]]) return compare1, compare2, compareBoth
) # Compare with CO2SYS v1.4 API par1g = np.broadcast_to(par1, np.broadcast(par1, par2).shape) par2g = np.broadcast_to(par2, np.broadcast(par1, par2).shape) co2dict = pyco2.CO2SYS( par1g, par2g, par1_type, par2_type, kwargs["salinity"], results["temperature"], results["temperature"], results["pressure"], results["pressure"], results["total_silicate"], results["total_phosphate"], results["opt_pH_scale"], results["opt_k_carbonic"], pyco2.convert.options_new2old( results["opt_k_bisulfate"], results["opt_total_borate"] ), WhichR=3, equilibria_in={"K1": kwargs["k_carbonic_1"]}, ) uncert_old, components_old = pyco2.uncertainty.propagate( co2dict, ["pHin", "isoQin", "TCO2"], {"PAR1": 2, "PAR2": 2, "pK1input": 0.02,}, equilibria_in={"K1": kwargs["k_carbonic_1"]}, )
phos = 3 h2s = 0.12 nh3 = 0.5 k1k2c = 16 kso4c = 3 phscale = 3 # - get the co2dict co2dict = pyco2.CO2SYS( par1, par2, par1type, par2type, sal, tempin, tempout, presin, presout, si, phos, phscale, k1k2c, kso4c, H2S=h2s, NH3=nh3, ) # - propagate the uncertainties grads_of = "all" grads_wrt = "all" co2derivs, dxs = pyco2.uncertainty.forward( co2dict, grads_of, grads_wrt,
"PAR1TYPE", "PAR2TYPE", "SAL", "TEMPIN", "TEMPOUT", "PRESIN", "PRESOUT", "SI", "PO4", "pHSCALEIN", "K1K2CONSTANTS", "KSO4CONSTANTS", ] ] go = time() co2py = pyco2.CO2SYS(*co2inputs, buffers_mode="none") print("PyCO2SYS runtime = {:.6f} s".format(time() - go)) co2py = pd.DataFrame(co2py) # short = ((co2inputs[2] == 1) & (co2inputs[3] == 4)) | ( # (co2inputs[2] == 4) & (co2inputs[3] == 1) # ) # short_ix = co2py.index[short] # co2py_short = pd.DataFrame( # pyco2.CO2SYS(*[i[short] for i in co2inputs], buffers_mode="none") # ) # short_diff = co2py.loc[short_ix, "BAlkin"].values - co2py_short["BAlkin"].values # Also test the original CO2SYS clone go = time() DATA, HEADERS, _ = pyco2.original.CO2SYS(*co2inputs)
"SAL", "TEMPIN", "TEMPOUT", "PRESIN", "PRESOUT", "SI", "PO4", "pHSCALEIN", "K1K2CONSTANTS", "KSO4CONSTANTS", "NH3", "H2S", "KFCONSTANT", ] ] co2py = pyco2.CO2SYS(*co2inputs, buffers_mode="auto") # Get override input dicts from co2py and use them in CO2SYS totals = pyco2.engine.dict2totals_umol(co2py) equilibria_in, equilibria_out = pyco2.engine.dict2equilibria(co2py) co2py_override = pyco2.CO2SYS(*co2inputs, buffers_mode="auto", totals=totals, equilibria_in=equilibria_in, equilibria_out=equilibria_out) # Compare results - should be ~identical co2py_diff = { k: co2py_override[k] - co2py[k] for k in co2py if k != "buffers_mode" }