示例#1
0
 def add_result (result_name, qp_v):
     nonlocal results
     H_v = vorpy.apply_along_axes(PendulumNd.H, (-2,-1), (qp_v,), output_axis_v=(), func_output_shape=())
     deviation_form_v = deviation_form(t_v=t_v, qp_v=qp_v, dH_dq=PendulumNd.dH_dq, dH_dp=PendulumNd.dH_dp)
     norm_deviation_form_v = vorpy.apply_along_axes(np.linalg.norm, (-2,-1), (deviation_form_v,), output_axis_v=(), func_output_shape=())
     norm_error_v = np.full(norm_deviation_form_v.shape, np.nan)
     results.add_result(result_name, dt, t_v, qp_v, H_v, norm_deviation_form_v, norm_error_v)
示例#2
0
def test__apply_along_axes__compare_with__apply_along_axis():
    rng = np.random.RandomState(42)
    a = rng.randn(4, 5, 6, 7)

    assert np.all(
        vorpy.apply_along_axes(np.sum, [0], [a]) == np.apply_along_axis(
            np.sum, 0, a))
    assert np.all(
        vorpy.apply_along_axes(np.sum, [1], [a]) == np.apply_along_axis(
            np.sum, 1, a))
    assert np.all(
        vorpy.apply_along_axes(np.sum, [2], [a]) == np.apply_along_axis(
            np.sum, 2, a))
    assert np.all(
        vorpy.apply_along_axes(np.sum, [3], [a]) == np.apply_along_axis(
            np.sum, 3, a))

    assert np.all(
        vorpy.apply_along_axes(np.sum, (0, ), (
            a, )) == np.apply_along_axis(np.sum, 0, a))
    assert np.all(
        vorpy.apply_along_axes(np.sum, (1, ), (
            a, )) == np.apply_along_axis(np.sum, 1, a))
    assert np.all(
        vorpy.apply_along_axes(np.sum, (2, ), (
            a, )) == np.apply_along_axis(np.sum, 2, a))
    assert np.all(
        vorpy.apply_along_axes(np.sum, (3, ), (
            a, )) == np.apply_along_axis(np.sum, 3, a))

    print('test__apply_along_axes__compare_with__apply_along_axis passed.')
示例#3
0
def test__salvaged_result ():
    import sys

    def dV_dq_complaining (q):
        # Introduce arbitrary error in order to test SalvagedResultException functionality.
        assert np.sum(np.square(q)) > 1.0e-2
        return KeplerNd.dV_dq(q)

    dt = 0.01
    t_v = np.arange(0.0, 60.0, dt)
    # R^3 Kepler problem
    qp_0 = np.array([
        [1.0, 0.0, 0.0],
        [0.0, 0.01, 0.0]
    ])
    order = 2
    omega = np.pi/(4*dt)
    assert np.allclose(2*omega*dt, np.pi/2)
    try:
        results = Results()
        qp_v = vorpy.symplectic_integration.separable_hamiltonian.integrate(
            initial_coordinates=qp_0,
            t_v=t_v,
            dK_dp=KeplerNd.dK_dp,
            dV_dq=dV_dq_complaining,
            update_step_coefficients=vorpy.symplectic_integration.separable_hamiltonian.update_step_coefficients.ruth4
        )
        assert False, 'did not catch SalvagedResultException as expected'
    except vorpy.symplectic_integration.exceptions.SalvagedResultException as e:
        print('caught SalvagedResultException as expected: {0}'.format(e))
        qp_v = e.salvaged_qp_v
        t_v = e.salvaged_t_v
        assert qp_v.shape[0] == t_v.shape[0]
        H_v = vorpy.apply_along_axes(KeplerNd.H, (-2,-1), (qp_v,), output_axis_v=(), func_output_shape=())
        deviation_form_v = deviation_form(t_v=t_v, qp_v=qp_v, dH_dq=KeplerNd.dH_dq, dH_dp=KeplerNd.dH_dp)
        norm_deviation_form_v = vorpy.apply_along_axes(np.linalg.norm, (-2,-1), (deviation_form_v,), output_axis_v=(), func_output_shape=())
        norm_error_v = np.full(norm_deviation_form_v.shape, np.nan)
        results.add_result('Kepler trajectory', dt, t_v, qp_v, H_v, norm_deviation_form_v, norm_error_v)
        # As you can see in this plot, the energy is not nearly conserved as time goes on, and the norm of the deviation form
        # diverges away from zero as time goes on.
        results.plot(filename=make_filename_in_artifacts_dir('symplectic_integration.separable_hamiltonian.salvaged_result.png'))
