예제 #1
0
def test_adaptive(ode, y0):
    """
    Проверяем алгоритмы выбора шага
    """
    t0, t1 = 0, 4 * np.pi

    atol = 1e-6
    rtol = 1e-3

    tss = []
    yss = []

    methods = (
        (ExplicitEulerMethod(), AdaptType.RUNGE),
        (RungeKuttaMethod(coeffs.rk4_coeffs), AdaptType.RUNGE),
        (EmbeddedRungeKuttaMethod(coeffs.dopri_coeffs), AdaptType.EMBEDDED),
    )

    for method, adapt_type in methods:
        ode.clear_call_counter()
        ts, ys = adaptive_step_integration(method=method,
                                           ode=ode,
                                           y_start=y0,
                                           t_span=(t0, t1),
                                           adapt_type=adapt_type,
                                           atol=atol,
                                           rtol=rtol)
        print(f'{method.name} took {ode.get_call_counter()} function calls')

        tss.append(np.array(ts))
        yss.append(ys)

    ts = np.array(sorted([t for ts in tss for t in ts]))
    exact = ode[ts].T
    y0 = np.array([y[0] for y in exact])

    # plots
    fig1, ax1 = plt.subplots(num='y(t)')
    fig1.suptitle('test_adaptive: y(t)')
    ax1.set_xlabel('t'), ax1.set_ylabel('y')
    ax1.plot(ts, y0, 'ko-', label='exact')

    fig2, ax2 = plt.subplots(num='dt(t)')
    fig2.suptitle('test_adaptive: step sizes')
    ax2.set_xlabel('t'), ax2.set_ylabel('dt')

    fig3, ax3 = plt.subplots(num='dy(t)')
    fig3.suptitle('test_adaptive: accuracies')
    ax3.set_xlabel('t'), ax3.set_ylabel('accuracy')

    for (m, _), ts, ys in zip(methods, tss, yss):
        ax1.plot(ts, [y[0] for y in ys], '.', label=m.name)
        ax2.plot(ts[:-1], ts[1:] - ts[:-1], '.-', label=m.name)
        ax3.plot(ts, get_accuracy(ode[ts].T, ys), '.-', label=m.name)

    ax1.legend()
    ax2.legend()
    ax3.legend()

    plt.show()
예제 #2
0
def test_stiff():
    """
    Проверяем явные и неявные методы на жёсткой задаче
    https://en.wikipedia.org/wiki/Van_der_Pol_oscillator
    Q: почему даже метод Розенброка иногда уменьшает шаг почти до нуля?
    """
    t0 = 0
    t1 = 800 * np.pi

    mu = 1000
    y0 = np.array([2., 0.])
    f = VanDerPol(y0, mu)

    fig1, ax1 = plt.subplots()
    fig2, (ax21, ax22) = plt.subplots(1, 2)
    fig3, ax3 = plt.subplots()

    colors = 'rgbcmyk'
    for i, (method, adapt_type) in enumerate([
        (ExplicitEulerMethod(), AdaptType.RUNGE),
        (ImplicitEulerMethod(), AdaptType.RUNGE),
        (EmbeddedRosenbrockMethod(coeffs.rosenbrock23_coeffs),
         AdaptType.EMBEDDED),
    ]):
        f.clear_call_counter()
        ts, ys = adaptive_step_integration(method,
                                           f,
                                           y0, (t0, t1),
                                           adapt_type=adapt_type,
                                           atol=1e-6,
                                           rtol=1e-3)
        print(
            f'{method.name}: {len(ts)-1} steps, {f.get_call_counter()} RHS calls'
        )

        ax1.plot([y[0] for y in ys], [y[1] for y in ys],
                 f'{colors[i]}.--',
                 label=method.name)

        ax21.plot(ts, [y[0] for y in ys], f'{colors[i]}.--', label=method.name)
        ax22.plot(ts, [y[1] for y in ys], f'{colors[i]}.--', label=method.name)

        ax3.plot(ts[:-1],
                 np.array(ts[1:]) - np.array(ts[:-1]),
                 f'{colors[i]}.--',
                 label=method.name)

    ax1.set_xlabel('x'), ax1.set_ylabel('y'), ax1.legend()
    fig1.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}, y(x)')

    ax21.set_xlabel('t'), ax21.set_ylabel('x'), ax21.legend()
    ax22.set_xlabel('t'), ax22.set_ylabel('y'), ax22.legend()
    fig2.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}, x(t)')

    ax3.set_xlabel('t'), ax3.set_ylabel('dt'), ax3.legend()
    fig3.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}, dt(t)')

    plt.show()
