def get_trajectory(parameterization: type = asb.DynamicsPointMass2DCartesian,
                   gravity=True,
                   drag=True,
                   plot=False):
    if parameterization is asb.DynamicsPointMass2DCartesian:
        dyn = parameterization(
            mass_props=asb.MassProperties(mass=1),
            x_e=0,
            z_e=0,
            u_e=u_e_0,
            w_e=w_e_0,
        )
    elif parameterization is asb.DynamicsPointMass2DSpeedGamma:
        dyn = parameterization(
            mass_props=asb.MassProperties(mass=1),
            x_e=0,
            z_e=0,
            speed=speed_0,
            gamma=gamma_0,
        )
    else:
        raise ValueError("Bad value of `parameterization`!")

    def derivatives(t, y):
        this_dyn = dyn.get_new_instance_with_state(y)
        if gravity:
            this_dyn.add_gravity_force()
        q = 0.5 * 1.225 * this_dyn.speed**2
        if drag:
            this_dyn.add_force(Fx=-1 * (0.1)**2 * q, axes="wind")

        return this_dyn.unpack_state(this_dyn.state_derivatives())

    res = integrate.solve_ivp(
        fun=derivatives,
        t_span=(time[0], time[-1]),
        t_eval=time,
        y0=dyn.unpack_state(),
        method="LSODA",
        # vectorized=True,
        rtol=1e-9,
        atol=1e-9,
    )

    dyn = dyn.get_new_instance_with_state(res.y)

    if plot:
        import matplotlib.pyplot as plt
        import aerosandbox.tools.pretty_plots as p

        fig, ax = plt.subplots()
        p.plot_color_by_value(dyn.x_e,
                              dyn.altitude,
                              c=dyn.speed,
                              colorbar=True)
        p.equal()
        p.show_plot("Trajectory", "$x_e$", "$z_e$")

    return dyn
def test_block_move_fixed_time():
    opti = asb.Opti()

    n_timesteps = 300

    time = np.linspace(0, 1, n_timesteps)

    dyn = asb.DynamicsPointMass1DHorizontal(
        mass_props=asb.MassProperties(mass=1),
        x_e=opti.variable(init_guess=np.linspace(0, 1, n_timesteps)),
        u_e=opti.variable(init_guess=1, n_vars=n_timesteps),
    )

    u = opti.variable(init_guess=np.linspace(1, -1, n_timesteps))

    dyn.add_force(
        Fx=u
    )

    dyn.constrain_derivatives(
        opti=opti,
        time=time
    )

    opti.subject_to([
        dyn.x_e[0] == 0,
        dyn.x_e[-1] == 1,
        dyn.u_e[0] == 0,
        dyn.u_e[-1] == 0,
    ])

    # effort = np.sum(
    #     np.trapz(dyn.X ** 2) * np.diff(time)
    # )

    effort = np.sum(  # More sophisticated integral-of-squares integration (closed form correct)
        np.diff(time) / 3 *
        (u[:-1] ** 2 + u[:-1] * u[1:] + u[1:] ** 2)
    )

    opti.minimize(effort)

    sol = opti.solve()

    dyn.substitute_solution(sol)

    assert dyn.x_e[0] == pytest.approx(0)
    assert dyn.x_e[-1] == pytest.approx(1)
    assert dyn.u_e[0] == pytest.approx(0)
    assert dyn.u_e[-1] == pytest.approx(0)
    assert np.max(dyn.u_e) == pytest.approx(1.5, abs=0.01)
    assert sol.value(u)[0] == pytest.approx(6, abs=0.05)
    assert sol.value(u)[-1] == pytest.approx(-6, abs=0.05)
def test_block_move_minimum_time():
    opti = asb.Opti()

    n_timesteps = 300

    time = np.linspace(
        0,
        opti.variable(init_guess=1, lower_bound=0),
        n_timesteps,
    )

    dyn = asb.DynamicsPointMass1DHorizontal(
        mass_props=asb.MassProperties(mass=1),
        x_e=opti.variable(init_guess=np.linspace(0, 1, n_timesteps)),
        u_e=opti.variable(init_guess=1, n_vars=n_timesteps),
    )

    u = opti.variable(init_guess=np.linspace(1, -1, n_timesteps), lower_bound=-1, upper_bound=1)

    dyn.add_force(
        Fx=u
    )

    dyn.constrain_derivatives(
        opti=opti,
        time=time
    )

    opti.subject_to([
        dyn.x_e[0] == 0,
        dyn.x_e[-1] == 1,
        dyn.u_e[0] == 0,
        dyn.u_e[-1] == 0,
    ])

    opti.minimize(
        time[-1]
    )

    sol = opti.solve()

    dyn.substitute_solution(sol)

    assert dyn.x_e[0] == pytest.approx(0)
    assert dyn.x_e[-1] == pytest.approx(1)
    assert dyn.u_e[0] == pytest.approx(0)
    assert dyn.u_e[-1] == pytest.approx(0)
    assert np.max(dyn.u_e) == pytest.approx(1, abs=0.01)
    assert sol.value(u)[0] == pytest.approx(1, abs=0.05)
    assert sol.value(u)[-1] == pytest.approx(-1, abs=0.05)
    assert np.mean(np.abs(sol.value(u))) == pytest.approx(1, abs=0.01)
