def main():
    # Load spice kernels.
    spice_interface.load_standard_spice_kernels()

    # Set simulation start epoch.
    simulation_start_epoch = 0.0

    # Set numerical integration fixed step size.
    fixed_step_size = 1.0

    # Set simulation end epoch.
    simulation_end_epoch = constants.JULIAN_DAY

    ###########################################################################
    # CREATE ENVIRONMENT ######################################################
    ###########################################################################

    bodies_to_create = ["Sun", "Earth", "Moon", "Mars", "Venus"]

    env = Environment(bodies_to_create,
                      user_defined_bodies=None,
                      frame_origin="SSB",
                      frame_orientation="ECLIPJ2000",
                      custom_body_settings=None,
                      alternative_kernels=None,
                      start_epoch=simulation_start_epoch,
                      end_epoch=simulation_end_epoch,
                      fixed_dt=fixed_step_size,
                      epoch_margin=300.0)

    ###########################################################################
    # CREATE VEHICLE ##########################################################
    ###########################################################################

    env.vehicles = ["Delfi-C3"]

    env.bodies["Delfi-C3"].set_constant_body_mass(400.0)

    ###########################################################################
    # CREATE VEHICLE - ENVIRONMENT INTERFACE ##################################
    ###########################################################################

    # Create aerodynamic interface settings for Delfi-C3.
    env.set_aerodynamic_coefficient_interface(
        target_body_name="Delfi-C3",
        reference_area=4.0,
        coefficients=1.2 * np.ones(3),
        coefficients_in_aerodynamic_frame=True,
        coefficients_in_negative_axis_direction=True,
        model="constant_coefficients")

    # Create radiation pressure interface settings for Delfi-C3.
    env.set_radiation_pressure_interface(target_body_name="Delfi-C3",
                                         reference_area=4.0,
                                         coefficient=1.2,
                                         occulting=["Earth"],
                                         source="Sun",
                                         model="cannon_ball")

    ###########################################################################
    # FINALIZE BODIES #########################################################
    ###########################################################################

    # Finalize body creation.
    env.finalize_environment(frame_origin="SSB", frame_orientation="J2000")

    ###########################################################################
    # CREATE ACCELERATIONS ####################################################
    ###########################################################################

    # Define bodies that are propagated.
    bodies_to_propagate = env.vehicles

    # Define central bodies.
    central_bodies = ["Earth"]

    # Define unique (Sun, Earth) accelerations acting on Delfi-C3.
    accelerations_of_delfi_c3 = dict(
        Sun=[
            simulation_setup.Acceleration.canon_ball_radiation_pressure()
            # AccelerationSettings(AvailableAcceleration.cannon_ball_radiation_pressure) # LEGACY DESIGN.
        ],
        Earth=[
            simulation_setup.Acceleration.spherical_harmonic_gravity(5, 5),
            # SphericalHarmonicAccelerationSettings(5, 5), # LEGACY DESIGN.
            simulation_setup.Acceleration.aerodynamic()
            # AccelerationSettings(AvailableAcceleration.aerodynamic) # LEGACY DESIGN.
        ])

    # Define other point mass accelerations acting on Delfi-C3.
    for other in set(bodies_to_create).difference({"Sun", "Earth"}):
        accelerations_of_delfi_c3[other] = [
            simulation_setup.Acceleration.point_mass_gravity()
        ]

    # Create global accelerations dictionary.
    acceleration_dict = {"Delfi-C3": accelerations_of_delfi_c3}

    # Create acceleration models.
    acceleration_models = simulation_setup.create_acceleration_models_dict(
        bodies_to_create, acceleration_dict, bodies_to_propagate,
        central_bodies)

    ###########################################################################
    # CREATE PROPAGATION SETTINGS #############################################
    ###########################################################################

    # Set initial conditions for the Asterix satellite that will be
    # propagated in this simulation. The initial conditions are given in
    # Keplerian elements and later on converted to Cartesian elements.

    # Set Keplerian elements for Delfi-C3
    earth_gravitational_parameter = env.bodies[
        "Earth"].gravity_field_model.get_gravitational_parameter()

    # LEGACY DESIGN.
    # KEI = orbital_element_conversions.KeplerianElementIndices
    # asterix_initial_state_in_keplerian_elements = np.zeros(6)
    # kep_state = asterix_initial_state_in_keplerian_elements
    # kep_state[int(KEI.semi_major_axis_index)] = 7500.0E3
    # kep_state[int(KEI.eccentricity_index)] = 0.1
    # kep_state[int(KEI.inclination_index)] = np.deg2rad(85.3)
    # kep_state[int(KEI.argument_of_periapsis_index)] = np.deg2rad(235.7)
    # kep_state[int(KEI.longitude_of_ascending_node_index)] = np.deg2rad(23.4)
    # kep_state[int(KEI.true_anomaly_index)] = np.deg2rad(139.87)
    # system_initial_state = corbital_element_conversions.onvert_keplerian_to_cartesian_elements(
    #     kep_state, earth_gravitational_parameter)

    # REVISED CONTEMPORARY DESIGN.
    system_initial_state = elements.keplerian2cartesian(
        mu=earth_gravitational_parameter,
        a=7500.0E3,
        ecc=0.1,
        inc=np.deg2rad(85.3),
        raan=np.deg2rad(23.4),
        argp=np.deg2rad(235.7),
        nu=np.deg2rad(139.87))

    # Create propagation settings.
    propagator_settings = propagators.TranslationalStatePropagatorSettings(
        central_bodies, acceleration_models, bodies_to_propagate,
        system_initial_state, simulation_end_epoch)
    # Create numerical integrator settings.
    integrator_settings = numerical_integrators.IntegratorSettings(
        numerical_integrators.AvailableIntegrators.rungeKutta4,
        simulation_start_epoch, fixed_step_size)

    ###########################################################################
    # PROPAGATE ORBIT #########################################################
    ###########################################################################

    # Create simulation object and propagate dynamics.
    dynamics_simulator = propagators.SingleArcDynamicsSimulator(
        bodies, integrator_settings, propagator_settings, True)
    result = dynamics_simulator.get_equations_of_motion_numerical_solution()

    ###########################################################################
    # PRINT INITIAL AND FINAL STATES ##########################################
    ###########################################################################

    print(f"""
Single Earth-Orbiting Satellite Example.
The initial position vector of Delfi-C3 is [km]: \n{
        result[simulation_start_epoch][:3] / 1E3}
The initial velocity vector of Delfi-C3 is [km]: \n{
        result[simulation_start_epoch][3:] / 1E3}
After {simulation_end_epoch} seconds the position vector of Delfi-C3 is [km]: \n{
        result[simulation_end_epoch][:3] / 1E3}
And the velocity vector of Delfi-C3 is [km]: \n{
        result[simulation_start_epoch][3:] / 1E3}
        """)

    ###########################################################################
    # SAVE RESULTS ############################################################
    ###########################################################################

    io.save2txt(
        solution=result,
        filename="singlePerturbedSatellitePropagationHistory.dat",
        directory="./tutorial_2",
    )

    # Final statement (not required, though good practice in a __main__).
    return 0