예제 #3
0
def test_stiff():
    """
    test explicit vs implicit methods on a stiff problem
    """
    t0 = 0
    t1 = 800*np.pi

    mu = 1000
    y0 = np.array([2., 0.])
    f = VanDerPol(y0, mu)

    fig1, ax1 = plt.subplots()
    fig2, (ax21, ax22) = plt.subplots(1, 2)
    fig3, ax3 = plt.subplots()

    colors = 'rgbcmyk'
    for i, (method, adapt_type) in enumerate(
            [
                (ExplicitEulerMethod(),                                AdaptType.RUNGE),
                (ImplicitEulerMethod(),                                AdaptType.RUNGE),
                (EmbeddedRosenbrockMethod(coeffs.rosenbrock23_coeffs), AdaptType.EMBEDDED),
            ]
    ):
        f.clear_call_counter()
        ts, ys = adaptive_step_integration(method, f, y0, (t0, t1),
                                           adapt_type=adapt_type,
                                           atol=1e-6, rtol=1e-3)
        print(f'{method.name}: {len(ts)-1} steps, {f.get_call_counter()} RHS calls')

        ax1.plot([y[0] for y in ys],
                 [y[1] for y in ys],
                 f'{colors[i]}.--', label=method.name)

        ax21.plot(ts,
                  [y[0] for y in ys],
                  f'{colors[i]}.--', label=method.name)
        ax22.plot(ts,
                  [y[1] for y in ys],
                  f'{colors[i]}.--', label=method.name)

        ax3.plot(ts[:-1],
                 np.array(ts[1:]) - np.array(ts[:-1]),
                 f'{colors[i]}.--', label=method.name)

    ax1.set_xlabel('x'), ax1.set_ylabel('y'), ax1.legend()
    fig1.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}, y(x)')

    ax21.set_xlabel('t'), ax21.set_ylabel('x'), ax21.legend()
    ax22.set_xlabel('t'), ax22.set_ylabel('y'), ax22.legend()
    fig2.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}, x(t)')

    ax3.set_xlabel('t'), ax3.set_ylabel('dt'), ax3.legend()
    fig3.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}, dt(t)')

    plt.show()
예제 #4
0
def test_stiff():
    """
    Проверяем явные и неявные методы на жёсткой задаче
    https://en.wikipedia.org/wiki/Van_der_Pol_oscillator
    Q: почему даже метод Розенброка иногда уменьшает шаг почти до нуля?
    """
    t0 = 0
    t1 = 2500

    mu = 1000
    y0 = np.array([2., 0.])
    ode = VanDerPol(y0, mu)

    fig, axs = plt.subplots(2, 2, figsize=(10, 8))

    colors = 'rgbcmyk'
    for i, (method, adapt_type) in enumerate([
        (ExplicitEulerMethod(), AdaptType.RUNGE),
        (ImplicitEulerMethod(), AdaptType.RUNGE),
        (EmbeddedRosenbrockMethod(coeffs.rosenbrock23_coeffs),
         AdaptType.EMBEDDED),
    ]):
        ode.clear_call_counter()
        ts, ys = adaptive_step_integration(method,
                                           ode,
                                           y0, (t0, t1),
                                           adapt_type=adapt_type,
                                           atol=1e-6,
                                           rtol=1e-3)
        print(
            f'{method.name}: {len(ts)-1} steps, {ode.get_call_counter()} RHS calls'
        )

        axs[0, 0].plot([y[0] for y in ys], [y[1] for y in ys],
                       f'{colors[i]}.--',
                       label=method.name)
        axs[0, 1].plot(ts[:-1],
                       np.diff(ts),
                       f'{colors[i]}.--',
                       label=method.name)
        axs[1, 0].plot(ts, [y[0] for y in ys],
                       f'{colors[i]}.--',
                       label=method.name)
        axs[1, 1].plot(ts, [y[1] for y in ys],
                       f'{colors[i]}.--',
                       label=method.name)

    axs[0, 0].legend(), axs[0, 0].set_title('y(x)')
    axs[0, 1].legend(), axs[0, 1].set_title('dt(t)')
    axs[1, 0].legend(), axs[1, 0].set_title('x(t)')
    axs[1, 1].legend(), axs[1, 1].set_title('y(t)')

    fig.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}')
    fig.tight_layout()
    plt.show()
