def evaluate(self, t0, qSDC, fSDC, node, feval, **kwargs): nnodes = fSDC.shape[1] f1eval = hasattr(feval, 'f1_evaluate') f2eval = hasattr(feval, 'f2_evaluate') if node == 'all': for m in range(nnodes): self.pf.state.node = m self.level.call_hooks('pre-feval', **kwargs) if f1eval and f2eval: feval.f1_evaluate(qSDC[m], t0, fSDC[0, m], **kwargs) feval.f2_evaluate(qSDC[m], t0, fSDC[1, m], **kwargs) elif f1eval: feval.f1_evaluate(qSDC[m], t0, fSDC[0, m], **kwargs) else: feval.f2_evaluate(qSDC[m], t0, fSDC[0, m], **kwargs) self.level.call_hooks('post-feval', **kwargs) else: self.pf.state.node = node self.level.call_hooks('pre-feval', **kwargs) if f1eval and f2eval: feval.f1_evaluate(qSDC[node], t0, fSDC[0, node], **kwargs) feval.f2_evaluate(qSDC[node], t0, fSDC[1, node], **kwargs) elif f1eval: feval.f1_evaluate(qSDC[node], t0, fSDC[0, node], **kwargs) else: feval.f2_evaluate(qSDC[node], t0, fSDC[0, node], **kwargs) self.level.call_hooks('post-feval', **kwargs)
def sweep(self, b, t0, dt, qSDC, fSDC, feval, **kwargs): r"""Perform one SDC sweep with new initial conditions and add FAS corrections. :param b: right hand side (numpy array of size ``(nnodes,nqvar)``) :param t0: initial time :param dt: time step :param qSDC: solution (numpy array of size ``(nnodes,nqvar)``) :param fSDC: function (numpy array of size ``(nnodes,nfvar)``) :param feval: implicit/explicit function evaluator (instance of :py:class:`pfasst.feval.FEval`) Note that *qSDC* and *fSDC* are over-written. The sweep performed uses forward/fackward Euler time-stepping: XXX .. math:: \begin{multline} U^{k+1}_{m+1} = U^k_m + \Delta t_m \bigl[ f_I(t_{m+1}, U^{k+1}_{m+1}) + f_E(t_{m}, U^{k+1}_{m}) \bigr] \\ + \vec{S}^{m,m+1}_E \, f_E(\vec{t}, \vec{U}^{k}) + \vec{S}^{m,m+1}_I \, f_I(\vec{t}, \vec{U}^{k}). \end{multline} """ exp = self.smat_exp imp = self.smat_imp pieces = fSDC.shape[0] nnodes = fSDC.shape[1] shape = fSDC.shape[2:] size = feval.size fSDCf = fSDC.reshape((pieces, nnodes, size)) # flatten so we can use np.dot rhs = dt * (np.dot(exp, fSDCf[0]) + np.dot(imp, fSDCf[1])) rhs = rhs.reshape((nnodes-1,)+shape) # unflatten # add b if b is not None: rhs += b[1:] # set initial condition and eval qSDC[0] = b[0] feval.f1_evaluate(qSDC[0], t0, fSDC[0,0], **kwargs) feval.f2_evaluate(qSDC[0], t0, fSDC[1,0], **kwargs) # sub time-stepping t = t0 dtsdc = dt * self.dsdc for m in range(self.nnodes-1): t += dtsdc[m] y = qSDC[m] + dtsdc[m]*fSDC[0,m] + rhs[m] feval.f2_solve(y, qSDC[m+1], t, dtsdc[m], fSDC[1,m+1], **kwargs) feval.f1_evaluate(qSDC[m+1], t, fSDC[0,m+1], **kwargs)
def sweep(self, t0, dt, F, **kwargs): r"""Perform one SDC sweep. Note that *qSDC* and *fSDC* are over-written. The sweep performed uses forward/backward Euler time-stepping. """ exp = self.smat_exp imp = self.smat_imp qSDC = F.qSDC fSDC = F.fSDC feval = F.feval pieces = fSDC.shape[0] nnodes = fSDC.shape[1] shape = fSDC.shape[2:] size = feval.size f1eval = hasattr(feval, 'f1_evaluate') f2eval = hasattr(feval, 'f2_evaluate') F.call_hooks('pre-sweep', **kwargs) # flatten so we can use np.dot fSDCf = fSDC.reshape((pieces, nnodes, size)) # integrate f if f1eval and f2eval: rhs = dt * (np.dot(exp, fSDCf[0]) + np.dot(imp, fSDCf[1])) elif f1eval: rhs = dt * np.dot(exp, fSDCf[0]) else: rhs = dt * np.dot(imp, fSDCf[0]) rhs = rhs.reshape((nnodes-1,)+shape) # add tau if F.tau is not None: rhs += F.tau # set initial condition and eval qSDC[0] = F.q0 self.evaluate(t0, qSDC, fSDC, 0, feval, **kwargs) if F.gSDC is not None: fSDC[0,0] += F.gSDC[0] # sub time-stepping t = t0 dtsdc = dt * self.dsdc for m in range(self.nnodes-1): t += dtsdc[m] self.pf.state.node = m + 1 self.level.call_hooks('pre-feval', **kwargs) if f1eval and f2eval: # imex q1 = qSDC[m] + dtsdc[m]*fSDC[0,m] + rhs[m] feval.f2_solve(q1, qSDC[m+1], t, dtsdc[m], fSDC[1,m+1], **kwargs) feval.f1_evaluate(qSDC[m+1], t, fSDC[0,m+1], **kwargs) elif f1eval: # explicit qSDC[m+1] = qSDC[m] + dtsdc[m]*fSDC[0,m] + rhs[m] feval.f1_evaluate(qSDC[m+1], t, fSDC[0,m+1], **kwargs) else: # implicit q1 = qSDC[m] + dtsdc[m]*fSDC[0,m] + rhs[m] feval.f2_solve(q1, qSDC[m+1], t, dtsdc[m], fSDC[0,m+1], **kwargs) self.level.call_hooks('post-feval', **kwargs) if F.gSDC is not None: fSDC[0,m+1] += F.gSDC[m+1] F.qend[...] = F.qSDC[-1] self.pf.state.node = -1 F.call_hooks('post-sweep', **kwargs)