Beispiel #2
0
def single_satellite_propagator(
        start_epoch=0.0,
        fixed_step_size=10.0,
        end_epoch=constants.JULIAN_DAY,
        parent_body="Earth",
        frame_orientation="ECLIPJ2000",
        frame_origin="SSB",
        satellite_name="Delfi-C3",
        sat_sma=7500.0E3,
        sat_ecc=0.1,
        sat_inc=np.deg2rad(85.3),
        sat_raan=np.deg2rad(23.4),
        sat_argp=np.deg2rad(235.7),
        sat_nu=np.deg2rad(139.87),
        return_output=False,
        print_output=True,
        output_type='markdown'  # [array, markdown, latex, string]
):
    """
    Tutorial 1 of the tudatpy library in function form.

    Warning
    -------
    This function is not suited to mass generation of output data, as it
    is creating the environment and simulation from scratch for each call.

    Parameters
    ----------
    start_epoch
    fixed_step_size
    end_epoch
    parent_body
    frame_orientation
    frame_origin
    satellite_name
    sat_sma
    sat_ecc
    sat_inc
    sat_raan
    sat_argp
    sat_nu
    return_output
    print_output
    output_type

    Returns
    -------

    """
    # Load spice kernels.
    spice_interface.load_standard_kernels()

    # Set simulation start epoch.
    simulation_start_epoch = start_epoch

    # Set numerical integration fixed step size.
    fixed_step_size = fixed_step_size

    # Set simulation end epoch.
    simulation_end_epoch = end_epoch

    ###########################################################################
    # CREATE ENVIRONMENT ######################################################
    ###########################################################################

    # Create body objects.
    bodies_to_create = [parent_body]

    body_settings = simulation_setup.get_default_body_settings(
        bodies_to_create)

    body_settings[
        parent_body].ephemeris_settings = simulation_setup.ConstantEphemerisSettings(
            np.zeros(6))

    body_settings[parent_body].rotation_model_settings.reset_original_frame(
        frame_orientation)

    # Create Earth Object.
    bodies = simulation_setup.create_bodies(body_settings)

    ###########################################################################
    # CREATE VEHICLE ##########################################################
    ###########################################################################

    # Create vehicle objects.
    bodies[satellite_name] = simulation_setup.Body()

    ###########################################################################
    # FINALIZE BODIES #########################################################
    ###########################################################################

    simulation_setup.set_global_frame_body_ephemerides(bodies, frame_origin,
                                                       frame_orientation)

    ###########################################################################
    # CREATE ACCELERATIONS ####################################################
    ###########################################################################

    # Define bodies that are propagated.
    bodies_to_propagate = [satellite_name]

    # Define central bodies.
    central_bodies = [parent_body]

    # Define accelerations acting on Delfi-C3.
    accelerations_of_satellite = {
        parent_body: [simulation_setup.Acceleration.point_mass_gravity()]
    }

    # Create global accelerations dictionary.
    accelerations = {satellite_name: accelerations_of_satellite}

    # Create acceleration models.
    acceleration_models = simulation_setup.create_acceleration_models_dict(
        bodies, accelerations, bodies_to_propagate, central_bodies)

    ###########################################################################
    # CREATE PROPAGATION SETTINGS #############################################
    ###########################################################################

    # Set initial conditions for the Asterix satellite that will be
    # propagated in this simulation. The initial conditions are given in
    # Keplerian elements and later on converted to Cartesian elements.

    # Set Keplerian elements for satellite
    parent_gravitational_parameter = bodies[
        parent_body].gravity_field_model.get_gravitational_parameter()

    # REVISED CONTEMPORARY DESIGN.
    system_initial_state = elements.keplerian2cartesian(
        mu=parent_gravitational_parameter,
        a=sat_sma,
        ecc=sat_ecc,
        inc=sat_inc,
        raan=sat_raan,
        argp=sat_argp,
        nu=sat_nu)

    # Create propagation settings.
    propagator_settings = propagators.TranslationalStatePropagatorSettings(
        central_bodies, acceleration_models, bodies_to_propagate,
        system_initial_state, simulation_end_epoch)
    # Create numerical integrator settings.
    integrator_settings = numerical_integrators.IntegratorSettings(
        numerical_integrators.AvailableIntegrators.rungeKutta4,
        simulation_start_epoch, fixed_step_size)

    ###########################################################################
    # PROPAGATE ORBIT #########################################################
    ###########################################################################

    # Create simulation object and propagate dynamics.
    dynamics_simulator = propagators.SingleArcDynamicsSimulator(
        bodies, integrator_settings, propagator_settings, True)
    result = dynamics_simulator.get_equations_of_motion_numerical_solution()

    ###########################################################################
    # OUTPUT HANDLING #########################################################
    ###########################################################################

    if output_type != 'array':
        df = pd.DataFrame(data=np.vstack((
            result[simulation_start_epoch] / 1E3,
            result[simulation_end_epoch] / 1E3,
        )),
                          columns=[
                              'R_x [km]', 'R_y [km]', 'R_z [km]', 'V_x [km/s]',
                              'V_y [km/s]', 'V_z [km/s]'
                          ])
        df.index = ['t_0', 't_f']

    # Output type
    if output_type == 'markdown':
        output = df.to_markdown()

    elif output_type == 'latex':
        output = df.to_latex(escape=False)

    elif output_type == 'df':
        output = df

    else:
        output = np.vstack((
            result[simulation_start_epoch] / 1E3,
            result[simulation_end_epoch] / 1E3,
        ))

    # Print output
    if print_output:
        print(output)

    # Return output
    if return_output:
        return output
    else:
        return None
