Merge pull request #19 from cthunter01/development

Fix build failures and add github CI actions. Automated builds on Ubuntu and Windows
This commit is contained in:
cthunter01 2024-08-14 18:28:54 -06:00 committed by GitHub
commit 3c9c8b8c6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
68 changed files with 1606 additions and 1264 deletions

View File

@ -0,0 +1,86 @@
# This starter workflow is for a CMake project running on multiple platforms. There is a different
# starter workflow if you just want a single platform.
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
name: CMake on multiple platforms
on:
push:
branches: [ "development" ]
pull_request:
branches: [ "development" ]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations.
# Consider changing this to true when your workflow is stable.
fail-fast: false
# Set up a matrix to run the following 3 configurations:
# 1. <Windows, Release, latest MSVC compiler toolchain on the default runner image, default generator>
# 2. <Linux, Release, latest GCC compiler toolchain on the default runner image, default generator>
# 3. <Linux, Release, latest Clang compiler toolchain on the default runner image, default generator>
#
# To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list.
matrix:
os: [ubuntu-latest, windows-latest]
build_type: [Release]
c_compiler: [gcc-13, clang, cl]
include:
- os: windows-latest
c_compiler: cl
cpp_compiler: cl
- os: ubuntu-latest
c_compiler: gcc-13
cpp_compiler: g++-13
#- os: ubuntu-latest
#c_compiler: clang
#cpp_compiler: clang++
exclude:
- os: windows-latest
c_compiler: gcc-13
- os: windows-latest
c_compiler: clang
- os: ubuntu-latest
c_compiler: cl
# Clang is broken on ubuntu-latest. C++20 brings in inconsistent libraries
- os: ubuntu-latest
c_compiler: clang
steps:
- uses: actions/checkout@v3
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: 6.6.2
target: desktop
- name: Set reusable strings
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
id: strings
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: >
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-S ${{ github.workspace }}
- name: Build
# Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
- name: Test
working-directory: ${{ steps.strings.outputs.build-output-dir }}
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest --build-config ${{ matrix.build_type }} -R 'qtrocket_*'

2
.gitignore vendored
View File

@ -38,6 +38,8 @@ build/
docs/doxygen/*
# IDE
*.swp
qtrocket.pro.user
.qmake.stash
CMakeLists.txt.user

View File

@ -2,14 +2,27 @@ cmake_minimum_required(VERSION 3.16)
project(qtrocket VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
enable_testing()
include(FetchContent)
# Google Test framework
FetchContent_Declare(googletest
GIT_REPOSITORY https://github.com/google/googletest
GIT_TAG v1.13.0)
if(WIN32)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
endif()
FetchContent_MakeAvailable(googletest)
# fmtlib dependency
FetchContent_Declare(fmt
GIT_REPOSITORY https://github.com/fmtlib/fmt
GIT_TAG 9.1.0)
FetchContent_MakeAvailable(fmt)
#FetchContent_Declare(fmt
# GIT_REPOSITORY https://github.com/fmtlib/fmt
# GIT_TAG 9.1.0)
#FetchContent_MakeAvailable(fmt)
# jsoncpp dependency
FetchContent_Declare(jsoncpp
@ -36,18 +49,30 @@ if(WIN32)
endif()
FetchContent_MakeAvailable(CURL)
# eigen dependency
FetchContent_Declare(Eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen
GIT_TAG 3.4.0)
FetchContent_MakeAvailable(Eigen)
# boost dependency
FetchContent_Declare(Boost
GIT_REPOSITORY https://github.com/boostorg/boost
GIT_TAG boost-1.84.0)
set(BOOST_INCLUDE_LIBRARIES property_tree)
FetchContent_MakeAvailable(Boost)
# Add qtrocket subdirectories. These are components that will be linked in
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(WIN32)
set(CMAKE_PREFIX_PATH $ENV{QTDIR})
include_directories("C:\\boost\\boost_1_82_0\\")
# include_directories("C:\\boost\\boost_1_82_0\\")
# find_package(Qt6Core REQUIRED)
# find_package(Qt6Widgets REQUIRED)
endif()
@ -84,61 +109,6 @@ set(PROJECT_SOURCES
gui/ThrustCurveMotorSelector.ui
gui/qcustomplot.cpp
gui/qcustomplot.h
model/MotorCase.cpp
model/MotorCase.h
model/MotorModel.cpp
model/MotorModel.h
model/MotorModelDatabase.cpp
model/MotorModelDatabase.h
model/Rocket.cpp
model/Rocket.h
model/ThrustCurve.cpp
model/ThrustCurve.h
sim/AtmosphericModel.h
sim/ConstantAtmosphere.h
sim/ConstantGravityModel.cpp
sim/ConstantGravityModel.h
sim/DESolver.h
sim/Environment.h
sim/GeoidModel.h
sim/GravityModel.cpp
sim/GravityModel.h
sim/Propagator.cpp
sim/Propagator.h
sim/RK4Solver.h
sim/SphericalGeoidModel.cpp
sim/SphericalGeoidModel.h
sim/SphericalGravityModel.cpp
sim/SphericalGravityModel.h
sim/StateData.cpp
sim/StateData.h
sim/USStandardAtmosphere.cpp
sim/USStandardAtmosphere.h
sim/WindModel.cpp
sim/WindModel.h
utils/BinMap.cpp
utils/BinMap.h
utils/CurlConnection.cpp
utils/CurlConnection.h
utils/Logger.cpp
utils/Logger.h
utils/MotorModelDatabase.cpp
utils/MotorModelDatabase.h
utils/RSEDatabaseLoader.cpp
utils/RSEDatabaseLoader.h
utils/ThreadPool.cpp
utils/ThreadPool.h
utils/ThrustCurveAPI.cpp
utils/ThrustCurveAPI.h
utils/Triplet.h
utils/TSQueue.h
utils/math/Constants.h
utils/math/Quaternion.cpp
utils/math/Quaternion.h
utils/math/UtilityMathFunctions.cpp
utils/math/UtilityMathFunctions.h
utils/math/Vector3.cpp
utils/math/Vector3.h
${TS_FILES}
)
@ -167,11 +137,26 @@ else()
)
endif()
#qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif()
#target_link_libraries(qtrocket PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${Qt_VERSION_MAJOR}::PrintSupport libcurl jsoncpp_static fmt::fmt-header-only)
target_link_libraries(qtrocket PRIVATE Qt6::Widgets Qt6::PrintSupport libcurl jsoncpp_static fmt::fmt-header-only)
add_subdirectory(utils)
add_subdirectory(sim)
add_subdirectory(model)
#target_link_libraries(qtrocket PRIVATE
# Qt6::Widgets
# Qt6::PrintSupport
# libcurl
# jsoncpp_static
# fmt::fmt-header-only
# eigen)
target_link_libraries(qtrocket PRIVATE
Qt6::Widgets
Qt6::PrintSupport
utils
sim
model)
set_target_properties(qtrocket PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com

View File

@ -1,416 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 10.0.0, 2023-04-26T18:22:10. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{126c64d7-12e8-468a-ad3f-06f0fbdaeca1}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="qlonglong">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="qlonglong" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
<value type="bool" key="EditorConfiguration.tintMarginArea">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="AutoTest.ActiveFrameworks">
<value type="bool" key="AutoTest.Framework.Boost">true</value>
<value type="bool" key="AutoTest.Framework.CTest">false</value>
<value type="bool" key="AutoTest.Framework.Catch">true</value>
<value type="bool" key="AutoTest.Framework.GTest">true</value>
<value type="bool" key="AutoTest.Framework.QtQuickTest">true</value>
<value type="bool" key="AutoTest.Framework.QtTest">true</value>
</valuemap>
<valuemap type="QVariantMap" key="AutoTest.CheckStates"/>
<value type="int" key="AutoTest.RunAfterBuild">0</value>
<value type="bool" key="AutoTest.UseGlobal">true</value>
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">6</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop Qt6</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop Qt6</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{834bc66d-170a-454c-a2b0-c17798dc7b12}</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="qlonglong" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="CMake.Build.Type">Debug</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=Debug
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Debug</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
<value type="QString" key="CMake.Build.Type">Release</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=Release
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-Release</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
<value type="QString" key="CMake.Build.Type">RelWithDebInfo</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-RelWithDebInfo</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Release with Debug Information</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.3">
<value type="QString" key="CMake.Build.Type">RelWithDebInfo</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="int" key="EnableQmlDebugging">0</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-Profile</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Profile</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.4">
<value type="QString" key="CMake.Build.Type">MinSizeRel</value>
<value type="int" key="CMake.Configure.BaseEnvironment">2</value>
<value type="bool" key="CMake.Configure.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMake.Configure.UserEnvironmentChanges"/>
<value type="QString" key="CMake.Initial.Parameters">-DCMAKE_GENERATOR:STRING=Ninja
-DCMAKE_BUILD_TYPE:STRING=MinSizeRel
-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{buildDir}/.qtc/package-manager/auto-setup.cmake
-DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable}
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX}
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C}
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx}
-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG}</value>
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/travis/build-qtrocket-Desktop_Qt6-MinSizeRel</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.BuildPreset"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="CMakeProjectManager.MakeStep.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.UserEnvironmentChanges"/>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Minimum Size Release</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.BuildConfigurationCount">5</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="qlonglong" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">qtrocket</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.qtrocket</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">qtrocket</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">/home/travis/build-qtrocket-Desktop_Qt6-Debug</value>
</valuemap>
<value type="qlonglong" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="qlonglong">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

View File

@ -1,4 +1,3 @@
/// \cond
// C headers
// C++ headers
@ -45,7 +44,7 @@ void guiWorker(int argc, char* argv[], int& ret)
// Go!
MainWindow w(QtRocket::getInstance());
logger->info("Showing MainWindow");
logger->debug("Showing MainWindow");
w.show();
ret = a.exec();
@ -65,7 +64,7 @@ void QtRocket::init()
std::lock_guard<std::mutex> lck(mtx);
if(!initialized)
{
utils::Logger::getInstance()->info("Instantiating new QtRocket");
utils::Logger::getInstance()->debug("Instantiating new QtRocket");
instance = new QtRocket();
initialized = true;
}
@ -81,10 +80,20 @@ QtRocket::QtRocket()
setEnvironment(std::make_shared<sim::Environment>());
rocket.first =
std::make_shared<Rocket>();
std::make_shared<model::RocketModel>();
rocket.second =
std::make_shared<sim::Propagator>(rocket.first);
motorDatabase = std::make_shared<utils::MotorModelDatabase>();
logger->debug("Initial states vector size: " + std::to_string(states.capacity()) );
// Reserve at least 1024 spaces for StateData
if(states.capacity() < 1024)
{
states.reserve(1024);
}
logger->debug("New states vector size: " + std::to_string(states.capacity()) );
}
int QtRocket::run(int argc, char* argv[])
@ -101,12 +110,21 @@ int QtRocket::run(int argc, char* argv[])
return 0;
}
void QtRocket::launchRocket()
{
// initialize the propagator
rocket.first->clearStates();
rocket.second->setCurrentTime(0.0);
// start the rocket motor
rocket.first->launch();
// run the propagator until it terminates
rocket.second->runUntilTerminate();
}
void QtRocket::addMotorModels(std::vector<model::MotorModel>& m)
{
for(const auto& i : m)
{
motorModels.push_back(i);
}
motorDatabase->addMotorModels(motorModels);
motorDatabase->addMotorModels(m);
// TODO: Now clear any duplicates?
}

View File

@ -14,13 +14,12 @@
// qtrocket headers
#include "model/MotorModel.h"
#include "model/Rocket.h"
#include "sim/AtmosphericModel.h"
#include "sim/GravityModel.h"
#include "model/RocketModel.h"
#include "sim/Environment.h"
#include "sim/Propagator.h"
#include "utils/Logger.h"
#include "utils/MotorModelDatabase.h"
#include "utils/math/MathTypes.h"
/**
* @brief The QtRocket class is the master controller for the QtRocket application.
@ -44,18 +43,29 @@ public:
std::shared_ptr<sim::Environment> getEnvironment() { return environment; }
void setTimeStep(double t) { rocket.second->setTimeStep(t); }
std::shared_ptr<Rocket> getRocket() { return rocket.first; }
std::shared_ptr<model::RocketModel> getRocket() { return rocket.first; }
std::shared_ptr<utils::MotorModelDatabase> getMotorDatabase() { return motorDatabase; }
void addMotorModels(std::vector<model::MotorModel>& m);
const std::vector<model::MotorModel>& getMotorModels() const { return motorModels; }
void addRocket(std::shared_ptr<Rocket> r) { rocket.first = r; }
void addRocket(std::shared_ptr<model::RocketModel> r) { rocket.first = r; rocket.second = std::make_shared<sim::Propagator>(r); }
void setEnvironment(std::shared_ptr<sim::Environment> e) { environment = e; }
void launchRocket();
/**
* @brief getStates returns a vector of time/state pairs generated during launch()
* @return vector of pairs of doubles, where the first value is a time and the second a state vector
*/
const std::vector<std::pair<double, StateData>>& getStates() const { return rocket.first->getStates(); }
/**
* @brief setInitialState sets the initial state of the Rocket.
* @param initState initial state vector (x, y, z, xDot, yDot, zDot, pitch, yaw, roll, pitchDot, yawDot, rollDot)
*/
void setInitialState(const StateData& initState) { rocket.first->setInitialState(initState); }
private:
QtRocket();
@ -66,16 +76,21 @@ private:
static std::mutex mtx;
static QtRocket* instance;
// Motor "database(s)"
std::vector<model::MotorModel> motorModels;
utils::Logger* logger;
std::pair<std::shared_ptr<Rocket>, std::shared_ptr<sim::Propagator>> rocket;
using Rocket = std::pair<std::shared_ptr<model::RocketModel>, std::shared_ptr<sim::Propagator>>;
Rocket rocket;
std::shared_ptr<sim::Environment> environment;
std::shared_ptr<utils::MotorModelDatabase> motorDatabase;
// Launch site
// ECEF coordinates
Vector3 launchSitePosition{0.0, 0.0, 0.0};
// Table of state data
std::vector<StateData> states;
};
#endif // QTROCKET_H