예제 #5
0
def adaptive_step_integration(method: OneStepMethod, func, y_start, t_span,
                              adapt_type: AdaptType, atol, rtol):
    """
    performs adaptive-step integration using one-step method
    t_span: (t0, t1)
    adapt_type: Runge or Embedded
    tolerances control the error:
        err <= atol
        err <= |y| * rtol
    return: list of t's, list of y's
    """
    y = y_start
    t, t_end = t_span

    ys = [y]
    ts = [t]

    p = method.p + 1
    tol = atol + np.linalg.norm(y) * rtol
    rside0 = func(t, y)
    delta = (1 / max(abs(t), abs(t_end)))**(p + 1) + np.linalg.norm(rside0)**(
        p + 1)
    h1 = (tol / delta)**(1 / (p + 1))
    u1 = ExplicitEulerMethod().step(func, t, y, h1)
    tnew = t + h1
    rside0 = func(tnew, u1)
    delta = (1 / max(abs(t), abs(t_end)))**(p + 1) + np.linalg.norm(rside0)**(
        p + 1)
    h1new = (tol / delta)**(1 / (p + 1))
    h = min(h1, h1new)
    while t < t_end:
        if t + h > t_end:
            h = t_end - t

        if adapt_type == AdaptType.RUNGE:
            y1 = method.step(func, t, y, h)
            yhalf = method.step(func, t, y, h / 2)
            y2 = method.step(func, t + h / 2, yhalf, h / 2)
            error = (y2 - y1) / (2**p - 1)
            ybetter = y2 + error
        else:
            ybetter, error = method.embedded_step(func, t, y, h)

        if np.linalg.norm(error) < tol:
            ys.append(ybetter)
            ts.append(t + h)
            y = ybetter
            t += h
            print(t)

        h *= (tol / np.linalg.norm(error))**(1 / (p + 1)) * 0.9
    return ts, ys
예제 #6
0
def test_adaptive_order():
    """
    Проверяем сходимость
    Q: почему наклон линии (число в скобках) соответствует порядку метода?
    """
    t0, t1 = 0, 2 * np.pi
    y0 = np.array([1., 1.])
    ode = Harmonic(y0, 1, 1)

    methods = (
        (ExplicitEulerMethod(), AdaptType.RUNGE),
        (RungeKuttaMethod(coeffs.rk4_coeffs), AdaptType.RUNGE),
        (RungeKuttaMethod(coeffs.dopri_coeffs), AdaptType.RUNGE),
        (EmbeddedRungeKuttaMethod(coeffs.dopri_coeffs), AdaptType.EMBEDDED),
    )
    tols = 10.**-np.arange(3, 9)

    plt.figure(figsize=(9, 6))
    for i, (method, adapt_type) in enumerate(methods):
        print(method.name)
        fcs = []
        errs = []
        for tol in tols:
            ode.clear_call_counter()
            ts, ys = adaptive_step_integration(method=method,
                                               ode=ode,
                                               y_start=y0,
                                               t_span=(t0, t1),
                                               adapt_type=adapt_type,
                                               atol=tol,
                                               rtol=tol * 1e3)
            err = np.linalg.norm(ys[-1] - ode[t1])
            fc = ode.get_call_counter()
            print(
                f'{method.name} with {adapt_type.name}: {fc} RHS calls, err = {err:.5f}'
            )
            errs.append(err)
            fcs.append(fc)

        x = np.log10(fcs)
        y = -np.log10(errs)
        k, b = np.polyfit(x, y, 1)
        plt.plot(x, k * x + b, 'k:')
        plt.plot(x, y, 'p', label=f'{method.name} {adapt_type} ({k:.2f})')

    plt.title('test_adaptive_order: check RHS evals')
    plt.xlabel('log10(function_calls)')
    plt.ylabel('accuracy')
    plt.legend()

    plt.show()