示例#4
0
def test__apply_along_axes():
    def symmetric_square(m):
        return np.einsum('ij,kj->ik', m, m)

    def is_symmetric(m):
        return np.all(m == m.T)

    rng = np.random.RandomState(42)
    a = rng.randn(2, 3, 4, 5)
    N = len(a.shape)

    # Use all possible combinations of input and output axes.
    for input_i0 in range(-N, N - 1):
        for input_i1 in range(input_i0 + 1, N):
            # Only test the pairs where input_i0 indexes an axis before that indexed by input_i1.
            if input_i0 + N >= input_i1:
                continue

            for output_i0 in range(-N, N - 1):
                for output_i1 in range(output_i0 + 1, N):
                    # Only test the pairs where output_i0 indexes an axis before that indexed by output_i1.
                    if output_i0 + N >= output_i1:
                        continue

                    output_axis_v = (output_i0, output_i1)
                    # Compute the result.  The multi-slice across the output axes should be a symmetric matrix.
                    result = vorpy.apply_along_axes(
                        symmetric_square, (input_i0, input_i1), (a, ),
                        output_axis_v=output_axis_v)
                    # Figure out which indices correspond to the input axes; call these result_non_output_axis_v.
                    all_indices = tuple(range(N))
                    normalized_output_axis_v = tuple(
                        output_axis if output_axis >= 0 else output_axis + N
                        for output_axis in output_axis_v)
                    result_non_output_axis_v = sorted(
                        list(
                            frozenset(all_indices) -
                            frozenset(normalized_output_axis_v)))
                    # print('output_axis_v = {0}, result_non_output_axis_v = {1}'.format(output_axis_v, result_non_output_axis_v))
                    assert len(result_non_output_axis_v) == 2
                    # Take all multi-slices and verify symmetry.
                    for check_i0, check_i1 in itertools.product(
                            range(result.shape[result_non_output_axis_v[0]]),
                            range(result.shape[result_non_output_axis_v[1]])):
                        # Construct the multi-slice to take.
                        multislice = [slice(None) for _ in range(4)]
                        multislice[result_non_output_axis_v[0]] = check_i0
                        multislice[result_non_output_axis_v[1]] = check_i1
                        # print('multislice = {0}'.format(multislice))
                        assert is_symmetric(result[tuple(multislice)])

    print('test__apply_along_axes passed.')
示例#5
0
def deviation_form(*, t_v, qp_v, dH_dq, dH_dp):
    """
    Hamilton's equations are

        dq/dt =   \partial H / \partial p
        dp/dt = - \partial H / \partial q

    This function computes the deviation of the discretized curve given by time values t_v and coordinates
    qp_v from satisfaction of Hamilton's equations.  A perfect solution would have a deviation of zero at all
    time/point pairs (though because we're dealing with a discretized curve, this wouldn't imply that the
    solution is exact).

    The value returned is the evaluation of a form equivalent to Hamilton's equations:

        dq/dt - \partial H / \partial p
        dp/dt + \partial H / \partial q

    and has the shape (T,A_1,A_2,...,A_K,2,N), which will be the same shape as qp_v, noting that K may be 0.
    Note that because t_v indexes the time values corresponding to the elements of qp_v.

    The [discrete] derivatives dq/dt and dp/dt are computed using a symmetric difference quotient:

        (dq/dt)[i] := (q[i+1] - q[i-1]) / (t[i+1] - t[i-1])

    with (dp/dt)[i] defined analogously.  For the first and last entries, a non-symmetric difference quotient
    will be used.

        (dq/dt)[ 0] := (q[ 1] - q[ 0]) / (t[ 1] - t[ 0])
        (dq/dt)[-1] := (q[-1] - q[-2]) / (t[-1] - t[-2])

    with (dp/dt)[0] and (dp/dt)[-1] defined analogously.

    TODO: Maybe only compute this for interior samples; end-point difference quotients might not be that useful.
    """

    #print('deviation_form; qp_v.shape = {0}'.format(qp_v.shape))

    assert np.all(
        np.diff(t_v) > 0
    ), 't_v must be an increasing sequence of time values'  # TODO: allow strictly decreasing time values
    assert t_v.shape[0] == qp_v.shape[0]
    assert t_v.shape[
        0] >= 2, 'no discrete derivative can be defined without at least two time values'
    assert qp_v.shape[-2] == 2

    # T is the number of time values
    T = t_v.shape[0]
    # N is the dimension of configuration space.
    N = qp_v.shape[-1]

    retval = np.ndarray(qp_v.shape, dtype=qp_v.dtype)
    # First populate retval with discrete derivatives of q and p.
    #print('deviation_form; retval[0,...].shape = {0}'.format(retval[0,...].shape))
    #print('deviation_form; retval[1:-1,...].shape = {0}'.format(retval[1:-1,...].shape))
    #print('deviation_form; (qp_v[2:] - qp_v[:-2]).shape = {0}'.format((qp_v[2:] - qp_v[:-2]).shape))
    #print('deviation_form; (t_v[2:] - t_v[:-2]).shape = {0}'.format((t_v[2:] - t_v[:-2]).shape))
    retval[0, ...] = (qp_v[1] - qp_v[0]) / (t_v[1] - t_v[0])
    retval[1:-1, ...] = qp_v[2:] - qp_v[:-2]
    retval[1:-1, ...] /= (t_v[2:] - t_v[:-2]).reshape(
        (T - 2, ) + (1, ) * (len(retval.shape) - 1)
    )  # The reshaping is necessary for correct broadcasting
    retval[-1, ...] = (qp_v[-1] - qp_v[-2]) / (t_v[-1] - t_v[-2])
    # Then subtract off the partials of the Hamiltonian in order to get the deviation form
    retval[...,
           0, :] -= vorpy.apply_along_axes(dH_dp, (-1, ),
                                           (qp_v[..., 0, :], qp_v[..., 1, :]),
                                           output_axis_v=(-1, ),
                                           func_output_shape=(N, ))
    retval[...,
           1, :] += vorpy.apply_along_axes(dH_dq, (-1, ),
                                           (qp_v[..., 0, :], qp_v[..., 1, :]),
                                           output_axis_v=(-1, ),
                                           func_output_shape=(N, ))

    return retval
