def test_n_jac_diags(n_jac_diags):
    N, n, nstencil = 10, 1, 7
    rd = ReactionDiffusion(n, [], [], [], N=N, nstencil=nstencil,
                           n_jac_diags=n_jac_diags, D=[9])
    assert np.allclose(rd.xcenters,
                       [.05, .15, .25, .35, .45, .55, .65, .75, .85, .95])
    y0 = np.ones(N)

    # Dense
    jref_cdns = np.zeros((n*N, n*N), order='F')
    jout_cdns = np.zeros((n*N, n*N), order='F')
    sm = SymRD.from_rd(rd)
    sm.dense_jac(0.0, y0.flatten(), jref_cdns)
    rd.dense_jac_cmaj(0.0, y0.flatten(), jout_cdns)
    assert np.allclose(jout_cdns, jref_cdns)

    # Banded
    jref_cbnd = rd.alloc_jout(order='F', pad=0)
    jout_cbnd = rd.alloc_jout(order='F')
    sm.banded_jac(0.0, y0.flatten(), jref_cbnd)
    rd.banded_jac_cmaj(0.0, y0.flatten(), jout_cbnd)
    assert np.allclose(jout_cbnd[rd.n*rd.n_jac_diags:, :], jref_cbnd)

    # Compressed
    jref_cmprs = rd.alloc_jout_compressed()
    jout_cmprs = rd.alloc_jout_compressed()
    sm.compressed_jac(0.0, y0.flatten(), jref_cmprs)
    rd.compressed_jac_cmaj(0.0, y0.flatten(), jout_cmprs)
    assert np.allclose(jout_cmprs, jref_cmprs)
def _test_f(rd, t, y, fref=None):
    fout = rd.alloc_fout()
    rd.f(t, np.asarray(y, dtype=np.float64), fout)
    if fref is None:
        fref = fout
    else:
        assert np.allclose(fout, fref)
        if isinstance(rd, SymRD):
            return
    _test_f(SymRD.from_rd(rd), t, y, fref)
Example #3
0
def test_SymRD():
    rd = SymRD(2, [[0]], [[1]], k=[5.0])

    fout = rd.alloc_fout()
    rd.f(0, [7, 3], fout)
    assert np.allclose(fout, [-5*7, 5*7])

    jout = rd.alloc_jout(banded=False)
    rd.dense_jac_rmaj(0, [7, 3], jout)
    assert np.allclose(jout, [[-5.0, 0.0], [5.0, 0.0]])
def _test_dense_jac_rmaj(rd, t, y, jref=None):
    jout = rd.alloc_jout(banded=False, order='C')
    rd.dense_jac_rmaj(t, np.asarray(y, dtype=np.float64), jout)
    atol = 2e-13
    rtol = 2e-13
    if jref is None:
        jref = jout
    else:
        # Not perfect Jacobian
        # only nearest neighbour
        # assert np.allclose(jout, jref)
        # ...hence:
        for ri in range(rd.ny):
            for ci in range(max(0, ri-rd.n), min(rd.ny, ri+rd.n+1)):
                out, ref = jout[ri, ci], jref[ri, ci]
                assert abs(out - ref) < atol + rtol*abs(ref)
        if isinstance(rd, SymRD):
            return
    _test_dense_jac_rmaj(SymRD.from_rd(rd), t, y, jref)
