Esempio n. 1
0
//! Function to get the unit vector colinear with position segment of a translational state.
Eigen::Vector3d getForceDirectionColinearWithPosition(
        const boost::function< void( Eigen::Vector6d& ) > currentStateFunction,
        const double currentTime, const bool putForceInOppositeDirection )
{
    static Eigen::Vector6d currentState;
    currentStateFunction( currentState );
    return ( ( putForceInOppositeDirection == 1 ) ? -1.0 : 1.0 ) * ( currentState.segment( 0, 3 ) ).normalized( );
}
//! Function determine the numerical partial derivative of the true anomaly wrt the elements of the Cartesian state
Eigen::Matrix< double, 1, 6 > calculateNumericalPartialOfTrueAnomalyWrtState(
        const Eigen::Vector6d& cartesianElements, const double gravitationalParameter,
        const Eigen::Vector6d& cartesianStateElementPerturbations )
{
    using namespace tudat::orbital_element_conversions;

    // Initialize partial to zero
    Eigen::Matrix< double, 1, 6 > partial = Eigen::Matrix< double, 1, 6 >::Zero( );

    // Iterate over all six elements and calculate partials.
    Eigen::Vector6d perturbedCartesianElements;
    double upPerturbedTrueAnomaly, downPerturbedTrueAnomaly;
    for( int i = 0; i < 6; i++ )
    {
        // Calculate true anomaly at up-perturbed cartesian element i
        perturbedCartesianElements = cartesianElements;
        perturbedCartesianElements( i ) += cartesianStateElementPerturbations( i );
        upPerturbedTrueAnomaly = convertCartesianToKeplerianElements( perturbedCartesianElements, gravitationalParameter )( trueAnomalyIndex );

        // Check validity of result
        if( upPerturbedTrueAnomaly != upPerturbedTrueAnomaly )
        {
            std::cout << "Error 1 in partial of true anomaly wrt cartesian state, element" << i
                      << ", keplerian state: " << std::endl
                      << convertCartesianToKeplerianElements( perturbedCartesianElements, gravitationalParameter ).transpose( ) << std::endl
                      << perturbedCartesianElements.transpose( ) << std::endl;
        }

        // Calculate true anomaly at down-perturbed cartesian element i
        perturbedCartesianElements = cartesianElements;
        perturbedCartesianElements( i ) -= cartesianStateElementPerturbations( i );
        downPerturbedTrueAnomaly = convertCartesianToKeplerianElements( perturbedCartesianElements, gravitationalParameter )( trueAnomalyIndex );

        // Check validity of result
        if( downPerturbedTrueAnomaly != downPerturbedTrueAnomaly )
        {
            std::cout << "Error 2 in partial of true anomaly wrt cartesian state, element" << i
                      << ", keplerian state: " << std::endl
                      << convertCartesianToKeplerianElements( perturbedCartesianElements, gravitationalParameter ).transpose( ) << std::endl
                      << perturbedCartesianElements.transpose( ) << std::endl;
        }

        // Calculate central difference of term i
        partial( 0, i ) = ( upPerturbedTrueAnomaly - downPerturbedTrueAnomaly ) / ( 2.0 * cartesianStateElementPerturbations( i ) );

        // Check validity of result
        if( partial( 0, i ) != partial( 0, i ) )
        {
            std::cout << "Error 2 in partial of true anomaly wrt cartesian state, element" << i << std::endl;
        }
    }

    return partial;
}
Esempio n. 3
0
double BodyNode::VelocityObjFunc::eval(Eigen::Map<const Eigen::VectorXd>& _x)
{
  assert(mBodyNode->getParentJoint()->getNumGenCoords() == _x.size());

  // Update forward kinematics information with _x
  // We are just insterested in spacial velocity of mBodyNode
  mBodyNode->getParentJoint()->setGenVels(_x, true, false);

  // Compute and return the geometric distance between body node transformation
  // and target transformation
  Eigen::Vector6d diff = mBodyNode->getWorldVelocity() - mVelocity;
  return diff.dot(diff);
}
Esempio n. 4
0
double BodyNode::TransformObjFunc::eval(Eigen::Map<const Eigen::VectorXd>& _x)
{
  assert(mBodyNode->getParentJoint()->getNumGenCoords() == _x.size());

  // Update forward kinematics information with _x
  // We are just insterested in transformation of mBodyNode
  mBodyNode->getParentJoint()->setConfigs(_x, true, false, false);

  // Compute and return the geometric distance between body node transformation
  // and target transformation
  Eigen::Isometry3d bodyT = mBodyNode->getWorldTransform();
  Eigen::Vector6d dist = math::logMap(bodyT.inverse() * mT);
  return dist.dot(dist);
}
//! Function to compute proper-time rate w.r.t. coordinate time, minus 1.0, from a speed and scalar potential
double calculateFirstCentralBodyProperTimeRateDifference(
        const Eigen::Vector6d relativeStateVector, const double centralBodyGravitationalParameter,
        const double equivalencePrincipleLpiViolationParameter )
{
    return calculateFirstCentralBodyProperTimeRateDifference(
                relativeStateVector.segment( 3, 3 ).norm( ), centralBodyGravitationalParameter /
                relativeStateVector.segment( 0, 3 ).norm( ), equivalencePrincipleLpiViolationParameter );
}
Esempio n. 6
0
void check_values(const std::vector<SimpleFrame*>& targets,
                  const std::vector<SimpleFrame*>& followers,
                  const Frame* relativeTo,
                  const Frame* inCoordinatesOf,
                  double tolerance)
{
  for(std::size_t i=0; i<targets.size(); ++i)
  {
    Frame* T = targets[i];
    Frame* F = followers[i];

    const Eigen::Isometry3d& tf_error =
        T->getTransform(relativeTo)*F->getTransform(relativeTo).inverse();
    Eigen::Vector6d error;
    Eigen::AngleAxisd rot_error(tf_error.rotation());
    error.block<3,1>(0,0) = rot_error.angle()*rot_error.axis();
    error.block<3,1>(3,0) = tf_error.translation();

    EXPECT_TRUE( error.norm() < tolerance );

    EXPECT_TRUE( equals(T->getSpatialVelocity(relativeTo, inCoordinatesOf),
                        F->getSpatialVelocity(relativeTo, inCoordinatesOf),
                        tolerance) );

    EXPECT_TRUE( equals(T->getLinearVelocity(relativeTo, inCoordinatesOf),
                        F->getLinearVelocity(relativeTo, inCoordinatesOf),
                        tolerance) );

    EXPECT_TRUE( equals(T->getAngularVelocity(relativeTo, inCoordinatesOf),
                        F->getAngularVelocity(relativeTo, inCoordinatesOf),
                        tolerance) );

    EXPECT_TRUE( equals(T->getSpatialAcceleration(relativeTo, inCoordinatesOf),
                        F->getSpatialAcceleration(relativeTo, inCoordinatesOf),
                        tolerance) );

    EXPECT_TRUE( equals(T->getLinearAcceleration(relativeTo, inCoordinatesOf),
                        F->getLinearAcceleration(relativeTo, inCoordinatesOf),
                        tolerance) );

    EXPECT_TRUE( equals(T->getAngularAcceleration(relativeTo, inCoordinatesOf),
                        F->getAngularAcceleration(relativeTo, inCoordinatesOf),
                        tolerance) );
  }
}
Esempio n. 7
0
bool InverseKinematics::inverseKinematics(const MultiBody& mb, MultiBodyConfig& mbc,
                                          const sva::PTransformd& ef_target)
{
	int iter = 0;
	bool converged = false;
	int dof = 0;
	rbd::forwardKinematics(mb, mbc);
	Eigen::MatrixXd jacMat;
	Eigen::Vector6d v = Eigen::Vector6d::Ones();
	Eigen::Vector3d rotErr;
	Eigen::VectorXd res = Eigen::VectorXd::Zero(3);
	while( ! converged && iter < max_iterations_)
	{
		jacMat = jac_.jacobian(mb, mbc);
		//non-strict zeros in jacobian can be a problem...
		jacMat = jacMat.unaryExpr(CwiseRoundOp(-almost_zero_, almost_zero_));
		svd_.compute(jacMat, Eigen::ComputeThinU | Eigen::ComputeThinV);
		rotErr = sva::rotationError(mbc.bodyPosW[ef_index_].rotation(),
		                            ef_target.rotation());
		v << rotErr, ef_target.translation() - mbc.bodyPosW[ef_index_].translation();
		converged = v.norm() < threshold_;
		res = svd_.solve(v);

		dof = 0;
		for(auto index : jac_.jointsPath())
		{
			std::vector<double>& qi = mbc.q[index];
			for(auto &qv : qi)
			{
				qv += lambda_*res[dof];
				++dof;
			}
		}

		rbd::forwardKinematics(mb, mbc);
		rbd::forwardVelocity(mb, mbc);
		iter++;
	}
	return converged;
}
//! Convert dimensionless Cartesian state to dimensional units.
Eigen::VectorXd convertDimensionlessCartesianStateToDimensionalUnits(
        const Eigen::Vector6d &dimensionlessCartesianState,
        const double gravitationalParameterOfPrimaryBody,
        const double gravitationalParameterOfSecondaryBody,
        const double distanceBetweenPrimaries )
{
    // Declare dimensional Cartesian state.
    Eigen::Vector6d dimensionalCartesianState;

    // Convert position to dimensional units.
    dimensionalCartesianState.segment( 0, 3 )
            = dimensionlessCartesianState.segment( 0, 3 ) * distanceBetweenPrimaries;

    // Convert velocity to dimensional units.
    dimensionalCartesianState.segment( 3, 3 )
            = dimensionlessCartesianState.segment( 3, 3 )
            * std::sqrt( ( gravitationalParameterOfPrimaryBody
                           + gravitationalParameterOfSecondaryBody ) / distanceBetweenPrimaries );

    // Return state in dimensional units.
    return dimensionalCartesianState;
}
//! Compute state derivative.
Eigen::Vector6d StateDerivativeCircularRestrictedThreeBodyProblem::computeStateDerivative(
        const double time, const Eigen::Vector6d& cartesianState )
{
    using namespace orbital_element_conversions;

    TUDAT_UNUSED_PARAMETER( time );

    // Compute distance to primary body.
    const double xCoordinateToPrimaryBodySquared =
            ( cartesianState( xCartesianPositionIndex ) + massParameter )
            * ( cartesianState( xCartesianPositionIndex ) + massParameter );

    const double yCoordinateSquared = cartesianState( yCartesianPositionIndex )
            * cartesianState( yCartesianPositionIndex );

    const double zCoordinateSquared = cartesianState( zCartesianPositionIndex )
            * cartesianState( zCartesianPositionIndex );

    const double normDistanceToPrimaryBodyCubed = pow(
                xCoordinateToPrimaryBodySquared + yCoordinateSquared + zCoordinateSquared, 1.5 );

    // Compute distance to secondary body.
    const double xCoordinateSecondaryBodySquared =
            ( cartesianState( xCartesianPositionIndex ) - ( 1.0 - massParameter ) )
            * ( cartesianState( xCartesianPositionIndex ) - ( 1.0 - massParameter ) );

    double normDistanceToSecondaryBodyCubed = pow(
                xCoordinateSecondaryBodySquared + yCoordinateSquared + zCoordinateSquared, 1.5 );

    // Compute derivative of state.
    Eigen::VectorXd stateDerivative( 6 );

    stateDerivative.segment( xCartesianPositionIndex, 3 ) = cartesianState.segment( xCartesianVelocityIndex, 3 );

    stateDerivative( 3 ) = cartesianState( xCartesianPositionIndex )
            - ( ( 1.0 - massParameter ) / normDistanceToPrimaryBodyCubed )
            * ( cartesianState( xCartesianPositionIndex ) + massParameter )
            - ( massParameter / normDistanceToSecondaryBodyCubed )
            * ( cartesianState( xCartesianPositionIndex ) - ( 1.0 - massParameter ) )
            + 2.0 * cartesianState( yCartesianVelocityIndex );
    stateDerivative( 4 ) = cartesianState( yCartesianPositionIndex )
            * ( 1.0 - ( ( 1.0 - massParameter ) / normDistanceToPrimaryBodyCubed )
                - ( massParameter / normDistanceToSecondaryBodyCubed ) )
            - 2.0 * cartesianState( xCartesianVelocityIndex );
    stateDerivative( 5 ) = -cartesianState( zCartesianPositionIndex )
            * ( ( ( 1.0 - massParameter ) / normDistanceToPrimaryBodyCubed )
                + ( massParameter / normDistanceToSecondaryBodyCubed ) );

    // Return computed state derivative.
    return stateDerivative;
}
Esempio n. 10
0
//==============================================================================
void ZeroDofJoint::setPartialAccelerationTo(
    Eigen::Vector6d& _partialAcceleration,
    const Eigen::Vector6d& /*_childVelocity*/)
{
  _partialAcceleration.setZero();
}
Esempio n. 11
0
//==============================================================================
std::string toString(const Eigen::Vector6d& _v)
{
  return boost::lexical_cast<std::string>(_v.transpose());
}
//! Function for updating common blocks of partial to current state.
void EmpiricalAccelerationPartial::update( const double currentTime )
{
    if( !( currentTime_ == currentTime ) )
    {

        using namespace tudat::basic_mathematics;
        using namespace tudat::linear_algebra;

        // Get current state and associated data.
        Eigen::Vector6d currentState = empiricalAcceleration_->getCurrentState( );
        Eigen::Vector3d angularMomentumVector = Eigen::Vector3d( currentState.segment( 0, 3 ) ).cross(
                    Eigen::Vector3d( currentState.segment( 3, 3 ) ) );
        Eigen::Vector3d crossVector = angularMomentumVector.cross( Eigen::Vector3d( currentState.segment( 0, 3 ) ) );

        // Compute constituent geometric partials.
        Eigen::Matrix3d normPositionWrtPosition = calculatePartialOfNormalizedVector( Eigen::Matrix3d::Identity( ), currentState.segment( 0, 3 ) );
        Eigen::Matrix3d angularMomentumWrtPosition = -getCrossProductMatrix( currentState.segment( 3, 3 ) );
        Eigen::Matrix3d angularMomentumWrtVelocity = getCrossProductMatrix( currentState.segment( 0, 3 ) );
        Eigen::Matrix3d normAngularMomentumWrtPosition = calculatePartialOfNormalizedVector( angularMomentumWrtPosition, angularMomentumVector );
        Eigen::Matrix3d normAngularMomentumWrtVelocity = calculatePartialOfNormalizedVector( angularMomentumWrtVelocity, angularMomentumVector );
        Eigen::Matrix3d crossVectorWrtPosition = getCrossProductMatrix( angularMomentumVector ) -
                angularMomentumWrtVelocity * angularMomentumWrtPosition;
        Eigen::Matrix3d crossVectorWrtVelocity = -getCrossProductMatrix( currentState.segment( 0, 3 ) ) *
                getCrossProductMatrix( currentState.segment( 0, 3 ) );
        Eigen::Matrix3d normCrossVectorWrtPosition = calculatePartialOfNormalizedVector( crossVectorWrtPosition, crossVector );
        Eigen::Matrix3d normCrossVectorWrtVelocity = calculatePartialOfNormalizedVector( crossVectorWrtVelocity, crossVector );

        // Retrieve current empirical acceleration
        Eigen::Vector3d localAcceleration = empiricalAcceleration_->getCurrentLocalAcceleration( );

        // Compute partial derivative contribution of derivative of rotation matrix from RSW to inertial frame
        currentPositionPartial_ = localAcceleration.x( ) * normPositionWrtPosition + localAcceleration.y( ) * normCrossVectorWrtPosition +
                localAcceleration.z( ) * normAngularMomentumWrtPosition;
        currentVelocityPartial_ = localAcceleration.y( ) * normCrossVectorWrtVelocity + localAcceleration.z( ) * normAngularMomentumWrtVelocity;

        // Compute partial derivative contribution of derivative of true anomaly
        Eigen::Matrix< double, 1, 6 > localTrueAnomalyPartial = calculateNumericalPartialOfTrueAnomalyWrtState(
                    empiricalAcceleration_->getCurrentState( ),
                    empiricalAcceleration_->getCurrentGravitationalParameter( ), cartesianStateElementPerturbations );
        Eigen::Matrix< double, 1, 6 > trueAnomalyPartial = localTrueAnomalyPartial;
        currentPositionPartial_ += empiricalAcceleration_->getCurrentToInertialFrame( ) * (
                    empiricalAcceleration_->getCurrentAccelerationComponent( basic_astrodynamics::sine_empirical ) *
                    std::cos( empiricalAcceleration_->getCurrentTrueAnomaly( ) ) -
                    empiricalAcceleration_->getCurrentAccelerationComponent( basic_astrodynamics::cosine_empirical ) *
                    std::sin( empiricalAcceleration_->getCurrentTrueAnomaly( ) )
                    ) * trueAnomalyPartial.block( 0, 0, 1, 3 );
        currentVelocityPartial_ +=
                ( empiricalAcceleration_->getCurrentToInertialFrame( ) * (
                      empiricalAcceleration_->getCurrentAccelerationComponent( basic_astrodynamics::sine_empirical ) *
                      std::cos( empiricalAcceleration_->getCurrentTrueAnomaly( ) ) -
                      empiricalAcceleration_->getCurrentAccelerationComponent( basic_astrodynamics::cosine_empirical ) *
                      std::sin( empiricalAcceleration_->getCurrentTrueAnomaly( ) ) ) ) * trueAnomalyPartial.block( 0, 3, 1, 3 );
        currentTime_ = currentTime;

        // Check output.
        if( currentPositionPartial_ != currentPositionPartial_ )
        {
            throw std::runtime_error( "Error, empirical acceleration position partials are NaN" );
        }
        if( currentVelocityPartial_ != currentVelocityPartial_ )
        {
            throw std::runtime_error( "Error, empirical acceleration velocity partials are NaN" );
        }
    }
}
//! Execute propagation of orbit of TeslaRoadster around the Earth.
int main( )
{
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////            USING STATEMENTS              //////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    using namespace tudat;
    using namespace tudat::simulation_setup;
    using namespace tudat::propagators;
    using namespace tudat::numerical_integrators;
    using namespace tudat::orbital_element_conversions;
    using namespace tudat::basic_mathematics;
    using namespace tudat::gravitation;
    using namespace tudat::numerical_integrators;


    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////     CREATE ENVIRONMENT AND VEHICLE       //////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


    // Load Spice kernels.
    spice_interface::loadStandardSpiceKernels( { input_output::getSpiceKernelPath( ) + "de430.bsp" } );

    // Set simulation time settings.
    const double simulationStartEpoch =
            ( 2458163.500000000 - basic_astrodynamics::JULIAN_DAY_ON_J2000 ) * 86400.0;
    const double simulationEndEpoch = 500.0 * physical_constants::JULIAN_YEAR;

    // Define body settings for simulation.
    std::vector< std::string > bodiesToCreate;
    bodiesToCreate.push_back( "Sun" );
    bodiesToCreate.push_back( "Earth" );
    bodiesToCreate.push_back( "Moon" );
    bodiesToCreate.push_back( "Mars" );
    bodiesToCreate.push_back( "Venus" );
    bodiesToCreate.push_back( "Jupiter" );
    bodiesToCreate.push_back( "Saturn" );
    bodiesToCreate.push_back( "Mercury" );

    // Create body objects.
    std::map< std::string, std::shared_ptr< BodySettings > > bodySettings =
            getDefaultBodySettings( bodiesToCreate );
//    bodySettings[ "Sun" ]->ephemerisSettings->resetFrameOrientation( "J2000" );
//    bodySettings[ "Moon" ]->ephemerisSettings->resetFrameOrientation( "J2000" );
//    bodySettings[ "Earth" ]->ephemerisSettings->resetFrameOrientation( "J2000" );

//    for( unsigned int i = 0; i < bodiesToCreate.size( ); i++ )
//    {
//        bodySettings[ bodiesToCreate.at( i ) ]->rotationModelSettings->resetOriginalFrame( "J2000" );
//    }

    bodySettings[ "Mars" ]->ephemerisSettings = std::make_shared< ApproximatePlanetPositionSettings >(
                ephemerides::ApproximatePlanetPositionsBase::mars, false );
    bodySettings[ "Jupiter" ]->ephemerisSettings = std::make_shared< ApproximatePlanetPositionSettings >(
                ephemerides::ApproximatePlanetPositionsBase::mars, false );
    bodySettings[ "Saturn" ]->ephemerisSettings = std::make_shared< ApproximatePlanetPositionSettings >(
                ephemerides::ApproximatePlanetPositionsBase::mars, false );
    bodySettings[ "Venus" ]->ephemerisSettings = std::make_shared< ApproximatePlanetPositionSettings >(
                ephemerides::ApproximatePlanetPositionsBase::mars, false );
    bodySettings[ "Mercury" ]->ephemerisSettings = std::make_shared< ApproximatePlanetPositionSettings >(
                ephemerides::ApproximatePlanetPositionsBase::mars, false );

    NamedBodyMap bodyMap = createBodies( bodySettings );

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////             CREATE VEHICLE            /////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    // Create spacecraft object.
    bodyMap[ "TeslaRoadster" ] = std::make_shared< simulation_setup::Body >( );

    bodyMap[ "TeslaRoadster" ]->setConstantBodyMass( 1500.0 );

    // Create radiation pressure settings
    double referenceAreaRadiation = 8.0;
    double radiationPressureCoefficient = 1.2;
    std::vector< std::string > occultingBodies;
    std::shared_ptr< RadiationPressureInterfaceSettings > teslaRoadsterRadiationPressureSettings =
            std::make_shared< CannonBallRadiationPressureInterfaceSettings >(
                "Sun", referenceAreaRadiation, radiationPressureCoefficient, occultingBodies );

    // Create and set radiation pressure settings
    bodyMap[ "TeslaRoadster" ]->setRadiationPressureInterface(
                "Sun", createRadiationPressureInterface(
                    teslaRoadsterRadiationPressureSettings, "TeslaRoadster", bodyMap ) );


    // Finalize body creation.
    setGlobalFrameBodyEphemerides( bodyMap, "SSB", "ECLIPJ2000" );

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////            CREATE ACCELERATIONS          //////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    // Define propagator settings variables.
    SelectedAccelerationMap accelerationMap;
    std::vector< std::string > bodiesToPropagate;
    std::vector< std::string > centralBodies;

    // Define propagation settings.
    std::map< std::string, std::vector< std::shared_ptr< AccelerationSettings > > > accelerationsOfAsterix;
    accelerationsOfAsterix[ "Earth" ].push_back( std::make_shared< AccelerationSettings >(
                                                     basic_astrodynamics::central_gravity ) );
    accelerationsOfAsterix[ "Sun" ].push_back( std::make_shared< AccelerationSettings >( 
                                                   basic_astrodynamics::central_gravity ) );
    accelerationsOfAsterix[ "Moon" ].push_back( std::make_shared< AccelerationSettings >(
                                                     basic_astrodynamics::central_gravity ) );
    accelerationsOfAsterix[ "Mars" ].push_back( std::make_shared< AccelerationSettings >(
                                                     basic_astrodynamics::central_gravity ) );
    accelerationsOfAsterix[ "Venus" ].push_back( std::make_shared< AccelerationSettings >(
                                                     basic_astrodynamics::central_gravity ) );
    accelerationsOfAsterix[ "Mercury" ].push_back( std::make_shared< AccelerationSettings >(
                                                     basic_astrodynamics::central_gravity ) );
    accelerationsOfAsterix[ "Saturn" ].push_back( std::make_shared< AccelerationSettings >(
                                                     basic_astrodynamics::central_gravity ) );
    accelerationsOfAsterix[ "Jupiter" ].push_back( std::make_shared< AccelerationSettings >(
                                                     basic_astrodynamics::central_gravity ) );
    accelerationsOfAsterix[ "Sun" ].push_back( std::make_shared< AccelerationSettings >(
                                                     basic_astrodynamics::cannon_ball_radiation_pressure ) );


    accelerationMap[  "TeslaRoadster" ] = accelerationsOfAsterix;
    bodiesToPropagate.push_back( "TeslaRoadster" );
    centralBodies.push_back( "Sun" );

    basic_astrodynamics::AccelerationMap accelerationModelMap = createAccelerationModelsMap(
                bodyMap, accelerationMap, bodiesToPropagate, centralBodies );

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////             CREATE PROPAGATION SETTINGS            ////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    // Set Keplerian elements for TeslaRoadster.
    Eigen::Vector6d teslaRoadsterInitialStateJ2000;
    teslaRoadsterInitialStateJ2000 << -1.484544094935328E+06, -1.530028575781120E+06, -4.100899567817330E+05,
    -2.358201939417945E+00, -2.459124989364402E+00, -6.370785284397021E-01;
    teslaRoadsterInitialStateJ2000 *= 1000.0;
    teslaRoadsterInitialStateJ2000 += spice_interface::getBodyCartesianStateAtEpoch(
                "Earth", "SSB", "J2000", "None", simulationStartEpoch );

    Eigen::Quaterniond toEclipJ2000 = spice_interface::computeRotationQuaternionBetweenFrames(
                                 "J2000", "ECLIPJ2000", 0.0 );

    Eigen::Vector6d teslaRoadsterInitialState;
    teslaRoadsterInitialState.segment( 0, 3 ) = toEclipJ2000 * teslaRoadsterInitialStateJ2000.segment( 0, 3 );
    teslaRoadsterInitialState.segment( 3, 3 ) = toEclipJ2000 * teslaRoadsterInitialStateJ2000.segment( 3, 3 );
\




    // Define list of dependent variables to save.
    std::vector< std::shared_ptr< SingleDependentVariableSaveSettings > > dependentVariablesList;
    dependentVariablesList.push_back(
                std::make_shared< SingleDependentVariableSaveSettings >(
                    relative_position_dependent_variable, "Earth", "Sun" ) );
    dependentVariablesList.push_back(
                std::make_shared< SingleDependentVariableSaveSettings >(
                    relative_position_dependent_variable, "Mars", "Sun" ) );
    dependentVariablesList.push_back(
                std::make_shared< SingleDependentVariableSaveSettings >(
                    relative_position_dependent_variable, "Venus", "Sun" ) );
    dependentVariablesList.push_back(
                std::make_shared< SingleDependentVariableSaveSettings >(
                    relative_distance_dependent_variable, "TeslaRoadster", "Earth" ) );

    // Create object with list of dependent variables
    std::shared_ptr< DependentVariableSaveSettings > dependentVariablesToSave =
            std::make_shared< DependentVariableSaveSettings >( dependentVariablesList );

    std::shared_ptr< TranslationalStatePropagatorSettings< double > > propagatorSettings =
            std::make_shared< TranslationalStatePropagatorSettings< double > >
            ( centralBodies, accelerationModelMap, bodiesToPropagate, teslaRoadsterInitialState, simulationEndEpoch, cowell,
              dependentVariablesToSave );

    std::shared_ptr< IntegratorSettings< > > integratorSettings
            = std::make_shared< tudat::numerical_integrators::BulirschStoerIntegratorSettings< > >(
                simulationStartEpoch, 3600.0,
                numerical_integrators::bulirsch_stoer_sequence, 4,
                std::numeric_limits< double >::epsilon( ), std::numeric_limits< double >::infinity( ),
                1.0E-15, 1.0E-12 );

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////             PROPAGATE ORBIT            ////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


    // Create simulation object and propagate dynamics.
    SingleArcDynamicsSimulator< > dynamicsSimulator(
                bodyMap, integratorSettings, propagatorSettings, true, false, false );
    std::map< double, Eigen::VectorXd > integrationResult = dynamicsSimulator.getEquationsOfMotionNumericalSolution( );
    std::map< double, Eigen::VectorXd > dependentVariableResult = dynamicsSimulator.getDependentVariableHistory( );


    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////        PROVIDE OUTPUT TO CONSOLE AND FILES           //////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    std::string outputSubFolder = "SpacexTeslaExample/";

    // Write perturbed satellite propagation history to file.
    input_output::writeDataMapToTextFile( integrationResult,
                                          "spacexTeslaPropagationHistory.dat",
                                          tudat_applications::getOutputPath( ) + outputSubFolder,
                                          "",
                                          std::numeric_limits< double >::digits10,
                                          std::numeric_limits< double >::digits10,
                                          "," );

    input_output::writeDataMapToTextFile( dependentVariableResult,
                                          "spacexTeslaDependentVariableHistory.dat",
                                          tudat_applications::getOutputPath( ) + outputSubFolder,
                                          "",
                                          std::numeric_limits< double >::digits10,
                                          std::numeric_limits< double >::digits10,
                                          "," );


    // Final statement.
    // The exit code EXIT_SUCCESS indicates that the program was successfully executed.
    return EXIT_SUCCESS;
}