View File

@ -35,8 +35,8 @@ AnalysisWindow::~AnalysisWindow()
void AnalysisWindow::onButton_plotAltitude_clicked()
{
std::shared_ptr<Rocket> rocket = QtRocket::getInstance()->getRocket();
const std::vector<std::pair<double, std::vector<double>>>& res = rocket->getStates();
QtRocket* qtRocket = QtRocket::getInstance();
const std::vector<std::pair<double, StateData>>& res = qtRocket->getStates();
auto& plot = ui->plotWidget;
plot->clearGraphs();
plot->setInteraction(QCP::iRangeDrag, true);
@ -46,7 +46,7 @@ void AnalysisWindow::onButton_plotAltitude_clicked()
for (int i = 0; i < tData.size(); ++i)
{
tData[i] = res[i].first;
zData[i] = res[i].second[2];
zData[i] = res[i].second.position[2];
}
// create graph and assign data to it:
plot->addGraph();
@ -62,8 +62,8 @@ void AnalysisWindow::onButton_plotAltitude_clicked()
void AnalysisWindow::onButton_plotVelocity_clicked()
{
std::shared_ptr<Rocket> rocket = QtRocket::getInstance()->getRocket();
const std::vector<std::pair<double, std::vector<double>>>& res = rocket->getStates();
QtRocket* qtRocket = QtRocket::getInstance();
const std::vector<std::pair<double, StateData>>& res = qtRocket->getStates();
auto& plot = ui->plotWidget;
plot->clearGraphs();
plot->setInteraction(QCP::iRangeDrag, true);
@ -74,7 +74,7 @@ void AnalysisWindow::onButton_plotVelocity_clicked()
for (int i = 0; i < tData.size(); ++i)
{
tData[i] = res[i].first;
zData[i] = res[i].second[5];
zData[i] = res[i].second.velocity[2];
}
// create graph and assign data to it:
plot->addGraph();
@ -91,8 +91,8 @@ void AnalysisWindow::onButton_plotVelocity_clicked()
void AnalysisWindow::onButton_plotMotorCurve_clicked()
{
std::shared_ptr<Rocket> rocket = QtRocket::getInstance()->getRocket();
model::MotorModel motor = rocket->getCurrentMotorModel();
std::shared_ptr<model::RocketModel> rocket = QtRocket::getInstance()->getRocket();
model::MotorModel motor = rocket->getMotorModel();
ThrustCurve tc = motor.getThrustCurve();
@ -122,4 +122,4 @@ void AnalysisWindow::onButton_plotMotorCurve_clicked()
plot->yAxis->setRange(*std::min_element(std::begin(fData), std::end(fData)), *std::max_element(std::begin(fData), std::end(fData)));
plot->replot();
}
}

View File

@ -20,7 +20,7 @@
#include "gui/MainWindow.h"
#include "gui/ThrustCurveMotorSelector.h"
#include "gui/SimOptionsWindow.h"
#include "model/Rocket.h"
#include "model/RocketModel.h"
#include "utils/RSEDatabaseLoader.h"
@ -83,6 +83,7 @@ MainWindow::MainWindow(QtRocket* _qtRocket, QWidget *parent)
this,
SLOT(onButton_getTCMotorData_clicked()));
ui->calculateTrajectory_btn->setDisabled(true);
}
MainWindow::~MainWindow()
@ -122,12 +123,16 @@ void MainWindow::onButton_calculateTrajectory_clicked()
double initialVelocityX = initialVelocity * std::cos(initialAngle / 57.2958);
double initialVelocityZ = initialVelocity * std::sin(initialAngle / 57.2958);
std::vector<double> initialState = {0.0, 0.0, 0.0, initialVelocityX, 0.0, initialVelocityZ, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
//std::vector<double> initialState = {0.0, 0.0, 0.0, initialVelocityX, 0.0, initialVelocityZ, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
StateData initialState;
initialState.position = {0.0, 0.0, 0.0};
initialState.velocity = {initialVelocityX, 0.0, initialVelocityZ};
auto rocket = QtRocket::getInstance()->getRocket();
rocket->setInitialState(initialState);
rocket->setMass(mass);
rocket->setDragCoefficient(dragCoeff);
rocket->launch();
qtRocket->setInitialState(initialState);
qtRocket->launchRocket();
AnalysisWindow aWindow;
aWindow.setModal(false);
@ -186,7 +191,13 @@ void MainWindow::onButton_setMotor_clicked()
QString motorName = ui->engineSelectorComboBox->currentText();
model::MotorModel mm = rseDatabase->getMotorModelByName(motorName.toStdString());
QtRocket::getInstance()->getRocket()->setMotorModel(mm);
QtRocket::getInstance()->addMotorModels(rseDatabase->getMotors());
// Now that we have a motor selected, we can enable the calculateTrajectory button
ui->calculateTrajectory_btn->setDisabled(false);
/// TODO: Figure out if this is the right place to populate the motor database
/// or from RSEDatabaseLoader where it currently is populated.
//QtRocket::getInstance()->addMotorModels(rseDatabase->getMotors());
}

View File

@ -1,11 +1,9 @@
/// \cond
// C headers
// C++ headers
// 3rd party headers
/// \endcond
#include "QtRocket.h"
#include "utils/Logger.h"
@ -14,54 +12,16 @@ int main(int argc, char *argv[])
// Instantiate logger
utils::Logger* logger = utils::Logger::getInstance();
logger->setLogLevel(utils::Logger::DEBUG_);
logger->setLogLevel(utils::Logger::PERF_);
logger->info("Logger instantiated at PERF level");
// instantiate QtRocket
logger->debug("Starting QtRocket");
QtRocket* qtrocket = QtRocket::getInstance();
// Run QtRocket. This'll start the GUI thread and block until the user
// exits the program
logger->debug("QtRocket->run()");
int retVal = qtrocket->run(argc, argv);
logger->debug("Returning");
return retVal;
}
/*
* This was the old main when it directly started the QtGui. It worked. The new way of
* starting the gui through QtRocket->run() also seems to work, but I'm leaving this here for
* now in case there are unforeseen issues with starting the gui in a separate thread via
* QtRocket::run()
*
#include "gui/MainWindow.h"
#include <QApplication>
#include <QLocale>
#include <QTranslator>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
a.setWindowIcon(QIcon(":/qtrocket.png"));
// Start translation component.
// TODO: Only support US English at the moment. Anyone want to help translate?
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages)
{
const QString baseName = "qtrocket_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName))
{
a.installTranslator(&translator);
break;
}
}
// Go!
MainWindow w;
w.show();
return a.exec();
}
*/

20
model/CMakeLists.txt Normal file
View File

@ -0,0 +1,20 @@
add_library(model
MotorModel.cpp
MotorModel.h
MotorModelDatabase.cpp
MotorModelDatabase.h
Part.cpp
Part.h
Propagatable.cpp
Propagatable.h
RocketModel.cpp
RocketModel.h
ThrustCurve.cpp
ThrustCurve.h
InertiaTensors.h)
target_link_libraries(model PRIVATE
utils)
# Unit tests
add_subdirectory(tests)

70
model/InertiaTensors.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef INERTIATENSORS_H
#define INERTIATENSORS_H
#include "utils/math/MathTypes.h"
namespace model
{
/**
* @brief The InertiaTensors class provides a collection of methods to
* deliver some common inertia tensors centered about the center of mass
*/
class InertiaTensors
{
public:
/**
* @brief SolidSphere
* @param radius (meters)
* @return
*/
static Matrix3 SolidSphere(double radius)
{
double xx = 0.4*radius*radius;
double yy = xx;
double zz = xx;
return Matrix3{{xx, 0, 0},
{0, yy, 0},
{0, 0, zz}};
}
/**
* @brief HollowSphere
* @param radius (meters)
* @return
*/
static Matrix3 HollowSphere(double radius)
{
double xx = (2.0/3.0)*radius*radius;
double yy = xx;
double zz = xx;
return Matrix3{{xx, 0, 0},
{0, yy, 0},
{0, 0, zz}};
}
/**
* @brief Tube - The longitudinal axis is the z-axis. Can also be used for a solid cylinder
* when innerRadius = 0.0
* @param innerRadius (meters)
* @param outerRadius (meters)
* @param length (meters)
* @return
*/
static Matrix3 Tube(double innerRadius, double outerRadius, double length)
{
double xx = (1.0/12.0)*(3.0*(innerRadius*innerRadius + outerRadius*outerRadius) + length*length);
double yy = xx;
double zz = (1.0/2.0)*(innerRadius*innerRadius + outerRadius*outerRadius);
return Matrix3{{xx, 0.0, 0.0},
{0.0, yy, 0.0},
{0.0, 0.0, zz}};
}
};
}
#endif // INERTIATENSORS_H

View File

@ -1 +0,0 @@
#include "MotorCase.h"