Beispiel #3
0
def main():
    # Load spice kernels.
    spice_interface.load_standard_spice_kernels()

    # Set simulation start epoch.
    simulation_start_epoch = 0.0

    # Set numerical integration fixed step size.
    fixed_step_size = 10.0

    # Set simulation end epoch.
    simulation_end_epoch = constants.JULIAN_DAY

    ###########################################################################
    # CREATE ENVIRONMENT ######################################################
    ###########################################################################

    # Create body objects.
    bodies_to_create = ["Earth"]

    body_settings = simulation_setup.get_default_body_settings(
        bodies_to_create)

    body_settings[
        "Earth"].ephemeris_settings = simulation_setup.ConstantEphemerisSettings(
            np.zeros(6))

    body_settings["Earth"].rotation_model_settings.reset_original_frame(
        "ECLIPJ2000")

    # Create Earth Object.
    bodies = simulation_setup.create_bodies(body_settings)

    ###########################################################################
    # CREATE VEHICLE ##########################################################
    ###########################################################################

    # Create vehicle objects.
    bodies["Delfi-C3"] = simulation_setup.Body()

    ###########################################################################
    # FINALIZE BODIES #########################################################
    ###########################################################################

    simulation_setup.set_global_frame_body_ephemerides(bodies, "SSB",
                                                       "ECLIPJ2000")

    ###########################################################################
    # CREATE ACCELERATIONS ####################################################
    ###########################################################################

    # Define bodies that are propagated.
    bodies_to_propagate = ["Delfi-C3"]

    # Define central bodies.
    central_bodies = ["Earth"]

    # Define accelerations acting on Delfi-C3.
    accelerations_of_delfi_c3 = dict(
        Earth=[simulation_setup.Acceleration.point_mass_gravity()])

    # Create global accelerations dictionary.
    accelerations = {"Delfi-C3": accelerations_of_delfi_c3}

    # Create acceleration models.
    acceleration_models = simulation_setup.create_acceleration_models_dict(
        bodies, accelerations, bodies_to_propagate, central_bodies)

    ###########################################################################
    # CREATE PROPAGATION SETTINGS #############################################
    ###########################################################################

    # Set initial conditions for the Asterix satellite that will be
    # propagated in this simulation. The initial conditions are given in
    # Keplerian elements and later on converted to Cartesian elements.

    # Set Keplerian elements for Delfi-C3
    earth_gravitational_parameter = bodies[
        "Earth"].gravity_field_model.get_gravitational_parameter()

    # LEGACY DESIGN.
    # KEI = orbital_element_conversions.KeplerianElementIndices
    # asterix_initial_state_in_keplerian_elements = np.zeros(6)
    # kep_state = asterix_initial_state_in_keplerian_elements
    # kep_state[int(KEI.semi_major_axis_index)] = 7500.0E3
    # kep_state[int(KEI.eccentricity_index)] = 0.1
    # kep_state[int(KEI.inclination_index)] = np.deg2rad(85.3)
    # kep_state[int(KEI.argument_of_periapsis_index)] = np.deg2rad(235.7)
    # kep_state[int(KEI.longitude_of_ascending_node_index)] = np.deg2rad(23.4)
    # kep_state[int(KEI.true_anomaly_index)] = np.deg2rad(139.87)
    # system_initial_state = corbital_element_conversions.onvert_keplerian_to_cartesian_elements(
    #     kep_state, earth_gravitational_parameter)

    # REVISED CONTEMPORARY DESIGN.
    system_initial_state = elements.keplerian2cartesian(
        mu=earth_gravitational_parameter,
        a=7500.0E3,
        ecc=0.1,
        inc=np.deg2rad(85.3),
        raan=np.deg2rad(23.4),
        argp=np.deg2rad(235.7),
        nu=np.deg2rad(139.87))

    # Create propagation settings.
    propagator_settings = propagators.TranslationalStatePropagatorSettings(
        central_bodies, acceleration_models, bodies_to_propagate,
        system_initial_state, simulation_end_epoch)
    # Create numerical integrator settings.
    integrator_settings = numerical_integrators.IntegratorSettings(
        numerical_integrators.AvailableIntegrators.rungeKutta4,
        simulation_start_epoch, fixed_step_size)

    ###########################################################################
    # PROPAGATE ORBIT #########################################################
    ###########################################################################

    t0 = time.time()
    # Create simulation object and propagate dynamics.
    dynamics_simulator = propagators.SingleArcDynamicsSimulator(
        bodies, integrator_settings, propagator_settings, True)
    result = dynamics_simulator.get_equations_of_motion_numerical_solution()

    ###########################################################################
    # PRINT INITIAL AND FINAL STATES ##########################################
    ###########################################################################

    print(f"""
Single Earth-Orbiting Satellite Example.
The initial position vector of Delfi-C3 is [km]: \n{
        result[simulation_start_epoch][:3] / 1E3} 
The initial velocity vector of Delfi-C3 is [km]: \n{
        result[simulation_start_epoch][3:] / 1E3}
After {simulation_end_epoch} seconds the position vector of Delfi-C3 is [km]: \n{
        result[simulation_end_epoch][:3] / 1E3}
And the velocity vector of Delfi-C3 is [km]: \n{
        result[simulation_start_epoch][3:] / 1E3}
        """)

    ###########################################################################
    # SAVE RESULTS ############################################################
    ###########################################################################
    #
    # io.save2txt(
    #     solution=result,
    #     filename="singleSatellitePropagationHistory.dat",
    #     directory="./tutorial_1",
    # )

    # Final statement (not required, though good practice in a __main__).
    return 0