示例#6
0
文件: rungekutta.py 项目: vdods/vorpy
    def do_stuff_1():
        import sympy as sp
        import vorpy
        import vorpy.symbolic
        import vorpy.symplectic

        np.set_printoptions(precision=20)

        # Define the Kepler problem and use it to test the integrator

        def phase_space_coordinates():
            return np.array(sp.var('x,y,p_x,p_y')).reshape(2, 2)

        def K(p):
            return np.dot(p.flat, p.flat) / 2

        def U(q):
            return -1 / sp.sqrt(np.dot(q.flat, q.flat))

        def H(qp):
            """Total energy -- should be conserved."""
            return K(qp[1, ...]) + U(qp[0, ...])

        def p_theta(qp):
            """Angular momentum -- should be conserved."""
            x, y, p_x, p_y = qp.reshape(-1)
            return x * p_y - y * p_x

        # Determine the Hamiltonian vector field of H.
        qp = phase_space_coordinates()
        X_H = vorpy.symplectic.symplectic_gradient_of(H(qp), qp)
        print(f'X_H:\n{X_H}')
        print('X_H lambdification')
        X_H_fast = vorpy.symbolic.lambdified(X_H,
                                             qp,
                                             replacement_d={
                                                 'array': 'np.array',
                                                 'dtype=object':
                                                 'dtype=np.float64'
                                             },
                                             verbose=True)

        print('H lambdification')
        H_fast = vorpy.symbolic.lambdified(H(qp),
                                           qp,
                                           replacement_d={'sqrt': 'np.sqrt'},
                                           verbose=True)
        print('p_theta lambdification')
        p_theta_fast = vorpy.symbolic.lambdified(p_theta(qp), qp, verbose=True)

        t_initial = 0.0
        qp_initial = np.array([[1.0, 0.0], [0.0, 0.5]])
        H_initial = H_fast(qp_initial)
        p_theta_initial = p_theta_fast(qp_initial)

        print(f'H_initial = {H_initial}')
        print(f'p_theta_initial = {p_theta_initial}')

        #integrator = RungeKutta_4(vector_field=V, parameter_shape=(2,))
        integrator = RungeKuttaFehlberg_4_5(
            vector_field=(lambda t, qp: X_H_fast(qp)),
            parameter_shape=vorpy.tensor.shape(qp_initial))
        t = t_initial
        y = qp_initial
        dt = 0.01
        t_max = 3.0

        t_v = [t]
        y_v = [np.copy(y)]
        ltee_v = [0.0]
        while t < t_max:
            integrator.set_inputs(t, y)
            integrator.step(dt)
            t, y = integrator.get_outputs()
            t_v.append(t)
            y_v.append(np.copy(y))
            ltee_v.append(np.sqrt(integrator.ltee_squared))

        print(f'ltee_v = {ltee_v}')

        # Convert the list of np.ndarray to a full np.ndarray.
        qp_t = np.array(y_v)

        H_v = vorpy.apply_along_axes(H_fast, (1, 2), (qp_t, ))
        H_error_v = vorpy.apply_along_axes(
            lambda qp: np.abs(H_fast(qp) - H_initial), (1, 2), (qp_t, ))
        #print(f'H_v = {H_v}')
        #print(f'H_error_v = {H_error_v}')

        p_theta_v = vorpy.apply_along_axes(p_theta_fast, (1, 2), (qp_t, ))
        p_theta_error_v = vorpy.apply_along_axes(
            lambda qp: np.abs(p_theta_fast(qp) - p_theta_initial), (1, 2),
            (qp_t, ))
        #print(f'p_theta_v = {p_theta_v}')
        #print(f'p_theta_error_v = {p_theta_error_v}')

        import matplotlib.pyplot as plt

        def plot_stuff():
            row_count = 1
            col_count = 5
            size = 5
            fig, axis_vv = plt.subplots(row_count,
                                        col_count,
                                        squeeze=False,
                                        figsize=(size * col_count,
                                                 size * row_count))

            axis = axis_vv[0][0]
            axis.set_title('position')
            axis.set_aspect('equal')
            axis.plot(qp_t[:, 0, 0], qp_t[:, 0, 1], '.')

            axis = axis_vv[0][1]
            axis.set_title('x and y')
            axis.plot(t_v, qp_t[:, 0, 0], '.')
            axis.plot(t_v, qp_t[:, 0, 1], '.')

            axis = axis_vv[0][2]
            axis.set_title('local trunc. err. est.')
            axis.semilogy(t_v, ltee_v, '.')

            axis = axis_vv[0][3]
            axis.set_title('H error')
            axis.semilogy(t_v, H_error_v, '.')

            axis = axis_vv[0][4]
            axis.set_title('p_theta error')
            axis.semilogy(t_v, p_theta_error_v, '.')

            fig.tight_layout()
            filename = 'runge-kutta-kepler.png'
            plt.savefig(filename, bbox_inches='tight')
            print('wrote to file "{0}"'.format(filename))
            # VERY important to do this -- otherwise your memory will slowly fill up!
            # Not sure which one is actually sufficient -- apparently none of them are, YAY!
            plt.clf()
            plt.close(fig)
            plt.close('all')
            del fig
            del axis_vv

        plot_stuff()
