예제 #1
0
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)
예제 #2
0
def test_get_odesys_3():
    M = u.molar
    s = u.second
    mol = u.mol
    m = u.metre
    substances = list(map(Substance, 'H2O H+ OH-'.split()))
    dissociation = Reaction({'H2O': 1}, {'H+': 1, 'OH-': 1}, 2.47e-5/s)
    recombination = Reaction({'H+': 1, 'OH-': 1}, {'H2O': 1}, 1.37e11/M/s)
    rsys = ReactionSystem([dissociation, recombination], substances)
    odesys = get_odesys(
        rsys, include_params=True, unit_registry=SI_base_registry,
        output_conc_unit=M)[0]
    c0 = {'H2O': 55.4*M, 'H+': 1e-7*M, 'OH-': 1e-4*mol/m**3}
    x, y, p = odesys.to_arrays(-42*u.second,
                               rsys.as_per_substance_array(c0, unit=M), ())
    fout = odesys.f_cb(x, y, p)

    time_unit = get_derived_unit(SI_base_registry, 'time')
    conc_unit = get_derived_unit(SI_base_registry, 'concentration')

    r1 = to_unitless(55.4*2.47e-5*M/s, conc_unit/time_unit)
    r2 = to_unitless(1e-14*1.37e11*M/s, conc_unit/time_unit)
    assert np.all(abs(fout[:, 0] - r2 + r1)) < 1e-10
    assert np.all(abs(fout[:, 1] - r1 + r2)) < 1e-10
    assert np.all(abs(fout[:, 2] - r1 + r2)) < 1e-10
예제 #3
0
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)
예제 #4
0
def test_get_odesys__late_binding():
    def _gibbs(args, T, R, backend, **kwargs):
        H, S = args
        return backend.exp(-(H - T*S)/(R*T))

    def _eyring(args, T, R, k_B, h, backend, **kwargs):
        H, S = args
        return k_B/h*T*backend.exp(-(H - T*S)/(R*T))

    gibbs_pk = ('temperature', 'molar_gas_constant')
    eyring_pk = gibbs_pk + ('Boltzmann_constant', 'Planck_constant')

    GibbsEC = MassActionEq.from_callback(_gibbs, argument_names=('H', 'S'), parameter_keys=gibbs_pk)
    EyringMA = MassAction.from_callback(_eyring, argument_names=('H', 'S'), parameter_keys=eyring_pk)

    uk_equil = ('He_assoc', 'Se_assoc')
    beta = GibbsEC(unique_keys=uk_equil)  # equilibrium parameters

    uk_kinet = ('Ha_assoc', 'Sa_assoc')
    bimol_barrier = EyringMA(unique_keys=uk_kinet)  # activation parameters

    eq = Equilibrium({'Fe+3', 'SCN-'}, {'FeSCN+2'}, beta)
    rsys = ReactionSystem(eq.as_reactions(kf=bimol_barrier))
    odesys, extra = get_odesys(rsys, include_params=False)
    pk, unique, p_units = map(extra.get, 'param_keys unique p_units'.split())
    assert sorted(unique) == sorted(uk_equil + uk_kinet)
    assert sorted(pk) == sorted(eyring_pk)