예제 #7
0
def test_arenstorf():
    """
    https://en.wikipedia.org/wiki/Richard_Arenstorf#The_Arenstorf_Orbit
    https://commons.wikimedia.org/wiki/File:Arenstorf_Orbit.gif
    Q: which parts of the orbit are fastest?
    """
    problem = Arenstorf()
    t0, t1 = 0, 1 * problem.t_period
    y0 = problem.y0

    atol = 1e-6
    rtol = 1e-3

    tss = []
    yss = []

    methods = (
        (ExplicitEulerMethod(), AdaptType.RUNGE),
        (RungeKuttaMethod(coeffs.rk4_coeffs), AdaptType.RUNGE),
        (EmbeddedRungeKuttaMethod(coeffs.dopri_coeffs), AdaptType.EMBEDDED),
    )

    fig1, ax1 = plt.subplots(num='traj')
    fig1.suptitle('Arenstorf orbit: trajectory')
    ax1.set_xlabel('x1'), ax1.set_ylabel('x2')

    fig2, ax2 = plt.subplots(num='dt(t)')
    fig2.suptitle('Arenstorf orbit: step sizes')
    ax2.set_xlabel('t'), ax2.set_ylabel('dt')

    for method, adapt_type in methods:
        ts, ys = adaptive_step_integration(method=method,
                                           func=problem,
                                           y_start=y0,
                                           t_span=(t0, t1),
                                           adapt_type=adapt_type,
                                           atol=atol,
                                           rtol=rtol)
        tss.append(np.array(ts))
        yss.append(ys)

    for (m, _), ts, ys in zip(methods, tss, yss):
        ax1.plot([y[0] for y in ys], [y[1] for y in ys], ':', label=m.name)
        ax2.plot(ts[:-1], ts[1:] - ts[:-1], '.-', label=m.name)

    ax1.plot(0, 0, 'bo', label='Earth')
    ax1.plot(1, 0, '.', color='grey', label='Moon')
    ax1.legend()
    ax2.legend()
    plt.show()
예제 #8
0
def test_stiff():
    """
    test explicit vs implicit methods on a stiff problem
    """
    t0 = 0
    t1 = 8*np.pi

    mu = 0
    y0 = np.array([2., 0.])
    f = VanDerPol(y0, mu)

    colors = 'rgbcmyk'
    for i, (method, adapt_type) in enumerate(
            [
                (ExplicitEulerMethod(),                                    AdaptType.RUNGE),
                (ImplicitEulerMethod(),                                    AdaptType.RUNGE),
                (RungeKuttaMethod(collection.rk4_coeffs),                  AdaptType.RUNGE),
                (EmbeddedRosenbrockMethod(collection.rosenbrock23_coeffs), AdaptType.EMBEDDED),
            ]
    ):
        f.clear_call_counter()
        ts, ys = adaptive_step_integration(method, f, y0, (t0, t1), adapt_type=adapt_type, atol=1e-6, rtol=1e-3)
        print(f'{method.name}: {len(ts)-1} steps, {f.get_call_counter()} RHS calls')

        plt.figure(1)
        plt.plot([y[0] for y in ys],
                 [y[1] for y in ys],
                 f'{colors[i]}.--', label=method.name)
        plt.figure(2)
        plt.subplot(1,2,1), plt.plot(ts, [y[0] for y in ys], f'{colors[i]}.--', label=method.name)
        plt.subplot(1,2,2), plt.plot(ts, [y[1] for y in ys], f'{colors[i]}.--', label=method.name)
        plt.figure(3)
        plt.plot(ts[:-1],
                 np.array(ts[1:]) - np.array(ts[:-1]),
                 f'{colors[i]}.--', label=method.name)

    plt.figure(1)
    plt.xlabel('x'), plt.ylabel('y'), plt.legend()
    plt.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}, y(x)')

    plt.figure(2)
    plt.subplot(1,2,1), plt.xlabel('t'), plt.ylabel('x'), plt.legend()
    plt.subplot(1,2,2), plt.xlabel('t'), plt.ylabel('y'), plt.legend()
    plt.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}, x(t)')

    plt.figure(3)
    plt.xlabel('t'), plt.ylabel('dt'), plt.legend()
    plt.suptitle(f'test_stiff: Van der Pol, mu={mu:.2f}, dt(t)')

    plt.show()