示例#7
0
文件: adaptive.py 项目: vdods/vorpy
    def do_three_body_problem() -> None:
        def phase_space_coordinates() -> np.ndarray:
            return np.array(
                sp.var('x_0,y_0,x_1,y_1,x_2,y_2,u_0,v_0,u_1,v_1,u_2,v_2')
            ).reshape(2, 3, 2)

        def K(
            p: np.ndarray
        ) -> typing.Any:  # Not sure how to annotate a general scalar
            return np.dot(p.flat, p.flat) / 2

        def U(q: np.ndarray) -> typing.Any:
            total = 0
            for i in range(3):
                for j in range(i):
                    delta = q[i, :] - q[j, :]
                    total += -1 / sp.sqrt(np.dot(delta, delta))
            return total

        def H(qp: np.ndarray) -> typing.Any:
            """Total energy -- should be conserved."""
            return K(qp[1, ...]) + U(qp[0, ...])

        def p_theta(qp: np.ndarray) -> typing.Any:
            """Angular momentum -- should be conserved."""
            total = 0
            for i in range(3):
                x, y, u, v = qp[:, i, :].reshape(-1)
                total += x * v - y * u
            return total

        def norm_deltas(qp: np.ndarray) -> np.ndarray:
            """Returns the expression defining the distance between bodies i and j for ij = 01, 02, 12 in that order."""
            def norm_delta_ij(i: int, j: int) -> typing.Any:
                q = qp[0, ...]
                q_i = q[i, :]
                q_j = q[j, :]
                delta = q_i - q_j
                return sp.sqrt(np.dot(delta, delta))

            return np.array([
                norm_delta_ij(0, 1),
                norm_delta_ij(0, 2),
                norm_delta_ij(1, 2)
            ])

        def body_vertex_angles(qp: np.ndarray) -> np.ndarray:
            """Returns the angle of the vertex of the shape triangle that body i sits at for i = 0, 1, 2."""
            def body_vertex_angle_i(i: int) -> typing.Any:
                q = qp[0, ...]
                # Determine the index of each of the other two bodies.
                j = (i + 1) % 3
                k = (i + 2) % 3
                q_i = q[i, :]
                q_j = q[j, :]
                q_k = q[k, :]
                delta_ij = q_j - q_i
                delta_ik = q_k - q_i
                norm_squared_delta_ij = np.dot(delta_ij, delta_ij)
                norm_squared_delta_ik = np.dot(delta_ik, delta_ik)
                cos_angle = np.dot(delta_ij, delta_ik) / sp.sqrt(
                    norm_squared_delta_ij * norm_squared_delta_ik)
                return sp.acos(cos_angle)

            return np.array([
                body_vertex_angle_i(0),
                body_vertex_angle_i(1),
                body_vertex_angle_i(2)
            ])

        def shape_area(qp: np.ndarray) -> typing.Any:
            """Area of the parallelopiped spanned by the segments 01 and 02."""
            q = qp[0, ...]
            delta_01 = q[1, :] - q[0, :]
            delta_02 = q[2, :] - q[0, :]
            return np.cross(delta_01, delta_02)[()]

        # Determine the Hamiltonian vector field of H.
        qp = phase_space_coordinates()
        X_H = vorpy.symplectic.symplectic_gradient_of(H(qp), qp.reshape(
            2, 6)).reshape(2, 3, 2)
        print(f'X_H:\n{X_H}')

        replacement_d = {
            'array': 'np.array',
            'dtype=object': 'dtype=np.float64',
            'sqrt': 'np.sqrt',
            'acos': 'np.arccos',
        }

        print('X_H lambdification')
        X_H_fast = vorpy.symbolic.lambdified(X_H,
                                             qp,
                                             replacement_d=replacement_d,
                                             verbose=True)

        print('H lambdification')
        H_fast = vorpy.symbolic.lambdified(H(qp),
                                           qp,
                                           replacement_d=replacement_d,
                                           verbose=True)
        print('p_theta lambdification')
        p_theta_fast = vorpy.symbolic.lambdified(p_theta(qp),
                                                 qp,
                                                 replacement_d=replacement_d,
                                                 verbose=True)
        print('shape_area lambdification')
        shape_area_fast = vorpy.symbolic.lambdified(
            shape_area(qp), qp, replacement_d=replacement_d, verbose=True)
        print('norm_deltas lambdification')
        norm_deltas_fast = vorpy.symbolic.lambdified(
            norm_deltas(qp), qp, replacement_d=replacement_d, verbose=True)
        print('body_vertex_angles lambdification')
        body_vertex_angles_fast = vorpy.symbolic.lambdified(
            body_vertex_angles(qp),
            qp,
            replacement_d=replacement_d,
            verbose=True)

        t_initial = 0.0
        qp_initial = np.array([
            [[-1.0, 0.0], [0.0, 1.0], [1.0, 0.0]],
            [[0.0, -0.3], [-0.8, 0.2], [0.1, -0.2]],
        ])
        H_initial = H_fast(qp_initial)
        p_theta_initial = p_theta_fast(qp_initial)

        print(f'H_initial = {H_initial}')
        print(f'p_theta_initial = {p_theta_initial}')

        H_cq = ControlledQuantity(
            name='H',
            reference_quantity=H_initial,
            #global_error_band=RealInterval(1.0e-10, 1.0e-6),
            global_error_band=RealInterval(1.0e-8, 1.0e-5),
            quantity_evaluator=(lambda t, qp: typing.cast(float, H_fast(qp))),
        )
        p_theta_cq = ControlledQuantity(
            name='p_theta',
            reference_quantity=p_theta_initial,
            #global_error_band=RealInterval(1.0e-10, 1.0e-6),
            global_error_band=RealInterval(1.0e-8, 1.0e-5),
            quantity_evaluator=(
                lambda t, qp: typing.cast(float, p_theta_fast(qp))),
        )
        controlled_sq_ltee = ControlledSquaredLTEE(
            global_error_band=RealInterval(1.0e-12**2, 1.0e-6**2), )

        try:
            results = integrate_vector_field(
                vector_field=(lambda t, qp: X_H_fast(qp)),
                t_initial=t_initial,
                y_initial=qp_initial,
                t_final=10.0,
                controlled_quantity_d={
                    'H abs error': H_cq,
                    'p_theta abs error': p_theta_cq,
                },
                controlled_sq_ltee=controlled_sq_ltee,
            )
            #print(f'results = {results}')
        except SalvagedResultsException as e:
            print('got SalvagedResultsException')
            results = e.args[0]
        finally:
            H_v = vorpy.apply_along_axes(H_fast, (1, 2, 3), (results.y_t, ))
            #H_error_v = vorpy.apply_along_axes(lambda qp:H_cq.error(0.0,qp), (1,2), (results.y_t,))
            #print(f'H_v = {H_v}')
            #print(f'H_error_v = {H_error_v}')

            p_theta_v = vorpy.apply_along_axes(p_theta_fast, (1, 2, 3),
                                               (results.y_t, ))
            #p_theta_error_v = vorpy.apply_along_axes(lambda qp:p_theta_cq.error(0.0,qp), (1,2), (results.y_t,))
            #print(f'p_theta_v = {p_theta_v}')
            #print(f'p_theta_error_v = {p_theta_error_v}')

            shape_area_v = vorpy.apply_along_axes(shape_area_fast, (1, 2, 3),
                                                  (results.y_t, ))

            norm_deltas_t = vorpy.apply_along_axes(norm_deltas_fast, (1, 2, 3),
                                                   (results.y_t, ))
            print(f'norm_deltas_t = {norm_deltas_t}')

            body_vertex_angles_t = vorpy.apply_along_axes(
                body_vertex_angles_fast, (1, 2, 3), (results.y_t, ))
            print(f'body_vertex_angles_t = {body_vertex_angles_t}')

            sign_change_v = shape_area_v[:-1] * shape_area_v[1:]
            zero_crossing_index_v = (sign_change_v < 0)
            zero_crossing_v = results.t_v[:-1][zero_crossing_index_v]

            print(
                f'body_vertex_angles_t[:-1][zero_crossing_index_v,:] = {body_vertex_angles_t[:-1][zero_crossing_index_v,:]}'
            )

            syzygy_v = np.argmax(
                body_vertex_angles_t[:-1][zero_crossing_index_v, :], axis=1)
            print(f'syzygy_v = {syzygy_v}')

            import matplotlib.pyplot as plt

            def plot_stuff() -> None:
                row_count = 2
                col_count = 4
                size = 10
                fig, axis_vv = plt.subplots(row_count,
                                            col_count,
                                            squeeze=False,
                                            figsize=(size * col_count,
                                                     size * row_count))

                axis = axis_vv[0][0]
                axis.set_title(
                    f'position (bodies 0,1,2 are R,G,B resp.)\nresults.succeeded = {results.succeeded}\nresults.failure_explanation_o = {results.failure_explanation_o}'
                )
                axis.set_aspect('equal')
                axis.plot(results.y_t[:, 0, 0, 0],
                          results.y_t[:, 0, 0, 1],
                          color='red')
                axis.plot(results.y_t[:, 0, 1, 0],
                          results.y_t[:, 0, 1, 1],
                          color='green')
                axis.plot(results.y_t[:, 0, 2, 0],
                          results.y_t[:, 0, 2, 1],
                          color='blue')

                axis = axis_vv[1][0]
                axis.set_title(
                    'norm delta ij (color is combination of body color)')
                axis.semilogy(results.t_v, norm_deltas_t[:, 0], color='yellow')
                axis.semilogy(results.t_v,
                              norm_deltas_t[:, 1],
                              color='magenta')
                axis.semilogy(results.t_v, norm_deltas_t[:, 2], color='cyan')
                for zero_crossing in zero_crossing_v:
                    axis.axvline(zero_crossing, color='black', alpha=0.5)

                #axis = axis_vv[1][0]
                #axis.set_title('momentum')
                #axis.set_aspect('equal')
                #axis.plot(results.y_t[:,1,0], results.y_t[:,1,1], '.')

                #axis = axis_vv[1][0]
                #axis.set_title('blue:(t,x), orange:(t,y)')
                #axis.plot(results.t_v, results.y_t[:,0,:], '.')
                ##axis.plot(results.t_v, results.y_t[:,0,1], '.')

                axis = axis_vv[0][1]
                axis.set_title('H abs error (global:blue, local:green)')
                axis.semilogy(results.t_v,
                              results.global_error_vd['H abs error'],
                              '.',
                              color='blue')
                axis.semilogy(results.t_v,
                              results.local_error_vd['H abs error'],
                              '.',
                              color='green')
                axis.axhline(
                    H_cq.global_error_schedule().global_error_band().inf,
                    color='green')
                axis.axhline(
                    H_cq.global_error_schedule().global_error_band().sup,
                    color='red')

                axis = axis_vv[1][1]
                axis.set_title('p_theta abs error (global:blue, local:green)')
                axis.semilogy(results.t_v,
                              results.global_error_vd['p_theta abs error'],
                              '.',
                              color='blue')
                axis.semilogy(results.t_v,
                              results.local_error_vd['p_theta abs error'],
                              '.',
                              color='green')
                axis.axhline(
                    p_theta_cq.global_error_schedule().global_error_band().inf,
                    color='green')
                axis.axhline(
                    p_theta_cq.global_error_schedule().global_error_band().sup,
                    color='red')

                axis = axis_vv[0][2]
                axis.set_title(ControlledSquaredLTEE.NAME +
                               ' (global:blue, local:green)')
                axis.semilogy(
                    results.t_v,
                    results.global_error_vd[ControlledSquaredLTEE.NAME],
                    '.',
                    color='blue')
                axis.semilogy(
                    results.t_v,
                    results.local_error_vd[ControlledSquaredLTEE.NAME],
                    '.',
                    color='green')
                axis.axhline(controlled_sq_ltee.global_error_schedule().
                             global_error_band().inf,
                             color='green')
                axis.axhline(controlled_sq_ltee.global_error_schedule().
                             global_error_band().sup,
                             color='red')

                axis = axis_vv[1][2]
                axis.set_title('shape_area (vertical line indicates syzygy)')
                axis.plot(results.t_v, shape_area_v)  #, '.')
                axis.axhline(0)
                for zero_crossing in zero_crossing_v:
                    axis.axvline(zero_crossing, color='black', alpha=0.5)

                axis = axis_vv[0][3]
                axis.set_title('timestep')
                axis.semilogy(results.t_v[1:], results.t_step_v, '.')

                axis = axis_vv[1][3]
                axis.set_title(
                    'body vertex angles (bodies 0,1,2 are R,G,B resp.)')
                axis.plot(results.t_v, body_vertex_angles_t[:, 0], color='red')
                axis.plot(results.t_v,
                          body_vertex_angles_t[:, 1],
                          color='green')
                axis.plot(results.t_v,
                          body_vertex_angles_t[:, 2],
                          color='blue')
                for zero_crossing in zero_crossing_v:
                    axis.axvline(zero_crossing, color='black', alpha=0.2)

                #axis = axis_vv[1][3]
                #axis.set_title('delta timestep (signed log_10 plot)')
                #delta_timestep = np.diff(results.t_step_v)
                #axis.plot(results.t_v[1:-1], np.sign(delta_timestep)*np.log10(np.abs(delta_timestep)), '.')

                fig.tight_layout()
                filename = 'threebody.png'
                plt.savefig(filename, bbox_inches='tight')
                print('wrote to file "{0}"'.format(filename))
                # VERY important to do this -- otherwise your memory will slowly fill up!
                # Not sure which one is actually sufficient -- apparently none of them are, YAY!
                plt.clf()
                plt.close(fig)
                plt.close('all')
                del fig
                del axis_vv

            plot_stuff()
