diff --git a/analysis/PWGDIL/dielectron/papaframework/PairAnalysisPairKF.cxx b/analysis/PWGDIL/dielectron/papaframework/PairAnalysisPairKF.cxx index 0579a77557a668208b9f8b039f6c7264788d1c3c..e79f053bf31d21d9f5e94f7b676dcf764ed4d40b 100644 --- a/analysis/PWGDIL/dielectron/papaframework/PairAnalysisPairKF.cxx +++ b/analysis/PWGDIL/dielectron/papaframework/PairAnalysisPairKF.cxx @@ -21,6 +21,8 @@ #include "PairAnalysisMC.h" #include "PairAnalysisTrack.h" +#include <TDatabasePDG.h> + ClassImp(PairAnalysisPairKF) PairAnalysisPairKF::PairAnalysisPairKF() diff --git a/macro/qa/run_ctest_commit.sh b/macro/qa/run_ctest_commit.sh new file mode 100755 index 0000000000000000000000000000000000000000..5cf5f3bea65e24067c4bb87fff129f922394eb47 --- /dev/null +++ b/macro/qa/run_ctest_commit.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +run_comparison() { + local commit=$1 + local short_com1=$(echo "$1"| cut -c1-9) + local BUILD_DIR=$2 + local CURRENT_DIR=$3 + output_file1="${CURRENT_DIR}/s100m3_qa_ts_eb_real_${short_com1}.qa.root" + output_file2="${BUILD_DIR}/macro/run/data/s100m3_qa_ts_eb_real_${short_com1}.qa.root" + if [ -f "$output_file1" ]; then + echo "File ${output_file1} exist" + return 0 + elif [ -f "$output_file2" ]; then + echo "File ${output_file2} exist" + cp ${output_file2} ${output_file1} + return 0 + fi + cd ${VMCWORKDIR} + echo "Checking out commit: $commit" + git checkout $commit || { echo "Failed to checkout $commit"; exit 1; } + echo "Installing CBMRoot..." + ./autoinstall_framework.sh --use_fairsoft /cvmfs/fairsoft.gsi.de/debian10/fairsoft/nov22p3 --use_fairroot /cvmfs/fairsoft.gsi.de/debian10/fairroot/v18.8.0_nov22p3 -cr || { echo "Installation failed"; exit 1; } + #./install_cbmroot.sh || { echo "Installation failed"; exit 1; } + + echo "Running Ctest" + cd ${BUILD_DIR} + ctest -R run_s100m3_qa_ts_eb_real + cd ${BUILD_DIR}/macro/run/data + cp s100m3_qa_ts_eb_real.qa.root ${CURRENT_DIR}/s100m3_qa_ts_eb_real_${short_com1}.qa.root + cd ${VMCWORKDIR} +} + +# Initialize variables + +# Save the current branch +current_branch=$(git rev-parse --abbrev-ref HEAD) + + +WORK_DIR=${VMCWORKDIR} + +BUILD_DIR=${VMCWORKDIR}/../cbmroot_build/ + +commits=() + +CURRENT_DIR="" + +# Parse command-line arguments +while [[ $# -gt 0 ]]; do + case ${1} in + --build_dir) + BUILD_DIR=${2} + shift 2 + ;; + --current_dir) + CURRENT_DIR=${2} + shift 2 + ;; + *) + commits+=("${1}") + shift + ;; + esac +done +if [[ ! -d "${BUILD_DIR}" ]]; then + BUILD_DIR="${VMCWORKDIR}/build" + if [[ ! -d "${BUILD_DIR}" ]]; then + printf "E- cbmroot_build directory was not found. Please:\n" + printf " - provide the build directory in the command line" + exit 2 + + fi +fi + + +# Loop through all commits and run the comparison +for commit in "${commits[@]}"; do + echo "Processing commit: $commit" + run_comparison "${commit}" "${BUILD_DIR}" "${CURRENT_DIR}" +done + +# Get the final branch you want to checkout +desired_branch=$(git rev-parse --abbrev-ref HEAD) + +# Check if the current branch is the same as the desired branch +if [ "$current_branch" != "$desired_branch" ]; then + echo "Checking out the original branch: $desired_branch" + git checkout $desired_branch || { echo "Failed to checkout $desired_branch"; exit 1; } + ./autoinstall_framework.sh --use_fairsoft /cvmfs/fairsoft.gsi.de/debian10/fairsoft/nov22p3 --use_fairroot /cvmfs/fairsoft.gsi.de/debian10/fairroot/v18.8.0_nov22p3 -cr || { echo "Installation failed"; exit 1; } + #./install_cbmroot.sh || { echo "Installation failed"; exit 1; } +else + echo "Already on the initial branch: $current_branch. Skipping checkout and installation." +fi diff --git a/services/CMakeLists.txt b/services/CMakeLists.txt index db898cd633680625740e2be7b8ded8b6acc49907..23b962b62fc452ba06044875304f2256da95b533 100644 --- a/services/CMakeLists.txt +++ b/services/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(histserv) add_subdirectory(online_par_dump) add_subdirectory(tsa_dump) add_subdirectory(run_info) +add_subdirectory(qa) diff --git a/services/qa/Application.cxx b/services/qa/Application.cxx new file mode 100644 index 0000000000000000000000000000000000000000..98c0b94a9b4e3efb7499dc206d9a477e9fc8201d --- /dev/null +++ b/services/qa/Application.cxx @@ -0,0 +1,144 @@ +/* Copyright (C) 2025 GSI/VECC, Darmstadt/Kolkata + SPDX-License-Identifier: GPL-3.0-only + Authors: Souvik Chattopadhyay[committer], Sergei Zharko */ + + +#include "Application.h" + +#include <iostream> +#include <map> +#include <memory> +#include <sstream> + +#include <limits.h> // for PATH_MAX +#include <unistd.h> // for getcwd() + +/** @brief Helper: get current working directory without filesystem **/ +std::string getCurrentDir() +{ + char buffer[PATH_MAX]; + if (getcwd(buffer, sizeof(buffer)) != nullptr) { + return std::string(buffer); + } + else { + perror("getcwd() error"); + return ""; + } +} + +/** @brief Constructor: Initializes the application with program options **/ +Application::Application(ApplicationParameter const& opt) +{ + std::string compareType = opt.getCompare(); + std::vector<std::string> names = opt.getNames(); + + configFileName = opt.getConfig(); + outputFileName = opt.getOutput(); + + ConfigEditor config(configFileName); + + if (compareType == "commit") { + citest(names, opt.getbuilddir()); + addVersionCommit(config, names); + config.SetDatasets({"default"}); + std::string currentDir = getCurrentDir(); + addFile(config, currentDir + "/%v.root", "qa_commit", {}); + } + + + else if (compareType == "weeklyTest") { + addVersionWeeklyTest(config, names); + config.SetDatasets({"default"}); + addFile(config, "%v.root", "qa_weekly", {}); + } + + else { + std::cerr << "Unknown compare type: " << compareType << std::endl; + } + + config.SaveConfig(opt.getConfig()); + exec("E"); +} + +/** @brief Adds commit versions to the configuration **/ +void Application::addVersionCommit(ConfigEditor& config, const std::vector<std::string>& names) +{ + std::map<std::string, std::string> versions; + for (const std::string& name : names) { + std::string label = name.substr(0, 9); + std::string path = "s100m3_qa_ts_eb_real_" + label + ".qa"; + versions[label] = path; + } + config.SetVersions(versions); +} + +/** @brief Adds weekly test versions to the configuration **/ +void Application::addVersionWeeklyTest(ConfigEditor& config, const std::vector<std::string>& names) +{ + std::map<std::string, std::string> versions; + for (const std::string& name : names) { + std::string path = + "/lustre/cbm/users/ploizeau/cdash/weekly_virgo3_vae23_dev_" + name + "/macro/run/data/s100h_qa_ts_eb_ideal.qa"; + versions[name] = path; + } + config.SetVersions(versions); +} + +/** @brief Adds a file with specified format and label **/ +void Application::addFile(ConfigEditor& config, std::string fileformat, std::string labelformat, + const std::vector<std::string>& objects) +{ + std::vector<std::tuple<std::string, std::string, std::vector<std::string>>> files; + files.emplace_back(fileformat, labelformat, objects); + config.SetFiles(files); +} + +/** @brief Run shell script for CI test with different commit **/ +void Application::citest(const std::vector<std::string>& names, std::string builddir) +{ + std::ostringstream cmd; + const char* vmworkdir = getenv("VMWORKDIR"); + if (vmworkdir != nullptr) { + + cmd << vmworkdir << "/macro/qa/run_ctest_commit.sh"; + //int ret = system(cmd.str().c_str()); + + + //cmd << "${VMWORKDIR}/macro/qa/run_ctest_commit.sh"; + + for (const auto& name : names) { + cmd << " " << name; + } + + if (!builddir.empty()) { + cmd << " --build_dir " << builddir; + } + + // Add current directory + std::string currentDir = getCurrentDir(); + cmd << " --current_dir " << currentDir; + + std::string finalCmd = cmd.str(); + std::cout << "Executing: " << finalCmd << std::endl; + + int ret = system(finalCmd.c_str()); + + if (ret != 0) { + std::cerr << "Script failed with return code: " << ret << std::endl; + return; + } + } + else { + std::cerr << "VMWORKDIR not set in environment!" << std::endl; + return; + } +} + +/** @brief Executes the comparison routine with an optional parameter **/ +void Application::exec(Option_t* option) +{ + auto pChecker = std::make_unique<cbm::qa::checker::Core>(); + pChecker->RegisterOutFile(outputFileName.c_str()); + pChecker->SetFromYAML(configFileName.c_str()); + pChecker->Process(option); +} diff --git a/services/qa/Application.h b/services/qa/Application.h new file mode 100644 index 0000000000000000000000000000000000000000..82a3dd48a687e64a0fa82b2e17f543b05e2e08c6 --- /dev/null +++ b/services/qa/Application.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2025 GSI/VECC, Darmstadt/Kolkata + SPDX-License-Identifier: GPL-3.0-only + Authors: Souvik Chattopadhyay[committer], Sergei Zharko */ + + +#ifndef APPLICATION_H +#define APPLICATION_H + +#include "ApplicationParameter.h" +#include "CbmQaCheckerCore.h" +#include "ConfigEditor.h" + +#include <map> +#include <memory> // For std::unique_ptr +#include <string> +#include <vector> + +class Application { + public: + /** @brief Constructor: Initializes the application with program options **/ + explicit Application(ApplicationParameter const& opt); + + /** @brief Executes the comparison routine with an optional parameter **/ + void exec(Option_t* option = "E"); + + private: + /** @brief Adds commit versions to the configuration **/ + void addVersionCommit(ConfigEditor& config, const std::vector<std::string>& names); + + /** @brief Adds weekly test versions to the configuration **/ + void addVersionWeeklyTest(ConfigEditor& config, const std::vector<std::string>& names); + + /** @brief Adds a file with specified format and label to the configaration **/ + void addFile(ConfigEditor& config, std::string fileformat, std::string labelformat, + const std::vector<std::string>& objects); + + + void citest(const std::vector<std::string>& names, std::string builddir = ""); + + + /** @brief Unique pointer to Checker **/ + // std::unique_ptr<cbm::qa::checker::Core> pChecker; + + + std::string configFileName; + std::string outputFileName; +}; + +#endif // APPLICATION_H diff --git a/services/qa/ApplicationParameter.cxx b/services/qa/ApplicationParameter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..eb5f2fc05a3acd9b0f631c86fa3a37b903947976 --- /dev/null +++ b/services/qa/ApplicationParameter.cxx @@ -0,0 +1,63 @@ +/* Copyright (C) 2025 GSI/VECC, Darmstadt/Kolkata + SPDX-License-Identifier: GPL-3.0-only + Authors: Souvik Chattopadhyay[committer], Sergei Zharko */ + + +#include "ApplicationParameter.h" + +#include <iostream> + +namespace po = boost::program_options; + +/** @brief Constructor: Parses command-line arguments **/ +ApplicationParameter::ApplicationParameter(int argc, char* argv[]) { parseCommandLine(argc, argv); } + +/** @brief Parses command-line arguments **/ +void ApplicationParameter::parseCommandLine(int argc, char* argv[]) +{ + try { + // Define command-line options + po::options_description desc("Allowed options"); + desc.add_options()("help,h", "Display help message")( + "compare,t", po::value<std::string>(&fcompare)->required()->value_name("commit"), + "Specify comparison type (only 'commit' or 'weeklyTest' are allowed)")( + "names,n", po::value<std::vector<std::string>>(&fnames)->multitoken()->value_name("<name1 name2 ...>"), + "List of commit hash or week numbers(yyyy_ww)")( + "output,o", po::value<std::string>(&foutput)->default_value("./output_compare_qa.root"), + "Specify output file name")("config,c", po::value<std::string>(&fconfig)->default_value("./objects.yaml"), + "Specify config file")( + "builddir,b", po::value<std::string>(&fbuilddir)->default_value(""), "Specify cbmroot build directory"); + + // Parse command-line arguments + po::variables_map vars; + po::store(po::parse_command_line(argc, argv, desc), vars); + + // Handle help request + if (vars.count("help")) { + std::cout << desc << std::endl; + exit(EXIT_SUCCESS); + } + + // Apply required options + po::notify(vars); + + // Validate "--compare" option (only "commit" or "weeklyTest" allowed) + if ((fcompare != "commit") && (fcompare != "weeklyTest")) { + throw po::validation_error(po::validation_error::invalid_option_value, "compare", fcompare); + } + } + catch (const po::error& e) { + std::cerr << "Error: " << e.what() << std::endl; + exit(EXIT_FAILURE); + } +} + +/** @brief Getters for parsed options **/ +std::string ApplicationParameter::getCompare() const { return fcompare; } + +std::vector<std::string> ApplicationParameter::getNames() const { return fnames; } + +std::string ApplicationParameter::getOutput() const { return foutput; } + +std::string ApplicationParameter::getConfig() const { return fconfig; } +std::string ApplicationParameter::getbuilddir() const { return fbuilddir; } diff --git a/services/qa/ApplicationParameter.h b/services/qa/ApplicationParameter.h new file mode 100644 index 0000000000000000000000000000000000000000..44011e10725de02f553e7ebab46dbdcd075f12a4 --- /dev/null +++ b/services/qa/ApplicationParameter.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2025 GSI/VECC, Darmstadt/Kolkata + SPDX-License-Identifier: GPL-3.0-only + Authors: Souvik Chattopadhyay[committer], Sergei Zharko */ + + +#ifndef APPLICATION_PARAMETER_H +#define APPLICATION_PARAMETER_H + +#include <boost/program_options.hpp> + +#include <string> +#include <vector> + +class ApplicationParameter { + public: + /** @brief Constructor: Parses command-line arguments **/ + ApplicationParameter(int argc, char* argv[]); + + + /** @brief Default copy constructor **/ + ApplicationParameter(const ApplicationParameter&) = default; + + /** @brief Default assignment operator **/ + ApplicationParameter& operator=(const ApplicationParameter&) = default; + + /** @brief Getters for parsed options **/ + std::string getCompare() const; + std::vector<std::string> getNames() const; + std::string getOutput() const; + std::string getConfig() const; + std::string getbuilddir() const; + + private: + /** @brief Parses command-line arguments **/ + void parseCommandLine(int argc, char* argv[]); + + // Variables to store parsed command-line arguments + std::string fcompare; + std::vector<std::string> fnames; + std::string foutput; + std::string fconfig; + std::string fbuilddir; +}; + +#endif // APPLICATION_PARAMETER_H diff --git a/services/qa/CMakeLists.txt b/services/qa/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3fd0fd99182ee8e0d747a7c781dbd01fc27aca70 --- /dev/null +++ b/services/qa/CMakeLists.txt @@ -0,0 +1,38 @@ +set(INCLUDE_DIRECTORIES + ${INCLUDE_DIRECTORIES} + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/core/qa + ) +# Source files +set(SRCS + main.cxx + Application.cxx + ConfigEditor.cxx + ApplicationParameter.cxx +) + +# Header files +set(HEADERS + Application.h + ConfigEditor.h + ApplicationParameter.h +) + +set(INCLUDE_DIRECTORIES + ${INCLUDE_DIRECTORIES} + ${CBMROOT_SOURCE_DIR} + ) + + + +add_executable(qachecker ${SRCS} ${HEADERS}) + +target_link_libraries(qachecker + PUBLIC + CbmQaBase + PRIVATE + Boost::program_options + FairLogger::FairLogger + external::yaml-cpp +) +install(TARGETS qachecker DESTINATION bin) diff --git a/services/qa/ConfigEditor.cxx b/services/qa/ConfigEditor.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1a5ff91913dfa4b3e30ef8369d59b730464d00bf --- /dev/null +++ b/services/qa/ConfigEditor.cxx @@ -0,0 +1,100 @@ +/* Copyright (C) 2025 GSI/VECC, Darmstadt/Kolkata + SPDX-License-Identifier: GPL-3.0-only + Authors: Souvik Chattopadhyay[committer], Sergei Zharko */ + +#include "ConfigEditor.h" + +#include <fstream> +#include <iostream> +/** @brief Constructor: Loads the YAML file **/ +ConfigEditor::ConfigEditor(const std::string& configFile) +{ + if (std::ifstream(configFile)) { + LoadConfig(configFile); + } + else { + SetDefault(); + } +} + +/** @brief Load YAML configuration **/ +void ConfigEditor::LoadConfig(const std::string& configFile) +{ + try { + yamlData = YAML::LoadFile(configFile); + } + catch (const std::exception& e) { + std::cerr << "Error loading YAML file: " << e.what() << std::endl; + } +} +/** @brief default YAML configuration **/ + +void ConfigEditor::SetDefault() +{ + + yamlData["checker"]["settings"]["ratio_min"] = 0.90; + yamlData["checker"]["settings"]["ratio_max"] = 1.10; + yamlData["checker"]["settings"]["pval_threshold"] = 0.01; +} + + +/** @brief Set new versions **/ +void ConfigEditor::SetVersions(const std::map<std::string, std::string>& newVersions) +{ + yamlData["checker"]["versions"] = YAML::Node(YAML::NodeType::Sequence); + for (const auto& [label, path] : newVersions) { + YAML::Node versionNode; + versionNode["label"] = label; + versionNode["path"] = path; + yamlData["checker"]["versions"].push_back(versionNode); + } +} + +/** @brief Set new dataset names **/ +void ConfigEditor::SetDatasets(const std::vector<std::string>& newDatasets) +{ + yamlData["checker"]["datasets"] = YAML::Node(YAML::NodeType::Sequence); + for (const auto& dataset : newDatasets) { + yamlData["checker"]["datasets"].push_back(dataset); + } +} + +/** @brief Set new files with labels **/ +void ConfigEditor::SetFiles(const std::vector<std::tuple<std::string, std::string, std::vector<std::string>>>& newFiles) +{ + yamlData["checker"]["files"] = YAML::Node(YAML::NodeType::Sequence); + for (const auto& [name, label, objects] : newFiles) { + YAML::Node fileNode; + fileNode["name"] = name; + fileNode["label"] = label; // Always add the label + + // Only add "objects" node if the objects vector is non-empty + if (!objects.empty()) { + YAML::Node objectsNode(YAML::NodeType::Sequence); + for (const auto& obj : objects) { + objectsNode.push_back(obj); + } + fileNode["objects"] = objectsNode; + } + + yamlData["checker"]["files"].push_back(fileNode); + } +} + +/** @brief Save the modified YAML file **/ +void ConfigEditor::SaveConfig(const std::string& configFile) const +{ + if (!configFile.empty() && yamlData.IsDefined()) { + std::ofstream outFile(configFile); + if (outFile.is_open()) { + outFile << yamlData; + outFile.close(); + } + else { + std::cerr << "Error: Unable to open file for saving!" << std::endl; + } + } + else { + std::cerr << "Error: No config file specified or YAML data is empty!" << std::endl; + } +} diff --git a/services/qa/ConfigEditor.h b/services/qa/ConfigEditor.h new file mode 100644 index 0000000000000000000000000000000000000000..204a4647dcfe4863be0d7473bf1a6dcb5210485b --- /dev/null +++ b/services/qa/ConfigEditor.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2025 GSI/VECC, Darmstadt/Kolkata + SPDX-License-Identifier: GPL-3.0-only + Authors: Souvik Chattopadhyay[committer], Sergei Zharko */ + + +#ifndef CONFIG_EDITOR_H +#define CONFIG_EDITOR_H + +#include <map> +#include <string> +#include <vector> + +#include <yaml-cpp/yaml.h> + +class ConfigEditor { + public: + /** @brief Constructor **/ + explicit ConfigEditor(const std::string& configFile = ""); + + /** @brief Load YAML configuration **/ + void LoadConfig(const std::string& configFile); + + /** @brief Load default configuration **/ + void SetDefault(); + + /** @brief Set and update version information **/ + void SetVersions(const std::map<std::string, std::string>& newVersions); + + /** @brief Set and update dataset names **/ + void SetDatasets(const std::vector<std::string>& newDatasets); + + /** @brief Set and update files **/ + void SetFiles(const std::vector<std::tuple<std::string, std::string, std::vector<std::string>>>& newFiles); + + /** @brief Save the modified YAML configuration **/ + void SaveConfig(const std::string& configFile) const; + + private: + YAML::Node yamlData; // Stores the configuration data +}; + +#endif // CONFIG_EDITOR_H diff --git a/services/qa/main.cxx b/services/qa/main.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c65618d5c7a91eeed195eb613bebab9eab5faec0 --- /dev/null +++ b/services/qa/main.cxx @@ -0,0 +1,29 @@ +/* Copyright (C) 2025 GSI/VECC, Darmstadt/Kolkata + SPDX-License-Identifier: GPL-3.0-only + Authors: Souvik Chattopadhyay[committer], Sergei Zharko */ + +#include "Application.h" +#include "ApplicationParameter.h" + +#include <iostream> + +int main(int argc, char* argv[]) +{ + try { + // Parse command-line arguments + ApplicationParameter opt(argc, argv); + + // Create the Application instance + Application app(opt); + + // Execute the comparison process with a default option + //app.exec("E"); + + // Return the process result + //return result; + } + catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return EXIT_FAILURE; + } +}