From 070013cff2422d34ce254679759ac812f4a905db Mon Sep 17 00:00:00 2001 From: Travis Hunter Date: Mon, 24 Apr 2023 20:43:18 -0600 Subject: [PATCH] Add SimulationOptions class to keep track of and encapsulate various simulation options --- QtRocket.cpp | 9 +- QtRocket.h | 13 +-- gui/MainWindow.cpp | 32 +------ gui/MainWindow.h | 4 +- gui/SimOptionsWindow.cpp | 14 +++ gui/SimOptionsWindow.h | 22 +++++ ...mulationOptions.ui => SimOptionsWindow.ui} | 4 +- gui/SimulationOptions.cpp | 14 --- gui/SimulationOptions.h | 22 ----- model/MotorModel.cpp | 12 ++- model/Rocket.cpp | 5 +- qtrocket.pro | 7 +- sim/SimulationOptions.h | 96 +++++++++++++++++++ utils/math/UtilityMathFunctions.h | 2 +- 14 files changed, 168 insertions(+), 88 deletions(-) create mode 100644 gui/SimOptionsWindow.cpp create mode 100644 gui/SimOptionsWindow.h rename gui/{SimulationOptions.ui => SimOptionsWindow.ui} (96%) delete mode 100644 gui/SimulationOptions.cpp delete mode 100644 gui/SimulationOptions.h create mode 100644 sim/SimulationOptions.h diff --git a/QtRocket.cpp b/QtRocket.cpp index e144d59..57522af 100644 --- a/QtRocket.cpp +++ b/QtRocket.cpp @@ -74,12 +74,9 @@ QtRocket::QtRocket() logger = utils::Logger::getInstance(); running = false; - atmosphere = - std::make_shared(); - - gravity = - std::make_shared(); - + // Need to set some sane defaults for Simulation Options + // The default constructor for SimulationOptions will do that for us, so just use that + setSimulationOptions(std::make_shared()); rocket = std::make_shared(); diff --git a/QtRocket.h b/QtRocket.h index f96fd78..61816c9 100644 --- a/QtRocket.h +++ b/QtRocket.h @@ -16,6 +16,7 @@ #include "model/Rocket.h" #include "sim/AtmosphericModel.h" #include "sim/GravityModel.h" +#include "sim/SimulationOptions.h" #include "utils/Logger.h" /** @@ -37,15 +38,16 @@ public: void runSim(); - std::shared_ptr getGravityModel() { return gravity; } - std::shared_ptr getAtmosphereModel() { return atmosphere; } - + std::shared_ptr getGravityModel() { return simOptions->getGravityModel(); } + std::shared_ptr getAtmosphereModel() { return simOptions->getAtmosphericModel(); } + double getTimeStep() { return simOptions->getTimeStep(); } + std::shared_ptr getRocket() { return rocket; } void addMotorModels(std::vector& m); void addRocket(std::shared_ptr r) { rocket = r; } - std::shared_ptr getRocket() { return rocket; } + void setSimulationOptions(std::shared_ptr options) { simOptions = options; } private: QtRocket(); @@ -63,9 +65,8 @@ private: utils::Logger* logger; std::shared_ptr rocket; - std::shared_ptr atmosphere; - std::shared_ptr gravity; + std::shared_ptr simOptions; }; diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index b83112e..ceec741 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -19,7 +19,7 @@ #include "gui/AnalysisWindow.h" #include "gui/MainWindow.h" #include "gui/ThrustCurveMotorSelector.h" -#include "gui/SimulationOptions.h" +#include "gui/SimOptionsWindow.h" #include "model/Rocket.h" #include "utils/RSEDatabaseLoader.h" @@ -102,32 +102,6 @@ void MainWindow::on_testButton2_clicked() aWindow.setModal(false); aWindow.exec(); - /* - const std::vector>>& res = rocket.getStates(); - for(const auto& i : res) - { - std::cout << i.first << ": " << "(" << i.second[0] << ", " << i.second[1] << ", " << i.second[2] << ")\n"; - } - auto& plot = ui->plotWindow; - // generate some data: - QVector tData(res.size()), zData(res.size()); - for (int i = 0; i < tData.size(); ++i) - { - tData[i] = res[i].first; - zData[i] = res[i].second[2]; - } - // create graph and assign data to it: - plot->addGraph(); - plot->graph(0)->setData(tData, zData); - // give the axes some labels: - plot->xAxis->setLabel("time"); - plot->yAxis->setLabel("Z"); - // set axes ranges, so we see all data: - plot->xAxis->setRange(*std::min_element(std::begin(tData), std::end(tData)), *std::max_element(std::begin(tData), std::end(tData))); - plot->yAxis->setRange(*std::min_element(std::begin(zData), std::end(zData)), *std::max_element(std::begin(zData), std::end(zData))); - plot->replot(); - */ - } void MainWindow::on_loadRSE_button_clicked() @@ -135,7 +109,7 @@ void MainWindow::on_loadRSE_button_clicked() QString rseFile = QFileDialog::getOpenFileName(this, tr("Import RSE Database File"), "/home", - tr("RSE Files (*.rse)")); + tr("Rocksim Engine Files (*.rse)")); utils::RSEDatabaseLoader loader(rseFile.toStdString()); @@ -166,7 +140,7 @@ void MainWindow::on_actionSimulation_Options_triggered() { if(!simOptionsWindow) { - simOptionsWindow = new SimulationOptions(this); + simOptionsWindow = new SimOptionsWindow(this); } simOptionsWindow->show(); diff --git a/gui/MainWindow.h b/gui/MainWindow.h index 4c79055..e762480 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -11,7 +11,7 @@ // qtrocket headers #include "QtRocket.h" -#include "gui/SimulationOptions.h" +#include "gui/SimOptionsWindow.h" QT_BEGIN_NAMESPACE @@ -51,6 +51,6 @@ private slots: Ui::MainWindow* ui; QtRocket* qtRocket; - SimulationOptions* simOptionsWindow{nullptr}; + SimOptionsWindow* simOptionsWindow{nullptr}; }; #endif // MAINWINDOW_H diff --git a/gui/SimOptionsWindow.cpp b/gui/SimOptionsWindow.cpp new file mode 100644 index 0000000..3342b03 --- /dev/null +++ b/gui/SimOptionsWindow.cpp @@ -0,0 +1,14 @@ +#include "SimOptionsWindow.h" +#include "ui_SimOptionsWindow.h" + +SimOptionsWindow::SimOptionsWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::SimOptionsWindow) +{ + ui->setupUi(this); +} + +SimOptionsWindow::~SimOptionsWindow() +{ + delete ui; +} diff --git a/gui/SimOptionsWindow.h b/gui/SimOptionsWindow.h new file mode 100644 index 0000000..9d160b1 --- /dev/null +++ b/gui/SimOptionsWindow.h @@ -0,0 +1,22 @@ +#ifndef SIMOPTIONSWINDOW_H +#define SIMOPTIONSWINDOW_H + +#include + +namespace Ui { +class SimOptionsWindow; +} + +class SimOptionsWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit SimOptionsWindow(QWidget *parent = nullptr); + ~SimOptionsWindow(); + +private: + Ui::SimOptionsWindow *ui; +}; + +#endif // SIMOPTIONSWINDOW_H diff --git a/gui/SimulationOptions.ui b/gui/SimOptionsWindow.ui similarity index 96% rename from gui/SimulationOptions.ui rename to gui/SimOptionsWindow.ui index 2ae26b0..1cbe0ce 100644 --- a/gui/SimulationOptions.ui +++ b/gui/SimOptionsWindow.ui @@ -1,7 +1,7 @@ - SimulationOptions - + SimOptionsWindow + 0 diff --git a/gui/SimulationOptions.cpp b/gui/SimulationOptions.cpp deleted file mode 100644 index f29038f..0000000 --- a/gui/SimulationOptions.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "SimulationOptions.h" -#include "ui_SimulationOptions.h" - -SimulationOptions::SimulationOptions(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::SimulationOptions) -{ - ui->setupUi(this); -} - -SimulationOptions::~SimulationOptions() -{ - delete ui; -} diff --git a/gui/SimulationOptions.h b/gui/SimulationOptions.h deleted file mode 100644 index 6c19c54..0000000 --- a/gui/SimulationOptions.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SIMULATIONOPTIONS_H -#define SIMULATIONOPTIONS_H - -#include - -namespace Ui { -class SimulationOptions; -} - -class SimulationOptions : public QMainWindow -{ - Q_OBJECT - -public: - explicit SimulationOptions(QWidget *parent = nullptr); - ~SimulationOptions(); - -private: - Ui::SimulationOptions *ui; -}; - -#endif // SIMULATIONOPTIONS_H diff --git a/model/MotorModel.cpp b/model/MotorModel.cpp index 985d71e..1319a74 100644 --- a/model/MotorModel.cpp +++ b/model/MotorModel.cpp @@ -1,5 +1,14 @@ + +/// \cond +// C headers +// C++ headers +// 3rd party headers +/// \endcond + +// qtrocket headers #include "model/MotorModel.h" #include "utils/math/Constants.h" +#include "utils/math/UtilityMathFunctions.h" namespace model { @@ -33,7 +42,7 @@ double MotorModel::getMass(double simTime) const // If thrustTime is equal to a data point that we have, then just return // the mass at that time. Otherwise it fell between two points and we // will interpolate - if(i->first == thrustTime) + if(utils::math::floatingPointEqual(i->first, thrustTime)) { // return empty mass + remaining propellant mass return emptyMass + i->second; @@ -53,6 +62,7 @@ double MotorModel::getMass(double simTime) const return currentMass; } + // motor has burned out else { return emptyMass; diff --git a/model/Rocket.cpp b/model/Rocket.cpp index 608318a..0a7b854 100644 --- a/model/Rocket.cpp +++ b/model/Rocket.cpp @@ -1,14 +1,14 @@ #include "Rocket.h" +#include "QtRocket.h" Rocket::Rocket() : propagator(this) { - propagator.setTimeStep(0.01); - //propagator.set } void Rocket::launch() { + propagator.setTimeStep(QtRocket::getInstance()->getTimeStep()); propagator.runUntilTerminate(); } @@ -19,6 +19,7 @@ void Rocket::setMotorModel(const model::MotorModel& motor) bool Rocket::terminateCondition(const std::pair>& cond) { + // Terminate propagation when the z coordinate drops below zero if(cond.second[2] < 0) return true; else diff --git a/qtrocket.pro b/qtrocket.pro index a2efda4..6e5090f 100644 --- a/qtrocket.pro +++ b/qtrocket.pro @@ -12,7 +12,7 @@ SOURCES += \ QtRocket.cpp \ gui/AboutWindow.cpp \ gui/AnalysisWindow.cpp \ - gui/SimulationOptions.cpp \ + gui/SimOptionsWindow.cpp \ gui/ThrustCurveMotorSelector.cpp \ gui/qcustomplot.cpp \ main.cpp \ @@ -47,7 +47,7 @@ HEADERS += \ gui/AnalysisWindow.h \ gui/RocketTreeView.h \ gui/MainWindow.h \ - gui/SimulationOptions.h \ + gui/SimOptionsWindow.h \ gui/ThrustCurveMotorSelector.h \ gui/qcustomplot.h \ model/MotorCase.h \ @@ -63,6 +63,7 @@ HEADERS += \ sim/GravityModel.h \ sim/Propagator.h \ sim/RK4Solver.h \ + sim/SimulationOptions.h \ sim/SphericalGeoidModel.h \ sim/SphericalGravityModel.h \ sim/StateData.h \ @@ -85,7 +86,7 @@ FORMS += \ gui/AboutWindow.ui \ gui/AnalysisWindow.ui \ gui/MainWindow.ui \ - gui/SimulationOptions.ui \ + gui/SimOptionsWindow.ui \ gui/ThrustCurveMotorSelector.ui TRANSLATIONS += \ diff --git a/sim/SimulationOptions.h b/sim/SimulationOptions.h new file mode 100644 index 0000000..68cba03 --- /dev/null +++ b/sim/SimulationOptions.h @@ -0,0 +1,96 @@ +#ifndef SIMULATIONOPTIONS_H +#define SIMULATIONOPTIONS_H + +/// \cond +// C headers +// C++ headers +#include +#include +#include +#include + +// 3rd party headers +/// \endcond + +// qtrocket headers +#include "sim/GravityModel.h" +#include "sim/SphericalGravityModel.h" +#include "sim/ConstantGravityModel.h" + +#include "sim/AtmosphericModel.h" +#include "sim/ConstantAtmosphere.h" +#include "sim/USStandardAtmosphere.h" + +namespace sim +{ + +/** + * @brief The SimulationOptions class holds the available simulation options and environmental models + */ +class SimulationOptions +{ +public: + SimulationOptions() + { + setTimeStep(0.01); + setGravityModel("Constant Gravity"); + setAtmosphereModel("Constant Atmosphere"); + } + ~SimulationOptions() = default; + SimulationOptions(const SimulationOptions&) = delete; + SimulationOptions(SimulationOptions&&) = delete; + SimulationOptions& operator=(const SimulationOptions&) = delete; + SimulationOptions& operator=(SimulationOptions&&) = delete; + + void setTimeStep(double t) { timeStep = t; } + void setGravityModel(const std::string& model) + { + if(model == "Constant Gravity") + { + gravityModel = model; + gravityModels[gravityModel].reset(new sim::ConstantGravityModel); + } + else if(model == "Spherical Gravity") + { + gravityModel = model; + gravityModels[gravityModel].reset(new sim::SphericalGravityModel); + } + } + + void setAtmosphereModel(const std::string& model) + { + if(model == "Constant Atmosphere") + { + atmosphereModel = model; + atmosphereModels[gravityModel].reset(new sim::ConstantAtmosphere); + } + else if(model == "US Standard 1976") + { + atmosphereModel = model; + atmosphereModels[gravityModel].reset(new sim::USStandardAtmosphere); + } + } + + std::shared_ptr getAtmosphericModel() { return atmosphereModels[atmosphereModel]; } + std::shared_ptr getGravityModel() { return gravityModels[gravityModel]; } + double getTimeStep() { return timeStep; } + +private: + + std::map> atmosphereModels{ + {"Constant Atmosphere", std::shared_ptr()}, + {"US Standard 1976", std::shared_ptr()}}; + + std::map> gravityModels{ + {"Constant Gravity", std::shared_ptr()}, + {"Spherical Gravity", std::shared_ptr()}}; + + double timeStep{0.01}; + + std::string gravityModel{"Constant Gravity"}; /// Constant Gravity Model is the default + std::string atmosphereModel{"Constant Atmosphere"}; /// Constant Atmosphere Model is the default +}; + +} + +#endif // SIMULATIONOPTIONS_H diff --git a/utils/math/UtilityMathFunctions.h b/utils/math/UtilityMathFunctions.h index bf47777..6688d91 100644 --- a/utils/math/UtilityMathFunctions.h +++ b/utils/math/UtilityMathFunctions.h @@ -19,7 +19,7 @@ namespace math * places to ignore * * This is derived from the example on cppreference.com: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon - * The default ulp of 8 with a numeric_limits::epsilon() of ~2e-16, so ulp of 8 yields 12 + * The default ulp of 4 with a numeric_limits::epsilon() of ~2e-16, so ulp of 4 yields 12 * significant figures. A ulp of 10 yields 6 significant figures. * @param a the first double to compare * @param b the second double to compare