示例#8
0
文件: adaptive.py 项目: vdods/vorpy
    def do_kepler_problem() -> None:
        def phase_space_coordinates() -> np.ndarray:
            return np.array(sp.var('x,y,p_x,p_y')).reshape(2, 2)

        def K(
            p: np.ndarray
        ) -> typing.Any:  # Not sure how to annotate a general scalar
            return np.dot(p.flat, p.flat) / 2

        def U(q: np.ndarray) -> typing.Any:
            return -1 / sp.sqrt(np.dot(q.flat, q.flat))

        def H(qp: np.ndarray) -> typing.Any:
            """Total energy -- should be conserved."""
            return K(qp[1, ...]) + U(qp[0, ...])

        def p_theta(qp: np.ndarray) -> typing.Any:
            """Angular momentum -- should be conserved."""
            x, y, p_x, p_y = qp.reshape(-1)
            return x * p_y - y * p_x

        # Determine the Hamiltonian vector field of H.
        qp = phase_space_coordinates()
        X_H = vorpy.symplectic.symplectic_gradient_of(H(qp), qp)
        print(f'X_H:\n{X_H}')
        print('X_H lambdification')
        X_H_fast = vorpy.symbolic.lambdified(X_H,
                                             qp,
                                             replacement_d={
                                                 'array': 'np.array',
                                                 'dtype=object':
                                                 'dtype=np.float64'
                                             },
                                             verbose=True)

        print('H lambdification')
        H_fast = vorpy.symbolic.lambdified(H(qp),
                                           qp,
                                           replacement_d={'sqrt': 'np.sqrt'},
                                           verbose=True)
        print('p_theta lambdification')
        p_theta_fast = vorpy.symbolic.lambdified(p_theta(qp), qp, verbose=True)

        t_initial = 0.0
        qp_initial = np.array([[1.0, 0.0], [0.0, 0.01]])
        H_initial = H_fast(qp_initial)
        p_theta_initial = p_theta_fast(qp_initial)

        print(f'H_initial = {H_initial}')
        print(f'p_theta_initial = {p_theta_initial}')

        H_cq = ControlledQuantity(
            name='H',
            reference_quantity=H_initial,
            global_error_band=RealInterval(1.0e-10, 1.0e-6),
            quantity_evaluator=(lambda t, qp: typing.cast(float, H_fast(qp))),
        )
        p_theta_cq = ControlledQuantity(
            name='p_theta',
            reference_quantity=p_theta_initial,
            global_error_band=RealInterval(1.0e-10, 1.0e-6),
            quantity_evaluator=(
                lambda t, qp: typing.cast(float, p_theta_fast(qp))),
        )
        controlled_sq_ltee = ControlledSquaredLTEE(
            global_error_band=RealInterval(1.0e-12**2, 1.0e-6**2), )

        try:
            results = integrate_vector_field(
                vector_field=(lambda t, qp: X_H_fast(qp)),
                t_initial=t_initial,
                y_initial=qp_initial,
                t_final=10.0,
                controlled_quantity_d={
                    'H abs error': H_cq,
                    'p_theta abs error': p_theta_cq,
                },
                controlled_sq_ltee=controlled_sq_ltee,
            )
            #print(f'results = {results}')
        except SalvagedResultsException as e:
            print('got SalvagedResultsException')
            results = e.args[0]
        finally:
            H_v = vorpy.apply_along_axes(H_fast, (1, 2), (results.y_t, ))
            #H_error_v = vorpy.apply_along_axes(lambda qp:H_cq.error(0.0,qp), (1,2), (results.y_t,))
            #print(f'H_v = {H_v}')
            #print(f'H_error_v = {H_error_v}')

            p_theta_v = vorpy.apply_along_axes(p_theta_fast, (1, 2),
                                               (results.y_t, ))
            #p_theta_error_v = vorpy.apply_along_axes(lambda qp:p_theta_cq.error(0.0,qp), (1,2), (results.y_t,))
            #print(f'p_theta_v = {p_theta_v}')
            #print(f'p_theta_error_v = {p_theta_error_v}')

            import matplotlib.pyplot as plt

            def plot_stuff() -> None:
                row_count = 2
                col_count = 4
                size = 5
                fig, axis_vv = plt.subplots(row_count,
                                            col_count,
                                            squeeze=False,
                                            figsize=(size * col_count,
                                                     size * row_count))

                axis = axis_vv[0][0]
                axis.set_title('position')
                axis.set_aspect('equal')
                axis.plot(results.y_t[:, 0, 0], results.y_t[:, 0, 1], '.')

                #axis = axis_vv[1][0]
                #axis.set_title('momentum')
                #axis.set_aspect('equal')
                #axis.plot(results.y_t[:,1,0], results.y_t[:,1,1], '.')

                axis = axis_vv[1][0]
                axis.set_title('blue:(t,x), orange:(t,y)')
                axis.plot(results.t_v, results.y_t[:, 0, :], '.')
                #axis.plot(results.t_v, results.y_t[:,0,1], '.')

                axis = axis_vv[0][1]
                axis.set_title('H abs error')
                axis.semilogy(results.t_v, results.error_vd['H abs error'],
                              '.')
                axis.axhline(
                    H_cq.global_error_schedule().global_error_band().inf,
                    color='green')
                axis.axhline(
                    H_cq.global_error_schedule().global_error_band().sup,
                    color='red')

                axis = axis_vv[1][1]
                axis.set_title('p_theta abs error')
                axis.semilogy(results.t_v,
                              results.error_vd['p_theta abs error'], '.')
                axis.axhline(
                    p_theta_cq.global_error_schedule().global_error_band().inf,
                    color='green')
                axis.axhline(
                    p_theta_cq.global_error_schedule().global_error_band().sup,
                    color='red')

                axis = axis_vv[0][2]
                axis.set_title(ControlledSquaredLTEE.NAME)
                axis.semilogy(results.t_v,
                              results.error_vd[ControlledSquaredLTEE.NAME],
                              '.')
                axis.axhline(controlled_sq_ltee.global_error_schedule().
                             global_error_band().inf,
                             color='green')
                axis.axhline(controlled_sq_ltee.global_error_schedule().
                             global_error_band().sup,
                             color='red')

                axis = axis_vv[0][3]
                axis.set_title('timestep')
                axis.semilogy(results.t_v[1:], results.t_step_v, '.')

                axis = axis_vv[1][3]
                axis.set_title('delta timestep')
                delta_timestep = np.diff(results.t_step_v)
                axis.plot(
                    results.t_v[1:-1],
                    np.sign(delta_timestep) * np.log10(np.abs(delta_timestep)),
                    '.')

                fig.tight_layout()
                filename = 'integrator.png'
                plt.savefig(filename, bbox_inches='tight')
                print('wrote to file "{0}"'.format(filename))
                # VERY important to do this -- otherwise your memory will slowly fill up!
                # Not sure which one is actually sufficient -- apparently none of them are, YAY!
                plt.clf()
                plt.close(fig)
                plt.close('all')
                del fig
                del axis_vv

            plot_stuff()
