WarpTwin
Documentation for WarpTwin models and classes.
Loading...
Searching...
No Matches
SixDOFDynamicsModel.h
/******************************************************************************
* Copyright (c) ATTX INC 2025. All Rights Reserved.
*
* This software and associated documentation (the "Software") are the 
* proprietary and confidential information of ATTX INC. The Software is 
* furnished under a license agreement between ATTX and the user organization 
* and may be used or copied only in accordance with the terms of the agreement.
* Refer to 'license/attx_license.adoc' for standard license terms.
*
* EXPORT CONTROL NOTICE: THIS SOFTWARE MAY INCLUDE CONTENT CONTROLLED UNDER THE
* INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) OR THE EXPORT ADMINISTRATION 
* REGULATIONS (EAR99). No part of the Software may be used, reproduced, or 
* transmitted in any form or by any means, for any purpose, without the express 
* written permission of ATTX INC.
******************************************************************************/
/*
6-DOF Dynamics header file

Author: Alex Reynolds
*/
/*
Metadata for MS GUI:
imdata = {"exclude" : True}
*/

#ifndef MODELS_SUPPORT_SIX_DOF_DYNAMICS_MODEL
#define MODELS_SUPPORT_SIX_DOF_DYNAMICS_MODEL

#include <vector>
#include <array>
#include <list>

#include "architecture/Time.h"
#include "flight/App.h"
#include "flight/FlightExecutive.h"
#include "frames/Frame.h"
#include "frames/Node.h"
#include "frames/Body.h"
#include "frames/FrameDynamics.h"
#include "gncutils/integrator/ForwardEulerIntegrator.hpp"
#include "gncutils/integrator/RK4Integrator.hpp"
#include "simulation/SimulationSteps.h"

namespace warptwin {

    enum integrator_type_e {
        FORWARD_EULER = 1,
        RK4 = 4
    };

    /// @brief  Model to implement 6-DOF dynamics
    /// 
    /// This file defines the dynamics used for 6-DOF simulation.
    /// 
    /// It inherits from the classical model architecture, but is designed
    /// to execute in a manner that propagates dynamics forward in time.
    /// 
    /// Tasks executed and order of operations:
    /// Start step: Nothing
    /// Derivative: 
    /// - Ensures frames are up to date by evaluating current state
    /// - Articulates forces and moments applied at nodes through the
    ///   kinematics chain to the appropriate bodies
    /// - Determines frame motion on the basis of applied forces/moments
    /// - Integrates/updates frame states on the basis of kinematics --
    ///   note the critical difference in model scheme here -- this model
    ///   updates frame states in derivative, and therefore must run at 
    ///   the end of the model order after forces and moments have been 
    ///   calculated. It cannot be used as a standard model
    /// End step: Nothing
    /// 
    /// Key restrictions
    /// - Must run at the end of model chain
    /// - Must be one, and only one, instance of this model for every 
    ///   simulation instance that uses 6-DOF frame dynamics
    class SixDOFDynamicsModel : public warpos::App {
    public:
        /// Model params
        ///         NAME                    TYPE                    DEFAULT VALUE
        START_PARAMS
            /** Input parameter describing the integrator type dynamics should use
             *  Valid choices are: "Forward Euler", "RK4" */
            SIGNAL(integrator_type,         int,                    RK4);
            /** Pointer to the root frame for the simulation. This pointer is used
             *  as the starting point for recursive calls to dynamics calculations*/ 
            SIGNAL(root_frame_ptr,          Frame*,                 nullptr);
        END_PARAMS

        /// Model inputs
        ///         NAME                    TYPE                    DEFAULT VALUE
        START_INPUTS
            /** Time at the start of the simulation step, in seconds/nsec as Time class */
            clockwerk::DataIO<clockwerk::Time> step_start_time = clockwerk::DataIO<clockwerk::Time>(this, "step_start_time");
            /** Time at the end of the simulation step, in seconds as a double */
            clockwerk::DataIO<clockwerk::Time> step_end_time = clockwerk::DataIO<clockwerk::Time>(this, "step_end_time");
        END_INPUTS

        /// Model outputs
        ///         NAME                    TYPE                    DEFAULT VALUE
        START_OUTPUTS
            /** The current simulation time as a time object */
            clockwerk::DataIO<clockwerk::Time> current_time = clockwerk::DataIO<clockwerk::Time>(this, "current_time");
        END_OUTPUTS

        /// Model-specific implementations of startup and derivative
        /// Must be scheduled manually to derivative
        SixDOFDynamicsModel(warpos::FlightExecutive &executive);
        virtual ~SixDOFDynamicsModel() {}

        /// @brief   Function to reset our integrator for next step
        void reset() {_integrator_step_num = 0;}
    protected:
        int16 start() override;
        int16 execute() override; 

        /// @brief   Function to recursively integrate the frame tree via 
        ///          forward euler
        /// @param   frame_ptr   Pointer to the root frame
        /// @return  Error code corresponding to success/failure
        int _integrateRecursiveForwardEuler(Frame* frame_ptr);
        /// @brief   Function to recursively integrate the frame tree via RK4
        /// @param   frame_ptr   Pointer to the root frame
        /// @return  Error code corresponding to success/failure
        int _integrateRecursiveRk4(Frame* frame_ptr);

        /// @brief   Function to recursively loop through frames and set
        ///          their integrators
        /// @return  Error code corresponding to success/failure
        int _recurseRefreshFrameIntegratorSet(Frame* frame_ptr);

        /// Variables to track integrator type and steps 
        unsigned int _integrator_step_num = 0;
        unsigned int _integrator_steps_per_step = 0;

        /// Vectors of integrators -- allows for dynamic integrator numbers
        std::list<warpos::ForwardEulerIntegrator<NUM_INTEGRATED_STATES>> _fe_integrators;
        std::list<warpos::RK4Integrator<NUM_INTEGRATED_STATES>> _rk4_integrators;
        warpos::RK4Integrator<NUM_INTEGRATED_STATES>* _rk4_ptr;
        warpos::ForwardEulerIntegrator<NUM_INTEGRATED_STATES>* _fe_ptr;

        /// Our dynamics model for frames
        FrameDynamics _frame_dynamics;

        /// Temporary variables to hold state output from integrator
        /// and frame children for recursion
        std::array<double, NUM_INTEGRATED_STATES> _tmp_state;
        std::vector<GraphTreeObject*> _frame_children;

        /// Temporary variable for time calculation in RK4
        clockwerk::Time _half_step_size;
    };

}

#endif