예제 #5
0
def test_get_odesys__Expr_as_param__unique_as_param():
    def _eyring_pe_coupled(args, T, S, backend=math, **kwargs):
        freq, = args
        return freq*T/S

    EyringPreExpCoupled = Expr.from_callback(_eyring_pe_coupled, argument_names=('freq',),
                                             parameter_keys=('temperature', 'S_u'))

    def _k(args, T, backend=math, **kwargs):
        A, H, S = args
        return A*backend.exp(-(H - T*S)/(8.314511*T))

    EyringMA = MassAction.from_callback(_k, parameter_keys=('temperature',),
                                        argument_names=('Aa', 'Ha', 'Sa'))
    kb_h = 2.08e10
    rxn = Reaction({'A'}, {'B'}, EyringMA(unique_keys=('A_u', 'H_u', 'S_u')))
    rsys = ReactionSystem([rxn], ['A', 'B'])
    odesys2, extra2 = get_odesys(rsys, include_params=False,
                                 substitutions={'A_u': EyringPreExpCoupled(kb_h)})
    y0 = defaultdict(float, {'A': 7.0})
    rt = 293.15
    xout2, yout2, info2 = odesys2.integrate(5, y0, {'H_u': 107e3, 'S_u': 150, 'temperature': rt},
                                            integrator='cvode', atol=1e-12, rtol=1e-10, nsteps=1000)
    kref2 = kb_h*rt*np.exp(-(107e3 - rt*150)/(8.314511*rt))/150
    ref2 = y0['A']*np.exp(-kref2*xout2)
    assert np.allclose(yout2[:, 0], ref2)
    assert np.allclose(yout2[:, 1], y0['A'] - ref2)
예제 #6
0
def test_get_ode__Radiolytic__substitutions__units():
    rad = Radiolytic([2.4e-7 * u.mol / u.joule])
    rxn = Reaction({'A': 4, 'B': 1}, {'C': 3, 'D': 2}, rad)
    rsys = ReactionSystem([rxn], 'A B C D')
    g_dm3 = u.gram / u.decimetre**3
    kg_dm3 = u.kg / u.decimetre**3
    substance_rho = Density(
        [1 * kg_dm3, -1 * g_dm3 / u.kelvin, 273.15 * u.kelvin])
    odesys = get_odesys(rsys,
                        include_params=True,
                        unit_registry=SI_base_registry,
                        substitutions={'density': substance_rho})[0]
    conc = {
        'A': 3 * u.molar,
        'B': 5 * u.molar,
        'C': 11 * u.molar,
        'D': 13 * u.molar
    }
    x, y, p = odesys.to_arrays(-37 * u.second, conc, {
        'doserate': 0.4 * u.gray / u.second,
        'temperature': 298.15 * u.kelvin
    })
    fout = odesys.f_cb(x, y, p)
    r = 2.4e-7 * 0.4 * 0.975 * 1e3  # mol/m3/s
    ref = [-4 * r, -r, 3 * r, 2 * r]
    assert np.all(abs((fout - ref) / ref) < 1e-14)
예제 #7
0
파일: stoich.py 프로젝트: yccai/chempy
def decompose_yields(yields, rxns, atol=1e-10):
    """ Decomposes yields into mass-action reactions

    This function offers a way to express a reaction with non-integer
    stoichiometric coefficients as a linear combination of production reactions
    with integer coefficients.

    Ak = y

    A is (n_species x n_reactions) matrix, k is "rate coefficient", y is yields


    Parameters
    ----------
    yields: OrderedDict
        specie names as keys and yields as values
    rxns: iterable :class:`Reaction` instances
        dict keys must match those of ``yields`` each pair
        of dictionaries gives stoichiometry
        (1st is reactant, 2nd is products)
    atol: float
        absolute tolerance for residuals


    Examples
    --------
    >>> from chempy import Reaction
    >>> h2a = Reaction({'H2O': 1}, {'H2': 1, 'O': 1})
    >>> h2b = Reaction({'H2O': 1}, {'H2': 1, 'H2O2': 1}, inact_reac={'H2O': 1})
    >>> decompose_yields({'H2': 3, 'O': 2, 'H2O2': 1}, [h2a, h2b])
    array([ 2.,  1.])

    Raises
    ------
    ValueError
        When atol is exceeded
    numpy.LinAlgError
        When numpy.linalg.lstsq fails to converge

    Returns
    -------
    1-dimensional array of effective rate coefficients.

    """
    from chempy import ReactionSystem
    # Sanity check:
    rxn_keys = set.union(*(rxn.keys() for rxn in rxns))
    for key in yields.keys():
        if key not in rxn_keys:
            raise ValueError("Substance key: %s not in reactions" % key)
    rsys = ReactionSystem(rxns, rxn_keys)
    A = rsys.net_stoichs(yields.keys())
    b = list(yields.values())
    unit = unit_of(b[0])
    x, residuals, rank, s = np.linalg.lstsq(A.T, to_unitless(b, unit))
    if len(residuals) > 0:
        if np.any(residuals > atol):
            raise ValueError("atol not satisfied")
    return x*unit