View File

@ -1,17 +0,0 @@
#ifndef MODEL_MOTORCASE_H
#define MODEL_MOTORCASE_H
namespace model
{
class MotorCase
{
public:
MotorCase();
~MotorCase();
private:
};
} // namespace model
#endif // MODEL_MOTORCASE_H

View File

@ -60,6 +60,7 @@ double MotorModel::getMass(double simTime) const
double propMassEnd = i->second;
double slope = (propMassEnd - propMassStart) / (tEnd - tStart);
double currentMass = emptyMass + propMassStart + (thrustTime - tStart) * slope;
utils::Logger::getInstance()->info("simTime: " + std::to_string(simTime) + ": motor mass: " + std::to_string(currentMass));
return currentMass;
}

View File

@ -406,7 +406,7 @@ public:
MetaData data;
private:
bool ignitionOccurred{false};
bool burnOutOccurred{false};
bool burnOutOccurred{false};
double emptyMass;
double isp;
double maxTime;

109
model/Part.cpp Normal file
View File

@ -0,0 +1,109 @@
#include "Part.h"
#include "utils/Logger.h"
namespace model
{
Part::Part(const std::string& n,
const Matrix3& I,
double m,
const Vector3& centerMass)
: parent(nullptr),
name(n),
inertiaTensor(I),
compositeInertiaTensor(I),
mass(m),
compositeMass(m),
cm(centerMass),
needsRecomputing(false),
childParts()
{ }
Part::~Part()
{}
Part::Part(const Part& orig)
: parent(orig.parent),
name(orig.name),
inertiaTensor(orig.inertiaTensor),
compositeInertiaTensor(orig.compositeInertiaTensor),
mass(orig.mass),
compositeMass(orig.compositeMass),
cm(orig.cm),
needsRecomputing(orig.needsRecomputing),
childParts()
{
// We are copying the whole tree. If the part we're copying itself has child
// parts, we are also copying all of them! This may be inefficient and not what
// is desired, but it is less likely to lead to weird bugs with the same part
// appearing in multiple locations of the rocket
utils::Logger::getInstance()->debug("Calling model::Part copy constructor. Recursively copying all child parts. Check Part names for uniqueness");
for(const auto& i : orig.childParts)
{
Part& x = *std::get<0>(i);
std::shared_ptr<Part> tempPart = std::make_shared<Part>(x);
childParts.emplace_back(tempPart, std::get<1>(i));;
}
}
double Part::getChildMasses(double t)
{
double childMasses{0.0};
for(const auto& i : childParts)
{
childMasses += std::get<0>(i)->getMass(t);
}
return childMasses;
}
void Part::addChildPart(const Part& childPart, Vector3 position)
{
double childMass = childPart.compositeMass;
Matrix3 childInertiaTensor = childPart.compositeInertiaTensor;
std::shared_ptr<Part> newChild = std::make_shared<Part>(childPart);
// Set the parent pointer
newChild->parent = this;
// Recompute inertia tensor
childInertiaTensor += childMass * ( position.dot(position) * Matrix3::Identity() - position*position.transpose());
compositeInertiaTensor += childInertiaTensor;
compositeMass += childMass;
childParts.emplace_back(std::move(newChild), std::move(position));
if(parent)
{
parent->markAsNeedsRecomputing();
parent->recomputeInertiaTensor();
}
}
void Part::recomputeInertiaTensor()
{
if(!needsRecomputing)
{
return;
}
// recompute the whole composite inertia tensor
// Reset the composite inertia tensor
compositeInertiaTensor = inertiaTensor;
compositeMass = mass;
for(auto& [child, pos] : childParts)
{
child->recomputeInertiaTensor();
compositeInertiaTensor += child->compositeInertiaTensor + child->compositeMass * ( pos.dot(pos) * Matrix3::Identity() - pos*pos.transpose());
compositeMass += child->compositeMass;
}
needsRecomputing = false;
}
} // namespace model

136
model/Part.h Normal file
View File

@ -0,0 +1,136 @@
#ifndef MODEL_PART_H
#define MODEL_PART_H
/// \cond
// C headers
// C++ headers
#include <vector>
#include <memory>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "utils/math/MathTypes.h"
namespace model
{
class Part
{
public:
Part(const std::string& name,
const Matrix3& I,
double m,
const Vector3& centerMass);
virtual ~Part();
Part(const Part&);
Part& operator=(Part other)
{
if(this != &other)
{
std::swap(parent, other.parent);
std::swap(name, other.name);
std::swap(inertiaTensor, other.inertiaTensor);
std::swap(compositeInertiaTensor, other.compositeInertiaTensor);
std::swap(mass, other.mass);
std::swap(compositeMass, other.compositeMass);
std::swap(cm, other.cm);
std::swap(needsRecomputing, other.needsRecomputing);
std::swap(childParts, other.childParts);
}
return *this;
}
Part& operator=(Part&& other)
{
parent = std::move(other.parent);
name = std::move(other.name);
inertiaTensor = std::move(other.inertiaTensor);
compositeInertiaTensor = std::move(other.compositeInertiaTensor);
mass = std::move(other.mass);
compositeMass = std::move(other.compositeMass);
cm = std::move(other.cm);
needsRecomputing = std::move(other.needsRecomputing);
childParts = std::move(other.childParts);
return *this;
}
void setMass(double m) { mass = m; }
// Set the inertia tensor
void setI(const Matrix3& I) { inertiaTensor = I; }
Matrix3 getI() { return inertiaTensor; }
Matrix3 getCompositeI() { return compositeInertiaTensor; }
void setCm(const Vector3& x) { cm = x; }
// Special version of setCM that assumes the cm lies along the body x-axis
void setCm(double x) { cm = {x, 0.0, 0.0}; }
double getMass(double t)
{
return mass;
}
double getCompositeMass(double t)
{
return compositeMass;
}
/**
* @brief Add a child part to this part.
*
* @param childPart Child part to add
* @param position Relative position of the child part's center-of-mass w.r.t the
* parent's center of mass
*/
void addChildPart(const Part& childPart, Vector3 position);
/**
* @brief Recomputes the inertia tensor. If the change is due to the change in inertia
* of a child part, an optional name of the child part can be given to
* only recompute that change rather than recompute all child inertia
* tensors
*
* @param name Optional name of the child part to recompute. If empty, it will
* recompute all child inertia tensors
*/
//void recomputeInertiaTensor(std::string name = "");
void recomputeInertiaTensor();
private:
// This is a pointer to the parent Part, if it has one. Purpose is to be able to
// tell the parent if it needs to recompute anything if this part changes. e.g.
// if a change to this part's inertia tensor occurs, the parent needs to recompute
// it's total inertia tensor.
Part* parent{nullptr};
std::string name;
double getChildMasses(double t);
void markAsNeedsRecomputing()
{ needsRecomputing = true; if(parent) { parent->markAsNeedsRecomputing(); }}
// Because a part is both a simple part and the composite of itself with all of it's children,
// we will keep track of this object's inertia tensor (without children), and the composite
// one with all of it's children attached
Matrix3 inertiaTensor; // moment of inertia tensor with respect to the part's center of mass and
Matrix3 compositeInertiaTensor;
double mass; // The moment of inertia tensor also has this, so don't double compute
double compositeMass; // The mass of this part along with all attached parts
Vector3 cm; // center of mass wrt middle of component
bool needsRecomputing{false};
/// @brief child parts and the relative positions of their center of mass w.r.t.
/// the center of mass of this part
std::vector<std::tuple<std::shared_ptr<Part>, Vector3>> childParts;
};
}
#endif // MODEL_PART_H

0
model/Propagatable.cpp Normal file
View File

58
model/Propagatable.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef MODEL_PROPAGATABLE_H
#define MODEL_PROPAGATABLE_H
/// \cond
// C headers
// C++ headers
#include <utility>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "sim/Aero.h"
#include "sim/StateData.h"
#include "utils/math/MathTypes.h"
namespace model
{
class Propagatable
{
public:
Propagatable() {}
virtual ~Propagatable() {}
virtual Vector3 getForces(double t) = 0;
virtual Vector3 getTorques(double t) = 0;
virtual double getMass(double t) = 0;
virtual Matrix3 getInertiaTensor(double t) = 0;
virtual bool terminateCondition(double t) = 0;
void setCurrentState(const StateData& st) { currentState = st; }
const StateData& getCurrentState() { return currentState; }
const StateData& getInitialState() { return initialState; }
void setInitialState(const StateData& init) { initialState = init; }
void appendState(double t, const StateData& st) { states.emplace_back(t, st); }
const std::vector<std::pair<double, StateData>>& getStates() { return states; }
void clearStates() { states.clear(); }
protected:
sim::Aero aeroData;
StateData initialState;
StateData currentState;
StateData nextState;
std::vector<std::pair<double, StateData>> states;
};
}
#endif // MODEL_PROPAGATABLE_H

View File

@ -1,34 +0,0 @@
#include "Rocket.h"
#include "QtRocket.h"
Rocket::Rocket() : propagator(this)
{
}
void Rocket::launch()
{
propagator.clearStates();
propagator.setCurrentTime(0.0);
mm.startMotor(0.0);
propagator.runUntilTerminate();
}
void Rocket::setMotorModel(const model::MotorModel& motor)
{
mm = motor;
}
bool Rocket::terminateCondition(const std::pair<double, std::vector<double>>& cond)
{
// Terminate propagation when the z coordinate drops below zero
if(cond.second[2] < 0)
return true;
else
return false;
}
double Rocket::getThrust(double t)
{
return mm.getThrust(t);
}

View File

@ -1,119 +0,0 @@
#ifndef ROCKET_H
#define ROCKET_H
/// \cond
// C headers
// C++ headers
#include <memory>
#include <string>
#include <utility> // std::move
// 3rd party headers
/// \endcond
// qtrocket headers
#include "model/ThrustCurve.h"
#include "model/MotorModel.h"
#include "sim/Propagator.h"
/**
* @brief The Rocket class holds all rocket components
*
*/
class Rocket
{
public:
/**
* @brief Rocket class constructor
*/
Rocket();
/**
* @brief launch Propagates the Rocket object until termination,
* normally when altitude crosses from positive to negative
*/
void launch();
/**
* @brief getStates returns a vector of time/state pairs generated during launch()
* @return vector of pairs of doubles, where the first value is a time and the second a state vector
*/
const std::vector<std::pair<double, std::vector<double>>>& getStates() const { return propagator.getStates(); }
/**
* @brief setInitialState sets the initial state of the Rocket.
* @param initState initial state vector (x, y, z, xDot, yDot, zDot, pitch, yaw, roll, pitchDot, yawDot, rollDot)
*/
void setInitialState(const std::vector<double>& initState) { propagator.setInitialState(initState); }
/**
* @brief getMass returns the current mass of the rocket. This is the sum of all components' masses
* @return total current mass of the Rocket
*/
double getMass(double simTime) const { return mass + mm.getMass(simTime); }
/**
* @brief setMass sets the current total mass of the Rocket
* @param m total Rocket mass
* @todo This should be dynamically computed, not set. Fix this
*/
void setMass(double m) { mass = m;}
/**
* @brief setDragCoefficient sets the current total drag coefficient of the Rocket
* @param d drag coefficient
* @todo This should be dynamically computed, not set. Fix this
*/
void setDragCoefficient(double d) { dragCoeff = d; }
/**
* @brief getDragCoefficient returns the current drag coefficient
*
* This is intended to be called by the propagator during propagation.
* @return the coefficient of drag
*/
double getDragCoefficient() const { return dragCoeff; }
/**
* @brief getThrust returns current motor thrust
* @param t current simulation time
* @return thrust in Newtons
*/
double getThrust(double t);
/**
* @brief setMotorModel
* @param motor
*/
void setMotorModel(const model::MotorModel& motor);
/**
* @brief Returns the current motor model.
* @return The current motor model
*/
const model::MotorModel& getCurrentMotorModel() const { return mm; }
/**
* @brief terminateCondition returns true or false, whether the passed-in time/state matches the terminate condition
* @param cond time/state pair
* @return true if the passed-in time/state satisfies the terminate condition
*/
bool terminateCondition(const std::pair<double, std::vector<double>>& cond);
/**
* @brief setName sets the rocket name
* @param n name to set the Rocket
*/
void setName(const std::string& n) { name = n; }
private:
std::string name; /// Rocket name
sim::Propagator propagator; /// propagator
double dragCoeff; /// @todo get rid of this, should be dynamically calculated
double mass; /// @todo get rid of this, should be dynamically computed, but is the current rocket mass
model::MotorModel mm; /// Current Motor Model
};
#endif // ROCKET_H

