Example #1
0
  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()
Example #2
0
  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()