예제 #8
0
def test_get_odesys__Equilibrium_as_reactions():
    from chempy import Equilibrium, ReactionSystem
    eq = Equilibrium({'Fe+3', 'SCN-'}, {'FeSCN+2'}, 10**2)
    substances = 'Fe+3 SCN- FeSCN+2'.split()
    rsys = ReactionSystem(eq.as_reactions(kf=3.0), substances)
    odesys, extra = get_odesys(rsys)
    init_conc = {'Fe+3': 1.0, 'SCN-': .3, 'FeSCN+2': 0}
    tout, Cout, info = odesys.integrate(5, init_conc, integrator='cvode', atol=1e-11, rtol=1e-12)
    cmplx_ref = binary_rev(tout, 3, 3.0/100, init_conc['FeSCN+2'], init_conc['Fe+3'], init_conc['SCN-'])
    assert np.allclose(Cout[:, 2], cmplx_ref)
def get_rsys():
    r1 = Reaction({'A'}, {'B'},
                  MassAction([4. / 100], unique_keys=['k1']),
                  name='R1: A cons.')
    r2 = Reaction({'B', 'C'}, {'A', 'C'},
                  MassAction([1e4], unique_keys=['k2']),
                  name='R2: A reform.')
    r3 = Reaction({'B': 2}, {'B', 'C'},
                  MassAction([3e7], unique_keys=['k3']),
                  name='R3: C form.')
    return ReactionSystem([r1, r2, r3])
예제 #10
0
def test_get_ode__Radiolytic():
    rad = Radiolytic([2.4e-7])
    rxn = Reaction({"A": 4, "B": 1}, {"C": 3, "D": 2}, rad)
    rsys = ReactionSystem([rxn], "A B C D")
    odesys = get_odesys(rsys, include_params=True)[0]
    c = {"A": 3, "B": 5, "C": 11, "D": 13}
    x, y, p = odesys.to_arrays(-37, c, {"doserate": 0.4, "density": 0.998})
    fout = odesys.f_cb(x, y, p)
    r = 2.4e-7 * 0.4 * 0.998
    ref = [-4 * r, -r, 3 * r, 2 * r]
    assert np.all(abs((fout - ref) / ref) < 1e-14)
예제 #11
0
def test_get_ode__Radiolytic():
    rad = Radiolytic([2.4e-7])
    rxn = Reaction({'A': 4, 'B': 1}, {'C': 3, 'D': 2}, rad)
    rsys = ReactionSystem([rxn], 'A B C D')
    odesys = get_odesys(rsys, include_params=True)[0]
    c = {'A': 3, 'B': 5, 'C': 11, 'D': 13}
    x, y, p = odesys.to_arrays(-37, c, {'doserate': 0.4, 'density': 0.998})
    fout = odesys.f_cb(x, y, p)
    r = 2.4e-7*0.4*0.998
    ref = [-4*r, -r, 3*r, 2*r]
    assert np.all(abs((fout - ref)/ref) < 1e-14)
예제 #12
0
def test_get_ode__TPoly():
    rate = MassAction(ShiftedTPoly([273.15*u.K, 10/u.molar/u.s, 2/u.molar/u.s/u.K]))
    rxn = Reaction({'A': 1, 'B': 1}, {'C': 3, 'D': 2}, rate, {'A': 3})
    rsys = ReactionSystem([rxn], 'A B C D')
    odesys = get_odesys(rsys, unit_registry=SI_base_registry)[0]
    conc = {'A': 3*u.molar, 'B': 5*u.molar, 'C': 11*u.molar, 'D': 13*u.molar}
    x, y, p = odesys.to_arrays(-37*u.second, conc, {'temperature': 298.15*u.kelvin})
    fout = odesys.f_cb(x, y, p)
    r = 3*5*(10+2*25)*1000  # mol/m3/s
    ref = [-4*r, -r, 3*r, 2*r]
    assert np.all(abs((fout - ref)/ref) < 1e-14)