79
model/RocketModel.cpp Normal file
View File

@ -0,0 +1,79 @@
// qtrocket headers
#include "RocketModel.h"
#include "QtRocket.h"
#include "InertiaTensors.h"
namespace model
{
RocketModel::RocketModel()
: topPart("NoseCone", InertiaTensors::SolidSphere(1.0), 1.0, {0.0, 0.0, 1.0})
{
}
double RocketModel::getMass(double t)
{
double mass = mm.getMass(t);
mass += topPart.getCompositeMass(t);
return mass;
}
Matrix3 RocketModel::getInertiaTensor(double)
{
return topPart.getCompositeI();
}
bool RocketModel::terminateCondition(double)
{
// Terminate propagation when the z coordinate drops below zero
if(currentState.position[2] < 0)
return true;
else
return false;
}
Vector3 RocketModel::getForces(double t)
{
// Get thrust
// Assume that thrust is always through the center of mass and in the rocket's Z-axis
Vector3 forces{0.0, 0.0, mm.getThrust(t)};
// Get gravity
auto gravityModel = QtRocket::getInstance()->getEnvironment()->getGravityModel();
Vector3 gravity = gravityModel->getAccel(currentState.position)*getMass(t);
forces += gravity;
// Calculate aero forces
return forces;
}
Vector3 RocketModel::getTorques(double t)
{
return Vector3{0.0, 0.0, 0.0};
}
double RocketModel::getThrust(double t)
{
return mm.getThrust(t);
}
void RocketModel::launch()
{
mm.startMotor(0.0);
}
void RocketModel::setMotorModel(const model::MotorModel& motor)
{
mm = motor;
}
} // namespace model

116
model/RocketModel.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef ROCKETMODEL_H
#define ROCKETMODEL_H
/// \cond
// C headers
// C++ headers
#include <vector>
#include <memory>
#include <string>
#include <utility> // std::move
// 3rd party headers
/// \endcond
// qtrocket headers
#include "model/Part.h"
#include "sim/Propagator.h"
#include "model/MotorModel.h"
#include "model/Propagatable.h"
// Not yet
//#include "model/Stage.h"
namespace model
{
/**
* @brief The Rocket class holds all rocket components
*
*/
class RocketModel : public Propagatable
{
public:
/**
* @brief Rocket class constructor
*/
RocketModel();
/**
* @brief Rocket class destructor
*
*/
virtual ~RocketModel() {}
/**
* @brief launch Propagates the Rocket object until termination,
* normally when altitude crosses from positive to negative
*/
void launch();
Vector3 getForces(double t) override;
Vector3 getTorques(double t) override;
/**
* @brief getMass returns current rocket mass
* @param t current simulation time
* @return mass in kg
*/
double getMass(double t) override;
/**
* @brief terminateCondition returns true or false, whether the passed-in time/state matches the terminate condition
* @param cond time/state pair
* @return true if the passed-in time/state satisfies the terminate condition
*/
bool terminateCondition(double t) override;
Matrix3 getInertiaTensor(double t) override;
/**
* @brief getThrust returns current motor thrust
* @param t current simulation time
* @return thrust in Newtons
*/
double getThrust(double t);
/**
* @brief setMotorModel
* @param motor
*/
void setMotorModel(const model::MotorModel& motor);
/**
* @brief getMotorModel
*/
MotorModel getMotorModel() { return mm; }
/**
* @brief Returns the current motor model.
* @return The current motor model
*/
//const model::MotorModel& getCurrentMotorModel() const { return mm; }
/**
* @brief setName sets the rocket name
* @param n name to set the Rocket
*/
void setName(const std::string& n) { name = n; }
double getDragCoefficient() { return 1.0; }
void setDragCoefficient(double d) { }
void setMass(double m) { }
private:
std::string name; /// Rocket name
model::MotorModel mm; /// Current Motor Model
model::Part topPart;
};
} // namespace model
#endif // ROCKETMODEL_H

View File

@ -8,8 +8,6 @@
/// \endcond
#include "model/ThrustCurve.h"
#include "utils/Logger.h"
ThrustCurve::ThrustCurve(std::vector<std::pair<double, double>>& tc)
: thrustCurve(tc),

View File

@ -0,0 +1,16 @@
add_executable(model_tests
PartTests.cpp
)
target_link_libraries(model_tests PRIVATE
model
utils
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(model_tests)
add_test(NAME qtrocket_model_tests COMMAND model_tests)

70
model/tests/PartTests.cpp Normal file
View File

@ -0,0 +1,70 @@
#include <gtest/gtest.h>
#include "model/Part.h"
class PartTest : public testing::Test
{
protected:
// Per-test-suite set-up.
// Called before the first test in this test suite.
// Can be omitted if not needed.
static void SetUpTestSuite()
{
//shared_resource_ = new ...;
// If `shared_resource_` is **not deleted** in `TearDownTestSuite()`,
// reallocation should be prevented because `SetUpTestSuite()` may be called
// in subclasses of FooTest and lead to memory leak.
//
// if (shared_resource_ == nullptr) {
// shared_resource_ = new ...;
// }
}
// Per-test-suite tear-down.
// Called after the last test in this test suite.
// Can be omitted if not needed.
static void TearDownTestSuite()
{
//delete shared_resource_;
//shared_resource_ = nullptr;
}
// You can define per-test set-up logic as usual.
void SetUp() override { }
// You can define per-test tear-down logic as usual.
void TearDown() override { }
// Some expensive resource shared by all tests.
//static T* shared_resource_;
};
//T* FooTest::shared_resource_ = nullptr;
TEST(PartTest, CreationTests)
{
Matrix3 inertia;
inertia << 1, 0, 0,
0, 1, 0,
0, 0, 1;
Vector3 cm{1, 0, 0};
model::Part testPart("testPart",
inertia,
1.0,
cm);
Matrix3 inertia2;
inertia2 << 1, 0, 0,
0, 1, 0,
0, 0, 1;
Vector3 cm2{1, 0, 0};
model::Part testPart2("testPart2",
inertia2,
1.0,
cm2);
Vector3 R{2.0, 2.0, 2.0};
testPart.addChildPart(testPart2, R);
}

0
sim/Aero.cpp Normal file
View File

40
sim/Aero.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef SIM_AERO_H
#define SIM_AERO_H
/// \cond
// C headers
// C++ headers
// 3rd party headers
/// \endcond
// qtrocket headers
#include "utils/math/MathTypes.h"
namespace sim
{
class Aero
{
public:
private:
Vector3 cp; /// center of pressure
double Cx; /// longitudinal coefficient
double Cy; /// These are probably the same for axial symmetric
double Cz; /// rockets. The coeffients in the y and z body directions
double Cl; // roll moment coefficient
double Cm; // pitch moment coefficient
double Cn; // yaw moment coefficient
double baseCd; // coefficient of drag due to base drag
double Cd; // total coeffient of drag
};
}
#endif // SIM_AERO_H

View File

@ -13,6 +13,10 @@ public:
virtual double getDensity(double altitude) = 0;
virtual double getPressure(double altitude) = 0;
virtual double getTemperature(double altitude) = 0;
virtual double getSpeedOfSound(double altitude) = 0;
virtual double getDynamicViscosity(double altitude) = 0;
};
} // namespace sim

28
sim/CMakeLists.txt Normal file
View File

@ -0,0 +1,28 @@
add_library(sim
Aero.cpp
Aero.h
AtmosphericModel.h
ConstantAtmosphere.h
ConstantGravityModel.h
DESolver.h
Environment.h
GeoidModel.h
GravityModel.h
Propagator.cpp
Propagator.h
RK4Solver.h
SphericalGeoidModel.cpp
SphericalGeoidModel.h
SphericalGravityModel.cpp
SphericalGravityModel.h
StateData.h
USStandardAtmosphere.cpp
USStandardAtmosphere.h
WindModel.cpp
WindModel.h)
target_link_libraries(sim PRIVATE
utils)
# Unit tests
add_subdirectory(tests)

View File

@ -15,6 +15,10 @@ public:
double getDensity(double) override { return 1.225; }
double getPressure(double) override { return 101325.0; }
double getTemperature(double) override { return 288.15; }
double getSpeedOfSound(double) override { return 340.294; }
double getDynamicViscosity(double) override { return 1.78938e-5; }
};
} // namespace sim

View File

@ -1,10 +0,0 @@
#include "ConstantGravityModel.h"
namespace sim {
ConstantGravityModel::ConstantGravityModel()
{
}
} // namespace sim

View File

@ -3,18 +3,21 @@
// qtrocket headers
#include "sim/GravityModel.h"
#include "utils/Triplet.h"
#include "utils/math/MathTypes.h"
namespace sim {
class ConstantGravityModel : public GravityModel
{
public:
ConstantGravityModel();
ConstantGravityModel() {}
virtual ~ConstantGravityModel() {}
virtual ~ConstantGravityModel() {}
TripletD getAccel(double, double, double) override { return TripletD(0.0, 0.0, -9.8); }
Vector3 getAccel(double, double, double) override
{
return Vector3(0.0, 0.0, -9.8);
}
};
} // namespace sim

View File

@ -4,14 +4,17 @@
/// \cond
// C headers
// C++ headers
#include <vector>
#include <utility>
// 3rd party headers
/// \endcond
// qtrocket headers
namespace sim
{
template<typename T>
class DESolver
{
public:
@ -19,7 +22,17 @@ public:
virtual ~DESolver() {}
virtual void setTimeStep(double ts) = 0;
virtual void step(double t, const std::vector<double>& curVal, std::vector<double>& res ) = 0;
/**
* @brief
*
* @param curVal
* @param res
* @param t Optional parameter, but not used in QtRocket. Some generic solvers take time as
* a parameter to ODEs, but QtRocket's kinematic equations don't. Since I wrote
* the RK4 solver independently as a general tool, this interface is needed
* here unfortunately.
*/
virtual std::pair<T, T> step(T& state, T& rate) = 0;
};
} // namespace sim

View File

