Ejemplo n.º 1
0
def test_rational_chebyshev_interpolation(show=False):
    """Test the inperpolation routine of ChebyshevRationalGrid"""
    import numpy as np
    from psecas import ChebyshevRationalGrid

    def psi(x, c):
        from numpy.polynomial.hermite import hermval

        return hermval(x, c) * np.exp(-x**2 / 2)

    N = 95
    grid = ChebyshevRationalGrid(N, C=4)

    grid_fine = ChebyshevRationalGrid(N * 4, C=1)
    z = grid_fine.zg

    y = psi(grid.zg, np.array(np.ones(4)))
    y_fine = psi(z, np.array(np.ones(4)))
    y_interpolated = grid.interpolate(z, y)

    if show:
        import matplotlib.pyplot as plt

        plt.figure(3)
        plt.clf()
        plt.title("Interpolation with rational Chebyshev")
        plt.plot(z, y_fine, "-")
        plt.plot(z, y_interpolated, "--")
        plt.plot(grid.zg, y, "+")
        plt.xlim(-15, 15)
        plt.show()

    np.testing.assert_allclose(y_fine, y_interpolated, atol=1e-12)
    return (y_fine, y_interpolated)
Ejemplo n.º 2
0
def test_channel(show=False, verbose=False):
    """Test eigenvalue solver using ChebyshevRationalGrid"""
    import numpy as np
    from psecas import Solver, ChebyshevRationalGrid, System

    grid = ChebyshevRationalGrid(N=199, z='z')

    class Channel(System):
        def make_background(self):
            import numpy as np

            zg = self.grid.zg
            self.h = np.exp(-zg**2 / 2)

    # Create the Channel system
    system = Channel(grid, variables='G', eigenvalue='K2')

    # Add the first (and only) equation
    system.add_equation("-h*K2*G = dz(dz(G)) +z*dz(G)", boundary=True)
    solver = Solver(grid, system, do_gen_evp=True)

    # Number of modes to test
    modes = 3
    results = np.zeros(modes, dtype=np.complex128)
    checks = np.array([85.08037778, 69.4741069099, 55.4410282999])

    def sorting_strategy(E):
        """Sorting strategy for channel modes"""
        E[E.real > 100.0] = 0
        E[E.real < -10.0] = 0
        index = np.argsort(np.real(E))[::-1]
        return (E, index)

    solver.sorting_strategy = sorting_strategy

    if show:
        import matplotlib.pyplot as plt

        plt.figure(3)
        plt.clf()
        fig, axes = plt.subplots(num=3, ncols=modes, sharey=True)
    for mode in range(modes):
        Ns = np.arange(1, 6) * 32
        omega, vec, err = solver.iterate_solver(Ns, mode=mode, verbose=True)
        results[mode] = omega
        if show:
            phi = np.arctan(vec[2].imag / vec[2].real)
            solver.keep_result(omega, vec * np.exp(-1j * phi), mode)
            axes[mode].set_title(r"$\sigma = ${:1.4f}".format(omega.real),
                                 fontsize=10)
            axes[mode].plot(grid.zg, system.result['G'].real)
            axes[mode].plot(grid.zg, system.result['G'].imag)
            axes[mode].set_xlim(-4, 4)

    if show:
        plt.show()

    np.testing.assert_allclose(results, checks, rtol=1e-6)
Ejemplo n.º 3
0
def test_rational_chebyshev_differentation(show=False):
    """Test the differentation routine of ChebyshevRationalGrid"""
    import numpy as np
    from psecas import ChebyshevRationalGrid

    def psi(x, c):
        from numpy.polynomial.hermite import hermval

        return hermval(x, c) * np.exp(-x**2 / 2)

    def dpsi(x, c):
        from numpy.polynomial.hermite import hermval, hermder

        yp = hermval(x, hermder(c)) * np.exp(-x**2 / 2) - x * psi(x, c)
        return yp

    def d2psi(x, c):
        """Second derivative of psi"""
        from numpy.polynomial.hermite import hermval, hermder

        yp = hermval(x, hermder(hermder(c))) * np.exp(-x**2 / 2)
        yp += -x * hermval(x, hermder(c)) * np.exp(-x**2 / 2)
        yp += -psi(x, c) - x * dpsi(x, c)
        return yp

    N = 100
    grid = ChebyshevRationalGrid(N, C=4)

    assert grid.zg[0] < grid.zg[-1]

    c = np.ones(4)
    y = psi(grid.zg, c)
    yp_exac = dpsi(grid.zg, c)
    yp_num = np.matmul(grid.d1, y)
    ypp_exac = d2psi(grid.zg, c)
    ypp_num = np.matmul(grid.d2, y)

    if show:
        import matplotlib.pyplot as plt

        plt.figure(1)
        plt.clf()
        fig, axes = plt.subplots(num=1, nrows=2)
        axes[0].set_title("Differentation with matrix (Sinc)")
        axes[0].plot(grid.zg, yp_exac, "-", grid.zg, yp_num, "--")
        axes[1].plot(grid.zg, ypp_exac, "-", grid.zg, ypp_num, "--")
        for ax in axes:
            ax.set_xlim(-15, 15)
        axes[0].set_ylim(-15, 15)
        plt.show()

    np.testing.assert_allclose(yp_num, yp_exac, atol=1e-12)
    np.testing.assert_allclose(ypp_num, ypp_exac, atol=1e-10)

    return (yp_num, yp_exac)