예제 #9
0
def test_adaptive_order():
    """
    test adaptive algorithms convergence
    """
    t0, t1 = 0, 2 * np.pi
    y0 = np.array([1., 1.])
    f = Harmonic(y0, 1, 1)

    methods = (
        (ExplicitEulerMethod(), AdaptType.RUNGE),
        (RungeKuttaMethod(coeffs=collection.rk4_coeffs), AdaptType.RUNGE),
        (EmbeddedRungeKuttaMethod(coeffs=collection.dopri_coeffs),
         AdaptType.EMBEDDED),
    )
    tols = 10.**-np.arange(3, 9)

    plt.figure()
    for i, (method, adapt_type) in enumerate(methods):
        print(method.name)
        fcs = []
        errs = []
        for tol in tols:
            f.clear_call_counter()
            ts, ys = adaptive_step_integration(method=method,
                                               func=f,
                                               y_start=y0,
                                               t_span=(t0, t1),
                                               adapt_type=adapt_type,
                                               atol=tol,
                                               rtol=tol * 1e3)
            err = np.linalg.norm(ys[-1] - f[t1])
            fc = f.get_call_counter()
            print(f'{method.name}: {fc} RHS calls, err = {err:.5f}')
            errs.append(err)
            fcs.append(fc)

        x = np.log10(fcs)
        y = -np.log10(errs)
        k, b = np.polyfit(x, y, 1)
        plt.plot(x, k * x + b, 'k:')
        plt.plot(x, y, 'p', label=f'{method.name} ({k:.2f})')
    plt.suptitle('test_adaptive_order: check RHS evals')
    plt.xlabel('log10(function_calls)')
    plt.ylabel('accuracy')
    plt.legend()
    plt.show()
예제 #10
0
def test_multi_step():
    """
    Проверяем методы Адамса
    Q: сравните правые графики для обоих случаев и объясните разницу
    """
    y0 = np.array([0., 1.])
    t0 = 0
    t1 = np.pi
    dt = 0.1

    f = Harmonic(y0, 1, 1)
    ts = np.arange(t0, t1 + dt, dt)
    exact = f[ts].T

    for one_step_method in [
            RungeKuttaMethod(collection.rk4_coeffs),
            ExplicitEulerMethod(),
    ]:
        fig, (ax1, ax2) = plt.subplots(1, 2)

        ax1.plot(ts, [e[0] for e in exact], 'k', label='Exact')
        for p, c in adams_coeffs.items():
            f.clear_call_counter()
            t_adams, y_adams = adams(f,
                                     y0,
                                     ts,
                                     c,
                                     one_step_method=one_step_method)
            n_calls = f.get_call_counter()
            print(
                f'{p}-order multi-step with one-step {one_step_method.name}: {n_calls} function calls'
            )

            err = get_accuracy(exact, y_adams)

            label = f"Adams's order {p}"
            ax1.plot(t_adams, [y[0] for y in y_adams], '.--', label=label)
            ax2.plot(t_adams, err, '.--', label=label)

        ax1.legend(), ax1.set_title('y(t)')
        ax2.legend(), ax2.set_title('accuracy')
        fig.suptitle(
            f'test_multi_step\none step method: {one_step_method.name}')
        fig.tight_layout()

    plt.show()
예제 #11
0
def test_one_step():
    """
    Проверяем методы Эйлера и Рунге-Кутты
    """
    y0 = np.array([0., 1.])
    t0 = 0
    t1 = np.pi

    ode = Harmonic(y0, 1, 1)

    for dt in [0.1, 0.01]:
        ts = np.arange(t0, t1 + dt, dt)

        exact = ode[ts].T
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))
        ax1.plot(ts, [e[0] for e in exact], 'k', label='Exact')

        colors = 'rgbcmyk'
        for i, method in enumerate([
                ExplicitEulerMethod(),
                ImplicitEulerMethod(),
                RungeKuttaMethod(collection.rk4_coeffs),
                RungeKuttaMethod(collection.dopri_coeffs),
        ]):
            ode.clear_call_counter()
            _, y = fix_step_integration(method, ode, y0, ts)
            n_calls = ode.get_call_counter()
            print(
                f'One-step {method.name}: {len(y)-1} steps, {n_calls} function calls'
            )

            ax1.plot(ts, [_y[0] for _y in y],
                     f'{colors[i]}.--',
                     label=method.name)
            ax2.plot(ts,
                     get_accuracy(exact, y),
                     f'{colors[i]}.--',
                     label=method.name)

        ax1.legend(), ax1.set_title('y(t)')
        ax2.legend(), ax2.set_title('accuracy')

        fig.suptitle(f'test_one_step, dt={dt}')
        fig.tight_layout()

    plt.show()