@ -17,7 +17,6 @@
#include "sim/ConstantAtmosphere.h"
#include "sim/USStandardAtmosphere.h"
#include "sim/GeoidModel.h"
namespace sim
{

View File

@ -1,14 +0,0 @@
#include "GravityModel.h"
namespace sim
{
GravityModel::GravityModel()
{
}
GravityModel::~GravityModel()
{
}
} // namespace sim

View File

@ -2,7 +2,7 @@
#define SIM_GRAVITYMODEL_H
// qtrocket headers
#include "utils/Triplet.h"
#include "utils/math/MathTypes.h"
namespace sim
{
@ -10,11 +10,11 @@ namespace sim
class GravityModel
{
public:
GravityModel();
virtual ~GravityModel();
GravityModel() {}
virtual ~GravityModel() {}
virtual TripletD getAccel(double x, double y, double z) = 0;
TripletD getAccel(const TripletD& t) { return this->getAccel(t.x1, t.x2, t.x3); }
virtual Vector3 getAccel(double x, double y, double z) = 0;
Vector3 getAccel(const Vector3& t) { return this->getAccel(t.x(), t.y(), t.z()); }
};
} // namespace sim

View File

@ -2,7 +2,6 @@
/// \cond
// C headers
// C++ headers
#include <cmath>
#include <chrono>
#include <iostream>
#include <sstream>
@ -14,47 +13,36 @@
// qtrocket headers
#include "Propagator.h"
#include "QtRocket.h"
#include "model/Rocket.h"
#include "sim/RK4Solver.h"
#include "utils/Logger.h"
namespace sim {
Propagator::Propagator(Rocket* r)
: integrator(),
rocket(r)
namespace sim
{
Propagator::Propagator(std::shared_ptr<model::Propagatable> r)
: linearIntegrator(),
object(r),
saveStates(true),
timeStep(0.01)
{
// Linear velocity and acceleration
std::function<std::pair<Vector3, Vector3>(Vector3&, Vector3&)> linearODEs = [this](Vector3& state, Vector3& rate) -> std::pair<Vector3, Vector3>
{
Vector3 dPosition;
Vector3 dVelocity;
// dx/dt
dPosition = rate;
// This is a little strange, but I have to populate the integrator unique_ptr
// with reset. make_unique() doesn't work because the compiler can't seem to
// deduce the template parameters correctly, and I don't want to specify them
// manually either. RK4Solver constructor is perfectly capable of deducing it's
// template types, and it derives from DESolver, so we can just reset the unique_ptr
// and pass it a freshly allocated RK4Solver pointer
// dvx/dt
dVelocity = object->getForces(currentTime) / object->getMass(currentTime);
// The state vector has components of the form:
// (x, y, z, xdot, ydot, zdot, pitch, yaw, roll, pitchRate, yawRate, rollRate)
integrator.reset(new RK4Solver(
/* dx/dt */ [](double, const std::vector<double>& s) -> double {return s[3]; },
/* dy/dt */ [](double, const std::vector<double>& s) -> double {return s[4]; },
/* dz/dt */ [](double, const std::vector<double>& s) -> double {return s[5]; },
/* dvx/dt */ [this](double, const std::vector<double>& ) -> double { return getForceX() / getMass(); },
/* dvy/dt */ [this](double, const std::vector<double>& ) -> double { return getForceY() / getMass(); },
/* dvz/dt */ [this](double, const std::vector<double>& ) -> double { return getForceZ() / getMass(); },
/* dpitch/dt */ [](double, const std::vector<double>& s) -> double { return s[9]; },
/* dyaw/dt */ [](double, const std::vector<double>& s) -> double { return s[10]; },
/* droll/dt */ [](double, const std::vector<double>& s) -> double { return s[11]; },
/* dpitchRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueP() - s[7] * s[8] * (getIroll() - getIyaw())) / getIpitch(); },
/* dyawRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueQ() - s[6] * s[9] * (getIpitch() - getIroll())) / getIyaw(); },
/* drollRate/dt */ [this](double, const std::vector<double>& s) -> double { return (getTorqueR() - s[6] * s[7] * (getIyaw() - getIpitch())) / getIroll(); }));
return std::make_pair(dPosition, dVelocity);
};
linearIntegrator.reset(new RK4Solver<Vector3>(linearODEs));
linearIntegrator->setTimeStep(timeStep);
integrator->setTimeStep(timeStep);
saveStates = true;
saveStates = true;
}
Propagator::~Propagator()
@ -63,61 +51,41 @@ Propagator::~Propagator()
void Propagator::runUntilTerminate()
{
std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point endTime;
std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point endTime;
while(true)
{
// tempRes gets overwritten
integrator->step(currentTime, currentState, tempRes);
Vector3 currentPosition;
Vector3 currentVelocity;
Vector3 nextPosition;
Vector3 nextVelocity;
while(true)
{
currentPosition = object->getCurrentState().position;
currentVelocity = object->getCurrentState().velocity;
std::swap(currentState, tempRes);
if(saveStates)
{
states.push_back(std::make_pair(currentTime, currentState));
}
if(rocket->terminateCondition(std::make_pair(currentTime, currentState)))
break;
std::tie(nextPosition, nextVelocity) = linearIntegrator->step(currentPosition, currentVelocity);
currentTime += timeStep;
}
endTime = std::chrono::steady_clock::now();
StateData nextState;
nextState.position = nextPosition;
nextState.velocity = nextVelocity;
object->setCurrentState(nextState);
std::stringstream duration;
duration << "runUntilTerminate time (microseconds): ";
duration << std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count();
utils::Logger::getInstance()->debug(duration.str());
if(saveStates)
{
object->appendState(currentTime, nextState);
}
if(object->terminateCondition(currentTime))
break;
currentTime += timeStep;
}
endTime = std::chrono::steady_clock::now();
std::stringstream duration;
duration << "runUntilTerminate time (microseconds): ";
duration << std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count();
utils::Logger::getInstance()->debug(duration.str());
}
double Propagator::getMass()
{
return rocket->getMass(currentTime);
}
double Propagator::getForceX()
{
QtRocket* qtrocket = QtRocket::getInstance();
return (currentState[3] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState[2])/ 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState[3]* currentState[3];
}
double Propagator::getForceY()
{
QtRocket* qtrocket = QtRocket::getInstance();
return (currentState[4] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState[2]) / 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState[4]* currentState[4];
}
double Propagator::getForceZ()
{
QtRocket* qtrocket = QtRocket::getInstance();
double gravity = (qtrocket->getEnvironment()->getGravityModel()->getAccel(currentState[0], currentState[1], currentState[2])).x3;
double airDrag = (currentState[5] >= 0 ? -1.0 : 1.0) * qtrocket->getEnvironment()->getAtmosphericModel()->getDensity(currentState[2]) / 2.0 * 0.008107 * rocket->getDragCoefficient() * currentState[5]* currentState[5];
double thrust = rocket->getThrust(currentTime);
return gravity + airDrag + thrust;
}
double Propagator::getTorqueP() { return 0.0; }
double Propagator::getTorqueQ() { return 0.0; }
double Propagator::getTorqueR() { return 0.0; }
} // namespace sim

View File

@ -5,17 +5,22 @@
// C headers
// C++ headers
#include <memory>
#include <vector>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "sim/DESolver.h"
#include "sim/RK4Solver.h"
#include "utils/math/MathTypes.h"
#include "sim/StateData.h"
#include "model/Propagatable.h"
// Forward declare
namespace model
{
class Rocket;
}
class QtRocket;
namespace sim
@ -24,22 +29,17 @@ namespace sim
class Propagator
{
public:
Propagator(Rocket* r);
Propagator(std::shared_ptr<model::Propagatable> o);
~Propagator();
void setInitialState(const std::vector<double>& initialState)
void setInitialState(const StateData& initialState)
{
currentState.resize(initialState.size());
for(std::size_t i = 0; i < initialState.size(); ++i)
{
currentState[i] = initialState[i];
}
object->setInitialState(initialState);
}
const std::vector<double>& getCurrentState() const
const StateData& getCurrentState() const
{
return currentState;
return object->getCurrentState();
}
void runUntilTerminate();
@ -49,41 +49,21 @@ public:
saveStates = s;
}
const std::vector<std::pair<double, std::vector<double>>>& getStates() const { return states; }
void clearStates() { states.clear(); }
void setCurrentTime(double t) { currentTime = t; }
void setTimeStep(double ts) { timeStep = ts; }
void setSaveStats(bool s) { saveStates = s; }
private:
double getMass();
double getForceX();
double getForceY();
double getForceZ();
double getTorqueP();
double getTorqueQ();
double getTorqueR();
std::unique_ptr<sim::RK4Solver<Vector3>> linearIntegrator;
// std::unique_ptr<sim::RK4Solver<Quaternion>> orientationIntegrator;
double getIpitch() { return 1.0; }
double getIyaw() { return 1.0; }
double getIroll() { return 1.0; }
std::shared_ptr<model::Propagatable> object;
//private:
std::unique_ptr<sim::DESolver> integrator;
Rocket* rocket;
std::vector<double> currentState{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
std::vector<double> tempRes{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
bool saveStates{true};
double currentTime{0.0};
double timeStep{0.01};
std::vector<std::pair<double, std::vector<double>>> states;
};
} // namespace sim

View File

@ -4,10 +4,8 @@
/// \cond
// C headers
// C++ headers
#include <cmath>
#include <functional>
#include <limits>
#include <vector>
// 3rd party headers
@ -16,84 +14,80 @@
// qtrocket headers
#include "sim/DESolver.h"
#include "utils/Logger.h"
#include "utils/math/MathTypes.h"
namespace sim {
template<typename... Ts>
class RK4Solver : public DESolver
/**
* @brief Runge-Kutta 4th order coupled ODE solver.
* @note This was written outside of the context of QtRocket, and it is very generic. There are
* some features of this solver that are note used by QtRocket, for example, it can solve
* and arbitrarily large system of coupled ODEs, but QtRocket only makes use of a system
* of size 6 (x, y, z, xDot, yDot, zDot) at a time.
*
* @tparam Ts
*/
template<typename T>
class RK4Solver : public DESolver<T>
{
public:
RK4Solver(Ts... funcs)
RK4Solver(std::function<std::pair<T, T>(T&, T&)> func)
{
(odes.push_back(funcs), ...);
temp.resize(sizeof...(Ts));
// This only works for Eigen Vector types.
// TODO: Figure out how to make this slightly more generic, but for now
// we're only using this for Vector3 and Quaternion types
static_assert(std::is_same<T, Vector3>::value
|| std::is_same<T, Quaternion>::value,
"You can only use Vector3 or Quaternion valued functions in RK4Solver");
odes = func;
}
virtual ~RK4Solver() {}
void setTimeStep(double inTs) override { dt = inTs; halfDT = dt / 2.0; }
void step(double t, const std::vector<double>& curVal, std::vector<double>& res) override
std::pair<T, T> step(T& state, T& rate) override
{
std::pair<T, T> res;
if(dt == std::numeric_limits<double>::quiet_NaN())
{
utils::Logger::getInstance()->error("Calling RK4Solver without setting dt first is an error");
res[0] = std::numeric_limits<double>::quiet_NaN();
return res;
}
for(size_t i = 0; i < len; ++i)
{
k1[i] = odes[i](t, curVal);
}
std::tie(k1State, k1Rate) = odes(state, rate);
// compute k2 values. This involves stepping the current values forward a half-step
// based on k1, so we do the stepping first
for(size_t i = 0; i < len; ++i)
{
temp[i] = curVal[i] + k1[i]*dt / 2.0;
}
for(size_t i = 0; i < len; ++i)
{
k2[i] = odes[i](t + halfDT, temp);
}
// repeat for k3
for(size_t i = 0; i < len; ++i)
{
temp[i] = curVal[i] + k2[i]*dt / 2.0;
}
for(size_t i = 0; i < len; ++i)
{
k3[i] = odes[i](t + halfDT, temp);
}
std::tie(tempState, tempRate) = std::make_pair(state + k1State*halfDT, rate + k1Rate*halfDT);
std::tie(k2State, k2Rate) = odes(tempState, tempRate);
// now k4
for(size_t i = 0; i < len; ++i)
{
temp[i] = curVal[i] + k3[i]*dt;
}
for(size_t i = 0; i < len; ++i)
{
k4[i] = odes[i](t + dt, temp);
}
std::tie(tempState, tempRate) = std::make_pair(state + k2State*halfDT, rate + k2Rate*halfDT);
std::tie(k3State, k3Rate) = odes(tempState, tempRate);
// now compute the result
for(size_t i = 0; i < len; ++i)
{
res[i] = curVal[i] + (dt / 6.0)*(k1[i] + 2.0*k2[i] + 2.0*k3[i] + k4[i]);
}
std::tie(tempState, tempRate) = std::make_pair(state + k3State*dt, rate + k3Rate*dt);
std::tie(k4State, k4Rate) = odes(tempState, tempRate);
res = std::make_pair(state + (dt / 6.0)*(k1State + 2.0*k2State + 2.0*k3State + k4State),
rate + (dt / 6.0)*(k1Rate + 2.0*k2Rate + 2.0*k3Rate + k4Rate));
return res;
}
private:
std::vector<std::function<double(double, const std::vector<double>&)>> odes;
std::function<std::pair<T, T>(T&, T&)> odes;
static constexpr size_t len = sizeof...(Ts);
double k1[len];
double k2[len];
double k3[len];
double k4[len];
T k1State;
T k2State;
T k3State;
T k4State;
T k1Rate;
T k2Rate;
T k3Rate;
T k4Rate;
std::vector<double> temp;
T tempState;
T tempRate;
double dt = std::numeric_limits<double>::quiet_NaN();
double halfDT = 0.0;

View File

@ -25,7 +25,7 @@ SphericalGravityModel::~SphericalGravityModel()
}
TripletD SphericalGravityModel::getAccel(double x, double y, double z)
Vector3 SphericalGravityModel::getAccel(double x, double y, double z)
{
// Convert x, y, z from meters to km. This is to avoid potential precision losses
// with using the earth's gravitation parameter in meters (14 digit number).
@ -43,7 +43,7 @@ TripletD SphericalGravityModel::getAccel(double x, double y, double z)
double ay = accelFactor * y_km * 1000.0;
double az = accelFactor * z_km * 1000.0;
return TripletD(ax, ay, az);
return Vector3(ax, ay, az);
}

View File

@ -2,7 +2,7 @@
#define SIM_SPHERICALGRAVITYMODEL_H
// qtrocket headers
#include "GravityModel.h"
#include "sim/GravityModel.h"
namespace sim
{
@ -13,7 +13,7 @@ public:
SphericalGravityModel();
virtual ~SphericalGravityModel();
TripletD getAccel(double x, double y, double z) override;
Vector3 getAccel(double x, double y, double z) override;
};
} // namespace sim

View File

@ -1,6 +0,0 @@
#include "StateData.h"
StateData::StateData()
{
}

View File

@ -1,9 +1,15 @@
#ifndef STATEDATA_H
#define STATEDATA_H
/// \cond
// C headers
// C++ headers
#include <vector>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "utils/math/Vector3.h"
#include "utils/math/Quaternion.h"
#include "utils/math/MathTypes.h"
/**
* @brief The StateData class holds physical state data. Things such as position, velocity,
@ -13,20 +19,76 @@
class StateData
{
public:
StateData();
StateData() {}
~StateData() {}
StateData(const StateData&) = default;
StateData(StateData&&) = default;
StateData& operator=(const StateData& rhs)
{
if(this != &rhs)
{
position = rhs.position;
velocity = rhs.velocity;
orientation = rhs.orientation;
orientationRate = rhs.orientationRate;
dcm = rhs.dcm;
eulerAngles = rhs.eulerAngles;
}
return *this;
}
StateData& operator=(StateData&& rhs)
{
if(this != &rhs)
{
position = std::move(rhs.position);
velocity = std::move(rhs.velocity);
orientation = std::move(rhs.orientation);
orientationRate = std::move(rhs.orientationRate);
dcm = std::move(rhs.dcm);
eulerAngles = std::move(rhs.eulerAngles);
}
return *this;
}
std::vector<double> getPosStdVector() const
{
return std::vector<double>{position[0], position[1], position[2]};
}
std::vector<double> getVelStdVector() const
{
return std::vector<double>{velocity[0], velocity[1], velocity[2]};
}
private:
math::Vector3 position{0.0, 0.0, 0.0};
math::Vector3 velocity{0.0, 0.0, 0.0};
/// TODO: Put these behind an interface
//Vector3 getPosition() const
//{
// return position;
//}
math::Quaternion orientation{0.0, 0.0, 0.0, 0.0}; // roll, pitch, yaw
math::Quaternion orientationRate{0.0, 0.0, 0.0, 0.0}; // roll-rate, pitch-rate, yaw-rate
// Necessary?
//math::Vector3 orientationAccel;
//Vector3 getVelocity() const
//{
// return velocity;
//}
// private:
// This is an array because the integrator expects it
double data[6];
// Intended to be used as world state data
Vector3 position{0.0, 0.0, 0.0};
Vector3 velocity{0.0, 0.0, 0.0};
// Orientation of body coordinates w.r.t. world coordinates
Quaternion orientation{0.0, 0.0, 0.0, 0.0}; /// (vector, scalar)
Quaternion orientationRate{0.0, 0.0, 0.0, 0.0}; /// (vector, scalar)
Matrix3 dcm{{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
/// Euler angles are yaw-pitch-roll, and (3-2-1) order
/// yaw - psi
/// pitch - theta
/// roll - phi
Vector3 eulerAngles{0.0, 0.0, 0.0};
};

View File

@ -10,6 +10,7 @@
// qtrocket headers
#include "sim/USStandardAtmosphere.h"
#include "utils/math/Constants.h"
#include "utils/math/UtilityMathFunctions.h"
using namespace utils::math;
@ -17,9 +18,9 @@ namespace sim
{
// Populate static data
utils::BinMap initTemps()
utils::Bin initTemps()
{
utils::BinMap map;
utils::Bin map;
map.insert(std::make_pair(0.0, 288.15));
map.insert(std::make_pair(11000.0, 216.65));
map.insert(std::make_pair(20000.0, 216.65));
@ -32,9 +33,9 @@ utils::BinMap initTemps()
}
utils::BinMap initLapseRates()
utils::Bin initLapseRates()
{
utils::BinMap map;
utils::Bin map;
map.insert(std::make_pair(0.0, 0.0065));
map.insert(std::make_pair(11000.0, 0.0));
map.insert(std::make_pair(20000.0, -0.001));
@ -46,9 +47,9 @@ utils::BinMap initLapseRates()
return map;
}
utils::BinMap initDensities()
utils::Bin initDensities()
{
utils::BinMap map;
utils::Bin map;
map.insert(std::make_pair(0.0, 1.225));
map.insert(std::make_pair(11000.0, 0.36391));
map.insert(std::make_pair(20000.0, 0.08803));
@ -60,11 +61,24 @@ utils::BinMap initDensities()
return map;
}
utils::BinMap USStandardAtmosphere::temperatureLapseRate(initLapseRates());
utils::BinMap USStandardAtmosphere::standardTemperature(initTemps());
utils::BinMap USStandardAtmosphere::standardDensity(initDensities());
utils::Bin initPressures()
{
utils::Bin map;
map.insert(std::make_pair(0.0, 101325));
map.insert(std::make_pair(11000.0, 22632.1));
map.insert(std::make_pair(20000.0, 5474.89));
map.insert(std::make_pair(32000.0, 868.02));
map.insert(std::make_pair(47000.0, 110.91));
map.insert(std::make_pair(51000.0, 66.94));
map.insert(std::make_pair(71000.0, 3.96));
return map;
}
utils::Bin USStandardAtmosphere::temperatureLapseRate(initLapseRates());
utils::Bin USStandardAtmosphere::standardTemperature(initTemps());
utils::Bin USStandardAtmosphere::standardDensity(initDensities());
utils::Bin USStandardAtmosphere::standardPressure(initPressures());
USStandardAtmosphere::USStandardAtmosphere()
{
@ -78,31 +92,64 @@ USStandardAtmosphere::~USStandardAtmosphere()
double USStandardAtmosphere::getDensity(double altitude)
{
if(temperatureLapseRate[altitude] == 0.0)
if(utils::math::floatingPointEqual(temperatureLapseRate[altitude], 0.0))
{
return standardDensity[altitude] * std::exp((-Constants::g0 * Constants::airMolarMass * (altitude - standardDensity.getBinBase(altitude)))
return standardDensity[altitude] * std::exp(
(-Constants::g0 * Constants::airMolarMass * (altitude - standardDensity.getBinBase(altitude)))
/ (Constants::Rstar * standardTemperature[altitude]));
}
else
{
double base = standardTemperature[altitude] /
(standardTemperature[altitude] + temperatureLapseRate[altitude] * (altitude - standardDensity.getBinBase(altitude)));
double base = (standardTemperature[altitude] - temperatureLapseRate[altitude] *
(altitude - standardDensity.getBinBase(altitude))) / standardTemperature[altitude];
double exponent = 1 + (Constants::g0 * Constants::airMolarMass) /
(Constants::Rstar * temperatureLapseRate[altitude]);
double exponent = (Constants::g0 * Constants::airMolarMass) /
(Constants::Rstar * temperatureLapseRate[altitude]) - 1.0;
return standardDensity[altitude] * std::pow(base, exponent);
}
}
double USStandardAtmosphere::getTemperature(double /*altitude*/)
double USStandardAtmosphere::getTemperature(double altitude)
{
return 0.0;
double baseTemp = standardTemperature[altitude];
double baseAltitude = standardTemperature.getBinBase(altitude);
return baseTemp - (altitude - baseAltitude) * temperatureLapseRate[altitude];
}
double USStandardAtmosphere::getPressure(double /* altitude */)
double USStandardAtmosphere::getPressure(double altitude)
{
return 0.0;
if(utils::math::floatingPointEqual(temperatureLapseRate[altitude], 0.0))
{
return standardPressure[altitude] * std::exp(
(-Constants::g0 * Constants::airMolarMass * (altitude - standardPressure.getBinBase(altitude)))
/ (Constants::Rstar * standardTemperature[altitude]));
}
else
{
double base = (standardTemperature[altitude] - temperatureLapseRate[altitude] *
(altitude - standardPressure.getBinBase(altitude))) / standardTemperature[altitude];
double exponent = (Constants::g0 * Constants::airMolarMass) /
(Constants::Rstar * temperatureLapseRate[altitude]);
return standardPressure[altitude] * std::pow(base, exponent);
}
}
double USStandardAtmosphere::getSpeedOfSound(double altitude)
{
return std::sqrt( (Constants::gamma * Constants::Rstar * getTemperature(altitude))
/
Constants::airMolarMass);
}
double USStandardAtmosphere::getDynamicViscosity(double altitude)
{
double temperature = getTemperature(altitude);
return (Constants::beta * std::pow(temperature, 1.5)) / ( temperature + Constants::S);
}
} // namespace sim