Ejemplo n.º 4
0
def test_hermite_solutions(show=False):

    import numpy as np
    from psecas import Solver, System
    from psecas import HermiteGrid, SincGrid, ChebyshevRationalGrid
    """
        Test of the behaviour of three different grids on the
        infinite domain.
        See also  the example hermite.py and note that the Chebyshev Rational
        grid uses roughly twice as many grid points.

        The example can be found in Boyd page 131-133.
        We consider the eigenvalue problem
        uₓₓ + (λ - x²) u = 0 with |u| → 0 as |x| → ∞
        which has exact solutions uⱼ(x) = exp(-x²/2)H₋j(x) where
        H₋j(x) is the jᵗʰ Hermite polynomial. The exact eigenvalues are
        λⱼ = 2 j + 1.
    """

    N = 40

    # Create grids
    grid1 = ChebyshevRationalGrid(N=2 * N - 1, C=2)
    grid2 = SincGrid(N=N, C=2)
    grid3 = HermiteGrid(N=N, C=1)

    grids = list([grid1, grid2, grid3])
    tols = [1e-8, 1e-7, 1e-12]

    class HermiteSolver(Solver):
        def sorting_strategy(self, E):
            """Sorting strategy for hermite modes. E is a list of
               eigenvalues"""
            E[E.real > 100.0] = 0
            # Ignore eigenvalues that are zero
            E[E.real == 0.0] = 1e5
            # Sort from smallest to largest eigenvalue
            index = np.argsort(np.real(E))
            return (E, index)

    if show:
        import matplotlib.pyplot as plt
        plt.figure(1)
        plt.clf()
        fig, axes = plt.subplots(num=1, nrows=3, ncols=10, sharex=True)

    for ii, grid in enumerate(grids):
        system = System(grid, variables="u", eigenvalue="sigma")
        if isinstance(grid, ChebyshevRationalGrid):
            boundary = True
        else:
            boundary = False
        system.add_equation("sigma*u = -dz(dz(u)) + z**2*u", boundary=boundary)
        solver = HermiteSolver(grid, system)
        for j in range(10):
            omega, vec = solver.solve(mode=j)
            np.testing.assert_allclose(2.0 * j + 1.0,
                                       omega.real,
                                       atol=tols[ii],
                                       rtol=tols[ii])

            if show:
                solver.keep_result(omega, vec / np.max(np.abs(vec)), mode=j)
                msg = r" $\sigma = ${:1.8f}"
                ylabel = type(grid).__name__
                axes[ii, j].set_title(msg.format(omega.real), fontsize=10)
                if isinstance(grid, HermiteGrid):
                    z = np.linspace(3 * grid.zmin / 5, 3 * grid.zmax / 5, 5000)
                else:
                    z = np.linspace(grid.zmin, grid.zmax, 5000)
                axes[ii, j].plot(z, grid.interpolate(z,
                                                     system.result["u"].real),
                                 "C0-")
                axes[ii, j].plot(z, grid.interpolate(z,
                                                     system.result["u"].imag),
                                 "C1-")
                axes[ii, j].plot(grid.zg, system.result["u"].real, "C0+")
                axes[ii, j].plot(grid.zg, system.result["u"].imag, "C1+")
                axes[ii, j].set_xlim(-15, 15)
                axes[ii, 0].set_ylabel(ylabel)
                plt.show()
Ejemplo n.º 5
0
is 

    F'' + K² h F = 0

and is solved  by employing a Neumann boundary condition on F.

One of the modes obtained here, with KH=3.1979, is not found
when solving 

    -h K² G = z G' + G'' 
    
Visual inspection reveals that the extra mode is numerical garbage.
Automated detection of such modes would be a good feature to implement.
"""

grid = ChebyshevRationalGrid(N=199, z='z')
system = Channel(grid)

ch = Solver(grid, system)


def sorting_strategy(E):
    """Sorting strategy for channel modes"""
    E[E.real > 100.0] = 0
    E[E.real < -10.0] = 0
    index = np.argsort(np.real(E))[::-1]
    return (E, index)


# Overwrite the default sorting strategy in the Solver class
ch.sorting_strategy = sorting_strategy
Ejemplo n.º 6
0
"""
    Illustration of the behaviour of three different grids on the
    infinite domain. The example can be found in Boyd page 131-133.
    We consider the eigenvalue problem
    uₓₓ + (λ - x²) u = 0 with |u| → 0 as |x| → ∞
    which has exact solutions uⱼ(x) = exp(-x²/2)H₋j(x) where
    H₋j(x) is the jᵗʰ Hermite polynomial. The exact eigenvalues are
    λⱼ = 2 j + 1.
