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_dc(): n = 7 k = [1]*(n-1) rd = ReactionDiffusion(n, [[i] for i in range(n-1)], [[i] for i in range(1, n)], k=k) fout = rd.alloc_fout() y0 = [0]*n y0[0] = 1 y_ = [0] + y0 y0 = np.asarray(y0, dtype=np.float64) rd.f(0, y0, fout) pos, neg = [0]+k, k+[0] _test_f(rd, 0, y0) fref = [pos[i]*y_[i] - neg[i]*y_[i+1] for i in range(n)] assert np.allclose(fref, fout) jout = rd.alloc_jout(order='C') rd.dense_jac_rmaj(0, y0, jout) jref = np.zeros_like(jout) for i in range(n): if i < n - 1: jref[i, i] = -k[i] if i > 0: jref[i, i-1] = k[i-1] assert np.allclose(jref, jout) _test_dense_jac_rmaj(rd, 0, y0)
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)