def test_water_self_diffusion_coefficient__units(): from chempy.units import allclose, linspace, default_units as u unit = u.m**2/u.s assert allclose(1e9*w_sd(298.15*u.K, units=u), 2.299*unit, rtol=1e-3, atol=1e-8*unit) assert allclose(1e9*w_sd(linspace(297, 299)*u.K, units=u), 2.299*u.m**2/u.s, rtol=5e-2, atol=1e-2*unit)
def test_water_density(): warnings.filterwarnings("error") assert abs(water_density(273.15 + 0) - 999.8395) < 0.004 assert abs(water_density(273.15 + 4) - 999.9720) < 0.003 assert abs(water_density(273.15 + 10) - 999.7026) < 0.0003 assert abs(water_density(273.15 + 15) - 999.1026) < 0.0001 assert abs(water_density(273.15 + 20) - 998.2071) < 0.0005 assert abs(water_density(273.15 + 22) - 997.7735) < 0.0007 assert abs(water_density(273.15 + 25) - 997.0479) < 0.0009 assert abs(water_density(273.15 + 30) - 995.6502) < 0.0016 assert abs(water_density(273.15 + 40) - 992.2) < 0.02 try: water_density(1) except UserWarning: pass # good warning raised else: raise warnings.resetwarnings() try: import quantities as pq import numpy as np unit = pq.kg/pq.m**3 assert allclose(water_density(298.15*pq.K, units=pq), 997.047021671824*unit, atol=1e-8*unit) assert allclose(water_density(np.linspace(297, 299)*pq.K, units=pq), 997*unit, rtol=1e-3, atol=1e-3*unit) except ImportError: pass
def test_water_self_diffusion_coefficient(): warnings.filterwarnings("error") assert abs(w_sd(273.15 + 0.) - 1.099e-9) < 0.027e-9 assert abs(w_sd(273.15 + 4.) - 1.261e-9) < 0.011e-9 assert abs(w_sd(273.15 + 10) - 1.525e-9) < 0.007e-9 assert abs(w_sd(273.15 + 15) - 1.765e-9) < 0.006e-9 assert abs(w_sd(273.15 + 20) - 2.023e-9) < 0.001e-9 assert abs(w_sd(273.15 + 25) - 2.299e-9) < 0.001e-9 assert abs(w_sd(273.15 + 30) - 2.594e-9) < 0.001e-9 assert abs(w_sd(273.15 + 35) - 2.907e-9) < 0.004e-9 try: w_sd(1) except UserWarning: pass # good warning raised else: raise warnings.resetwarnings() try: import quantities as pq import numpy as np unit = pq.m**2 / pq.s assert allclose(1e9 * w_sd(298.15 * pq.K, units=pq), 2.299 * unit, rtol=1e-3, atol=1e-8 * unit) assert allclose(1e9 * w_sd(np.linspace(297, 299) * pq.K, units=pq), 2.299 * pq.m**2 / pq.s, rtol=5e-2, atol=1e-2 * unit) except ImportError: pass
def test_integrate_nondimensionalisation(from_rsys): from chempy import Reaction, ReactionSystem from chempy.units import allclose, default_units as u # 2A -> B if from_rsys: rxn = Reaction.from_string('2 A -> B; 2e-3*metre**3/mol/hour', None) rsys = ReactionSystem([rxn], 'A B') rd = ReactionDiffusion.from_ReactionSystem(rsys, unit_registry=SI_base_registry) else: rd = ReactionDiffusion.nondimensionalisation( 2, [[0, 0]], [[1]], [2e-9/(umol/metre**3)/hour], unit_registry=SI_base_registry) C0 = [3*molar, 4*molar] tout = np.linspace(0, 1)*day integr = Integration(rd, C0, tout, integrator='scipy') k_m3_p_mol_p_sec = 2e-3/3600 t_sec = np.linspace(0, 24*3600) C0_mol_p_m3 = [3000, 4000] Cref_mol_p_m3 = np.empty(integr.Cout.squeeze().shape) Cref_mol_p_m3[:, 0] = 1/(C0_mol_p_m3[0]**-1 + 2*k_m3_p_mol_p_sec*t_sec) missing_A = (C0_mol_p_m3[0] - Cref_mol_p_m3[:, 0]) Cref_mol_p_m3[:, 1] = C0_mol_p_m3[1] + missing_A/2 assert allclose(integr.with_units('tout'), t_sec*u.s) assert allclose(integr.with_units('Cout').squeeze(), Cref_mol_p_m3*u.mol/u.metre**3, rtol=1e-6)
def test_TPiecewise(): expr0 = ShiftedTPoly( [273.15 * u.K, 10 / u.molar / u.s, 0.1 / u.molar / u.s / u.K]) expr1 = ShiftedTPoly([ 298.15 * u.K, 12.5 / u.molar / u.s, 0 / u.molar / u.s / u.K, 2 / u.molar / u.s / u.K**2, ]) pwma = MassAction( TPiecewise([273.15 * u.K, expr0, 298.15 * u.K, expr1, 373.15 * u.K])) r = Reaction({"e-(aq)": 2}, {"H2": 1, "OH-": 2}, inact_reac={"H2O": 2}) res0 = pwma({ "temperature": 293.15 * u.K, "e-(aq)": 1e-13 * u.molar }, reaction=r) ref0 = 12 * 1e-26 * u.molar / u.s assert allclose(res0, ref0) assert not allclose(res0, 2 * ref0) res1 = pwma({ "temperature": 300.15 * u.K, "e-(aq)": 2e-13 * u.molar }, reaction=r) ref1 = 20.5 * 4e-26 * u.molar / u.s assert allclose(res1, ref1) assert not allclose(res1, ref1 / 2)
def test_Expr_dedimensionalisation__2(): Poly = Expr.from_callback(_poly, parameter_keys=('E', ), argument_names=('x0', Ellipsis)) T = Poly([3 * u.J, 7 * u.K, 5 * u.K / u.J]) T = Poly([0.7170172084130019 * u.cal, 12.6 * u.Rankine, 5 * u.K / u.J]) _ref = 0.8108020083055849 # Al at 273.15 K with R=8.3145 cv_Al = _get_cv(u.kelvin, u.gram, u.mol)['Al'] assert isinstance(cv_Al, EinsteinSolid) assert cv_Al.args[0] == 0.806 * 428 * u.kelvin assert abs( cv_Al({ 'temperature': 273.15 * u.K, 'molar_gas_constant': 8.3145 * u.J / u.K / u.mol }) - _ref * u.J / u.gram / u.kelvin) < 1e-14 cv_Al_units, Al_dedim = cv_Al.dedimensionalisation(SI_base_registry) assert allclose(cv_Al_units, [u.K, u.kg / u.mol]) assert isinstance(Al_dedim, EinsteinSolid) T_units, dT = T.dedimensionalisation(SI_base_registry) assert allclose(T_units, [u.J, u.K, u.K / u.J]) assert allclose(dT.args, [3, 7, 5]) assert abs( Al_dedim({ 'temperature': 273.15, 'molar_gas_constant': 8.3145 }) - _ref * 1000) < 1e-14 assert abs( Al_dedim({ 'temperature': dT, 'E': (273.15 - 7) / 5 + 3, 'molar_gas_constant': 8.3145 }) - _ref * 1000) < 1e-14
def test_integrate_nondimensionalisation__g_values(from_rsys): from chempy import Reaction, ReactionSystem from chempy.units import allclose, default_units as u rstr = "-> H + OH; Radiolytic({'radiolytic_yield': 2.1e-7*mol/J})" if from_rsys: rxn = Reaction.from_string(rstr, None) rsys = ReactionSystem([rxn], 'H OH') rd = ReactionDiffusion.from_ReactionSystem( rsys, unit_registry=SI_base_registry, variables=dict(doserate=0.15*u.Gy/u.s, density=0.998*u.kg/u.dm3)) assert rd.g_value_parents == [-1] assert rd.g_values == [[2.1e-7]*2] assert abs(rd.fields[0][0] - 0.15*998) < 1e-14 else: rd = ReactionDiffusion.nondimensionalisation( 2, [[]], [[0, 1]], [2.1e-7*0.15*0.998*u.molar/u.second], unit_registry=SI_base_registry) C0 = [3*molar, 4*molar] tout = np.linspace(0, 1)*day integr = Integration(rd, C0, tout, integrator='scipy') k_m3_p_mol_p_sec = 0.15*998*2.1e-7 t_sec = np.linspace(0, 24*3600) C0_mol_p_m3 = [3000, 4000] Cref_mol_p_m3 = np.empty(integr.Cout.squeeze().shape) Cref_mol_p_m3[:, 0] = C0_mol_p_m3[0] + k_m3_p_mol_p_sec*t_sec Cref_mol_p_m3[:, 1] = C0_mol_p_m3[1] + k_m3_p_mol_p_sec*t_sec print(integr.with_units('Cout').squeeze()) print(integr.with_units('Cout').squeeze() - Cref_mol_p_m3*u.mole/u.metre**3) assert allclose(integr.with_units('tout'), t_sec*u.s) assert allclose(integr.with_units('Cout').squeeze(), Cref_mol_p_m3*u.mole/u.metre**3)
def test_water_density(): warnings.filterwarnings("error") assert abs(water_density(273.15 + 0) - 999.8395) < 0.004 assert abs(water_density(273.15 + 4) - 999.9720) < 0.003 assert abs(water_density(273.15 + 10) - 999.7026) < 0.0003 assert abs(water_density(273.15 + 15) - 999.1026) < 0.0001 assert abs(water_density(273.15 + 20) - 998.2071) < 0.0005 assert abs(water_density(273.15 + 22) - 997.7735) < 0.0007 assert abs(water_density(273.15 + 25) - 997.0479) < 0.0009 assert abs(water_density(273.15 + 30) - 995.6502) < 0.0016 assert abs(water_density(273.15 + 40) - 992.2) < 0.02 try: water_density(1) except UserWarning: pass # good warning raised else: raise warnings.resetwarnings() try: import quantities as pq import numpy as np unit = pq.kg / pq.m**3 assert allclose(water_density(298.15 * pq.K, units=pq), 997.047021671824 * unit, atol=1e-8 * unit) assert allclose(water_density(np.linspace(297, 299) * pq.K, units=pq), 997 * unit, rtol=1e-3, atol=1e-3 * unit) except ImportError: pass
def test_water_self_diffusion_coefficient(): warnings.filterwarnings("error") assert abs(w_sd(273.15 + 0.) - 1.099e-9) < 0.027e-9 assert abs(w_sd(273.15 + 4.) - 1.261e-9) < 0.011e-9 assert abs(w_sd(273.15 + 10) - 1.525e-9) < 0.007e-9 assert abs(w_sd(273.15 + 15) - 1.765e-9) < 0.006e-9 assert abs(w_sd(273.15 + 20) - 2.023e-9) < 0.001e-9 assert abs(w_sd(273.15 + 25) - 2.299e-9) < 0.001e-9 assert abs(w_sd(273.15 + 30) - 2.594e-9) < 0.001e-9 assert abs(w_sd(273.15 + 35) - 2.907e-9) < 0.004e-9 try: w_sd(1) except UserWarning: pass # good warning raised else: raise warnings.resetwarnings() try: import quantities as pq import numpy as np unit = pq.m**2/pq.s assert allclose(1e9*w_sd(298.15*pq.K, units=pq), 2.299*unit, rtol=1e-3, atol=1e-8*unit) assert allclose(1e9*w_sd(np.linspace(297, 299)*pq.K, units=pq), 2.299*pq.m**2/pq.s, rtol=5e-2, atol=1e-2*unit) except ImportError: pass
def test_water_permittivity__units(): assert allclose(water_permittivity(298.15 * u.K, 1 * u.bar, units=u), 78.38436874203077) assert allclose( water_permittivity(linspace(297.5, 298.65) * u.K, 1 * u.bar, units=u), 78, rtol=1e-2, atol=1e-2, )
def test_chained_parameter_variation_from_ReactionSystem(): g_E_mol_J = 2.1e-7 rsys = ReactionSystem.from_string( """ (H2O) -> e-(aq) + H+ + OH; Radiolytic(%.2e*mol/J) 2 OH -> H2O2; 3.6e9/M/s H+ + OH- -> H2O; 1.4e11/M/s H2O -> H+ + OH-; 1.4e-3/s N2O + e-(aq) -> N2 + O-; 9.6e9/M/s O- + H+ -> OH; 1e11/M/s """ % g_E_mol_J # neglecting a large body of reactions (just a test-case after all) ) ureg = SI_base_registry field_u = get_derived_unit(ureg, 'doserate') * get_derived_unit(ureg, 'density') rd = ReactionDiffusion.from_ReactionSystem(rsys, fields=[[0*field_u]], unit_registry=ureg, param_names=['doserate']) dens_kg_dm3 = 0.998 odesys = rd._as_odesys( variables_from_params=dict( density=lambda self, params: dens_kg_dm3*1e3*u.kg/u.m**3 ) ) npoints = 5 durations = [59*u.second, 42*u.minute, 2*u.hour] doserates = [135*u.Gy/u.s, 11*u.Gy/u.s, 180*u.Gy/u.minute] M = u.molar ic = defaultdict(lambda: 0*M, {'H2O': 55.4*M, 'H+': 1e-7*M, 'OH-': 1e-7*M, 'N2O': 20e-3*M}) result = odesys.chained_parameter_variation(durations, ic, {'doserate': doserates}, npoints=npoints) ref_xout_s = [0] for dur in map(lambda dur: to_unitless(dur, u.s), durations): ref_xout_s += list(np.linspace(ref_xout_s[-1], ref_xout_s[-1] + dur, npoints+1)[1:]) assert allclose(result.xout, ref_xout_s*u.s) N2_M = to_unitless(result.named_dep('N2'), u.M) H2O2_M = to_unitless(result.named_dep('H2O2'), u.M) e_accum_molar = 0 for i, (dur, dr) in enumerate(zip(durations, doserates)): dur_s = to_unitless(dur, u.s) dr_Gy_s = to_unitless(dr, u.Gy/u.s) local_ts = np.linspace(0, dur_s, npoints+1) # local_ic = {k: result.named_dep(k)[i*npoints] for k in odesys.names} for j, (lt, ld) in enumerate(zip(local_ts[1:], np.diff(local_ts))): e_accum_molar += ld*g_E_mol_J*dr_Gy_s*dens_kg_dm3 assert abs(N2_M[i*npoints + j + 1] - e_accum_molar)/e_accum_molar < 1e-3 assert abs(H2O2_M[i*npoints + j + 1] - e_accum_molar)/e_accum_molar < 1e-3 res2 = odesys.integrate(durations[0], ic, {'doserate': doserates[0]}, integrator='cvode') dr2 = res2.params[res2.odesys.param_names.index('doserate')] assert np.asarray(res2.params).shape[-1] == len(odesys.param_names) assert allclose(dr2, doserates[0]) assert allclose(res2.xout[-1], durations[0]) assert allclose(res2.named_dep('N2')[-1], durations[0]*doserates[0]*g_E_mol_J*u.mol/u.J*dens_kg_dm3*u.kg/u.dm3) to_unitless(res2.xout, u.s) to_unitless(res2.yout, u.molar) to_unitless(dr2, u.Gy/u.s)
def test_MassAction__expression(): class GibbsExpr(Expr): parameter_keys = ("temperature", ) argument_names = tuple("dS_over_R dCp_over_R dH_over_R Tref".split()) def __call__(self, variables, backend=patched_numpy, **kwargs): am = dict( zip( self.argument_names, map(simplified, self.all_args(variables, backend=backend)), )) (T, ) = self.all_params(variables, backend=backend) return (backend.exp(am["dS_over_R"]) * (T / am["Tref"])**am["dCp_over_R"] * backend.exp(-am["dH_over_R"] / T)) GeNH3 = GibbsExpr( dict( dS_over_R=18.8 * u.cal / u.K / u.mol / default_constants.molar_gas_constant, # NOQA dCp_over_R=52 * u.cal / u.K / u.mol / default_constants.molar_gas_constant, # NOQA dH_over_R=-0.87e3 * u.cal / u.mol / default_constants.molar_gas_constant, # NOQA Tref=298.15 * u.K, # NOQA )) reac_prod = {"NH3": 1, "H2O": 1}, {"NH4+": 1, "OH-": 1} Equilibrium(*reac_prod, GeNH3).check_consistent_units(throw=True) Equilibrium(*reac_prod[::-1], 1 / GeNH3).check_consistent_units(throw=True) Ea = 40e3 * u.J / u.mol R = default_constants.molar_gas_constant A, Ea_over_R = 1.2e11 / u.molar**2 / u.second, Ea / R arrh = Arrhenius([A, Ea_over_R]) ama = MassAction(arrh) ma_mul_expr = ama * GeNH3 ma_div_expr = ama / GeNH3 expr_mul_ma = GeNH3 * ama expr_div_ma = GeNH3 / ama assert all( isinstance(expr, MassAction) for expr in [ma_mul_expr, ma_div_expr, expr_mul_ma, expr_div_ma]) Reaction(*reac_prod, ama).check_consistent_units(throw=True) Reaction(*reac_prod[::-1], 42 * ma_div_expr).check_consistent_units(throw=True) Reaction(*reac_prod[::-1], 42 / u.M / u.s / GeNH3).check_consistent_units(throw=True) varbls = {"temperature": 298.15 * u.K} r_ama, r_GeNH3 = ama.rate_coeff(varbls), GeNH3(varbls) assert allclose(ma_mul_expr.rate_coeff(varbls), r_ama * r_GeNH3) assert allclose(ma_div_expr.rate_coeff(varbls), r_ama / r_GeNH3) assert allclose(expr_mul_ma.rate_coeff(varbls), r_GeNH3 * r_ama) assert allclose(expr_div_ma.rate_coeff(varbls), r_GeNH3 / r_ama)
def test_water_self_diffusion_coefficient__units(): from chempy.units import allclose, linspace, default_units as u unit = u.m**2 / u.s assert allclose(1e9 * w_sd(298.15 * u.K, units=u), 2.299 * unit, rtol=1e-3, atol=1e-8 * unit) assert allclose(1e9 * w_sd(linspace(297, 299) * u.K, units=u), 2.299 * u.m**2 / u.s, rtol=5e-2, atol=1e-2 * unit)
def test_MassAction__rate_coeff(): perMolar_perSecond = u.perMolar_perSecond p1 = MassAction(Constant(perMolar_perSecond) * 10**RTPoly([1, 2*u.kelvin, 3*u.kelvin**2])) rcoeff1 = p1.rate_coeff({'temperature': 283.15*u.K}) ref1 = 10**(1 + 2/283.15 + 3/283.15**2) * perMolar_perSecond assert allclose(rcoeff1, ref1) rxn1 = Reaction({'A', 'B'}, {'C'}, p1) rat1 = rxn1.rate({'A': 2, 'B': 3, 'temperature': 283.15*u.K}) assert allclose(rat1['A'], -2*3*ref1) assert allclose(rat1['B'], -2*3*ref1) assert allclose(rat1['C'], 2*3*ref1)
def test_TPiecewise(): expr0 = ShiftedTPoly([273.15*u.K, 10/u.molar/u.s, 0.1/u.molar/u.s/u.K]) expr1 = ShiftedTPoly([298.15*u.K, 12.5/u.molar/u.s, 0/u.molar/u.s/u.K, 2/u.molar/u.s/u.K**2]) pwma = MassAction(TPiecewise([273.15*u.K, expr0, 298.15*u.K, expr1, 373.15*u.K])) r = Reaction({'e-(aq)': 2}, {'H2': 1, 'OH-': 2}, inact_reac={'H2O': 2}) res0 = pwma({'temperature': 293.15*u.K, 'e-(aq)': 1e-13*u.molar}, reaction=r) ref0 = 12*1e-26 * u.molar/u.s assert allclose(res0, ref0) assert not allclose(res0, 2*ref0) res1 = pwma({'temperature': 300.15*u.K, 'e-(aq)': 2e-13*u.molar}, reaction=r) ref1 = 20.5*4e-26 * u.molar/u.s assert allclose(res1, ref1) assert not allclose(res1, ref1/2)
def test_MassAction__rate_coeff(): perMolar_perSecond = u.perMolar_perSecond p1 = MassAction( Constant(perMolar_perSecond) * 10**RTPoly([1, 2 * u.kelvin, 3 * u.kelvin**2])) rcoeff1 = p1.rate_coeff({"temperature": 283.15 * u.K}) ref1 = 10**(1 + 2 / 283.15 + 3 / 283.15**2) * perMolar_perSecond assert allclose(rcoeff1, ref1) rxn1 = Reaction({"A", "B"}, {"C"}, p1) rat1 = rxn1.rate({"A": 2, "B": 3, "temperature": 283.15 * u.K}) assert allclose(rat1["A"], -2 * 3 * ref1) assert allclose(rat1["B"], -2 * 3 * ref1) assert allclose(rat1["C"], 2 * 3 * ref1)
def test_ShiftedTPoly__units(): stp1 = ShiftedTPoly([273.15*u.kelvin, 5, 7/u.kelvin]) allclose(stp1({'temperature': 274.15*u.kelvin}), 5+7) allclose(stp1({'temperature': 273.15*u.kelvin}), 5) stp2 = ShiftedTPoly([273.15*u.kelvin, 5*u.m, 7*u.m/u.kelvin, 13*u.m*u.kelvin**-2]) allclose(stp2({'temperature': 274.15*u.kelvin}), (5+7+13)*u.m) allclose(stp2({'temperature': 273.15*u.kelvin}), 5*u.m)
def test_decompose_yields__units_1(): from chempy import Reaction from chempy.units import default_units as u gamma_yields = { 'OH-': 0.5*u.per100eV, 'H2O2': 0.7*u.per100eV, 'OH': 2.7*u.per100eV, 'H2': 0.45*u.per100eV, 'H': 0.66*u.per100eV, 'H+': 3.1*u.per100eV, 'HO2': 0.02*u.per100eV, 'e-(aq)': 2.6*u.per100eV, } rxns = [ Reaction({'H2O': 1}, {'H+': 1, 'OH-': 1}), Reaction({'H2O': 1}, {'H+': 1, 'e-(aq)': 1, 'OH': 1}), Reaction({'H2O': 1}, {'H': 2, 'H2O2': 1}, inact_reac={'H2O': 1}), Reaction({'H2O': 1}, {'H2': 1, 'H2O2': 1}, inact_reac={'H2O': 1}), Reaction({'H2O': 1}, {'H2': 1, 'OH': 2}, inact_reac={'H2O': 1}), Reaction({'H2O': 1}, {'H2': 3, 'HO2': 2}, inact_reac={'H2O': 3}), ] k = decompose_yields(gamma_yields, rxns) k_ref = [0.5, 2.6, 0.33, 0.37, 0.05, 0.01]*u.per100eV assert allclose(k, k_ref) G_H2O = [rxn.net_stoich(['H2O'])[0]*k[i] for i, rxn in enumerate(rxns)] ref = 4.64*u.per100eV assert abs((_sum(G_H2O)+ref)/ref) < 1e-3
def test_create_odesys__ShiftedTPoly(): rxn = Reaction({'A': 1, 'B': 1}, {'C': 3, 'D': 2}, 'k_bi', {'A': 3}) rsys = ReactionSystem([rxn], 'A B C D') _k0, _k1, T0C = 10, 2, 273.15 rate = MassAction(ShiftedTPoly([T0C*u.K, _k0/u.molar/u.s, _k1/u.molar/u.s/u.K])) T_C = 25 T = (T0C+T_C)*u.kelvin p1 = rate.rate_coeff({'temperature': T}) assert allclose(p1, (_k0 + _k1*T_C)/u.molar/u.s) odesys, odesys_extra = create_odesys(rsys) ics = {'A': 3*u.molar, 'B': 5*u.molar, 'C': 11*u.molar, 'D': 13*u.molar} pars = dict(k_bi=p1) validation = odesys_extra['validate'](dict(ics, **pars)) assert set(map(str, validation['not_seen'])) == {'C', 'D'} dedim_ctx = _mk_dedim(SI_base_registry) (t, c, _p), dedim_extra = dedim_ctx['dedim_tcp'](-37*u.s, [ics[k] for k in odesys.names], pars) fout = odesys.f_cb(t, c, [_p[pk] for pk in odesys.param_names]) r = 3*5*(_k0 + _k1*25)*1000 # mol/m3/s ref = [-4*r, -r, 3*r, 2*r] assert np.all(abs((fout - ref)/ref) < 1e-14) odesys.integrate(t, c, _p)
def test_get_native__conc_roots(): M, s = u.M, u.s rsys = ReactionSystem.from_string("2 O3 -> 3 O2; 'k2'") u_reg = SI_base_registry.copy() odesys, extra = get_odesys(rsys, include_params=False, unit_registry=u_reg) c0 = {"O3": 4.2e-3 * M, "O2": 0 * M} cr = ["O2"] native = get_native(rsys, odesys, "cvode", conc_roots=cr) tend = 1e5 * u.s params = {"k2": logspace_from_lin(1e-3 / M / s, 1e3 / M / s, 14)} tgt_O2 = 1e-3 * M results = native.integrate( tend, c0, params, integrator="native", return_on_root=True, special_settings=[unitless_in_registry(tgt_O2, u_reg)], ) assert len(results) == params["k2"].size # dydt = -p*y**2 # 1/y0 - 1/y = -2*pt # t = 1/2/p*(1/y - 1/y0) tgt_O3 = c0["O3"] - 2 / 3 * tgt_O2 for r in results: ref = rescale( 1 / 2 / r.named_param("k2") * (1 / tgt_O3 - 1 / c0["O3"]), u.s) assert allclose(r.xout[-1], ref, rtol=1e-6)
def test_get_odesys__with_units(): a = Substance('A') b = Substance('B') molar = u.molar second = u.second r = Reaction({'A': 2}, {'B': 1}, param=1e-3/molar/second) rsys = ReactionSystem([r], [a, b]) odesys = get_odesys(rsys, include_params=True, unit_registry=SI_base_registry)[0] c0 = { 'A': 13*u.mol / u.metre**3, 'B': .2 * u.molar } conc_unit = get_derived_unit(SI_base_registry, 'concentration') t = np.linspace(0, 10)*u.hour xout, yout, info = odesys.integrate( t, rsys.as_per_substance_array(c0, unit=conc_unit), atol=1e-10, rtol=1e-12) t_unitless = to_unitless(xout, u.second) Aref = dimerization_irrev(t_unitless, 1e-6, 13.0) # Aref = 1/(1/13 + 2*1e-6*t_unitless) yref = np.zeros((xout.size, 2)) yref[:, 0] = Aref yref[:, 1] = 200 + (13-Aref)/2 assert allclose(yout, yref*conc_unit)
def test_get_odesys__with_units(): a = Substance('A') b = Substance('B') molar = u.molar second = u.second r = Reaction({'A': 2}, {'B': 1}, param=1e-3/molar/second) rsys = ReactionSystem([r], [a, b]) odesys = get_odesys(rsys, include_params=True, unit_registry=SI_base_registry)[0] c0 = { 'A': 13*u.mol / u.metre**3, 'B': .2 * u.molar } conc_unit = get_derived_unit(SI_base_registry, 'concentration') t = np.linspace(0, 10)*u.hour xout, yout, info = odesys.integrate( t, rsys.as_per_substance_array(c0, unit=conc_unit), atol=1e-10, rtol=1e-12) t_unitless = to_unitless(xout, u.second) Aref = dimerization_irrev(t_unitless, 1e-6, 13.0) # Aref = 1/(1/13 + 2*1e-6*t_unitless) yref = np.zeros((xout.size, 2)) yref[:, 0] = Aref yref[:, 1] = 200 + (13-Aref)/2 print((yout - yref*conc_unit)/yout) assert allclose(yout, yref*conc_unit)
def test_ArrheniusMassAction__units(R_from_constants): import numpy as np Ea = 40e3 * u.J / u.mol R = (default_constants.molar_gas_constant if R_from_constants else (8.3145 * u.J / u.mol / u.K)) A, Ea_over_R = 1.2e11 / u.molar**2 / u.second, Ea / R ref1 = A * np.exp(-to_unitless(Ea_over_R / (290 * u.K))) arrh = Arrhenius([A, Ea_over_R]) assert allclose(arrh({"temperature": 290 * u.K}), ref1) ama = MassAction(arrh) r = Reaction({"A": 2, "B": 1}, {"C": 1}, ama, {"B": 1}) T_ = "temperature" def ref(v): return (1.2e11 / u.molar**2 / u.second * math.exp(-Ea_over_R.simplified / v[T_]) * v["B"] * v["A"]**2) ma = r.rate_expr() for params in [ (11.0 * u.molar, 13.0 * u.molar, 17.0 * u.molar, 311.2 * u.kelvin), (12 * u.molar, 8 * u.molar, 5 * u.molar, 270 * u.kelvin), ]: var = dict(zip(["A", "B", "C", T_], params)) ref_val = ref(var) assert abs((ma(var, reaction=r) - ref_val) / ref_val) < 1e-14
def test_Expr__single_arg__units(): p = Pressure1(3 * u.mol) variables = { 'temperature': 273.15 * u.kelvin, 'volume': 170 * u.dm3, 'R': 8.314 * u.J / u.K / u.mol } assert allclose(p(variables), 3 * 8.314 * 273.15 / 0.17 * u.Pa)
def test_Expr__single_arg__units(): p = Pressure1(3 * u.mol) variables = { "temperature": 273.15 * u.kelvin, "volume": 170 * u.dm3, "R": 8.314 * u.J / u.K / u.mol, } assert allclose(p(variables), 3 * 8.314 * 273.15 / 0.17 * u.Pa)
def test_MassAction__expression(): class GibbsExpr(Expr): parameter_keys = ('temperature', ) argument_names = tuple("dS_over_R dCp_over_R dH_over_R Tref".split()) def __call__(self, variables, backend=patched_numpy, **kwargs): am = dict( zip(self.argument_names, map(simplified, self.all_args(variables, backend=backend)))) T, = self.all_params(variables, backend=backend) return backend.exp(am['dS_over_R']) * ( T / am['Tref'])**am['dCp_over_R'] * backend.exp( -am['dH_over_R'] / T) GeNH3 = GibbsExpr( dict( dS_over_R=18.8 * u.cal / u.K / u.mol / default_constants.molar_gas_constant, # NOQA dCp_over_R=52 * u.cal / u.K / u.mol / default_constants.molar_gas_constant, # NOQA dH_over_R=-0.87e3 * u.cal / u.mol / default_constants.molar_gas_constant, # NOQA Tref=298.15 * u.K # NOQA )) Ea = 40e3 * u.J / u.mol R = default_constants.molar_gas_constant A, Ea_over_R = 1.2e11 / u.molar**2 / u.second, Ea / R arrh = Arrhenius([A, Ea_over_R]) ama = MassAction(arrh) ma_mul_expr = ama * GeNH3 ma_div_expr = ama / GeNH3 expr_mul_ma = GeNH3 * ama expr_div_ma = GeNH3 / ama assert all( isinstance(expr, MassAction) for expr in [ma_mul_expr, ma_div_expr, expr_mul_ma, expr_div_ma]) varbls = {'temperature': 298.15 * u.K} r_ama, r_GeNH3 = ama.rate_coeff(varbls), GeNH3(varbls) assert allclose(ma_mul_expr.rate_coeff(varbls), r_ama * r_GeNH3) assert allclose(ma_div_expr.rate_coeff(varbls), r_ama / r_GeNH3) assert allclose(expr_mul_ma.rate_coeff(varbls), r_GeNH3 * r_ama) assert allclose(expr_div_ma.rate_coeff(varbls), r_GeNH3 / r_ama)
def test_MassAction__subclass_from_callback__units(): def rate_coeff(variables, all_args, backend): return all_args[0]*backend.exp(all_args[1]/variables['temperature']) CustomMassAction = MassAction.subclass_from_callback( rate_coeff, cls_attrs=dict(parameter_keys=('temperature',), nargs=2)) k1 = CustomMassAction([2.1e10/u.molar**2/u.second, -5132.2*u.kelvin], rxn=Reaction({'H2': 2, 'O2': 1}, {'H2O': 2})) res = k1({'temperature': 491.67*u.rankine, 'H2': 7000*u.mol/u.metre**3, 'O2': 13*u.molar}, backend=Backend()) ref = 7*7*13*2.1e10*math.exp(-5132.2/273.15) * u.molar/u.second assert allclose(res, ref)
def test_EyringParamWithUnits(): mol = u.mol J = u.joule K = u.kelvin T = 273.15*K k = EyringParamWithUnits(42e3 * J/mol, 123*J/mol/K)(T) ref = _kB_over_h * 273.15 * math.exp(123/_R) * math.exp(-42e3/_R/273.15) ref /= u.second assert allclose(k, ref)
def test_GibbsEqConst__units(): R, T = dc.molar_gas_constant, 298.15 * du.K DH = -4e3 * du.J / du.mol DS = 16 * du.J / du.K / du.mol be = Backend() gee = GibbsEqConst([DH / R, DS / R]) res = gee.eq_const({'temperature': T}, backend=be) ref = be.exp(-(DH - T * DS) / (R * T)) assert allclose(res, ref)
def test_GibbsEquilibriumConstant__units(): R, T = dc.molar_gas_constant, 298.15*du.K DH = -4e3 * du.J/du.mol DS = 16 * du.J/du.K/du.mol be = Backend() gee = GibbsEquilibriumConstant([DH/R, DS/R]) res = gee({'temperature': T}, backend=be) ref = be.exp(-(DH - T*DS)/(R*T)) assert allclose(res, ref)
def test_Expr__single_arg__units__dimensionality(): p = Pressure2(unique_keys=("n1", )) variables = { "temperature": 273.15 * u.kelvin, "volume": 170 * u.dm3, "R": 8.314 * u.J / u.K / u.mol, } assert allclose(p(dict(n1=3 * u.mol, **variables)), 3 * 8.314 * 273.15 / 0.17 * u.Pa)
def test_Expr__single_arg__units__dimensionality(): p = Pressure2(unique_keys=('n1', )) variables = { 'temperature': 273.15 * u.kelvin, 'volume': 170 * u.dm3, 'R': 8.314 * u.J / u.K / u.mol } assert allclose(p(dict(n1=3 * u.mol, **variables)), 3 * 8.314 * 273.15 / 0.17 * u.Pa)
def test_TPiecewise(): expr0 = TPolyMassAction( [273.15 * u.K, 10 / u.molar / u.s, 0.1 / u.molar / u.s / u.K]) expr1 = TPolyMassAction([ 298.15 * u.K, 12.5 / u.molar / u.s, 0 / u.molar / u.s / u.K, 2 / u.molar / u.s / u.K**2 ]) pw = TPiecewise( [273.15 * u.K, 298.15 * u.K, expr0, 298.15 * u.K, 373.15 * u.K, expr1]) Reaction({'e-(aq)': 2}, {'H2': 1, 'OH-': 2}, pw, {'H2O': 2}) res0 = pw({'temperature': 293.15 * u.K, 'e-(aq)': 1e-13 * u.molar}) ref0 = 12 * 1e-26 * u.molar / u.s assert allclose(res0, ref0) assert not allclose(res0, 2 * ref0) res1 = pw({'temperature': 300.15 * u.K, 'e-(aq)': 2e-13 * u.molar}) ref1 = 20.5 * 4e-26 * u.molar / u.s assert allclose(res1, ref1) assert not allclose(res1, ref1 / 2)
def test_ArrheniusParamWithUnits(): _2 = _get_ref2_units() ap = ArrheniusParamWithUnits(_2.A, _2.Ea) k = ap(_2.T) assert abs((k - _2.k)/_2.k) < 1e-4 r = Reaction({'H2O2': 1}, {'OH': 2}, ap) ratc = r.rate_expr().rate_coeff({'temperature': _2.T}) assert allclose(ratc, _2.k, rtol=1e-4)
def test_SpecialFraction_with_units(): k, kprime = 3.142 * u.s**-1 * u.molar**-0.5, 2.718 rsys = _get_SpecialFraction_rsys(k, kprime) odesys = get_odesys(rsys, include_params=True, unit_registry=SI_base_registry)[0] c0 = {'H2': 13*u.molar, 'Br2': 16*u.molar, 'HBr': 19*u.molar} r = k*c0['H2']*c0['Br2']**(3/2)/(c0['Br2'] + kprime*c0['HBr']) conc_unit = u.mol/u.metre**3 rate_unit = conc_unit/u.second ref = rsys.as_per_substance_array({'H2': -r, 'Br2': -r, 'HBr': 2*r}, unit=rate_unit) res = odesys.f_cb(0, rsys.as_per_substance_array(c0, unit=conc_unit)) assert allclose(to_unitless(ref, rate_unit), res)
def test_Expr_dedimensionalisation__2(): Poly = Expr.from_callback(_poly, parameter_keys=('E',), argument_names=('x0', Ellipsis)) T = Poly([3*u.J, 7*u.K, 5*u.K/u.J]) T = Poly([0.7170172084130019*u.cal, 12.6*u.Rankine, 5*u.K/u.J]) _ref = 0.8108020083055849 # Al at 273.15 K with R=8.3145 cv_Al = _get_cv(u.kelvin, u.gram, u.mol)['Al'] assert isinstance(cv_Al, EinsteinSolid) assert cv_Al.args[0] == 0.806*428*u.kelvin assert abs(cv_Al({'temperature': 273.15*u.K, 'molar_gas_constant': 8.3145*u.J/u.K/u.mol}) - _ref*u.J/u.gram/u.kelvin) < 1e-14 cv_Al_units, Al_dedim = cv_Al.dedimensionalisation(SI_base_registry) assert allclose(cv_Al_units, [u.K, u.kg/u.mol]) assert isinstance(Al_dedim, EinsteinSolid) T_units, dT = T.dedimensionalisation(SI_base_registry) assert allclose(T_units, [u.J, u.K, u.K/u.J]) assert allclose(dT.args, [3, 7, 5]) assert abs(Al_dedim({'temperature': 273.15, 'molar_gas_constant': 8.3145}) - _ref*1000) < 1e-14 assert abs(Al_dedim({'temperature': dT, 'E': (273.15-7)/5 + 3, 'molar_gas_constant': 8.3145}) - _ref*1000) < 1e-14
def test_Expr__single_arg__units(): class Pressure(Expr): argument_names = ('n',) parameter_keys = ('temperature', 'volume', 'R') def __call__(self, variables, backend=None): n, = self.all_args(variables, backend=backend) T, V, R = self.all_params(variables, backend=backend) return n*R*T/V p = Pressure(3*u.mol) variables = {'temperature': 273.15*u.kelvin, 'volume': 170*u.dm3, 'R': 8.314*u.J/u.K/u.mol} assert allclose(p(variables), 3*8.314*273.15/0.17*u.Pa)
def test_decompose_yields__units_1(): from chempy import Reaction from chempy.units import default_units as u gamma_yields = { "OH-": 0.5 * u.per100eV, "H2O2": 0.7 * u.per100eV, "OH": 2.7 * u.per100eV, "H2": 0.45 * u.per100eV, "H": 0.66 * u.per100eV, "H+": 3.1 * u.per100eV, "HO2": 0.02 * u.per100eV, "e-(aq)": 2.6 * u.per100eV, } rxns = [ Reaction({"H2O": 1}, { "H+": 1, "OH-": 1 }), Reaction({"H2O": 1}, { "H+": 1, "e-(aq)": 1, "OH": 1 }), Reaction({"H2O": 1}, { "H": 2, "H2O2": 1 }, inact_reac={"H2O": 1}), Reaction({"H2O": 1}, { "H2": 1, "H2O2": 1 }, inact_reac={"H2O": 1}), Reaction({"H2O": 1}, { "H2": 1, "OH": 2 }, inact_reac={"H2O": 1}), Reaction({"H2O": 1}, { "H2": 3, "HO2": 2 }, inact_reac={"H2O": 3}), ] k = decompose_yields(gamma_yields, rxns) k_ref = [0.5, 2.6, 0.33, 0.37, 0.05, 0.01] * u.per100eV assert allclose(k, k_ref) G_H2O = [rxn.net_stoich(["H2O"])[0] * k[i] for i, rxn in enumerate(rxns)] ref = 4.64 * u.per100eV assert abs((_sum(G_H2O) + ref) / ref) < 1e-3
def test_decompose_yields__units_1(): from chempy import Reaction from chempy.units import default_units as u gamma_yields = { 'OH-': 0.5 * u.per100eV, 'H2O2': 0.7 * u.per100eV, 'OH': 2.7 * u.per100eV, 'H2': 0.45 * u.per100eV, 'H': 0.66 * u.per100eV, 'H+': 3.1 * u.per100eV, 'HO2': 0.02 * u.per100eV, 'e-(aq)': 2.6 * u.per100eV, } rxns = [ Reaction({'H2O': 1}, { 'H+': 1, 'OH-': 1 }), Reaction({'H2O': 1}, { 'H+': 1, 'e-(aq)': 1, 'OH': 1 }), Reaction({'H2O': 1}, { 'H': 2, 'H2O2': 1 }, inact_reac={'H2O': 1}), Reaction({'H2O': 1}, { 'H2': 1, 'H2O2': 1 }, inact_reac={'H2O': 1}), Reaction({'H2O': 1}, { 'H2': 1, 'OH': 2 }, inact_reac={'H2O': 1}), Reaction({'H2O': 1}, { 'H2': 3, 'HO2': 2 }, inact_reac={'H2O': 3}), ] k = decompose_yields(gamma_yields, rxns) k_ref = [0.5, 2.6, 0.33, 0.37, 0.05, 0.01] * u.per100eV assert allclose(k, k_ref) G_H2O = [rxn.net_stoich(['H2O'])[0] * k[i] for i, rxn in enumerate(rxns)] ref = 4.64 * u.per100eV assert abs((_sum(G_H2O) + ref) / ref) < 1e-3
def test_ArrheniusParamWithUnits(): s = u.second mol = u.mol J = u.joule K = u.kelvin act_J__mol = 42e3 ap = ArrheniusParamWithUnits(1e10 / s, act_J__mol * J / mol) freezing_K = 273.15 k = ap(freezing_K * K) ref = 1e10 / s * math.exp(-act_J__mol / (8.3145 * freezing_K)) assert abs((k - ref) / ref) < 1e-4 r = Reaction({'H2O2': 1}, {'OH': 2}, ap) ratc = r.rate_expr().rate_coeff({'temperature': freezing_K * u.K}) assert allclose(ratc, ref, rtol=1e-4)
def test_get_odesys__time_dep_temperature(): import sympy as sp def refA(t, A0, A, Ea_over_R, T0, dTdt): T = (T0 + dTdt * t) d_Ei = sp.Ei(-Ea_over_R / T0).n(100).round(90) - sp.Ei( -Ea_over_R / T).n(100).round(90) d_Texp = T0 * sp.exp(-Ea_over_R / T0) - T * sp.exp(-Ea_over_R / T) return A0 * sp.exp(A / dTdt * (Ea_over_R * d_Ei + d_Texp)).n(30) params = A0, A, Ea_over_R, T0, dTdt = [13, 1e10, 56e3 / 8, 273, 2] B0 = 11 rate = MassAction(Arrhenius([A, Ea_over_R])) rxn = Reaction({'A': 1}, {'B': 3}, rate) rsys = ReactionSystem([rxn], 'A B') rt = RampedTemp([T0, dTdt], ('init_temp', 'ramp_rate')) odesys, extra = get_odesys(rsys, False, substitutions={'temperature': rt}) all_pk, unique, p_units = map(extra.get, 'param_keys unique p_units'.split()) conc = {'A': A0, 'B': B0} tout = [2, 5, 10] for ramp_rate in [2, 3, 4]: unique['ramp_rate'] = ramp_rate xout, yout, info = odesys.integrate(10, conc, unique, atol=1e-10, rtol=1e-12) params[-1] = ramp_rate Aref = np.array([float(refA(t, *params)) for t in xout]) # Aref = 1/(1/13 + 2*1e-6*t_unitless) yref = np.zeros((xout.size, 2)) yref[:, 0] = Aref yref[:, 1] = B0 + 3 * (A0 - Aref) assert allclose(yout, yref) unique['ramp_rate'] = 2 x, y, p = odesys.to_arrays(tout, conc, unique) fout = odesys.f_cb(x, y, p) def r(t): return A * np.exp(-Ea_over_R / (T0 + dTdt * t)) * A0 # refA(t, *params) ref = np.array([[-r(2), -r(5), -r(10)], [3 * r(2), 3 * r(5), 3 * r(10)]]).T assert np.allclose(fout, ref)
def test_Expr__single_arg__units(): class Pressure(Expr): argument_names = ('n', ) parameter_keys = ('temperature', 'volume', 'R') def __call__(self, variables, backend=None): n, = self.all_args(variables, backend=backend) T, V, R = self.all_params(variables, backend=backend) return n * R * T / V p = Pressure(3 * u.mol) variables = { 'temperature': 273.15 * u.kelvin, 'volume': 170 * u.dm3, 'R': 8.314 * u.J / u.K / u.mol } assert allclose(p(variables), 3 * 8.314 * 273.15 / 0.17 * u.Pa)
def test_create_odesys__validate__catalyst(): rsys1 = ReactionSystem.from_string(""" H2O2 + Pt -> 2 OH + Pt; 'k_decomp' """) ic1 = defaultdict(lambda: 0*u.molar, {'H2O2': 3.0*u.molar, 'Pt': 0.5*u.molar}) t1 = linspace(0*u.s, .3*u.s, 7) p1 = dict(k_decomp=42/u.second/u.molar) odesys1, odesys_extra = create_odesys(rsys1) validation = odesys_extra['validate'](dict(ic1, **p1)) assert not validation['not_seen'] dedim_ctx = _mk_dedim(SI_base_registry) (t, c, _p), dedim_extra = dedim_ctx['dedim_tcp'](t1, [ic1[k] for k in odesys1.names], p1) result1 = odesys1.integrate(t, c, _p) tout = result1.xout * dedim_extra['unit_time'] cout = result1.yout * dedim_extra['unit_conc'] yref1 = ic1['H2O2']*np.exp(-tout*ic1['Pt']*p1['k_decomp']) assert allclose(yref1, cout[:, odesys1.names.index('H2O2')], rtol=1e-6)
def test_get_odesys__time_dep_temperature(): import sympy as sp def refA(t, A0, A, Ea_over_R, T0, dTdt): T = (T0 + dTdt*t) d_Ei = sp.Ei(-Ea_over_R/T0).n(100).round(90) - sp.Ei(-Ea_over_R/T).n(100).round(90) d_Texp = T0*sp.exp(-Ea_over_R/T0) - T*sp.exp(-Ea_over_R/T) return A0*sp.exp(A/dTdt*(Ea_over_R*d_Ei + d_Texp)).n(30) params = A0, A, Ea_over_R, T0, dTdt = [13, 1e10, 56e3/8, 273, 2] B0 = 11 rate = MassAction(Arrhenius([A, Ea_over_R])) rxn = Reaction({'A': 1}, {'B': 3}, rate) rsys = ReactionSystem([rxn], 'A B') rt = RampedTemp([T0, dTdt], ('init_temp', 'ramp_rate')) odesys, extra = get_odesys(rsys, False, substitutions={'temperature': rt}) all_pk, unique, p_units = map(extra.get, 'param_keys unique p_units'.split()) conc = {'A': A0, 'B': B0} tout = [2, 5, 10] for ramp_rate in [2, 3, 4]: unique['ramp_rate'] = ramp_rate xout, yout, info = odesys.integrate(10, conc, unique, atol=1e-10, rtol=1e-12) params[-1] = ramp_rate Aref = np.array([float(refA(t, *params)) for t in xout]) # Aref = 1/(1/13 + 2*1e-6*t_unitless) yref = np.zeros((xout.size, 2)) yref[:, 0] = Aref yref[:, 1] = B0 + 3*(A0-Aref) assert allclose(yout, yref) unique['ramp_rate'] = 2 x, y, p = odesys.to_arrays(tout, conc, unique) fout = odesys.f_cb(x, y, p) def r(t): return A*np.exp(-Ea_over_R/(T0 + dTdt*t))*A0 # refA(t, *params) ref = np.array([ [-r(2), -r(5), -r(10)], [3*r(2), 3*r(5), 3*r(10)] ]).T assert np.allclose(fout, ref)
def test_get_native__conc_roots(): M, s = u.M, u.s rsys = ReactionSystem.from_string("2 O3 -> 3 O2; 'k2'") u_reg = SI_base_registry.copy() odesys, extra = get_odesys(rsys, include_params=False, unit_registry=u_reg) c0 = {'O3': 4.2e-3*M, 'O2': 0*M} cr = ['O2'] native = get_native(rsys, odesys, 'cvode', conc_roots=cr) tend = 1e5*u.s params = {'k2': logspace_from_lin(1e-3/M/s, 1e3/M/s, 14)} tgt_O2 = 1e-3*M results = native.integrate(tend, c0, params, integrator='native', return_on_root=True, special_settings=[unitless_in_registry(tgt_O2, u_reg)]) assert len(results) == params['k2'].size # dydt = -p*y**2 # 1/y0 - 1/y = -2*pt # t = 1/2/p*(1/y - 1/y0) tgt_O3 = c0['O3'] - 2/3 * tgt_O2 for r in results: ref = rescale(1/2/r.named_param('k2')*(1/tgt_O3 - 1/c0['O3']), u.s) assert allclose(r.xout[-1], ref, rtol=1e-6)
def test_ArrheniusMassAction__units(R_from_constants): import numpy as np Ea = 40e3*u.J/u.mol R = default_constants.molar_gas_constant if R_from_constants else (8.3145*u.J/u.mol/u.K) A, Ea_over_R = 1.2e11/u.molar**2/u.second, Ea/R ref1 = A*np.exp(-to_unitless(Ea_over_R/(290*u.K))) arrh = Arrhenius([A, Ea_over_R]) assert allclose(arrh({'temperature': 290*u.K}), ref1) ama = MassAction(arrh) r = Reaction({'A': 2, 'B': 1}, {'C': 1}, ama, {'B': 1}) T_ = 'temperature' def ref(v): return 1.2e11/u.molar**2/u.second*math.exp( -Ea_over_R.simplified/v[T_])*v['B']*v['A']**2 ma = r.rate_expr() for params in [(11.*u.molar, 13.*u.molar, 17.*u.molar, 311.2*u.kelvin), (12*u.molar, 8*u.molar, 5*u.molar, 270*u.kelvin)]: var = dict(zip(['A', 'B', 'C', T_], params)) ref_val = ref(var) assert abs((ma(var, reaction=r) - ref_val)/ref_val) < 1e-14
def test_eval_template(): rendered = eval_template("${2*pi*arg*m**2}", arg=1/math.pi) val = eval(rendered, get_parsing_context()) assert allclose(val, 2*u.m**2)
def test_Expr__single_arg__units(): p = Pressure1(3*u.mol) variables = {'temperature': 273.15*u.kelvin, 'volume': 170*u.dm3, 'R': 8.314*u.J/u.K/u.mol} assert allclose(p(variables), 3*8.314*273.15/0.17*u.Pa)
def test_Expr__single_arg__units__dimensionality(): p = Pressure2(unique_keys=('n1',)) variables = {'temperature': 273.15*u.kelvin, 'volume': 170*u.dm3, 'R': 8.314*u.J/u.K/u.mol} assert allclose(p(dict(n1=3*u.mol, **variables)), 3*8.314*273.15/0.17*u.Pa)
def test_ArrheniusParamWithUnits__from_rateconst_at_T(): _2 = _get_ref2_units() apu = ArrheniusParamWithUnits.from_rateconst_at_T(_2.Ea, (_2.T, _2.k)) assert allclose(apu(_2.T), _2.k)
def test_eval_template__Reaction(): rendered = eval_template("2 OH -> H2O2; ${6*pi*arg}/M/s", arg=1/math.pi) assert allclose(Reaction.from_string(rendered).param, Reaction.from_string("2 OH -> H2O2; 6.0/M/s").param)
def test_nernst_potential__units(): J = default_units.joule K = default_units.kelvin coulomb = default_units.coulomb v = nernst_potential(145, 15, 1, 310*K, default_constants) assert allclose(1000 * v, 60.605*J/coulomb, rtol=1e-4)