Ejemplo n.º 1
0
def test_coloured_spy():
    from matplotlib.axes import Axes
    A = np.arange(9).reshape((3, 3))
    for log in (False, True, -5):
        ax_im, ax_cb = coloured_spy(A, log=log)
        assert isinstance(ax_im, Axes)
        assert isinstance(ax_cb, Axes)
Ejemplo n.º 2
0
def integrate_rd(tend=10.0, N=1, nt=500, jac_spy=False,
                 linear_solver='default', logy=False, logt=False,
                 plot=False, savefig='None', verbose=False, graph=False,
                 **kwargs):
    """
    Integrates the reaction system defined by
    :download:`four_species.json <examples/four_species.json>`
    """
    rd = load(os.path.join(os.path.dirname(
        __file__), 'four_species.json'), N=N, x=N, logy=logy, logt=logt)

    y0 = np.array([1.3, 1e-4, 0.7, 1e-4])
    y0 = np.concatenate([y0/(i+1)*(0.25*i**2+1) for i in range(N)])
    t0 = 1e-10

    if linear_solver == 'default':
        if rd.N == 1:
            linear_solver = 'dense'
        elif rd.N > 1:
            linear_solver = 'banded'
    if linear_solver not in ('dense', 'banded'):
        raise NotImplementedError("dense or banded linear_solver")

    import matplotlib.pyplot as plt
    if jac_spy:
        fout = np.empty(rd.n*rd.N)
        rd.f(t0, y0, fout)
        print(fout)
        if linear_solver == 'dense':
            jout = np.zeros((rd.n*rd.N, rd.n*rd.N), order='F')
            rd.dense_jac_cmaj(t0, y0, jout)
            coloured_spy(np.log(np.abs(jout)))
        elif linear_solver == 'banded':
            # note rd.n*3 needed in call from scipy.integrate.ode
            jout = np.zeros((rd.n*2+1, rd.n*rd.N), order='F')
            rd.banded_packed_jac_cmaj(t0, y0, jout)
            coloured_spy(np.log(np.abs(jout)))
        print(jout)
        plt.show()
    else:
        tout = np.linspace(t0, tend, nt)
        integr = run(rd, y0, tout, **kwargs)
        if verbose:
            print(integr.info)
        if plot:
            plt.figure(figsize=(6, 4))
            for i, l in enumerate('ABCD'):
                plt.plot(integr.tout, integr.Cout[:, 0, i], label=l)
            plt.title("Time evolution of concentrations")
            plt.legend()
            save_and_or_show_plot(savefig=savefig)

            plt.figure(figsize=(6, 10))
            plot_jacobian(
                rd,
                np.log(integr.tout) if rd.logt else integr.tout,
                np.log(integr.Cout) if rd.logy else integr.Cout,
                'ABCD',
                lintreshy=1e-10
            )
            plt.tight_layout()
            if savefig != 'None':
                base, ext = os.path.splitext(savefig)
                savefig = base + '_jacobian' + ext
            save_and_or_show_plot(savefig=savefig)

            plt.figure(figsize=(6, 10))
            plot_per_reaction_contribution(
                integr,
                'ABCD'
            )
            plt.tight_layout()
            if savefig != 'None':
                savefig = base + '_per_reaction' + ext
            save_and_or_show_plot(savefig=savefig)
    if graph:
        print(rsys2graph(ReactionSystem.from_ReactionDiffusion(rd, 'ABCD'),
                         'four_species_graph.png', save='.'))
    return integr
Ejemplo n.º 3
0
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)