def main():
    # Load spice kernels.
    spice_interface.load_standard_spice_kernels()

    # Set simulation start epoch.
    simulation_start_epoch = 0.0

    # Set numerical integration fixed step size.
    fixed_step_size = 1.0

    # Set simulation end epoch.
    simulation_end_epoch = constants.JULIAN_DAY

    ###########################################################################
    # CREATE ENVIRONMENT ######################################################
    ###########################################################################

    bodies_to_create = ["Sun", "Earth", "Moon", "Mars", "Venus"]

    env = Environment(tudatpy_bodies=bodies_to_create,
                      custom_bodies=None,
                      frame_origin="SSB",
                      frame_orientation="ECLIPJ2000",
                      start_epoch=simulation_start_epoch,
                      end_epoch=simulation_end_epoch,
                      epoch_margin=300.0)

    ###########################################################################
    # CREATE VEHICLE ##########################################################
    ###########################################################################

    env["Delfi-C3"] = Body(env)

    env["Delfi-C3"].set_constant_body_mass(400.0)

    ###########################################################################
    # CREATE VEHICLE - ENVIRONMENT INTERFACE ##################################
    ###########################################################################

    # Create aerodynamic coefficient interface settings
    reference_area = 4.0
    aerodynamic_coefficient = 1.2
    aero_c_settings = simulation_setup.ConstantAerodynamicCoefficientSettings(
        reference_area,
        aerodynamic_coefficient * np.ones(3),
        are_coefficients_in_aerodynamic_frame=True,
        are_coefficients_in_negative_axis_direction=True)
    # Create and set aerodynamic coefficients object
    env._bodies["Delfi-C3"].set_aerodynamic_coefficient_interface(
        simulation_setup.create_aerodynamic_coefficient_interface(
            aero_c_settings, "Delfi-C3"))
    # TODO: Simplify (post 1.0.0 work)

    # Create radiation pressure settings
    reference_area_radiation = 4.0
    radiation_pressure_coefficient = 1.2
    occulting_bodies = ["Earth"]
    rad_press_settings = simulation_setup.CannonBallRadiationPressureInterfaceSettings(
        "Sun", reference_area_radiation, radiation_pressure_coefficient,
        occulting_bodies)

    # Create and set radiation pressure settings
    env._bodies["Delfi-C3"].set_radiation_pressure_interface(
        "Sun",
        simulation_setup.create_radiation_pressure_interface(
            rad_press_settings, "Delfi-C3", env._bodies))

    # # Create aerodynamic interface settings for Delfi-C3.
    # env["Delfi-C3"]._set_aerodynamic_coefficient_interface(
    #     reference_area=4.0,
    #     coefficients=1.2 * np.ones(3),
    #     coefficients_in_aerodynamic_frame=True,
    #     coefficients_in_negative_axis_direction=True,
    #     model="constant_coefficients")
    #
    # # Create radiation pressure interface settings for Delfi-C3.
    # env["Delfi-C3"]._set_radiation_pressure_interface(
    #     reference_area=4.0,
    #     coefficient=1.2,
    #     occulting=["Earth"],
    #     source="Sun",
    #     model="cannon_ball")

    ###########################################################################
    # FINALIZE BODIES #########################################################
    ###########################################################################

    # Finalize body creation.
    env.finalize_environment()

    ###########################################################################
    # CREATE ACCELERATIONS ####################################################
    ###########################################################################

    # Define bodies that are propagated.
    bodies_to_propagate = ["Delfi-C3"]

    # Define central bodies.
    central_bodies = ["Earth"]

    # Define unique (Sun, Earth) accelerations acting on Delfi-C3.
    accelerations_of_delfi_c3 = dict(
        Sun=[
            simulation_setup.Acceleration.canon_ball_radiation_pressure()
            # AccelerationSettings(AvailableAcceleration.cannon_ball_radiation_pressure) # LEGACY DESIGN.
        ],
        Earth=[
            simulation_setup.Acceleration.spherical_harmonic_gravity(5, 5),
            # SphericalHarmonicAccelerationSettings(5, 5), # LEGACY DESIGN.
            simulation_setup.Acceleration.aerodynamic()
            # AccelerationSettings(AvailableAcceleration.aerodynamic) # LEGACY DESIGN.
        ])

    # Define other point mass accelerations acting on Delfi-C3.
    for other in set(bodies_to_create).difference({"Sun", "Earth"}):
        accelerations_of_delfi_c3[other] = [
            simulation_setup.Acceleration.point_mass_gravity()
        ]

    # Create global accelerations dictionary.
    acceleration_dict = {"Delfi-C3": accelerations_of_delfi_c3}

    # Create acceleration models.

    acceleration_models = simulation_setup.create_acceleration_models_dict(
        env._bodies, acceleration_dict, bodies_to_propagate, central_bodies)

    ###########################################################################
    # CREATE PROPAGATION SETTINGS #############################################
    ###########################################################################

    # Set initial conditions for the Asterix satellite that will be
    # propagated in this simulation. The initial conditions are given in
    # Keplerian elements and later on converted to Cartesian elements.

    # Set Keplerian elements for Delfi-C3
    earth_gravitational_parameter = env[
        "Earth"].gravity_field_model.get_gravitational_parameter()

    # REVISED CONTEMPORARY DESIGN.
    system_initial_state = elements.keplerian2cartesian(
        mu=earth_gravitational_parameter,
        a=7500.0E3,
        ecc=0.1,
        inc=np.deg2rad(85.3),
        raan=np.deg2rad(23.4),
        argp=np.deg2rad(235.7),
        nu=np.deg2rad(139.87))

    # Create propagation settings.
    propagator_settings = propagators.TranslationalStatePropagatorSettings(
        central_bodies, acceleration_models, bodies_to_propagate,
        system_initial_state, simulation_end_epoch)
    # Create numerical integrator settings.
    integrator_settings = numerical_integrators.IntegratorSettings(
        numerical_integrators.AvailableIntegrators.rungeKutta4,
        simulation_start_epoch, fixed_step_size)

    ###########################################################################
    # PROPAGATE ORBIT #########################################################
    ###########################################################################

    t0 = time.time()
    # Create simulation object and propagate dynamics.
    print(env._bodies)
    dynamics_simulator = propagators.SingleArcDynamicsSimulator(
        env._bodies, integrator_settings, propagator_settings, True)
    print("dynamics_simulator: ", time.time() - t0)
    result = dynamics_simulator.get_equations_of_motion_numerical_solution()

    ###########################################################################
    # PRINT INITIAL AND FINAL STATES ##########################################
    ###########################################################################

    print(f"""
Single Earth-Orbiting Satellite Example.
The initial position vector of Delfi-C3 is [km]: \n{
        result[simulation_start_epoch][:3] / 1E3}
The initial velocity vector of Delfi-C3 is [km/s]: \n{
        result[simulation_start_epoch][3:] / 1E3}
After {simulation_end_epoch} seconds the position vector of Delfi-C3 is [km]: \n{
        result[simulation_end_epoch][:3] / 1E3}
And the velocity vector of Delfi-C3 is [km/s]: \n{
        result[simulation_start_epoch][3:] / 1E3}
        """)

    ###########################################################################
    # SAVE RESULTS ############################################################
    ###########################################################################

    io.save2txt(
        solution=result,
        filename="singlePerturbedSatellitePropagationHistory.dat",
        directory="./tutorial_2_prototype",
    )

    # Final statement (not required, though good practice in a __main__).
    return 0