Example #5
0
def integrate_rd(tend=1e2, A0=1.0, B0=0.0, C0=0.0, k1=0.04, k2=1e4, k3=3e7,
                 t0=1e2, nt=100, N=1, nstencil=3, logt=False, logy=False,
                 plot=False, savefig='None', verbose=False, dump_expr='False',
                 use_chempy=False, D=2e-3):
    if N == 1:
        init_conc = (A0, B0, C0)
    else:
        init_conc = np.tile((A0, B0, C0), (N, 1))
        init_conc /= np.linspace(1, 2, N).reshape((N, 1))**.5

    rsys = ReactionSystem(get_reactions((k1, k2, k3)), 'ABC')
    if verbose:
        print([str(_) for _ in rsys.rxns])
    if use_chempy:
        from chempy.kinetics.ode import get_odesys
        odesys = get_odesys(rsys, include_params=True)
        if N != 1:
            raise ValueError("ChemPy does not support diffusion")
        odesys.integrate(np.logspace(log10(t0), log10(tend)), init_conc)
        if plot:
            odesys.plot_result(xscale='log', yscale='log')
        result = None
    else:
        rd = ReactionDiffusion.from_ReactionSystem(
            rsys, N=N, nstencil=1 if N == 1 else nstencil, logt=logt,
            logy=logy, D=[D/2, D/3, D/5])

        if dump_expr.lower() not in ('false', '0'):
            from chemreac.symbolic import SymRD
            import sympy as sp
            cb = {'latex': sp.latex,
                  'ccode': sp.ccode}.get(dump_expr.lower(), str)
            srd = SymRD.from_rd(rd, k=sp.symbols('k:3'))
            print('dydx:')
            print('\n'.join(map(cb, srd._f)))
            print('jac:')
            for ri, row in enumerate(srd.jacobian.tolist()):
                for ci, expr in enumerate(row):
                    if expr == 0:
                        continue
                    print(ri, ci, cb(expr))
            return None

        if t0 == 0 and logt:
            t0 = 1e-3*suggest_t0(rd, init_conc)
            if verbose:
                print("Using t0 = %12.5g" % t0)

        t = np.logspace(np.log10(t0), np.log10(tend), nt)
        print(t[0], t[-1])
        integr = run(rd, init_conc, t)

        if verbose:
            import pprint
            pprint.pprint(integr.info)

        if plot:
            if N == 1:
                plot_C_vs_t(integr, xscale='log', yscale='log')
            else:
                import matplotlib.pyplot as plt
                for idx, name in enumerate('ABC', 1):
                    plt.subplot(1, 3, idx)
                    rgb = [.5, .5, .5]
                    rgb[idx-1] = 1
                    plot_faded_time(integr, name, rgb=rgb, log_color=True)
        result = integr

    if plot:
        save_and_or_show_plot(savefig=savefig)

    return result
