def _integrate(self): """ Performs the integration by calling the callback chosen by :attr:`integrator`. If rd.logy == True, a transformation of self.C0 to log_b(C0) will be performed before running the integration (the same is done for self.tout / rd.logt == True). After the integration is done the attributes `Cout`, `info` and `yout` are set. Cout is guaranteed to be linear concentrations (transformed from yout by calling exp if rd.logy==True) and yout is the unprocessed output from the integrator. """ # Pre-processing # -------------- C0 = self.C0 # Transform initial concentrations if self.rd.logy: if not self.C0_is_log: C0 = self.rd.logb(C0 + self.tiny) if self.sigm_damp is True: y0 = sigm(C0) elif isinstance(self.sigm_damp, tuple): y0 = sigm(C0, *self.sigm_damp) else: y0 = C0 else: if self.C0_is_log: if self.sigm_damp is True: y0 = self.rd.expb(sigm(C0)) elif isinstance(self.sigm_damp, tuple): y0 = self.rd.expb(sigm(C0, *self.sigm_damp)) else: y0 = self.rd.expb(C0) else: y0 = C0 # Transform time tout = self.tout if tout[0] == 0.0 and self.rd.logt: t0_set = True t0 = suggest_t0(self.rd, y0) t = self.rd.logb(tout + t0) # conserve total time else: t0_set = False t = self.rd.logb(tout) if self.rd.logt else tout # Run the integration # ------------------- self.yout, self.internal_t, self.info = self._callbacks[self.integrator](self.rd, y0, t, **self.kwargs) self.info['t0_set'] = t0 if t0_set else False # Post processing # --------------- # Back-transform independent variable into linear time if self.rd.logt: self.tout = (self.rd.expb(self.internal_t) - (t0 if t0_set else 0)) else: self.tout = self.internal_t # Back-transform integration output into linear concentration self.Cout = self.rd.expb(self.yout) if self.rd.logy else self.yout
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