def reconstruction(self, coeffs=None): r"""Fully un-rolled reconstruction kernel for uniform grids. The reconstruction kernel computes the WENO reconstruction based on the weights *omega* (which have already been computed) and the reconstruction coefficients *coeffs*. """ from symbols import omega, fs, fr, f kernel = Kernel() if coeffs is None: coeffs = getattr(self, 'coeffs', symbolic.reconstruction_coefficients(self.k, self.xi)) n = coeffs.get('n') k = coeffs.get('k') nc = coeffs.get('l', k) varpi = getattr(self, 'varpi', None) split = getattr(self, 'split', None) if varpi is None: varpi, split = symbolic.optimal_weights(self.k, self.xi) scale = { (l,s): sum([ varpi[l,r][s] for r in range(0, k) ]) for l in range(n) for s in (0, 1) if split[l] } # reconstructions for l in range(n): for r in range(k): v = sum([ coeffs[l,r,j] * f[-r+j] for j in range(nc) ]) kernel.assign(fr[l,r], v) # weighted reconstruction for l in range(n): if not split[l]: v = sum([ omega[l,r] * fr[l,r] for r in range(k) ]) if not self.weights_normalised: v /= sum([ omega[l,r] for r in range(k) ]) else: vp = sum([ omega[l,r,0] * fr[l,r] for r in range(k) ]) if not self.weights_normalised: vp /= sum([ omega[l,r,0] for r in range(k) ]) vm = sum([ omega[l,r,1] * fr[l,r] for r in range(k) ]) if not self.weights_normalised: vm /= sum([ omega[l,r,1] for r in range(k) ]) v = scale[l,0] * vp - scale[l,1] * vm kernel.assign(fs[l], v) return kernel.body()
def weights(self, varpi=None, split=None, normalise=False, power=2, epsilon='1.0e-6'): r"""Fully un-rolled weights kernel for uniform grids. The weights kernel computes the weights :math:`\omega^r` determined by the smoothness coefficients :math:`\sigma^r` (which have already been computed). The weights :math:`\omega^r` are computed from the optimal weights :math:`\varpi^r` according to: .. math:: \omega^r = \frac{\varpi^r}{(\sigma^r + \epsilon)^p} The weights are subsequently renormalised (if requested) according to: .. math:: \omega^r = \frac{\omega^r}{\sum_j \omega^j} :param normalise: re-normalise the weights? :param power: power :math:`p` of the denominator :param epsilon: :math:`\epsilon` If *normalise* is ``False`` the weights are not re-normalised. Instead, the re-normalisation occurs during the reconstruction step. This saves a few divisions if the weights are computed during the reconstruction. """ from symbols import real, omega, sigma kernel = Kernel() varpi = varpi or getattr(self, 'varpi', None) split = split or getattr(self, 'split', None) if varpi is None: varpi, split = symbolic.optimal_weights(self.k, self.xi) n = varpi.get('n') k = varpi.get('k') nc = varpi.get('l', k) scale = { (l,s): sum([ varpi[l,r][s] for r in range(0, k) ]) for l in range(n) for s in (0, 1) if split[l] } self.weights_normalised = normalise epsilon = real(epsilon) accsym = real('acc') for l in range(n): if not split[l]: for r in range(0, k): kernel.assign(omega[l,r], varpi[l,r] / (sigma[r] + epsilon)**power) if normalise: kernel.assign(accsym, sum([ omega[l,r] for r in range(0, k) ])) for r in range(0, k): kernel.assign(omega[l,r], omega[l,r] / accsym) else: for s, pm in enumerate(('p', 'm')): for r in range(0, k): kernel.assign(omega[l,r,s], varpi[l,r][s] / scale[l,s] / (sigma[r] + epsilon)**power) if normalise: kernel.assign(accsym, sum([ omega[l,r,s] for r in range(0, k) ])) for r in range(0, k): kernel.assign(omega[l,r,s], omega[l,r,s] / accsym) self.varpi = varpi self.split = split return kernel.body()