def test_ReactionDiffusion__3_reactions_4_species_5_bins_k_factor(
        geom_refl):
    # UNSUPPORTED since `bin_k_factor` was replaced with `fields`
    # if a real world scenario need per bin modulation of binary
    # reactions and the functionality is reintroduced, this test
    # is useful
    from sympy import finite_diff_weights
    geom, refl = geom_refl
    lrefl, rrefl = refl
    # r[0]: A + B -> C
    # r[1]: D + C -> D + A + B
    # r[2]: B + B -> D
    #              r[0]     r[1]       r[2]
    stoich_active = [[0, 1], [2, 3],    [1, 1]]
    stoich_prod = [[2],    [0, 1, 3], [3]]
    n = 4
    N = 5
    D = np.array([2.6, 3.7, 5.11, 7.13])*213
    y0 = np.array([
        2.5, 1.2, 3.2, 4.3,
        2.7, 0.8, 1.6, 2.4,
        3.1, 0.3, 1.5, 1.8,
        3.3, 0.6, 1.6, 1.4,
        3.6, 0.9, 1.7, 1.2
    ]).reshape((5, 4))
    x = np.array([11.0, 13.3, 17.0, 23.2, 29.8, 37.2])
    xc_ = x[:-1]+np.diff(x)/2
    xc_ = [x[0]-(xc_[0]-x[0])]+list(xc_)+[x[-1]+(x[-1]-xc_[-1])]
    assert len(xc_) == 7
    k = [31.0, 37.0, 41.0]

    # (r[0], r[1]) modulations over bins
    modulated_rxns = [0, 1]
    modulation = [[i+3 for i in range(N)],
                  [i+4 for i in range(N)]]
    nstencil = 3
    nsidep = 1
    rd = ReactionDiffusion(
        4, stoich_active, stoich_prod, k, N, D=D, x=x,
        geom=geom, nstencil=nstencil, lrefl=lrefl,
        rrefl=rrefl, modulated_rxns=modulated_rxns,
        modulation=modulation)

    assert np.allclose(xc_, rd.xc)

    lb = stencil_pxci_lbounds(nstencil, N, lrefl, rrefl)
    if lrefl:
        if rrefl:
            assert lb == [0, 1, 2, 3, 4]
        else:
            assert lb == [0, 1, 2, 3, 3]
    else:
        if rrefl:
            assert lb == [1, 1, 2, 3, 4]
        else:
            assert lb == [1, 1, 2, 3, 3]
    assert lb == list(map(rd._stencil_bi_lbound, range(N)))

    pxci2bi = pxci_to_bi(nstencil, N)
    assert pxci2bi == [0, 0, 1, 2, 3, 4, 4]
    assert pxci2bi == list(map(rd._xc_bi_map, range(N+2)))

    D_weight = []
    for bi in range(N):
        local_x_serie = xc_[lb[bi]:lb[bi]+nstencil]
        local_x_around = xc_[nsidep+bi]
        w = finite_diff_weights(
            2, local_x_serie, x0=local_x_around
        )
        D_weight.append(w[-1][-1])
        if geom == 'f':
            pass
        elif geom == 'c':
            for wi in range(nstencil):
                # first order derivative
                D_weight[bi][wi] += w[-2][-1][wi]*1/local_x_around
        elif geom == 's':
            for wi in range(nstencil):
                # first order derivative
                D_weight[bi][wi] += w[-2][-1][wi]*2/local_x_around
        else:
            raise RuntimeError
    assert np.allclose(rd.D_weight, np.array(D_weight, dtype=np.float64).flatten())

    def cflux(si, bi):
        f = 0.0
        for k in range(nstencil):
            f += rd.D_weight[bi*nstencil+k]*y0[pxci2bi[lb[bi]+k], si]
        return D[si]*f

    r = [
        [k[0]*modulation[0][bi]*y0[bi, 0]*y0[bi, 1] for
         bi in range(N)],
        [k[1]*modulation[1][bi]*y0[bi, 3]*y0[bi, 2] for
         bi in range(N)],
        [k[2]*y0[bi, 1]**2 for bi in range(N)],
    ]

    fref = np.array([[
        -r[0][bi] + r[1][bi] + cflux(0, bi),
        -r[0][bi] + r[1][bi] - 2*r[2][bi] + cflux(1, bi),
        r[0][bi] - r[1][bi] + cflux(2, bi),
        r[2][bi] + cflux(3, bi)
    ] for bi in range(N)]).flatten()

    # Now let's check that the Jacobian is correctly computed.
    def dfdC(bi, lri, lci):
        v = 0.0
        for ri in range(len(stoich_active)):
            totl = (stoich_prod[ri].count(lri) -
                    stoich_active[ri].count(lri))
            if totl == 0:
                continue
            actv = stoich_active[ri].count(lci)
            if actv == 0:
                continue
            v += actv*totl*r[ri][bi]/y0[bi, lci]
        return v

    def jac_elem(ri, ci):
        bri, bci = ri // n, ci // n
        lri, lci = ri % n,  ci % n
        elem = 0.0

        def _diffusion():
            _elem = 0.0
            for k in range(nstencil):
                if pxci2bi[lb[bri]+k] == bci:
                    _elem += D[lri]*rd.D_weight[bri*nstencil+k]
            return _elem

        if bri == bci:
            # on block diagonal
            elem += dfdC(bri, lri, lci)
            if lri == lci:
                elem += _diffusion()
        elif bri == bci - 1:
            if lri == lci:
                elem = _diffusion()
        elif bri == bci + 1:
            if lri == lci:
                elem = _diffusion()
        return elem

    jref = np.zeros((n*N, n*N), order='C')
    for ri, ci in np.ndindex(n*N, n*N):
        jref[ri, ci] = jac_elem(ri, ci)

    # Compare to what is calculated using our C++ callback
    _test_f_and_dense_jac_rmaj(rd, 0, y0.flatten(), fref, jref)

    jout_cmaj = np.zeros((n*N, n*N), order='F')
    rd.dense_jac_cmaj(0.0, y0.flatten(), jout_cmaj)
    assert np.allclose(jout_cmaj, jref)

    ref_banded_j = get_banded(jref, n, N)

    ref_banded_j_symbolic = rd.alloc_jout(order='F', pad=0)
    symrd = SymRD.from_rd(rd)
    symrd.banded_jac(0.0, y0.flatten(), ref_banded_j_symbolic)
    assert np.allclose(ref_banded_j_symbolic, ref_banded_j)

    jout_bnd_packed_cmaj = np.zeros((3*n+1, n*N), order='F')
    rd.banded_jac_cmaj(0.0, y0.flatten(), jout_bnd_packed_cmaj)

    if os.environ.get('plot_tests', False):
        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt
        from chemreac.util.plotting import coloured_spy
        fig = plt.figure()
        ax = fig.add_subplot(3, 1, 1)
        coloured_spy(ref_banded_j, ax=ax)
        plt.title('ref_banded_j')
        ax = fig.add_subplot(3, 1, 2)
        coloured_spy(jout_bnd_packed_cmaj[n:, :], ax=ax)
        plt.title('jout_bnd_packed_cmaj')
        ax = fig.add_subplot(3, 1, 3)
        coloured_spy(ref_banded_j-jout_bnd_packed_cmaj[n:, :], ax=ax)
        plt.title('diff')
        plt.savefig(__file__+'.png')

    assert np.allclose(jout_bnd_packed_cmaj[n:, :], ref_banded_j)