예제 #12
0
def test_multi_step():
    """
    test Adams method
    Q: compare the right plot for both cases and explain the difference
    """
    y0 = np.array([0., 1.])
    t0 = 0
    t1 = 1.
    dt = 0.1

    f = Harmonic(y0, 1, 1)
    ts = np.arange(t0, t1 + dt, dt)
    exact = f[ts].T

    for one_step_method in [
            RungeKuttaMethod(collection.rk4_coeffs),
            ExplicitEulerMethod(),
    ]:
        _, (ax1, ax2) = plt.subplots(1, 2)

        ax1.plot(ts, [e[0] for e in exact], 'k', label='Exact')
        for p, c in adams_coeffs.items():
            f.clear_call_counter()
            t_adams, y_adams = adams(f,
                                     y0,
                                     ts,
                                     c,
                                     one_step_method=one_step_method)
            n_calls = f.get_call_counter()
            print(
                f'{p}-order multi-step with one-step {one_step_method.name}: {n_calls} function calls'
            )

            err = get_accuracy(exact, y_adams)

            label = f"Adams's order {p}"
            ax1.plot(t_adams, [y[0] for y in y_adams], '.--', label=label)
            ax2.plot(t_adams, err, '.--', label=label)

        ax1.set_xlabel('t'), ax1.set_ylabel('y'), ax1.legend()
        ax2.set_xlabel('t'), ax2.set_ylabel('accuracy'), ax2.legend()
        plt.suptitle(
            f'test_multi_step\none step method: {one_step_method.name}')
    plt.show()
예제 #13
0
def test_multi_step():
    """
    test Adams method
    Q: compare the right plot for both cases and explain the difference
    """
    y0 = np.array([0., 1.])
    t0 = 0
    t1 = 1.
    dt = 0.1

    f = Harmonic(y0, 1, 1)
    ts = np.arange(t0, t1 + dt, dt)
    exact = f[ts].T

    for one_step_method in [
            RungeKuttaMethod(collection.rk4_coeffs),
            ExplicitEulerMethod(),
    ]:
        plt.figure()
        plt.subplot(1, 2, 1), plt.plot(ts, [e[0] for e in exact],
                                       'k',
                                       label='Exact')
        for p, c in adams_coeffs.items():
            t_adams, y_adams = adams(f,
                                     y0,
                                     ts,
                                     c,
                                     one_step_method=one_step_method)
            print(f'Function calls: {f.get_call_counter()}')

            err = get_log_error(exact, y_adams)

            label = f"Adams's order {p}"
            plt.subplot(1, 2, 1), plt.plot(t_adams, [y[0] for y in y_adams],
                                           '.--',
                                           label=label)
            plt.subplot(1, 2, 2), plt.plot(t_adams, err, '.--', label=label)

        plt.subplot(1, 2, 1), plt.xlabel('t'), plt.ylabel('y'), plt.legend()
        plt.subplot(1, 2,
                    2), plt.xlabel('t'), plt.ylabel('accuracy'), plt.legend()
        plt.suptitle(
            f'test_multi_step\none step method: {one_step_method.name}')
    plt.show()
예제 #14
0
def test_one_step():
    """
    test Euler and RK methods
    """
    y0 = np.array([0., 1.])
    t0 = 0
    t1 = np.pi / 2
    dt = 0.1

    f = Harmonic(y0, 1, 1)
    ts = np.arange(t0, t1 + dt, dt)

    exact = f[ts].T
    _, (ax1, ax2) = plt.subplots(1, 2)
    ax1.plot(ts, [e[0] for e in exact], 'k', label='Exact')

    colors = 'rgbcmyk'
    for i, method in enumerate([
            ExplicitEulerMethod(),
            ImplicitEulerMethod(),
            RungeKuttaMethod(collection.rk4_coeffs),
            RungeKuttaMethod(collection.dopri_coeffs),
    ]):
        f.clear_call_counter()
        _, y = fix_step_integration(method, f, y0, ts)
        n_calls = f.get_call_counter()
        print(
            f'One-step {method.name}: {len(y)-1} steps, {n_calls} function calls'
        )

        ax1.plot(ts, [_y[0] for _y in y], f'{colors[i]}.--', label=method.name)
        ax2.plot(ts,
                 get_accuracy(exact, y),
                 f'{colors[i]}.--',
                 label=method.name)

    ax1.set_xlabel('t'), ax1.set_ylabel('y'), ax1.legend()
    ax2.set_xlabel('t'), ax2.set_ylabel('accuracy'), ax2.legend()
    plt.suptitle('test_one_step')
    plt.show()