View File

@ -3,7 +3,7 @@
// qtrocket headers
#include "sim/AtmosphericModel.h"
#include "utils/BinMap.h"
#include "utils/Bin.h"
namespace sim
{
@ -28,10 +28,15 @@ public:
double getPressure(double altitude) override;
double getTemperature(double altitude) override;
double getSpeedOfSound(double altitude) override;
double getDynamicViscosity(double altitude) override;
private:
static utils::BinMap temperatureLapseRate;
static utils::BinMap standardTemperature;
static utils::BinMap standardDensity;
static utils::Bin temperatureLapseRate;
static utils::Bin standardTemperature;
static utils::Bin standardDensity;
static utils::Bin standardPressure;
};

View File

@ -13,9 +13,9 @@ WindModel::~WindModel()
{
}
TripletD WindModel::getWindSpeed(double /* x */, double /* y */ , double /* z */)
Vector3 WindModel::getWindSpeed(double /* x */, double /* y */ , double /* z */)
{
return TripletD(0.0, 0.0, 0.0);
return Vector3(0.0, 0.0, 0.0);
}
} // namespace sim

View File

@ -2,7 +2,7 @@
#define SIM_WINDMODEL_H
// qtrocket headers
#include "utils/Triplet.h"
#include "utils/math/MathTypes.h"
namespace sim
{
@ -13,7 +13,7 @@ public:
WindModel();
virtual ~WindModel();
virtual TripletD getWindSpeed(double x, double y, double z);
virtual Vector3 getWindSpeed(double x, double y, double z);
};

