# Symbolics¶

PyWENO contains a symbolic module to help authors develop their own WENO methods and/or explore the basics of WENO methods. Below are a few quick examples demonstrating how the symbolic routines of PyWENO are used.

## Interpolating polynomials¶

First, let’s build some grid points and y-values:

```
>>> import sympy
>>> import pyweno
>>> (x0, x1, x2) = sympy.var('x0 x1 x2')
>>> (y0, y1, y2) = sympy.var('y0 y1 y2')
```

Then, the polynomial that interpolates the points `(x0, y0)`, `(x1,
y1)`, and `(x2, y2)` is given by:

```
>>> p = pyweno.symbolic.polynomial_interpolator([x0, x1, x2], [y0, y1, y2])
>>> p
y0*(x - x1)*(x - x2)/((x0 - x1)*(x0 - x2)) + y1*(x - x0)*(x - x2)/((x1 - x0)*(x1 - x2)) + y2*(x - x0)*(x - x1)/((x2 - x0)*(x2 - x1))
```

and is a function of the SymPy variable `x`. For example:

```
>>> x = sympy.var('x')
>>> p.subs(x, x2)
y2
```

The polynomial that interpolates the primitive function of \(f\) such that

is given by:

```
>>> P = pyweno.symbolic.primitive_polynomial_interpolator([x0, x1, x2], [y1, y2])
>>> P
y1*(x - x0)*(x - x2)/(x1 - x2) + (x - x0)*(x - x1)*(y1*(x1 - x0) + y2*(x2 - x1))/((x2 - x0)*(x2 - x1))
```

and is also a function of the SymPy variable `x`. For example:

```
>>> P.subs(x, x1)
y1*(x1 - x0)
```

For uniform grids, one could define the grid points by:

```
>>> (x, dx) = sympy.var('x dx')
>>> xs = [ dx, 2*dx, 3*dx ]
>>> p = pyweno.symbolic.polynomial_interpolator(xs, [y0, y1, y2])
>>> p
y0*(x - 3*dx)*(x - 2*dx)/(2*dx**2) + y2*(x - dx)*(x - 2*dx)/(2*dx**2) - y1*(x - dx)*(x - 3*dx)/dx**2
```

## Reconstruction coefficients¶

Hereafter we assume that the grid is uniform. Furthermore, to specify a point within a cell, the interval [-1, 1] is used as a reference.

The reconstruction coefficients for a 5th (=2k-1 where k=3) order WENO scheme corresponding to the reconstruction point at the left side (\(\xi\) = -1) of each grid cell are given by:

```
>>> c = pyweno.symbolic.reconstruction_coefficients(k=3, xi=[ -1 ])
>>> c
{'k': 3,
'n': 1,
(0, 0, 0): 11/6,
(0, 0, 1): -7/6,
(0, 0, 2): 1/3,
(0, 1, 0): 1/3,
(0, 1, 1): 5/6,
(0, 1, 2): -1/6,
(0, 2, 0): -1/6,
(0, 2, 1): 5/6,
(0, 2, 2): 1/3
```

Note that the return value `c` is a dictionary of SymPy objects,
indexed according to `c[l,r,j]` where `l` is the index of the
reconstruction point and `r` is the left-shift of the stencil.

Recall that the reconstruction coefficients \(c\) are used to
reconstruct the original (unknown) function \(f\) at each point
\(\xi_l\) in `xi` according to

for each \(l\) from 0 to *len(xi)*, where \(\bar{f}_{i-r+j}\) is
the cell average of \(f\) in the cell \(i-r+j\).

## Optimal weights¶

The optimal weights for a 5th (=2k-1 where k=3) order WENO scheme corresponding to the reconstruction point at the left side of each grid cell are given by:

```
>>> w = pyweno.symbolic.optimal_weights(3, [ -1 ])
>>> w
({'k': 3, 'n': 1, (0, 0): 1/10, (0, 1): 3/5, (0, 2): 3/10}, {0: False, 'n': 1})
```

Note that the return value *w* is a tuple of dictionaries of SymPy
objects. The first dictionary contains the weights, and is indexed
according to `w[l,r]`. the second dictionary contains boolean
values determining if the weights are split (negative).

Recall that the optimal weights are used to obtain an optimally high-order reconstruction of the original function \(f\) given the low-order reconstructions \(f^r(\xi^l)\) according to

## Smoothness coefficients¶

The Jiang-Shu smoothness coefficients for a 5th (=2k-1 where k=3) order WENO scheme are given by:

```
>>> beta = pyweno.symbolic.jiang_shu_smoothness_coefficients(3)
```

The return value *beta* is a dictionary of SymPy objects, and is
indexed according to `beta[r,m,n]` (see the reference documentation
for details).

Recall that the smoothness coefficients `beta[r, m, n]` are used to
compute the non-linear weights \(\omega^{l,r}\) (used in place of
\(\varpi^{l,r}\) in non-smooth regions) according to

where

and