예제 #15
0
def test_one_step():
    """
    test Euler and RK methods
    """
    y0 = np.array([0., 1.])
    t0 = 0
    t1 = np.pi / 2
    dt = 0.1

    f = Harmonic(y0, 1, 1)
    ts = np.arange(t0, t1 + dt, dt)

    exact = f[ts].T
    plt.figure()
    plt.subplot(1, 2, 1)
    plt.plot(ts, [e[0] for e in exact], 'k', label='Exact')

    colors = 'rgbcmyk'
    for i, method in enumerate([
            ExplicitEulerMethod(),
            ImplicitEulerMethod(),
            RungeKuttaMethod(collection.rk4_coeffs),
            RungeKuttaMethod(collection.dopri_coeffs),
    ]):
        _, y = fix_step_integration(method, f, y0, ts)
        print(f'len(Y): {len(y)}')
        print(f'Function calls: {f.get_call_counter()}')

        plt.subplot(1, 2, 1), plt.plot(ts, [_y[0] for _y in y],
                                       f'{colors[i]}.--',
                                       label=method.name)
        plt.subplot(1, 2, 2), plt.plot(ts,
                                       get_log_error(exact, y),
                                       f'{colors[i]}.--',
                                       label=method.name)

    plt.subplot(1, 2, 1), plt.xlabel('t'), plt.ylabel('y'), plt.legend()
    plt.subplot(1, 2, 2), plt.xlabel('t'), plt.ylabel('accuracy'), plt.legend()
    plt.suptitle('test_one_step')
    plt.show()
예제 #16
0
def test_adaptive(f, y0):
    """
    test adaptive step algorithms
    """
    t0, t1 = 0, 4 * np.pi

    atol = 1e-6
    rtol = 1e-3

    tss = []
    yss = []

    methods = (
        (ExplicitEulerMethod(), AdaptType.RUNGE),
        (RungeKuttaMethod(coeffs=collection.rk4_coeffs), AdaptType.RUNGE),
        (EmbeddedRungeKuttaMethod(coeffs=collection.dopri_coeffs),
         AdaptType.EMBEDDED),
    )

    for method, adapt_type in methods:
        f.clear_call_counter()
        ts, ys = adaptive_step_integration(method=method,
                                           func=f,
                                           y_start=y0,
                                           t_span=(t0, t1),
                                           adapt_type=adapt_type,
                                           atol=atol,
                                           rtol=rtol)
        print(f'{method.name} took {f.get_call_counter()} function calls')

        tss.append(np.array(ts))
        yss.append(ys)

    ts = np.array(sorted([t for ts in tss for t in ts]))
    exact = f[ts].T
    y0 = np.array([y[0] for y in exact])

    # plots
    plt.figure('y(t)'), plt.suptitle('test_adaptive: y(t)'), plt.xlabel(
        't'), plt.ylabel('y')
    plt.plot(ts, y0, 'ko-', label='exact')

    plt.figure('dt(t)'), plt.suptitle('test_adaptive: step sizes'), plt.xlabel(
        't'), plt.ylabel('dt')
    plt.figure('dy(t)'), plt.suptitle('test_adaptive: accuracies'), plt.xlabel(
        't'), plt.ylabel('accuracy')

    for (m, _), ts, ys in zip(methods, tss, yss):
        plt.figure('y(t)'), plt.plot(ts, [y[0] for y in ys], '.', label=m.name)
        plt.figure('dt(t)'), plt.plot(ts[:-1],
                                      ts[1:] - ts[:-1],
                                      '.-',
                                      label=m.name)
        plt.figure('dy(t)'), plt.plot(ts,
                                      get_log_error(f[ts].T, ys),
                                      '.-',
                                      label=m.name)

    plt.figure('y(t)'), plt.legend()
    plt.figure('dt(t)'), plt.legend()
    plt.figure('dy(t)'), plt.legend()

    plt.show()