예제 #13
0
def test_get_ode__ArrheniusParam():
    rxn = Reaction({'A': 1}, {'B': 1}, None)
    rxn.param = ArrheniusParam(1e10, 40e3)
    rsys = ReactionSystem([rxn], 'A B')
    odesys = get_odesys(rsys, include_params=True)[0]
    conc = {'A': 3, 'B': 5}
    x, y, p = odesys.to_arrays(-37, conc, {'temperature': 200})
    fout = odesys.f_cb(x, y, p)
    ref = 3*1e10*np.exp(-40e3/8.314472/200)
    assert np.all(abs((fout[:, 0] + ref)/ref) < 1e-14)
    assert np.all(abs((fout[:, 1] - ref)/ref) < 1e-14)
예제 #14
0
def test_ode_with_global_parameters():
    ratex = MassAction(Arrhenius([1e10, 40e3/8.3145]))
    rxn = Reaction({'A': 1}, {'B': 1}, ratex)
    rsys = ReactionSystem([rxn], 'A B')
    odesys, extra = get_odesys(rsys, include_params=False)
    param_keys, unique_keys, p_units = map(extra.get, 'param_keys unique p_units'.split())
    conc = {'A': 3, 'B': 5}
    x, y, p = odesys.to_arrays(-37, conc, {'temperature': 298.15})
    fout = odesys.f_cb(x, y, p)
    ref = 3*1e10*np.exp(-40e3/8.3145/298.15)
    assert np.all(abs((fout[:, 0] + ref)/ref) < 1e-14)
    assert np.all(abs((fout[:, 1] - ref)/ref) < 1e-14)
예제 #15
0
def get_rsys():
    r1 = Reaction(
        {"A"}, {"B"}, MassAction([4.0 / 100], unique_keys=["k1"]), name="R1: A cons."
    )
    r2 = Reaction(
        {"B", "C"},
        {"A", "C"},
        MassAction([1e4], unique_keys=["k2"]),
        name="R2: A reform.",
    )
    r3 = Reaction(
        {"B": 2}, {"B", "C"}, MassAction([3e7], unique_keys=["k3"]), name="R3: C form."
    )
    return ReactionSystem([r1, r2, r3])
예제 #16
0
def test_EyringMassAction():
    args = kB_h_times_exp_dS_R, dH_over_R, c0 = 1.2e11 / 273.15, 40e3 / 8, 1
    ama = MassAction(Eyring(args, ("Sfreq", "Hact")))
    rxn1 = Reaction({"A": 2, "B": 1}, {"C": 1}, ama, {"B": 1})
    T_ = "temperature"

    def ref(v):
        return (v.get("Sfreq", 1.2e11 / 273.15) * v[T_] *
                math.exp(-v.get("Hact", 40e3 / 8) / v[T_]) * v["B"] *
                v["A"]**2)

    for params in [(11.0, 13.0, 17.0, 311.2), (12, 8, 5, 270)]:
        var = dict(zip(["A", "B", "C", T_], params))
        ref_val = ref(var)
        assert abs((ama(var, reaction=rxn1) - ref_val) / ref_val) < 1e-14

    with pytest.raises(ValueError):
        MassAction(Eyring([1, 1, 1, 1, 1]))

    # assert ama.as_mass_action({T_: 273.15}).args[0] == 1.2e11*math.exp(-40e3/8/273.15)

    ama2 = MassAction(
        Eyring4([1.2e11 / 273, 40e3 / 8, 1.2, 1e3],
                ("Sfreq", "Hact", "Sref", "Href")))
    rxn2 = Reaction({"C": 1}, {"A": 2, "B": 2}, ama2)
    var2 = {"C": 29, "temperature": 273}

    def ref2(var):
        return (var["C"] * var.get("temperature", 273) *
                var.get("Sfreq", 1.2e11 / 273) / var.get("Sref", 1.2) *
                math.exp((var.get("Href", 1e3) - var.get("Hact", 5e3)) /
                         var.get("temperature", 273)))

    r2 = ref2(var2)
    assert abs((ama2(var2, reaction=rxn2) - r2) / r2) < 1e-14

    rsys = ReactionSystem([rxn1, rxn2])
    var3 = {
        "A": 11,
        "B": 13,
        "C": 17,
        "temperature": 298,
        "Sfreq": 1.2e11 / 298
    }
    rates = rsys.rates(var3)
    rf3 = ref(var3)
    rb3 = ref2(var3)
    ref_rates = {"A": 2 * (rb3 - rf3), "B": 2 * (rb3 - rf3), "C": rf3 - rb3}
    for k, v in ref_rates.items():
        assert abs((rates[k] - v) / v) < 1e-14