示例#9
0
    def plot_result(self, result_name, axis_v, *, detrend_Hamiltonian=False):
        result = self.result_d[result_name]
        N = result['N']
        can_plot_phase_space = result['can_plot_phase_space']
        dt = result['dt']
        t_v = result['t_v']
        qp_v = result['qp_v']
        H_v = result['H_v']
        norm_deviation_form_v = result['norm_deviation_form_v']
        norm_error_v = result['norm_error_v']

        can_plot_phase_space = N == 1
        T = qp_v.shape[0]
        assert H_v.shape[0] == T

        H_v_reshaped = H_v.reshape(T, -1)
        if detrend_Hamiltonian:
            # Detrend each H_v, so that the plot is just the deviation from the mean and the min and max are more meaningful
            H_v_reshaped -= np.mean(H_v_reshaped, axis=0)

        norm_deviation_form_v_reshaped = norm_deviation_form_v.reshape(T, -1)
        norm_error_v_reshaped = norm_error_v.reshape(T, -1)

        min_H = np.min(H_v_reshaped)
        max_H = np.max(H_v_reshaped)
        range_H = max_H - min_H

        max_norm_deviation_form = np.max(norm_deviation_form_v_reshaped[1:-1])
        max_norm_error = np.max(norm_error_v_reshaped)

        axis = axis_v[0]
        axis.set_title('Hamiltonian{0}; range = {1:.2e}\nmethod: {2}'.format(
            ' (detrended)' if detrend_Hamiltonian else '', range_H,
            result_name))
        axis.plot(t_v, H_v_reshaped)
        axis.axhline(min_H, color='green')
        axis.axhline(max_H, color='green')

        sqd_v = vorpy.apply_along_axes(lambda x: np.sum(np.square(x)),
                                       (-2, -1), (qp_v - qp_v[0], ))
        sqd_v_reshaped = sqd_v.reshape(T, -1)

        axis = axis_v[1]
        axis.set_title('{0} : sq dist from initial'.format(result_name))
        axis.semilogy(t_v, sqd_v_reshaped)

        axis = axis_v[2]
        axis.set_title(
            '{0} : norm of deviation form; max = {1:.2e}\ndt = {2:.2e}'.format(
                result_name, max_norm_deviation_form, dt))
        axis.semilogy(t_v[1:-1], norm_deviation_form_v_reshaped[1:-1])
        axis.axhline(max_norm_deviation_form, color='green')

        axis = axis_v[3]
        axis.set_title(
            '{0} : norm of error (compare to reference); max = {1:.2e}'.format(
                result_name, max_norm_error))
        axis.semilogy(t_v, norm_error_v_reshaped)
        axis.axhline(max_norm_error, color='green')

        # We can only directly plot the phase space if the configuration space is 1-dimensional.
        if can_plot_phase_space:
            # This is to get rid of the last axis, which has size 1, and therefore can be canonically reshaped away
            # via the canonical identification between 1-vectors and scalars.
            qp_v_reshaped = qp_v.reshape(T, -1, 2)
            print('qp_v.shape = {0}'.format(qp_v.shape))
            print('qp_v_reshaped.shape = {0}'.format(qp_v_reshaped.shape))

            axis = axis_v[-1]
            axis.set_title('phase space\nmethod: {0}'.format(result_name))
            axis.set_aspect('equal')
            axis.plot(qp_v_reshaped[..., 0], qp_v_reshaped[..., 1])