def get_trajectory(
    parameterization: type = asb.DynamicsPointMass3DCartesian,
    gravity=True,
    drag=True,
    sideforce=True,
    plot=False,
    verbose=False,
):
    opti = asb.Opti()

    if parameterization is asb.DynamicsPointMass3DCartesian:
        dyn = parameterization(
            mass_props=asb.MassProperties(mass=1),
            x_e=opti.variable(np.linspace(0, 300, N)),
            y_e=opti.variable(np.linspace(0, 0, N), scale=1),
            z_e=opti.variable(np.linspace(0, 0, N), scale=100),
            u_e=opti.variable(np.linspace(100, 50, N)),
            v_e=opti.variable(np.linspace(0, 0, N), scale=1),
            w_e=opti.variable(np.linspace(-100, 50, N)),
        )
    elif parameterization is asb.DynamicsPointMass3DSpeedGammaTrack:
        dyn = parameterization(
            mass_props=asb.MassProperties(mass=1),
            x_e=opti.variable(np.linspace(0, 300, N)),
            y_e=opti.variable(np.linspace(0, 0, N), scale=1),
            z_e=opti.variable(np.linspace(0, 0, N), scale=100),
            speed=opti.variable(np.linspace(100, 50, N)),
            gamma=opti.variable(np.linspace(0, 0, N)),
            track=opti.variable(np.linspace(0, 0, N)),
        )
    else:
        raise ValueError("Bad value of `parameterization`!")

    if gravity:
        dyn.add_gravity_force()
    q = 0.5 * 1.225 * dyn.speed**2
    if drag:
        dyn.add_force(Fx=-1 * (0.1)**2 * q, axes="wind")
    if sideforce:
        strouhal = 0.2
        frequency = 5  # strouhal * dyn.speed / 0.1
        dyn.add_force(Fy=q * 1 * (0.1)**2 *
                      np.sin(2 * np.pi * frequency * time),
                      axes="wind")

    dyn.constrain_derivatives(
        opti=opti,
        time=time,
    )

    opti.subject_to([
        dyn.x_e[0] == 0,
        dyn.y_e[0] == 0,
        dyn.z_e[0] == 0,
        dyn.u_e[0] == 100,
        dyn.v_e[0] == 0,
        dyn.w_e[0] == -100,
    ])

    sol = opti.solve(verbose=verbose)

    dyn.substitute_solution(sol)

    if plot:
        import matplotlib.pyplot as plt
        import aerosandbox.tools.pretty_plots as p

        fig, ax = plt.subplots()
        p.plot_color_by_value(dyn.x_e,
                              dyn.altitude,
                              c=dyn.speed,
                              colorbar=True)
        p.equal()
        p.show_plot("Trajectory", "$x_e$", "$z_e$")

    return dyn
Exemple #5
0
def test_rocket():
    ### Environment
    opti = asb.Opti()

    ### Time discretization
    N = 500  # Number of discretization points
    time_final = 100  # seconds
    time = np.linspace(0, time_final, N)

    ### Constants
    mass_initial = 500e3  # Initial mass, 500 metric tons
    z_e_final = -100e3  # Final altitude, 100 km
    g = 9.81  # Gravity, m/s^2
    alpha = 1 / (
        300 * g
    )  # kg/(N*s), Inverse of specific impulse, basically - don't worry about this

    dyn = asb.DynamicsPointMass1DVertical(
        mass_props=asb.MassProperties(
            mass=opti.variable(init_guess=mass_initial, n_vars=N)),
        z_e=opti.variable(
            init_guess=np.linspace(0, z_e_final, N)
        ),  # Altitude (negative due to Earth-axes convention)
        w_e=opti.variable(init_guess=-z_e_final / time_final,
                          n_vars=N),  # Velocity
    )

    dyn.add_gravity_force(g=g)
    thrust = opti.variable(init_guess=g * mass_initial, n_vars=N)
    dyn.add_force(Fz=-thrust)

    dyn.constrain_derivatives(
        opti=opti,
        time=time,
    )

    ### Fuel burn
    opti.constrain_derivative(
        derivative=-alpha * thrust,
        variable=dyn.mass_props.mass,
        with_respect_to=time,
        method="midpoint",
    )

    ### Boundary conditions
    opti.subject_to([
        dyn.z_e[0] == 0,
        dyn.w_e[0] == 0,
        dyn.mass_props.mass[0] == mass_initial,
        dyn.z_e[-1] == z_e_final,
    ])

    ### Path constraints
    opti.subject_to([dyn.mass_props.mass >= 0, thrust >= 0])

    ### Objective
    opti.minimize(-dyn.mass_props.mass[-1]
                  )  # Maximize the final mass == minimize fuel expenditure

    ### Solve
    sol = opti.solve(verbose=False)
    print(f"Solved in {sol.stats()['iter_count']} iterations.")
    dyn.substitute_solution(sol)

    assert dyn.mass_props.mass[-1] == pytest.approx(290049.81034472014,
                                                    rel=0.05)
    assert np.abs(dyn.w_e).max() == pytest.approx(1448, rel=0.05)