예제 #17
0
def test_get_ode__Radiolytic__substitutions():
    rad = Radiolytic([2.4e-7])
    rxn = Reaction({'A': 4, 'B': 1}, {'C': 3, 'D': 2}, rad)
    rsys = ReactionSystem([rxn], 'A B C D')
    substance_rho = Density([1, -1e-3, 273.15])
    odesys = get_odesys(rsys, include_params=True,
                        substitutions={'density': substance_rho})[0]
    conc = {'A': 3, 'B': 5, 'C': 11, 'D': 13}
    state = {'doserate': 0.4, 'temperature': 298.15}
    x, y, p = odesys.to_arrays(-37, conc, state)
    fout = odesys.f_cb(x, y, p)
    r = 2.4e-7*0.4*substance_rho({'temperature': 298.15})
    ref = [-4*r, -r, 3*r, 2*r]
    assert np.all(abs((fout - ref)/ref) < 1e-14)
예제 #18
0
def test_EyringMassAction():
    args = kB_h_times_exp_dS_R, dH_over_R, c0 = 1.2e11 / 273.15, 40e3 / 8, 1
    ama = MassAction(Eyring(args, ('Sfreq', 'Hact')))
    rxn1 = Reaction({'A': 2, 'B': 1}, {'C': 1}, ama, {'B': 1})
    T_ = 'temperature'

    def ref(v):
        return v.get('Sfreq', 1.2e11 / 273.15) * v[T_] * math.exp(
            -v.get('Hact', 40e3 / 8) / v[T_]) * v['B'] * v['A']**2

    for params in [(11., 13., 17., 311.2), (12, 8, 5, 270)]:
        var = dict(zip(['A', 'B', 'C', T_], params))
        ref_val = ref(var)
        assert abs((ama(var, reaction=rxn1) - ref_val) / ref_val) < 1e-14

    with pytest.raises(ValueError):
        MassAction(Eyring([1, 1, 1, 1, 1]))

    # assert ama.as_mass_action({T_: 273.15}).args[0] == 1.2e11*math.exp(-40e3/8/273.15)

    ama2 = MassAction(
        Eyring4([1.2e11 / 273, 40e3 / 8, 1.2, 1e3],
                ('Sfreq', 'Hact', 'Sref', 'Href')))
    rxn2 = Reaction({'C': 1}, {'A': 2, 'B': 2}, ama2)
    var2 = {'C': 29, 'temperature': 273}

    def ref2(var):
        return var['C'] * var.get('temperature', 273) * var.get(
            'Sfreq', 1.2e11 / 273) / var.get('Sref', 1.2) * math.exp(
                (var.get('Href', 1e3) - var.get('Hact', 5e3)) /
                var.get('temperature', 273))

    r2 = ref2(var2)
    assert abs((ama2(var2, reaction=rxn2) - r2) / r2) < 1e-14

    rsys = ReactionSystem([rxn1, rxn2])
    var3 = {
        'A': 11,
        'B': 13,
        'C': 17,
        'temperature': 298,
        'Sfreq': 1.2e11 / 298
    }
    rates = rsys.rates(var3)
    rf3 = ref(var3)
    rb3 = ref2(var3)
    ref_rates = {'A': 2 * (rb3 - rf3), 'B': 2 * (rb3 - rf3), 'C': rf3 - rb3}
    for k, v in ref_rates.items():
        assert abs((rates[k] - v) / v) < 1e-14
