From b3a8a2ad4cfb25a62961025cc828f15acc2ca8f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Jun 2025 01:12:36 +0000 Subject: [PATCH 1/4] Initial plan From dfb3d4b0bda683ecba2780e9c673dde77dab9775 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Jun 2025 01:24:29 +0000 Subject: [PATCH 2/4] Update CLI11 to v1.3.0 and remove unnecessary includes Co-authored-by: msolanik <22960818+msolanik@users.noreply.github.com> --- Input/src/InputValidation.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Input/src/InputValidation.cpp b/Input/src/InputValidation.cpp index 9293bf6..5d3f94b 100644 --- a/Input/src/InputValidation.cpp +++ b/Input/src/InputValidation.cpp @@ -11,8 +11,6 @@ #include #include -#include "CLI/App.hpp" -#include "CLI/Option.hpp" #include "spdlog/spdlog.h" #include "MeasureValuesTransformation.hpp" From 4f8992ff37e9459e92e6af63d5d2fd080e2637f8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Jun 2025 01:28:48 +0000 Subject: [PATCH 3/4] Refactor parseParams function to reduce cyclomatic complexity Co-authored-by: msolanik <22960818+msolanik@users.noreply.github.com> --- Input/include/ParseParams.hpp | 88 +++++++++++++ Input/src/ParseParams.cpp | 227 ++++++++++++++++++++++------------ 2 files changed, 237 insertions(+), 78 deletions(-) diff --git a/Input/include/ParseParams.hpp b/Input/include/ParseParams.hpp index ac24428..b975a73 100644 --- a/Input/include/ParseParams.hpp +++ b/Input/include/ParseParams.hpp @@ -14,6 +14,8 @@ #include #include "ParamsCarrier.hpp" +#include "CLI/App.hpp" +#include "CLI/Option.hpp" /** * @brief ParseParams is responsible for parsing arguments from CLI. @@ -61,6 +63,92 @@ class ParseParams * @return Path where Geliosphere is located */ std::string getApplicationPath(char **argv); + + /** + * @brief Setup CLI options for the application. + * + * @param app CLI::App instance to setup options on + * @param inputFile Reference to input file string + * @param pathToLogFile Reference to log file path string + * @param newDt Reference to new dt value + * @param newK0 Reference to new K0 value + * @param newV Reference to new V value + * @param month Reference to month value + * @param year Reference to year value + * @param newDestination Reference to destination string + * @param settings Reference to settings string + * @param customModelString Reference to custom model string + * @param numberOfTestParticles Reference to number of test particles + */ + void setupCliOptions(CLI::App& app, std::string& inputFile, std::string& pathToLogFile, + float& newDt, float& newK0, float& newV, int& month, int& year, + std::string& newDestination, std::string& settings, std::string& customModelString, + int& numberOfTestParticles); + + /** + * @brief Setup option relationships (excludes, requires). + */ + void setupOptionRelationships(); + + /** + * @brief Process general options like csv, run_simulation, destination. + * + * @param pathToLogFile Log file path + * @param newDestination Destination path + * @return 1 on success, -1 on failure + */ + int processGeneralOptions(const std::string& pathToLogFile, const std::string& newDestination); + + /** + * @brief Process value options like dt, K0, V, numberOfTestParticles. + * + * @param newDt New dt value + * @param newK0 New K0 value + * @param newV New V value + * @param numberOfTestParticles Number of test particles + * @return 1 on success, -1 on failure + */ + int processValueOptions(float newDt, float newK0, float newV, int numberOfTestParticles); + + /** + * @brief Process model selection options. + * + * @param customModelString Custom model string + * @param inputFile Input file for batch run + * @return 1 on success, -1 on failure + */ + int processModelOptions(const std::string& customModelString, const std::string& inputFile); + + /** + * @brief Process settings and time-related options. + * + * @param settings Settings file path + * @param month Month value + * @param year Year value + * @param currentApplicationPath Current application path + * @return 1 on success, -1 on failure + */ + int processSettingsOptions(const std::string& settings, int month, int year, + const std::string& currentApplicationPath); + + // CLI option pointers - stored as class members to be accessible across functions + CLI::Option *forwardModel; + CLI::Option *backwardModel; + CLI::Option *solarPropLikeModel; + CLI::Option *geliosphereModel; + CLI::Option *csv; + CLI::Option *run_simulation; + CLI::Option *cpuOnly; + CLI::Option *batchRun; + CLI::Option *dtset; + CLI::Option *kset; + CLI::Option *vset; + CLI::Option *destination; + CLI::Option *setNumberOfTestParticles; + CLI::Option *monthOption; + CLI::Option *yearOption; + CLI::Option *settingsOption; + CLI::Option *customModel; }; #endif \ No newline at end of file diff --git a/Input/src/ParseParams.cpp b/Input/src/ParseParams.cpp index 93ce72d..e2ea157 100644 --- a/Input/src/ParseParams.cpp +++ b/Input/src/ParseParams.cpp @@ -21,33 +21,107 @@ int ParseParams::parseParams(int argc, char **argv) int month, year; std::string newDestination, settings, customModelString; int numberOfTestParticles; + singleTone = singleTone->instance(); std::string currentApplicationPath = getApplicationPath(argv); singleTone->putString("currentApplicationPath", currentApplicationPath); - InputValidation *inputValidation = new InputValidation(); + CLI::App app{"App description"}; - CLI::Option *forwardModel = app.add_flag("-F,--forward", "Run a 1D forward-in-time model")->group("models"); - CLI::Option *backwardModel = app.add_flag("-B,--backward", "Run a 1D backward-in-time model")->group("models"); - CLI::Option *solarPropLikeModel = app.add_flag("-E,--solarprop-like-model", "Run a SolarProp-like 2D backward model")->group("models"); - CLI::Option *geliosphereModel = app.add_flag("-T,--geliosphere-2d-model", "Run a Geliosphere 2D backward model")->group("models"); - CLI::Option *csv = app.add_flag("-c,--csv", "Output will be in .csv"); - CLI::Option *run_simulation = app.add_option("--evaluation", pathToLogFile,"Simulation excluded, run only evaluation "); + + // Setup CLI options + setupCliOptions(app, inputFile, pathToLogFile, newDt, newK0, newV, month, year, + newDestination, settings, customModelString, numberOfTestParticles); + + // Setup option relationships + setupOptionRelationships(); + + spdlog::info("Started to parsing input parameters"); + CLI11_PARSE(app, argc, argv); + + // Validate that at least one model is selected + if (!*forwardModel && !*backwardModel && !*solarPropLikeModel && !*geliosphereModel && !*batchRun) + { + spdlog::error("At least one model must be selected!"); + return -1; + } + + // Process different option categories + int result; + + result = processGeneralOptions(pathToLogFile, newDestination); + if (result == -1) return -1; + + result = processValueOptions(newDt, newK0, newV, numberOfTestParticles); + if (result == -1) return -1; + + result = processModelOptions(customModelString, inputFile); + if (result == -1) return -1; + + result = processSettingsOptions(settings, month, year, currentApplicationPath); + if (result == -1) return -1; + + printParameters(singleTone); + return 1; +} + +ParamsCarrier *ParseParams::getParams() +{ + return singleTone; +} + + +void ParseParams::printParameters(ParamsCarrier *params) +{ + InputValidation *inputValidation = new InputValidation(); + spdlog::info("Chosen model:" + singleTone->getString("model", "1D Fp")); + spdlog::info("K0:" + std::to_string(params->getFloat("K0", params->getFloat("K0_default", 5e22 * 4.4683705e-27))) + " au^2 / s"); + spdlog::info("V:" + std::to_string(params->getFloat("V", params->getFloat("V_default", 400 * 6.68458712e-9))) + " au / s"); + spdlog::info("dt:" + std::to_string(params->getFloat("dt", params->getFloat("dt_default", 5.0f))) + " s"); + if (inputValidation->isInputSolarPropLikeModel(singleTone->getString("model", "1D Fp")) || inputValidation->isInputGeliosphere2DModel(singleTone->getString("model", "1D Fp"))) + { + spdlog::info("tilt_angle:" + std::to_string(params->getFloat("tilt_angle", -1.0f))); + spdlog::info("polarity:" + std::to_string(params->getInt("polarity", -1.0f))); + } +} + +std::string ParseParams::getApplicationPath(char **argv) +{ + std::regex regexp(R"(.*\/)"); + std::cmatch m; + std::regex_search(argv[0], m, regexp); + return m[0]; +} + +void ParseParams::setupCliOptions(CLI::App& app, std::string& inputFile, std::string& pathToLogFile, + float& newDt, float& newK0, float& newV, int& month, int& year, + std::string& newDestination, std::string& settings, std::string& customModelString, + int& numberOfTestParticles) +{ + forwardModel = app.add_flag("-F,--forward", "Run a 1D forward-in-time model")->group("models"); + backwardModel = app.add_flag("-B,--backward", "Run a 1D backward-in-time model")->group("models"); + solarPropLikeModel = app.add_flag("-E,--solarprop-like-model", "Run a SolarProp-like 2D backward model")->group("models"); + geliosphereModel = app.add_flag("-T,--geliosphere-2d-model", "Run a Geliosphere 2D backward model")->group("models"); + csv = app.add_flag("-c,--csv", "Output will be in .csv"); + run_simulation = app.add_option("--evaluation", pathToLogFile,"Simulation excluded, run only evaluation "); #if GPU_ENABLED == 1 - CLI::Option *cpuOnly = app.add_flag("--cpu-only", "Use only CPU for calculaions"); + cpuOnly = app.add_flag("--cpu-only", "Use only CPU for calculaions"); #else singleTone->putInt("isCpu", 1); #endif - CLI::Option *batchRun = app.add_option("-b,--batchrun", inputFile,"Input batch file")->group("models"); - CLI::Option *dtset = app.add_option("-d,--dt", newDt, "Set dt to new value(s)"); - CLI::Option *kset = app.add_option("-K,--K0", newK0, "Set K to new value(cm^2/s)"); - CLI::Option *vset = app.add_option("-V,--V", newV, "Set V to new value(km/s)"); - CLI::Option *destination = app.add_option("-p,--path", newDestination, "Set destination folder name"); - CLI::Option *setNumberOfTestParticles = app.add_option("-N,--number-of-test-particles", numberOfTestParticles, "Set number of test particles in millions(round up due to GPU execution)"); - CLI::Option *monthOption = app.add_option("-m,--month", month, "Set month for using meassured values"); - CLI::Option *yearOption = app.add_option("-y,--year", year, "Set year for using meassured values"); - CLI::Option *settingsOption = app.add_option("-s,--settings", settings, "Path to .toml file"); - CLI::Option *customModel = app.add_option("--custom-model", customModelString, "Run custom user-implemented model."); + batchRun = app.add_option("-b,--batchrun", inputFile,"Input batch file")->group("models"); + dtset = app.add_option("-d,--dt", newDt, "Set dt to new value(s)"); + kset = app.add_option("-K,--K0", newK0, "Set K to new value(cm^2/s)"); + vset = app.add_option("-V,--V", newV, "Set V to new value(km/s)"); + destination = app.add_option("-p,--path", newDestination, "Set destination folder name"); + setNumberOfTestParticles = app.add_option("-N,--number-of-test-particles", numberOfTestParticles, "Set number of test particles in millions(round up due to GPU execution)"); + monthOption = app.add_option("-m,--month", month, "Set month for using meassured values"); + yearOption = app.add_option("-y,--year", year, "Set year for using meassured values"); + settingsOption = app.add_option("-s,--settings", settings, "Path to .toml file"); + customModel = app.add_option("--custom-model", customModelString, "Run custom user-implemented model."); +} +void ParseParams::setupOptionRelationships() +{ kset->excludes(monthOption, yearOption); vset->excludes(monthOption, yearOption); @@ -60,14 +134,10 @@ int ParseParams::parseParams(int argc, char **argv) dtset, setNumberOfTestParticles, kset, vset, monthOption, yearOption); monthOption->requires(yearOption); +} - spdlog::info("Started to parsing input parameters"); - CLI11_PARSE(app, argc, argv); - if (!*forwardModel && !*backwardModel && !*solarPropLikeModel && !geliosphereModel && !batchRun) - { - spdlog::error("At least one model must be selected!"); - return -1; - } +int ParseParams::processGeneralOptions(const std::string& pathToLogFile, const std::string& newDestination) +{ if(*run_simulation){ singleTone->putInt("run_simulation", 0); singleTone->putString("pathToLogFile",pathToLogFile); @@ -75,19 +145,41 @@ int ParseParams::parseParams(int argc, char **argv) else{ singleTone->putInt("run_simulation", 1); } + if (*csv) { singleTone->putInt("csv", 1); } + +#if GPU_ENABLED == 1 + if (*cpuOnly) + { + singleTone->putInt("isCpu", 1); + } +#endif + + if (*destination) + { + singleTone->putString("destination", newDestination); + } + + return 1; +} + +int ParseParams::processValueOptions(float newDt, float newK0, float newV, int numberOfTestParticles) +{ + InputValidation *inputValidation = new InputValidation(); + if (*dtset) { if (!inputValidation->checkDt(newDt)) { spdlog::error("dt is out of range!(3-5000)"); - return false; + return -1; } inputValidation->setDt(singleTone, newDt); } + if (*kset) { if (!inputValidation->checkK0(newK0)) @@ -101,6 +193,7 @@ int ParseParams::parseParams(int argc, char **argv) } inputValidation->setK0(singleTone, newK0); } + if (*setNumberOfTestParticles) { if (!inputValidation->checkNumberOfTestParticles(numberOfTestParticles)) @@ -110,6 +203,7 @@ int ParseParams::parseParams(int argc, char **argv) } inputValidation->setNumberOfTestParticles(singleTone, numberOfTestParticles); } + if (*vset) { if (!inputValidation->checkV(newV)) @@ -119,29 +213,12 @@ int ParseParams::parseParams(int argc, char **argv) } inputValidation->setV(singleTone, newV); } - if (*settingsOption) - { - inputValidation->newSettingsLocationCheck(singleTone, settings); - } - else - { - if (access(settings.c_str(), F_OK) == 0) { - TomlSettings *tomlSettings = new TomlSettings(currentApplicationPath + "Settings.toml"); - tomlSettings->parseFromSettings(singleTone); - } else { - spdlog::warn("No settings file exists on default path."); - } - } -#if GPU_ENABLED == 1 - if (*cpuOnly) - { - singleTone->putInt("isCpu", 1); - } -#endif - if (*destination) - { - singleTone->putString("destination", newDestination); - } + + return 1; +} + +int ParseParams::processModelOptions(const std::string& customModelString, const std::string& inputFile) +{ if (*forwardModel) { singleTone->putString("model", "1D Fp"); @@ -166,41 +243,35 @@ int ParseParams::parseParams(int argc, char **argv) { singleTone->putString("model", "batch run"); singleTone->putString("inputBatchFile", inputFile); - return 1; + return 1; // Special case - batch run returns early } - if (*monthOption && *yearOption) - { - inputValidation->monthYearCheck(singleTone, year, month, currentApplicationPath); - } - - printParameters(singleTone); + return 1; } -ParamsCarrier *ParseParams::getParams() -{ - return singleTone; -} - - -void ParseParams::printParameters(ParamsCarrier *params) +int ParseParams::processSettingsOptions(const std::string& settings, int month, int year, + const std::string& currentApplicationPath) { InputValidation *inputValidation = new InputValidation(); - spdlog::info("Chosen model:" + singleTone->getString("model", "1D Fp")); - spdlog::info("K0:" + std::to_string(params->getFloat("K0", params->getFloat("K0_default", 5e22 * 4.4683705e-27))) + " au^2 / s"); - spdlog::info("V:" + std::to_string(params->getFloat("V", params->getFloat("V_default", 400 * 6.68458712e-9))) + " au / s"); - spdlog::info("dt:" + std::to_string(params->getFloat("dt", params->getFloat("dt_default", 5.0f))) + " s"); - if (inputValidation->isInputSolarPropLikeModel(singleTone->getString("model", "1D Fp")) || inputValidation->isInputGeliosphere2DModel(singleTone->getString("model", "1D Fp"))) + + if (*settingsOption) { - spdlog::info("tilt_angle:" + std::to_string(params->getFloat("tilt_angle", -1.0f))); - spdlog::info("polarity:" + std::to_string(params->getInt("polarity", -1.0f))); + inputValidation->newSettingsLocationCheck(singleTone, settings); } -} - -std::string ParseParams::getApplicationPath(char **argv) -{ - std::regex regexp(R"(.*\/)"); - std::cmatch m; - std::regex_search(argv[0], m, regexp); - return m[0]; + else + { + if (access(settings.c_str(), F_OK) == 0) { + TomlSettings *tomlSettings = new TomlSettings(currentApplicationPath + "Settings.toml"); + tomlSettings->parseFromSettings(singleTone); + } else { + spdlog::warn("No settings file exists on default path."); + } + } + + if (*monthOption && *yearOption) + { + inputValidation->monthYearCheck(singleTone, year, month, currentApplicationPath); + } + + return 1; } \ No newline at end of file From aa64881fc702d5c963a5bb54c209876eccd58a25 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 30 Jun 2025 21:13:00 +0000 Subject: [PATCH 4/4] Implement state machine pattern to reduce cyclomatic complexity and parameter count Co-authored-by: msolanik <22960818+msolanik@users.noreply.github.com> --- Input/include/ParseParams.hpp | 97 ++++++----- Input/src/ParseParams.cpp | 303 ++++++++++++++++------------------ 2 files changed, 198 insertions(+), 202 deletions(-) diff --git a/Input/include/ParseParams.hpp b/Input/include/ParseParams.hpp index b975a73..21c3c7a 100644 --- a/Input/include/ParseParams.hpp +++ b/Input/include/ParseParams.hpp @@ -64,26 +64,38 @@ class ParseParams */ std::string getApplicationPath(char **argv); + /** + * @brief Parse state enumeration for state machine pattern. + */ + enum class ParseState { + SETUP, + PARSING, + VALIDATION, + PROCESSING, + COMPLETE, + ERROR + }; + + /** + * @brief Configuration structure to hold parsing parameters. + */ + struct ParseConfig { + std::string inputFile; + std::string pathToLogFile; + float newDt, newK0, newV; + int month, year; + std::string newDestination, settings, customModelString; + int numberOfTestParticles; + std::string currentApplicationPath; + }; + /** * @brief Setup CLI options for the application. * * @param app CLI::App instance to setup options on - * @param inputFile Reference to input file string - * @param pathToLogFile Reference to log file path string - * @param newDt Reference to new dt value - * @param newK0 Reference to new K0 value - * @param newV Reference to new V value - * @param month Reference to month value - * @param year Reference to year value - * @param newDestination Reference to destination string - * @param settings Reference to settings string - * @param customModelString Reference to custom model string - * @param numberOfTestParticles Reference to number of test particles + * @param config Configuration structure containing all parsing parameters */ - void setupCliOptions(CLI::App& app, std::string& inputFile, std::string& pathToLogFile, - float& newDt, float& newK0, float& newV, int& month, int& year, - std::string& newDestination, std::string& settings, std::string& customModelString, - int& numberOfTestParticles); + void setupCliOptions(CLI::App& app, ParseConfig& config); /** * @brief Setup option relationships (excludes, requires). @@ -91,45 +103,50 @@ class ParseParams void setupOptionRelationships(); /** - * @brief Process general options like csv, run_simulation, destination. + * @brief Execute state machine transition. + * + * @param currentState Current parsing state + * @param config Configuration structure + * @param app CLI app instance + * @param argc Argument count + * @param argv Argument values + * @return Next state + */ + ParseState executeState(ParseState currentState, ParseConfig& config, CLI::App& app, int argc, char** argv); + + /** + * @brief Setup state handler. * - * @param pathToLogFile Log file path - * @param newDestination Destination path - * @return 1 on success, -1 on failure + * @param config Configuration structure + * @param app CLI app instance + * @return Next state */ - int processGeneralOptions(const std::string& pathToLogFile, const std::string& newDestination); + ParseState handleSetupState(ParseConfig& config, CLI::App& app); /** - * @brief Process value options like dt, K0, V, numberOfTestParticles. + * @brief Parsing state handler. * - * @param newDt New dt value - * @param newK0 New K0 value - * @param newV New V value - * @param numberOfTestParticles Number of test particles - * @return 1 on success, -1 on failure + * @param app CLI app instance + * @param argc Argument count + * @param argv Argument values + * @return Next state */ - int processValueOptions(float newDt, float newK0, float newV, int numberOfTestParticles); + ParseState handleParsingState(CLI::App& app, int argc, char** argv); /** - * @brief Process model selection options. + * @brief Validation state handler. * - * @param customModelString Custom model string - * @param inputFile Input file for batch run - * @return 1 on success, -1 on failure + * @return Next state */ - int processModelOptions(const std::string& customModelString, const std::string& inputFile); + ParseState handleValidationState(); /** - * @brief Process settings and time-related options. + * @brief Processing state handler. * - * @param settings Settings file path - * @param month Month value - * @param year Year value - * @param currentApplicationPath Current application path - * @return 1 on success, -1 on failure + * @param config Configuration structure + * @return Next state */ - int processSettingsOptions(const std::string& settings, int month, int year, - const std::string& currentApplicationPath); + ParseState handleProcessingState(const ParseConfig& config); // CLI option pointers - stored as class members to be accessible across functions CLI::Option *forwardModel; diff --git a/Input/src/ParseParams.cpp b/Input/src/ParseParams.cpp index e2ea157..59c6736 100644 --- a/Input/src/ParseParams.cpp +++ b/Input/src/ParseParams.cpp @@ -15,51 +15,25 @@ int ParseParams::parseParams(int argc, char **argv) { - std::string inputFile; - std::string pathToLogFile; - float newDt, newK0, newV, newMu; - int month, year; - std::string newDestination, settings, customModelString; - int numberOfTestParticles; - + ParseConfig config; singleTone = singleTone->instance(); - std::string currentApplicationPath = getApplicationPath(argv); - singleTone->putString("currentApplicationPath", currentApplicationPath); + config.currentApplicationPath = getApplicationPath(argv); + singleTone->putString("currentApplicationPath", config.currentApplicationPath); CLI::App app{"App description"}; - // Setup CLI options - setupCliOptions(app, inputFile, pathToLogFile, newDt, newK0, newV, month, year, - newDestination, settings, customModelString, numberOfTestParticles); + // Initialize state machine + ParseState currentState = ParseState::SETUP; - // Setup option relationships - setupOptionRelationships(); - - spdlog::info("Started to parsing input parameters"); - CLI11_PARSE(app, argc, argv); + // Run state machine + while (currentState != ParseState::COMPLETE && currentState != ParseState::ERROR) { + currentState = executeState(currentState, config, app, argc, argv); + } - // Validate that at least one model is selected - if (!*forwardModel && !*backwardModel && !*solarPropLikeModel && !*geliosphereModel && !*batchRun) - { - spdlog::error("At least one model must be selected!"); + if (currentState == ParseState::ERROR) { return -1; } - - // Process different option categories - int result; - - result = processGeneralOptions(pathToLogFile, newDestination); - if (result == -1) return -1; - result = processValueOptions(newDt, newK0, newV, numberOfTestParticles); - if (result == -1) return -1; - - result = processModelOptions(customModelString, inputFile); - if (result == -1) return -1; - - result = processSettingsOptions(settings, month, year, currentApplicationPath); - if (result == -1) return -1; - printParameters(singleTone); return 1; } @@ -92,186 +66,191 @@ std::string ParseParams::getApplicationPath(char **argv) return m[0]; } -void ParseParams::setupCliOptions(CLI::App& app, std::string& inputFile, std::string& pathToLogFile, - float& newDt, float& newK0, float& newV, int& month, int& year, - std::string& newDestination, std::string& settings, std::string& customModelString, - int& numberOfTestParticles) +ParseParams::ParseState ParseParams::executeState(ParseState currentState, ParseConfig& config, CLI::App& app, int argc, char** argv) { - forwardModel = app.add_flag("-F,--forward", "Run a 1D forward-in-time model")->group("models"); - backwardModel = app.add_flag("-B,--backward", "Run a 1D backward-in-time model")->group("models"); - solarPropLikeModel = app.add_flag("-E,--solarprop-like-model", "Run a SolarProp-like 2D backward model")->group("models"); - geliosphereModel = app.add_flag("-T,--geliosphere-2d-model", "Run a Geliosphere 2D backward model")->group("models"); - csv = app.add_flag("-c,--csv", "Output will be in .csv"); - run_simulation = app.add_option("--evaluation", pathToLogFile,"Simulation excluded, run only evaluation "); -#if GPU_ENABLED == 1 - cpuOnly = app.add_flag("--cpu-only", "Use only CPU for calculaions"); -#else - singleTone->putInt("isCpu", 1); -#endif - batchRun = app.add_option("-b,--batchrun", inputFile,"Input batch file")->group("models"); - dtset = app.add_option("-d,--dt", newDt, "Set dt to new value(s)"); - kset = app.add_option("-K,--K0", newK0, "Set K to new value(cm^2/s)"); - vset = app.add_option("-V,--V", newV, "Set V to new value(km/s)"); - destination = app.add_option("-p,--path", newDestination, "Set destination folder name"); - setNumberOfTestParticles = app.add_option("-N,--number-of-test-particles", numberOfTestParticles, "Set number of test particles in millions(round up due to GPU execution)"); - monthOption = app.add_option("-m,--month", month, "Set month for using meassured values"); - yearOption = app.add_option("-y,--year", year, "Set year for using meassured values"); - settingsOption = app.add_option("-s,--settings", settings, "Path to .toml file"); - customModel = app.add_option("--custom-model", customModelString, "Run custom user-implemented model."); + switch (currentState) { + case ParseState::SETUP: + return handleSetupState(config, app); + case ParseState::PARSING: + return handleParsingState(app, argc, argv); + case ParseState::VALIDATION: + return handleValidationState(); + case ParseState::PROCESSING: + return handleProcessingState(config); + default: + return ParseState::ERROR; + } } -void ParseParams::setupOptionRelationships() +ParseParams::ParseState ParseParams::handleSetupState(ParseConfig& config, CLI::App& app) { - kset->excludes(monthOption, yearOption); - vset->excludes(monthOption, yearOption); + // Setup CLI options + setupCliOptions(app, config); + + // Setup option relationships + setupOptionRelationships(); + + return ParseState::PARSING; +} - backwardModel->excludes(forwardModel, solarPropLikeModel, geliosphereModel, customModel, batchRun); - forwardModel->excludes(backwardModel, solarPropLikeModel, geliosphereModel, customModel, batchRun); - solarPropLikeModel->excludes(backwardModel, forwardModel, geliosphereModel, customModel, batchRun); - geliosphereModel->excludes(backwardModel, forwardModel, solarPropLikeModel, customModel, batchRun); - customModel->excludes(backwardModel, forwardModel, solarPropLikeModel, geliosphereModel, batchRun); - batchRun->excludes(backwardModel, forwardModel, solarPropLikeModel, geliosphereModel, customModel, - dtset, setNumberOfTestParticles, kset, vset, monthOption, yearOption); +ParseParams::ParseState ParseParams::handleParsingState(CLI::App& app, int argc, char** argv) +{ + spdlog::info("Started to parsing input parameters"); + try { + app.parse(argc, argv); + } catch (const CLI::ParseError &e) { + app.exit(e); + return ParseState::ERROR; + } + + return ParseState::VALIDATION; +} - monthOption->requires(yearOption); +ParseParams::ParseState ParseParams::handleValidationState() +{ + // Validate that at least one model is selected + if (!*forwardModel && !*backwardModel && !*solarPropLikeModel && !*geliosphereModel && !*batchRun) { + spdlog::error("At least one model must be selected!"); + return ParseState::ERROR; + } + + return ParseState::PROCESSING; } -int ParseParams::processGeneralOptions(const std::string& pathToLogFile, const std::string& newDestination) +ParseParams::ParseState ParseParams::handleProcessingState(const ParseConfig& config) { - if(*run_simulation){ + InputValidation *inputValidation = new InputValidation(); + + // Process general options + if (*run_simulation) { singleTone->putInt("run_simulation", 0); - singleTone->putString("pathToLogFile",pathToLogFile); - } - else{ + singleTone->putString("pathToLogFile", config.pathToLogFile); + } else { singleTone->putInt("run_simulation", 1); } - if (*csv) - { + if (*csv) { singleTone->putInt("csv", 1); } #if GPU_ENABLED == 1 - if (*cpuOnly) - { + if (*cpuOnly) { singleTone->putInt("isCpu", 1); } #endif - if (*destination) - { - singleTone->putString("destination", newDestination); + if (*destination) { + singleTone->putString("destination", config.newDestination); } - return 1; -} - -int ParseParams::processValueOptions(float newDt, float newK0, float newV, int numberOfTestParticles) -{ - InputValidation *inputValidation = new InputValidation(); - - if (*dtset) - { - if (!inputValidation->checkDt(newDt)) - { + // Process value options with validation + if (*dtset) { + if (!inputValidation->checkDt(config.newDt)) { spdlog::error("dt is out of range!(3-5000)"); - return -1; + return ParseState::ERROR; } - inputValidation->setDt(singleTone, newDt); + inputValidation->setDt(singleTone, config.newDt); } - if (*kset) - { - if (!inputValidation->checkK0(newK0)) - { + if (*kset) { + if (!inputValidation->checkK0(config.newK0)) { spdlog::error("K0 is out of range!(>0)"); - return -1; + return ParseState::ERROR; } - if (newK0 < 1e19 || newK0 > 1e23) - { + if (config.newK0 < 1e19 || config.newK0 > 1e23) { spdlog::warn("K0 is out of recommended range!(1e19-1e23 cm^2/s)"); } - inputValidation->setK0(singleTone, newK0); + inputValidation->setK0(singleTone, config.newK0); } - if (*setNumberOfTestParticles) - { - if (!inputValidation->checkNumberOfTestParticles(numberOfTestParticles)) - { + if (*setNumberOfTestParticles) { + if (!inputValidation->checkNumberOfTestParticles(config.numberOfTestParticles)) { spdlog::error("Number of test particles must be greater than 0!"); - return -1; + return ParseState::ERROR; } - inputValidation->setNumberOfTestParticles(singleTone, numberOfTestParticles); + inputValidation->setNumberOfTestParticles(singleTone, config.numberOfTestParticles); } - if (*vset) - { - if (!inputValidation->checkV(newV)) - { + if (*vset) { + if (!inputValidation->checkV(config.newV)) { spdlog::error("V is out of range!(100-1500 km/s)"); - return -1; + return ParseState::ERROR; } - inputValidation->setV(singleTone, newV); + inputValidation->setV(singleTone, config.newV); } - return 1; -} - -int ParseParams::processModelOptions(const std::string& customModelString, const std::string& inputFile) -{ - if (*forwardModel) - { + // Process model options + if (*forwardModel) { singleTone->putString("model", "1D Fp"); - } - else if (*backwardModel) - { + } else if (*backwardModel) { singleTone->putString("model", "1D Bp"); - } - else if (*solarPropLikeModel) - { + } else if (*solarPropLikeModel) { singleTone->putString("model", "2D SolarProp-like"); - } - else if (*geliosphereModel) - { + } else if (*geliosphereModel) { singleTone->putString("model", "2D Geliosphere"); - } - else if (*customModel) - { - singleTone->putString("model", customModelString); - } - else if (*batchRun) - { + } else if (*customModel) { + singleTone->putString("model", config.customModelString); + } else if (*batchRun) { singleTone->putString("model", "batch run"); - singleTone->putString("inputBatchFile", inputFile); - return 1; // Special case - batch run returns early + singleTone->putString("inputBatchFile", config.inputFile); + return ParseState::COMPLETE; // Special case - batch run returns early } - return 1; -} - -int ParseParams::processSettingsOptions(const std::string& settings, int month, int year, - const std::string& currentApplicationPath) -{ - InputValidation *inputValidation = new InputValidation(); - - if (*settingsOption) - { - inputValidation->newSettingsLocationCheck(singleTone, settings); - } - else - { - if (access(settings.c_str(), F_OK) == 0) { - TomlSettings *tomlSettings = new TomlSettings(currentApplicationPath + "Settings.toml"); + // Process settings options + if (*settingsOption) { + inputValidation->newSettingsLocationCheck(singleTone, config.settings); + } else { + if (access(config.settings.c_str(), F_OK) == 0) { + TomlSettings *tomlSettings = new TomlSettings(config.currentApplicationPath + "Settings.toml"); tomlSettings->parseFromSettings(singleTone); } else { spdlog::warn("No settings file exists on default path."); } } - if (*monthOption && *yearOption) - { - inputValidation->monthYearCheck(singleTone, year, month, currentApplicationPath); + if (*monthOption && *yearOption) { + inputValidation->monthYearCheck(singleTone, config.year, config.month, config.currentApplicationPath); } - return 1; + return ParseState::COMPLETE; +} +void ParseParams::setupCliOptions(CLI::App& app, ParseConfig& config) +{ + forwardModel = app.add_flag("-F,--forward", "Run a 1D forward-in-time model")->group("models"); + backwardModel = app.add_flag("-B,--backward", "Run a 1D backward-in-time model")->group("models"); + solarPropLikeModel = app.add_flag("-E,--solarprop-like-model", "Run a SolarProp-like 2D backward model")->group("models"); + geliosphereModel = app.add_flag("-T,--geliosphere-2d-model", "Run a Geliosphere 2D backward model")->group("models"); + csv = app.add_flag("-c,--csv", "Output will be in .csv"); + run_simulation = app.add_option("--evaluation", config.pathToLogFile, "Simulation excluded, run only evaluation "); +#if GPU_ENABLED == 1 + cpuOnly = app.add_flag("--cpu-only", "Use only CPU for calculaions"); +#else + singleTone->putInt("isCpu", 1); +#endif + batchRun = app.add_option("-b,--batchrun", config.inputFile, "Input batch file")->group("models"); + dtset = app.add_option("-d,--dt", config.newDt, "Set dt to new value(s)"); + kset = app.add_option("-K,--K0", config.newK0, "Set K to new value(cm^2/s)"); + vset = app.add_option("-V,--V", config.newV, "Set V to new value(km/s)"); + destination = app.add_option("-p,--path", config.newDestination, "Set destination folder name"); + setNumberOfTestParticles = app.add_option("-N,--number-of-test-particles", config.numberOfTestParticles, "Set number of test particles in millions(round up due to GPU execution)"); + monthOption = app.add_option("-m,--month", config.month, "Set month for using meassured values"); + yearOption = app.add_option("-y,--year", config.year, "Set year for using meassured values"); + settingsOption = app.add_option("-s,--settings", config.settings, "Path to .toml file"); + customModel = app.add_option("--custom-model", config.customModelString, "Run custom user-implemented model."); +} + +void ParseParams::setupOptionRelationships() +{ + kset->excludes(monthOption, yearOption); + vset->excludes(monthOption, yearOption); + + backwardModel->excludes(forwardModel, solarPropLikeModel, geliosphereModel, customModel, batchRun); + forwardModel->excludes(backwardModel, solarPropLikeModel, geliosphereModel, customModel, batchRun); + solarPropLikeModel->excludes(backwardModel, forwardModel, geliosphereModel, customModel, batchRun); + geliosphereModel->excludes(backwardModel, forwardModel, solarPropLikeModel, customModel, batchRun); + customModel->excludes(backwardModel, forwardModel, solarPropLikeModel, geliosphereModel, batchRun); + batchRun->excludes(backwardModel, forwardModel, solarPropLikeModel, geliosphereModel, customModel, + dtset, setNumberOfTestParticles, kset, vset, monthOption, yearOption); + + monthOption->requires(yearOption); } \ No newline at end of file