"""


N = 40

# Create grids
grid1 = ChebyshevRationalGrid(N=N - 1, C=2)
grid2 = SincGrid(N=N, C=2)
grid3 = HermiteGrid(N=N, C=1)

grids = list([grid1, grid2, grid3])

# Mode number
j = 8


class HermiteSolver(Solver):
    def sorting_strategy(self, E):
        """Sorting strategy for hermite modes. E is a list of eigenvalues"""
        E[E.real > 100.0] = 0
        # Ignore eigenvalues that are zero
        E[E.real == 0.0] = 1e5
Ejemplo n.º 7
0
After solving for G, F can be found from 

    F = -1/(K h) G'

The division by h gives some numerical issues, since
h → 0 as z → ± ∞. Alternatively, we can solve their
equation 17 for F directly,

    F'' + K² h F = 0

by employing a Neumann boundary condition on F. This is explored in
the script channel.py.
"""

# Create grid
grid = ChebyshevRationalGrid(N=199, C=1, z='z')
# grid = SincGrid(N=299, C=1, z='z')


# Make a Child of the System class and override the make_background method
class Channel(System):
    def make_background(self):
        import numpy as np

        zg = self.grid.zg
        self.h = np.exp(-zg ** 2 / 2)


# Create the Channel system
system = Channel(grid, variables='G', eigenvalue='K2')
Ejemplo n.º 8
0
This problem is described in the paper

*MRI channel flows in vertically stratified models of accretion discs*,
https://doi.org/10.1111/j.1365-2966.2010.16759.x,
by Henrik N. Latter, Sebastien Fromang, Oliver Gressel

We solve their equation 16 as a coupled system:

    h K F = - G'
    K G = F'

The spurious mode found in channel.py also appears here.
"""

# Create grid
grid = ChebyshevRationalGrid(N=199, C=1, z='z')
# grid = SincGrid(N=599, C=2, z='z')


# Make a Child of the System class and override the make_background method
class Channel(System):
    def make_background(self):
        import numpy as np

        zg = self.grid.zg
        self.h = np.exp(-zg ** 2 / 2)


# Create the Channel system
system = Channel(grid, variables=['F', 'G'], eigenvalue='K')
Ejemplo n.º 9
0
                   (1 + 1 / 3 * (2 - q) * (p + q) * h**2 + q *
                    (1 - (1 + 2 / 3 * z**2 * h**2) /
                     ((1 + z**2 * h**2)**(3 / 2)))))
        drhodz_sym = sym.diff(rho_sym, z)
        domgdz_sym = sym.diff(Omg_sym, z)

        zg = self.grid.zg
        self.rho = np.ones_like(zg) * lambdify(z, rho_sym)(zg)
        self.Omg = np.ones_like(zg) * lambdify(z, Omg_sym)(zg)
        self.shr = np.ones_like(zg) * lambdify(z, shr_sym)(zg)
        self.drhodz = np.ones_like(zg) * lambdify(z, drhodz_sym)(zg)
        self.domgdz = np.ones_like(zg) * lambdify(z, domgdz_sym)(zg)


# Create a grid
grid = ChebyshevRationalGrid(N=200, C=0.2)
# grid = ChebyshevExtremaGrid(N=199, zmin=-5, zmax=5)

# Create the system
system = VerticalShearInstability(grid,
                                  variables=['rh', 'wx', 'wy', 'wz'],
                                  eigenvalue='sigma')

# The linearized equations
system.add_equation("-sigma*rh = - 1j*kx*wx - 1/h*dz(wz) - 1/h*drhodz/rho*wz")
system.add_equation("-sigma*wx = + 2*Omg*wy - 1j*kx*(h/O0)**2*rh")
system.add_equation("-sigma*wy = - (2*Omg + shr)*wx - 1/h*domgdz*wz")
system.add_equation("-sigma*wz = - h/O0**2*dz(rh)", boundary=True)

solver = Solver(grid, system, do_gen_evp=True)
Ejemplo n.º 10
0
from psecas import Solver, ChebyshevRationalGrid
from psecas.systems.kh_hydro_sheet import KelvinHelmholtzHydroOnlySlab
from psecas import plot_solution, get_2Dmap
import numpy as np
import matplotlib.pyplot as plt
"""
    Find the eigenmodes of the KH instability on the domain z ∈ [-∞, ∞]
    assuming that the perturbations are zero at the boundaries.

    This the pure hydro version of the Kelvin-Helmholtz instability.
    The equilibrium changes sign at z=0 and is therefore not periodic.
"""

grid = ChebyshevRationalGrid(N=32, C=0.4)

u0 = 1.0
delta = 1.0
kx = 5.1540899
kx = 3.5128310

system = KelvinHelmholtzHydroOnlySlab(grid, u0, delta, kx)
system.boundaries = [True, True, True, True]

solver = Solver(grid, system)

Ns = np.arange(1, 32) * 32 - 1
omega, vec, err = solver.iterate_solver(Ns, mode=0, verbose=True)

xmin = 0
xmax = 2 * np.pi / kx
zmin = -4