예제 #19
0
def test_get_ode__Radiolytic__units():
    rad = Radiolytic([2.4e-7*u.mol/u.joule])
    rxn = Reaction({'A': 4, 'B': 1}, {'C': 3, 'D': 2}, rad)
    rsys = ReactionSystem([rxn], 'A B C D')
    odesys = get_odesys(rsys, include_params=True,
                        unit_registry=SI_base_registry)[0]
    conc = {'A': 3*u.molar, 'B': 5*u.molar, 'C': 11*u.molar, 'D': 13*u.molar}
    x, y, p = odesys.to_arrays(-37*u.second, conc, {
        'doserate': 0.4*u.gray/u.second,
        'density': 0.998*u.kg/u.decimetre**3
    })
    fout = odesys.f_cb(x, y, p)  # f_cb does not carry any units
    r = 2.4e-7*0.4*0.998*1e3  # mol/m3
    ref = [-4*r, -r, 3*r, 2*r]
    assert np.all(abs((fout - ref)/ref) < 1e-14)
예제 #20
0
def test_get_ode__Radiolytic__substitutions():
    rad = Radiolytic([2.4e-7])
    rxn = Reaction({"A": 4, "B": 1}, {"C": 3, "D": 2}, rad)
    rsys = ReactionSystem([rxn], "A B C D")
    substance_rho = Density([1, -1e-3, 273.15])
    odesys = get_odesys(
        rsys, include_params=True, substitutions={"density": substance_rho}
    )[0]
    conc = {"A": 3, "B": 5, "C": 11, "D": 13}
    state = {"doserate": 0.4, "temperature": 298.15}
    x, y, p = odesys.to_arrays(-37, conc, state)
    fout = odesys.f_cb(x, y, p)
    r = 2.4e-7 * 0.4 * substance_rho({"temperature": 298.15})
    ref = [-4 * r, -r, 3 * r, 2 * r]
    assert np.all(abs((fout - ref) / ref) < 1e-14)
예제 #21
0
def test_get_odesys__Equilibrium_as_reactions():
    from chempy import Equilibrium, ReactionSystem

    eq = Equilibrium({"Fe+3", "SCN-"}, {"FeSCN+2"}, 10 ** 2)
    substances = "Fe+3 SCN- FeSCN+2".split()
    rsys = ReactionSystem(eq.as_reactions(kf=3.0), substances)
    odesys, extra = get_odesys(rsys)
    init_conc = {"Fe+3": 1.0, "SCN-": 0.3, "FeSCN+2": 0}
    tout, Cout, info = odesys.integrate(
        5, init_conc, integrator="cvode", atol=1e-11, rtol=1e-12
    )
    cmplx_ref = binary_rev(
        tout, 3, 3.0 / 100, init_conc["FeSCN+2"], init_conc["Fe+3"], init_conc["SCN-"]
    )
    assert np.allclose(Cout[:, 2], cmplx_ref)