15
sim/tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,15 @@
add_executable(sim_tests
USStandardAtmosphereTests.cpp
)
target_link_libraries(sim_tests
sim
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(sim_tests)
add_test(NAME qtrocket_sim_tests COMMAND sim_tests)

View File

@ -0,0 +1,90 @@
#include <gtest/gtest.h>
#include "sim/USStandardAtmosphere.h"
TEST(USStandardAtmosphereTests, DensityTests)
{
sim::USStandardAtmosphere atmosphere;
// Test that the calucated values are with 0.1% of the published values in the NOAA report
EXPECT_NEAR(atmosphere.getDensity(0.0) / 1.225, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(1000.0) / 1.112, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(2000.0) / 1.007, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(3000.0) / 0.9093, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(4000.0) / 0.8194, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(5000.0) / 0.7364, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(6000.0) / 0.6601, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(7000.0) / 0.5900, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(15000.0) / 0.19367, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(20000.0) / 0.088035, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(25000.0) / 0.039466, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(30000.0) / 0.018012, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getDensity(40000.0) / 0.0038510, 1.0, 0.001);
// These are generally accurate to ~0.5%. Slight deviation of calculated
// density from the given density in the report table
EXPECT_NEAR(atmosphere.getDensity(8000.0) / 0.52579, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(9000.0) / 0.46706, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(10000.0) / 0.41351, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(50000.0) / 0.00097752, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(60000.0) / 0.00028832, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(70000.0) / 0.000074243, 1.0, 0.005);
EXPECT_NEAR(atmosphere.getDensity(80000.0) / 0.000015701, 1.0, 0.005);
}
TEST(USStandardAtmosphereTests, PressureTests)
{
sim::USStandardAtmosphere atmosphere;
// Test that the calucated values are with 0.1% of the published values in the NOAA report
EXPECT_NEAR(atmosphere.getPressure(0.0) / 101325.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(1000.0) / 89876.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(2000.0) / 79501.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(3000.0) / 70108.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(4000.0) / 61640.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(5000.0) / 54019.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(6000.0) / 47181.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(7000.0) / 41060.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(8000.0) / 35599.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(9000.0) / 30742.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(10000.0) / 26436.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(15000.0) / 12044.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(20000.0) / 5474.8, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(25000.0) / 2511.0, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(30000.0) / 1171.8, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(40000.0) / 277.52, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(50000.0) / 75.944, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(60000.0) / 20.314, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(70000.0) / 4.6342, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getPressure(80000.0) / 0.88627, 1.0, 0.001);
}
TEST(USStandardAtmosphereTests, TemperatureTests)
{
sim::USStandardAtmosphere atmosphere;
// Test that the calucated values are with 0.1% of the published values in the NOAA report
EXPECT_NEAR(atmosphere.getTemperature(0.0) / 288.15, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(1000.0) / 281.651, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(2000.0) / 275.154, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(3000.0) / 268.659, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(4000.0) / 262.166, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(5000.0) / 255.676, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(6000.0) / 249.187, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(7000.0) / 242.7, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(8000.0) / 236.215, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(9000.0) / 229.733, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(10000.0) / 223.252, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(15000.0) / 216.65, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(20000.0) / 216.65, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(25000.0) / 221.552, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(30000.0) / 226.509, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(40000.0) / 251.05, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(50000.0) / 270.65, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(60000.0) / 245.45, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(70000.0) / 217.450, 1.0, 0.001);
EXPECT_NEAR(atmosphere.getTemperature(80000.0) / 196.650, 1.0, 0.001);
}

View File

@ -3,15 +3,14 @@
// C headers
// C++ headers
#include <algorithm>
#include <sstream>
#include <format>
#include <stdexcept>
// 3rd party headers
#include <fmt/core.h>
/// \endcond
// qtrocket headers
#include "BinMap.h"
#include "Bin.h"
// TODO: Check on the availability of this in Clang.
// Replace libfmt with format when LLVM libc++ supports it
@ -20,33 +19,33 @@
namespace utils
{
BinMap::BinMap()
Bin::Bin()
: bins()
{
}
BinMap::BinMap(BinMap&& o)
Bin::Bin(Bin&& o)
: bins(std::move(o.bins))
{
}
BinMap::~BinMap()
Bin::~Bin()
{
}
// TODO: Very low priority, but if anyone wants to make this more efficient it could be
// interesting
void BinMap::insert(const std::pair<double, double>& toInsert)
void Bin::insert(const std::pair<double, double>& toInsert)
{
bins.push_back(toInsert);
std::sort(bins.begin(), bins.end(),
[](const auto& a, const auto& b){ return a.first < b.first; });
}
double BinMap::operator[](double key)
double Bin::operator[](double key)
{
auto iter = bins.begin();
// If the key is less than the lowest bin value, then it is out of range
@ -56,12 +55,12 @@ double BinMap::operator[](double key)
if(key < iter->first)
{
throw std::out_of_range(
fmt::format("{} less than lower bound {} of BinMap", key, iter->first));
std::format("{} less than lower bound {} of BinMap", key, iter->first));
}
// Increment it and start searching If we reach the end without finding an existing key
// greater than our search term, then we've just hit the last bin and return that
iter++;
double retVal = bins.end()->second;
double retVal = bins.back().second;
while(iter != bins.end())
{
if(key < iter->first)
@ -74,7 +73,7 @@ double BinMap::operator[](double key)
return retVal;
}
double BinMap::getBinBase(double key)
double Bin::getBinBase(double key)
{
auto iter = bins.begin();
// If the key is less than the lowest bin value, then it is out of range
@ -84,7 +83,7 @@ double BinMap::getBinBase(double key)
if(key < iter->first)
{
throw std::out_of_range(
fmt::format("{} less than lower bound {} of BinMap", key, iter->first));
std::format("{} less than lower bound {} of BinMap", key, iter->first));
}
// Increment it and start searching If we reach the end without finding an existing key
// greater than our search term, then we've just hit the last bin and return that

View File

@ -1,5 +1,5 @@
#ifndef UTILS_BINMAP_H
#define UTILS_BINMAP_H
#ifndef UTILS_BIN_H
#define UTILS_BIN_H
/// \cond
// C headers
@ -22,12 +22,12 @@ namespace utils {
* @todo Make this class behave more like a proper STL container. Templetize it for one
*
*/
class BinMap
class Bin
{
public:
BinMap();
BinMap(BinMap&& o);
~BinMap();
Bin();
Bin(Bin&& o);
~Bin();
void insert(const std::pair<double, double>& toInsert);
double operator[](double key);
@ -40,4 +40,4 @@ private:
} // namespace utils
#endif // UTILS_BINMAP_H
#endif // UTILS_BIN_H

30
utils/CMakeLists.txt Normal file
View File

@ -0,0 +1,30 @@
add_library(utils
Bin.cpp
Bin.h
CurlConnection.cpp
CurlConnection.h
Logger.cpp
Logger.h
MotorModelDatabase.cpp
MotorModelDatabase.h
RSEDatabaseLoader.cpp
RSEDatabaseLoader.h
ThreadPool.cpp
ThreadPool.h
ThrustCurveAPI.cpp
ThrustCurveAPI.h
TSQueue.h
math/Constants.h
math/MathTypes.h
math/UtilityMathFunctions.h)
#target_include_directories(utils PRIVATE
# ${Boost_INCLUDE_DIRS})
target_link_libraries(utils PUBLIC
libcurl
Boost::property_tree
jsoncpp_static
eigen)

View File

@ -40,6 +40,13 @@ void Logger::log(std::string_view msg, const LogLevel& lvl)
// all levels at or lower than the current level.
switch(currentLevel)
{
case PERF_:
if(lvl == PERF_)
{
outFile << "[PERF] " << msg << std::endl;
std::cout << "[PERF] " << msg << "\n";
}
[[fallthrough]];
case DEBUG_:
if(lvl == DEBUG_)
{

View File

@ -25,7 +25,8 @@ public:
ERROR_,
WARN_,
INFO_,
DEBUG_
DEBUG_,
PERF_
};
static Logger* getInstance();
@ -38,16 +39,11 @@ public:
void setLogLevel(const LogLevel& lvl);
/*
std::function<void(std::string_view)> error;
std::function<void(std::string_view)> warn;
std::function<void(std::string_view)> info;
std::function<void(std::string_view)> debug;
*/
inline void error(std::string_view msg) { log(msg, ERROR_); }
inline void warn(std::string_view msg) { log(msg, WARN_); }
inline void info(std::string_view msg) { log(msg, INFO_); }
inline void debug(std::string_view msg) { log(msg, DEBUG_); }
inline void perf(std::string_view msg) { log(msg, PERF_); }
void log(std::ostream& o, const std::string& msg);

View File

@ -68,20 +68,6 @@ std::optional<model::MotorModel> MotorModelDatabase::getMotorModel(const std::st
void MotorModelDatabase::saveMotorDatabase(const std::string& filename)
{
/*
<MotorDatabase>
<version>1.0</version>
<MotorModels>
<model name="XYZ">
<totalWeight>10.0</totalWeight>
<totalImpulse>123.4</totalImpulse>
</model>
</MotorModels>
</MotorDatabase>
*/
namespace pt = boost::property_tree;
// top-level tree
@ -112,6 +98,15 @@ void MotorModelDatabase::saveMotorDatabase(const std::string& filename)
motor.put("type", m.data.type.str());
motor.put("lastUpdated", m.data.lastUpdated);
// delays tag is in the form of a csv string
std::stringstream delays;
for (std::size_t i = 0; i < m.data.delays.size() - 1; ++i)
{
delays << std::to_string(m.data.delays[i]) << ",";
}
delays << std::to_string(m.data.delays[m.data.delays.size() - 1]);
motor.put("delays", delays.str());
// thrust data
{
pt::ptree tc;

View File

@ -74,4 +74,4 @@ private:
} // namespace utils
#endif // UTILS_MOTORMODELDATABASE_H
#endif // UTILS_MOTORMODELDATABASE_H

View File

@ -5,6 +5,7 @@
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
// 3rd party headers
#include <boost/property_tree/xml_parser.hpp>
@ -58,6 +59,16 @@ void RSEDatabaseLoader::buildAndAppendMotorModel(boost::property_tree::ptree& v)
mm.commonName = v.get<std::string>("<xmlattr>.code", "");
// mm.delays = extract vector from csv list
std::string delays = v.get<std::string>("<xmlattr>.delays", "1000");
std::size_t pos{0};
std::string tok;
while ((pos = delays.find(",")) != std::string::npos)
{
tok = delays.substr(0, pos);
mm.delays.push_back(std::atoi(tok.c_str()));
delays.erase(0, pos + 1);
}
mm.delays.push_back(std::atoi(delays.c_str()));
// mm.designation = What is this?

View File

@ -4,6 +4,7 @@
// C++ headers
// 3rd party headers
#include <json/json.h>
#include <optional>
/// \endcond
// qtrocket headers
@ -25,6 +26,58 @@ ThrustCurveAPI::~ThrustCurveAPI()
}
std::optional<ThrustCurve> ThrustCurveAPI::getThrustCurve(const std::string& id)
{
std::stringstream endpoint;
endpoint << hostname << "api/v1/download.json?motorId=" << id << "&data=samples";
std::vector<std::string> extraHeaders = {};
std::string res = curlConnection.get(endpoint.str(), extraHeaders);
model::MotorModel mm;
if(!res.empty())
{
try
{
Json::Reader reader;
Json::Value jsonResult;
reader.parse(res, jsonResult);
std::vector<std::pair<double, double>> samples;
for(Json::ValueConstIterator iter = jsonResult["results"].begin();
iter != jsonResult["results"].end();
++iter)
{
// if there are more than 1 items in the results list, we only want the RASP data
// Otherwise just take whatever is there
if(std::next(iter) != jsonResult["results"].end())
{
if( (*iter)["format"].asString() != "RASP")
continue;
}
for(Json::ValueConstIterator samplesIter = (*iter)["samples"].begin();
samplesIter != (*iter)["samples"].end();
++samplesIter)
{
samples.push_back(std::make_pair((*samplesIter)["time"].asDouble(),
(*samplesIter)["thrust"].asDouble()));
}
}
return ThrustCurve(samples);
}
catch(const std::exception& e)
{
std::string err("Unable to parse JSON from Thrustcurve motor data request. Error: ");
err += e.what();
Logger::getInstance()->error(err);
}
}
return std::nullopt;
}
model::MotorModel ThrustCurveAPI::getMotorData(const std::string& motorId)
{
@ -182,7 +235,9 @@ std::vector<model::MotorModel> ThrustCurveAPI::searchMotors(const SearchCriteria
{
Json::Reader reader;
Json::Value jsonResult;
Logger::getInstance()->debug("1");
reader.parse(result, jsonResult);
Logger::getInstance()->debug("2");
for(Json::ValueConstIterator iter = jsonResult["results"].begin();
iter != jsonResult["results"].end();
@ -191,6 +246,7 @@ std::vector<model::MotorModel> ThrustCurveAPI::searchMotors(const SearchCriteria
model::MotorModel motorModel;
model::MotorModel::MetaData mm;
mm.commonName = (*iter)["commonName"].asString();
Logger::getInstance()->debug("3");
std::string availability = (*iter)["availability"].asString();
if(availability == "regular")
@ -200,6 +256,7 @@ std::vector<model::MotorModel> ThrustCurveAPI::searchMotors(const SearchCriteria
mm.avgThrust = (*iter)["avgThrustN"].asDouble();
mm.burnTime = (*iter)["burnTimeS"].asDouble();
Logger::getInstance()->debug("4");
// TODO fill in certOrg
// TODO fill in delays
mm.designation = (*iter)["designation"].asString();
@ -226,7 +283,14 @@ std::vector<model::MotorModel> ThrustCurveAPI::searchMotors(const SearchCriteria
else
mm.type = model::MotorModel::MotorType(model::MotorModel::MOTORTYPE::HYBRID);
Logger::getInstance()->debug("5");
auto tc = getThrustCurve(mm.motorIdTC);
motorModel.moveMetaData(std::move(mm));
Logger::getInstance()->debug("6");
if(tc)
{
motorModel.addThrustCurve(*tc);
}
retVal.push_back(motorModel);
}
}

View File

@ -7,6 +7,7 @@
// C++ headers
#include <map>
#include <string>
#include <optional>
// 3rd party headers
/// \endcond
@ -91,6 +92,8 @@ private:
const std::string hostname;
CurlConnection curlConnection;
std::optional<ThrustCurve> getThrustCurve(const std::string& id);
// no extra headers, but CurlConnection library wants them
const std::vector<std::string> extraHeaders{};
};

View File

@ -1,21 +0,0 @@
#ifndef TRIPLET_H
#define TRIPLET_H
/**
* The purpose of this class is to get rid of using std::tuple for coordinate triplets.
*/
template<typename T>
struct Triplet
{
Triplet(const T& a, const T& b, const T& c)
: x1(a), x2(b), x3(c)
{}
T x1;
T x2;
T x3;
};
using TripletD = Triplet<double>;
#endif // TRIPLET_H

View File

@ -6,9 +6,19 @@ namespace utils::math
namespace Constants
{
constexpr double Rstar = 8.3144598;
constexpr double Rstar = 8.31432;
constexpr const double g0 = 9.80665;
constexpr const double airMolarMass = 0.0289644;
// gamma is the ratio of the specific heat of air at constant pressure to that at
// constant volume. Used in computing the speed of sound
constexpr const double gamma = 1.4;
// beta is used in calculating the dynamic viscosity of air. Based on the 1976 US Standard
// Atmosphere report, it is empirically measured to be:
constexpr const double beta = 1.458e-6;
// Sutherland's constant
constexpr const double S = 110.4;
constexpr const double standardTemperature = 288.15;
constexpr const double standardDensity = 1.2250;
constexpr const double meanEarthRadiusWGS84 = 6371008.8;

74
utils/math/MathTypes.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef UTILS_MATH_MATHTYPES_H
#define UTILS_MATH_MATHTYPES_H
#include <Eigen/Dense>
#include <vector>
/// This is not in any namespace. These typedefs are intended to be used throughout QtRocket,
/// so keeping them in the global namespace seems to make sense.
template <int Size>
using MyMatrix = Eigen::Matrix<double, Size, Size>;
template <int Size>
using MyVector = Eigen::Matrix<double, Size, 1>;
typedef Eigen::Quaterniond Quaternion;
using Matrix3 = MyMatrix<3>;
using Matrix4 = MyMatrix<4>;
using Vector3 = MyVector<3>;
using Vector6 = MyVector<6>;
/*
namespace utils
{
std::vector<double> myVectorToStdVector(const Vector3& x)
{
return std::vector<double>{x.coeff(0), x.coeff(1), x.coeff(2)};
}
std::vector<double> myVectorToStdVector(const Vector6& x)
{
return std::vector<double>{x.coeff(0),
x.coeff(1),
x.coeff(2),
x.coeff(3),
x.coeff(4),
x.coeff(5)};
}
}
class Vector3 : public MyVector<3>
{
public:
template<typename... Args>
Vector3(Args&&... args) : MyVector<3>(std::forward<Args>(args)...)
{}
operator std::vector<double>()
{
return std::vector<double>{this->coeff(0), this->coeff(1), this->coeff(2)};
}
};
class Vector6 : public MyVector<6>
{
public:
template<typename... Args>
Vector6(Args&&... args) : MyVector<6>(std::forward<Args>(args)...)
{}
operator std::vector<double>()
{
return std::vector<double>{this->coeff(0),
this->coeff(1),
this->coeff(2),
this->coeff(3),
this->coeff(4),
this->coeff(5)};
}
};
*/
#endif // UTILS_MATH_MATHTYPES_H

View File

@ -1,25 +0,0 @@
// qtrocket headers
#include "utils/math/Quaternion.h"
namespace math
{
Quaternion::Quaternion()
{
}
Quaternion::Quaternion(double r, const Vector3& i)
: real(r),
imag(i)
{
}
Quaternion::Quaternion(double r, double i1, double i2, double i3)
: real(r),
imag(i1, i2, i3)
{
}
} // namespace math

View File

@ -1,63 +0,0 @@
#ifndef MATH_QUATERNION_H
#define MATH_QUATERNION_H
/// \cond
// C headers
// C++ headers
#include <utility>
// 3rd party headers
/// \endcond
// qtrocket headers
#include "Vector3.h"
namespace math
{
class Quaternion
{
public:
Quaternion();
~Quaternion() {}
Quaternion(double r, const Vector3& i);
Quaternion(double r, double i1, double i2, double i3);
Quaternion(const Quaternion&) = default;
Quaternion(Quaternion&&) = default;
Quaternion& operator=(const Quaternion& rhs)
{
if(this == &rhs)
return *this;
real = rhs.real;
imag = rhs.imag;
return *this;
}
Quaternion& operator=(Quaternion&& rhs)
{
if(this == &rhs)
return *this;
real = std::move(rhs.real);
imag = std::move(rhs.imag);
return *this;
}
/*
Quaternion operator-() {}
Quaternion operator-(const Quaternion& ) {}
Quaternion operator+(const Quaternion& ) {}
Quaternion operator*(double ) {}
Quaternion operator*(const Quaternion& ) {}
*/
private:
double real;
Vector3 imag;
};
} // namespace math
#endif // MATH_QUATERNION_H

View File

@ -1,15 +0,0 @@
/// \cond
// C headers
// C++ headers
// 3rd party headers
/// \endcond
namespace utils
{
namespace math
{
} // namespace math
} // namespace utils

View File

@ -1,68 +0,0 @@
// qtrocket headers
#include "utils/math/Vector3.h"
namespace math
{
Vector3::Vector3()
: x1(0.0),
x2(0.0),
x3(0.0)
{
}
Vector3::Vector3(const double& inX1,
const double& inX2,
const double& inX3)
: x1(inX1),
x2(inX2),
x3(inX3)
{
}
Vector3::Vector3(const Vector3& o)
: x1(o.x1),
x2(o.x2),
x3(o.x3)
{
}
Vector3::~Vector3()
{}
Vector3 Vector3::operator=(const Vector3& rhs)
{
return Vector3(rhs.x1, rhs.x2, rhs.x3);
}
Vector3 Vector3::operator-()
{
return Vector3(-x1, -x2, -x3);
}
Vector3 Vector3::operator-(const Vector3& rhs)
{
return Vector3(x1 - rhs.x1,
x2 - rhs.x2,
x3 - rhs.x3);
}
Vector3 Vector3::operator+(const Vector3& rhs)
{
return Vector3(x1 + rhs.x1,
x2 + rhs.x2,
x3 + rhs.x3);
}
Vector3 Vector3::operator*(const double& s)
{
return Vector3(x1 * s,
x2 * s,
x3 * s);
}
} // namespace math

View File

@ -1,40 +0,0 @@
#ifndef MATH_VECTOR3_H
#define MATH_VECTOR3_H
namespace math
{
class Vector3
{
public:
Vector3();
Vector3(const double& inX1,
const double& inX2,
const double& inX3);
Vector3(const Vector3& o);
~Vector3();
Vector3 operator=(const Vector3& rhs);
Vector3 operator-();
Vector3 operator-(const Vector3& rhs);
Vector3 operator+(const Vector3& rhs);
Vector3 operator*(const double& s);
double getX1() { return x1; }
double getX2() { return x2; }
double getX3() { return x3; }
//private:
double x1;
double x2;
double x3;
};
} // namespace math
#endif // MATH_VECTOR3_H