예제 #22
0
def test_chained_parameter_variation():
    ratex = MassAction(Arrhenius([1e10, 63e3 / 8.3145]))
    rxn = Reaction({'A': 1}, {'B': 1}, ratex)
    rsys = ReactionSystem([rxn], 'A B')
    odesys, extra = get_odesys(rsys, include_params=False)
    param_keys, unique_keys, p_units = map(extra.get,
                                           'param_keys unique p_units'.split())
    conc = {'A': 3.17, 'B': 5.03}
    Ts = (294, 304, 317)
    times = [3.1, 2.1, 5.3]
    kw = dict(integrator='cvode', atol=1e-12, rtol=1e-13, first_step=1e-14)
    tout, cout, info = chained_parameter_variation(odesys,
                                                   times,
                                                   conc, {'temperature': Ts},
                                                   {},
                                                   integrate_kwargs=kw)
    assert len(info['nfev']) == 3
    assert info['nfev'][0] > 2
    assert info['nfev'][1] > 2
    assert info['nfev'][2] > 2
    assert np.all(np.diff(tout) > 0)
    tout1 = tout[tout <= times[0]]
    tout23 = tout[tout > times[0]]
    tout2 = tout23[tout23 <= times[0] + times[1]]
    tout3 = tout23[tout23 > times[0] + times[1]]

    def _ref(y0, x, T, x0):
        k = 1e10 * np.exp(-63e3 / 8.3145 / T)
        return y0 * np.exp(-k * (x - x0))

    Aref1 = _ref(conc['A'], tout1, Ts[0], tout1[0])
    Bref1 = conc['B'] + conc['A'] - Aref1

    Aref2 = _ref(Aref1[-1], tout2, Ts[1], tout1[-1])
    Bref2 = Bref1[-1] + Aref1[-1] - Aref2

    Aref3 = _ref(Aref2[-1], tout3, Ts[2], tout2[-1])
    Bref3 = Bref2[-1] + Aref2[-1] - Aref3

    cref = np.concatenate([
        np.vstack((a, b)).T
        for a, b in [(Aref1, Bref1), (Aref2, Bref2), (Aref3, Bref3)]
    ])
    forgive = 27 * 1.1
    assert np.allclose(cref,
                       cout,
                       atol=kw['atol'] * forgive,
                       rtol=kw['rtol'] * forgive)
예제 #23
0
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)
예제 #24
0
def test_get_odesys__rate_exprs_cb():
    k = .2
    a = Substance('A')
    b = Substance('B')
    r = Reaction({'A': 1}, {'B': 1}, param=k)
    rsys = ReactionSystem([r], [a, b])
    assert sorted(rsys.substances.keys()) == ['A', 'B']
    odesys, extra = get_odesys(rsys)
    c0 = {'A': 1.0, 'B': 3.0}
    t = np.linspace(0.0, 10.0)
    res = odesys.integrate(t, c0)
    yref = np.zeros((t.size, 2))
    yref[:, 0] = np.exp(-k*t)
    yref[:, 1] = 4 - np.exp(-k*t)
    assert np.allclose(res.yout, yref)
    rate = extra['rate_exprs_cb'](res.xout, res.yout, res.params)
    assert np.allclose(rate[:, 0], k*yref[:, 0])
예제 #25
0
def test_get_ode__Radiolytic__units__multi():
    rad = Radiolytic([2.4e-7 * u.mol / u.joule])
    rxn = Reaction({"A": 4, "B": 1}, {"C": 3, "D": 2}, rad)
    rsys = ReactionSystem([rxn], "A B C D")
    odesys = get_odesys(rsys, include_params=True, unit_registry=SI_base_registry)[0]
    conc = {"A": 3 * u.molar, "B": 5 * u.molar, "C": 11 * u.molar, "D": 13 * u.molar}
    doserates = [dr * u.gray / u.second for dr in [0.1, 0.2, 0.3, 0.4]]
    results = odesys.integrate(
        37 * u.second,
        conc,
        {"doserate": doserates, "density": 0.998 * u.kg / u.decimetre ** 3},
    )
    assert len(results) == 4
    for i, r in enumerate(results):
        dr = r.params[odesys.param_names.index("doserate")]
        assert dr.ndim == 0 or len(dr) == 1
        assert dr == doserates[i]
예제 #26
0
def test_get_ode__Radiolytic__units__multi():
    rad = Radiolytic([2.4e-7*u.mol/u.joule])
    rxn = Reaction({'A': 4, 'B': 1}, {'C': 3, 'D': 2}, rad)
    rsys = ReactionSystem([rxn], 'A B C D')
    odesys = get_odesys(rsys, include_params=True,
                        unit_registry=SI_base_registry)[0]
    conc = {'A': 3*u.molar, 'B': 5*u.molar, 'C': 11*u.molar, 'D': 13*u.molar}
    doserates = [dr*u.gray/u.second for dr in [.1, .2, .3, .4]]
    results = odesys.integrate(37*u.second, conc, {
        'doserate': doserates,
        'density': 0.998*u.kg/u.decimetre**3
    })
    assert len(results) == 4
    for i, r in enumerate(results):
        dr = r.params[odesys.param_names.index('doserate')]
        assert dr.ndim == 0 or len(dr) == 1
        assert dr == doserates[i]
예제 #27
0
def test_get_odesys__time_dep_rate():
    class RampedRate(Expr):
        argument_names = ("rate_constant", "ramping_rate")

        def __call__(self, variables, reaction, backend=math):
            rate_constant, ramping_rate = self.all_args(variables, backend=backend)
            return rate_constant * ramping_rate * variables["time"]

    rate = MassAction(RampedRate([7, 2]))
    rxn = Reaction({"A": 1}, {"B": 3}, rate)
    rsys = ReactionSystem([rxn], "A B")
    odesys = get_odesys(rsys)[0]
    conc = {"A": 3, "B": 11}
    x, y, p = odesys.to_arrays([5, 13, 17], conc, ())
    fout = odesys.f_cb(x, y, p)
    r = 2 * 7 * 3
    ref = np.array([[-r * 5, -r * 13, -r * 17], [r * 5 * 3, r * 13 * 3, r * 17 * 3]]).T
    assert np.allclose(fout, ref)
예제 #28
0
def test_get_odesys_1():
    k = .2
    a = Substance('A')
    b = Substance('B')
    r = Reaction({'A': 1}, {'B': 1}, param=k)
    rsys = ReactionSystem([r], [a, b])
    assert sorted(rsys.substances.keys()) == ['A', 'B']
    odesys = get_odesys(rsys, include_params=True)[0]
    c0 = {
        'A': 1.0,
        'B': 3.0,
    }
    t = np.linspace(0.0, 10.0)
    xout, yout, info = odesys.integrate(t, c0)
    yref = np.zeros((t.size, 2))
    yref[:, 0] = np.exp(-k*t)
    yref[:, 1] = 4 - np.exp(-k*t)
    assert np.allclose(yout, yref)
예제 #29
0
def test_get_odesys_2():
    g = Radiolytic([3.14])
    a = Substance('A')
    b = Substance('B')
    r = Reaction({'A': 1}, {'B': 1}, param=g)
    rsys = ReactionSystem([r], [a, b])
    odesys = get_odesys(rsys, include_params=True)[0]
    c0 = {
        'A': 1.0,
        'B': 3.0,
    }
    t = np.linspace(0.0, .1)
    xout, yout, info = odesys.integrate(t, rsys.as_per_substance_array(c0),
                                        {'doserate': 2.72, 'density': .998})
    yref = np.zeros((t.size, 2))
    k = 3.14*2.72*.998
    yref[:, 0] = 1 - k*t
    yref[:, 1] = 3 + k*t
    assert np.allclose(yout, yref)
예제 #30
0
def test_get_odesys_2():
    g = Radiolytic([3.14])
    a = Substance("A")
    b = Substance("B")
    r = Reaction({"A": 1}, {"B": 1}, param=g)
    rsys = ReactionSystem([r], [a, b])
    odesys = get_odesys(rsys, include_params=True)[0]
    c0 = {
        "A": 1.0,
        "B": 3.0,
    }
    t = np.linspace(0.0, 0.1)
    xout, yout, info = odesys.integrate(
        t, rsys.as_per_substance_array(c0), {"doserate": 2.72, "density": 0.998}
    )
    yref = np.zeros((t.size, 2))
    k = 3.14 * 2.72 * 0.998
    yref[:, 0] = 1 - k * t
    yref[:, 1] = 3 + k * t
    assert np.allclose(yout, yref)