diff --git a/core/config/CbmConfigBase.h b/core/config/CbmConfigBase.h new file mode 100644 index 0000000000000000000000000000000000000000..7129c88e6779e961f563d50beaeaf42c29604aa2 --- /dev/null +++ b/core/config/CbmConfigBase.h @@ -0,0 +1,154 @@ +#pragma once + +#include "CbmDefs.h" + +#include <FairLogger.h> + +#include <TSystem.h> + +#include <boost/property_tree/json_parser.hpp> + +#include <cassert> +#include <iostream> +#include <map> +#include <regex> + +namespace pt = boost::property_tree; + +template<class Config_t, class Obj_t> +class CbmConfigBase { +private: +public: + using TagSet_t = std::set<std::string>; + + virtual ~CbmConfigBase() = default; + + static bool Load(Obj_t& obj, const std::string& path) + { + pt::ptree tree; + LoadFromFile(path, tree); + if (!Load(obj, tree)) return false; + return true; + } + + static bool Load(Obj_t& obj, const pt::ptree& tree) + { + SetLogLevel(tree); + auto moduleTree {tree.get_child_optional(Config_t::GetModuleTag())}; + if (!moduleTree) { + LOG(error) << "CbmConfig: module tag is not correct!\n"; + return false; + } + if (!Validate(moduleTree.get())) return false; + if (!Config_t::LoadImpl(obj, moduleTree.get())) return false; + return true; + } + + static void LoadFromFile(const std::string& path, pt::ptree& tree) + { + std::string absPath = path; + if (absPath.at(0) != '/') absPath = gSystem->GetWorkingDirectory() + "/" + path; + LOG(info) << "CbmConfig: loading config from file: " << absPath << std::endl; + pt::read_json(path, tree); + } + + static bool Validate(const pt::ptree& tree) + { + const auto validationSet {Config_t::GetValidationTags()}; + TagSet_t treeSet; + ParseTree(tree, "", treeSet); + + std::vector<std::string> diff; + std::set_difference(treeSet.begin(), treeSet.end(), validationSet.begin(), validationSet.end(), + std::inserter(diff, diff.begin())); + + if (!diff.empty()) { + LOG(error) << "CbmConfig: Invalid tags: "; + for (auto s : diff) + std::cout << s << ", "; + std::cout << std::endl; + PrintAvailableTags(); + return false; + } + return true; + } + + static void ParseTree(const pt::ptree& pt, std::string key, TagSet_t& treeSet) + { + std::string nkey; + + if (!key.empty()) { + nkey = key; + if (nkey.back() != '.') nkey += "."; + LOG(debug) << "CbmConfig: key: " << key << "\tnkey: " << nkey; + } + + if (pt.empty() /* && !pt.data().empty()*/) { + if (key.back() == '.') key.pop_back(); + LOG(debug) << "CbmConfig: Insert: " << key; + if (key.find("#") > key.size()) //used for comments + treeSet.insert(key); + } + + for (auto node : pt) { + LOG(debug) << "CbmConfig: Try: " << nkey + node.first; + ParseTree(node.second, nkey + node.first, treeSet); + } + } + + static void PrintAvailableTags() + { + auto tags = Config_t::GetValidationTags(); + std::cout << "\nAvailable config tags:\n"; + for (auto& tag : tags) + std::cout << tag << std::endl; + } + + static ECbmModuleId stringToECbmModuleId(std::string s) + { + std::map<std::string, ECbmModuleId> stringToModuleId = { + {"cave", ECbmModuleId::kCave}, {"magnet", ECbmModuleId::kMagnet}, {"pipe", ECbmModuleId::kPipe}, + {"target", ECbmModuleId::kTarget}, {"mvd", ECbmModuleId::kMvd}, {"sts", ECbmModuleId::kSts}, + {"rich", ECbmModuleId::kRich}, {"much", ECbmModuleId::kMuch}, {"trd", ECbmModuleId::kTrd}, + {"tof", ECbmModuleId::kTof}, {"psd", ECbmModuleId::kPsd}, {"hodo", ECbmModuleId::kHodo}, + {"shield", ECbmModuleId::kShield}, {"platform", ECbmModuleId::kPlatform}}; + if (stringToModuleId.find(s) == stringToModuleId.end()) { + LOG(error) << "CbmConfig: detector subsystem not recognized: " << s; + std::cout << "list of available detector subsystems:\n"; + for (auto& p : stringToModuleId) + std::cout << p.first << std::endl; + assert(0); + return ECbmModuleId::kNotExist; + } + else + return stringToModuleId.at(s); + } + + static std::string GetStringValue(boost::optional<std::string> opt) { return ParseString(opt.get()); } + + static std::string GetStringValue(pt::ptree tree, std::string key, std::string fallback) + { + return ParseString(tree.get<std::string>(key, fallback)); + } + + static std::string ParseString(std::string s) + { + std::regex rgx("\\$\\{?\\w+\\}?"); + std::smatch match; + while (s.find("$") < s.size()) { + std::regex_search(s, match, rgx); + std::string varString = match[0]; + std::string varName = std::regex_replace(varString, std::regex("\\$|\\{|\\}"), ""); + s.replace(s.find(varString), varString.size(), gSystem->Getenv(varName.c_str())); + } + return s; + } + + static void SetLogLevel(const pt::ptree& moduleTree) + { + auto logScreenLevel = moduleTree.get_optional<std::string>("logScreenLevel"); + if (logScreenLevel) FairLogger::GetLogger()->SetLogScreenLevel(logScreenLevel.get().c_str()); + auto logVerbosityLevel = moduleTree.get_optional<std::string>("logVerbosityLevel"); + if (logVerbosityLevel) FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosityLevel.get().c_str()); + } +}; diff --git a/macro/run/CMakeLists.txt b/macro/run/CMakeLists.txt index 26f834b8880e5a070ba7dd1d6a2c29eb56023434..6877a0887318bde5cbb71f9a175cd075c76776cc 100644 --- a/macro/run/CMakeLists.txt +++ b/macro/run/CMakeLists.txt @@ -1,5 +1,7 @@ # ===== Generate the needed shell scripts ================================ GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_tra_file.C) +GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_transport_json_config.C) +GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_digi_json_config.C) GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_tra_beam.C) GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_digi.C) GENERATE_ROOT_TEST_SCRIPT(${CBMROOT_SOURCE_DIR}/macro/run/run_reco.C) @@ -108,6 +110,30 @@ foreach(setup IN LISTS cbm_setup) RESOURCE_LOCK beamParDb_${setup} ) + # --- Test run_transport_json_config + # --- Transport run using run_transport_json_config.C + set(testname run_transport_json_config) + add_test(${testname} ${MACRO_DIR}/run_transport_json_config.sh) + set_tests_properties(${testname} PROPERTIES + TIMEOUT ${timeOutTime} + PASS_REGULAR_EXPRESSION "Macro finished successfully" + FIXTURES_REQUIRED cleanup + FIXTURES_SETUP fixt_digi_json_config + RESOURCE_LOCK json_config_ParDb + ) + + # --- Test run_digi_json_config + # --- Digitization run with using run_digi_json_config.C + set(testname run_digi_json_config) + add_test(${testname} ${MACRO_DIR}/run_digi_json_config.sh) + set_tests_properties(${testname} PROPERTIES + TIMEOUT ${timeOutTime} + PASS_REGULAR_EXPRESSION "Macro finished successfully" + FIXTURES_REQUIRED fixt_digi_json_config + FIXTURES_SETUP fixt_reco_json_config + RESOURCE_LOCK json_config_ParDb + ) + # --- Test run_digi_ev # --- Detector response simulation, event-by-event, using run_digi.C set(testname run_${sname}_digi_ev) @@ -209,7 +235,7 @@ endforeach(setup IN LISTS cbm_setup) -Install(FILES .rootrc run_transport.C run_digi.C run_reco_event.C check_overlaps.C +Install(FILES .rootrc run_transport.C run_transport_json_config.C run_digi_json_config.C config.json run_digi.C run_reco_event.C check_overlaps.C DESTINATION share/cbmroot/macro/run ) Install(DIRECTORY modules DESTINATION share/cbmroot/macro/run) diff --git a/macro/run/config.json b/macro/run/config.json new file mode 100644 index 0000000000000000000000000000000000000000..136720decf09e25bee97698bb8384c6e1b8b9fb2 --- /dev/null +++ b/macro/run/config.json @@ -0,0 +1,109 @@ +{ + "logScreenLevel": "INFO", + "logVerbosityLevel": "LOW", + "transport": { + "input": [ + {"generator": "unigen", + "file": "${VMCWORKDIR}/input/urqmd.auau.10gev.centr.root"}, + {"generator": "pluto", + "file": "${VMCWORKDIR}/input/pluto.auau.8gev.omega.mpmm.0001.root", + "plutoPdg": 0}, + {"generator": "beam", + "beamA": 197, + "beamZ": 79, + "beamQ": 79, + "beamP": 12.0, + "beamStartZ": -1.0} + ], + "output.path": "", + "target": { + "material": "Gold", + "thickness": 0.025, + "diameter": 2.5, + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "rotation.y": 0.0 + }, + "beam": { + "position": { + "x": 0.0, + "y": 0.0, + "z": 0.0, + "sigmaX": 0.1, + "sigmaY": 0.1 + }, + "angle": { + "x": 0.0, + "y": 0.0, + "sigmaX": 0.001, + "sigmaY": 0.001 + } + }, + "randomRP": true, + "geantVersion": 4, + "geant4vmcSettings": { + "physicsLists": "QGSP_BERT_EMV+optical", + "specialProcesses": "stepLimiter", + "maxNsteps": 10000000, + "geant4commands": [""] + }, + "geometry": { + "baseSetup": "sis100_electron", + "magneticField": { + "tag": "v18a", + "scale": 1.0, + "position": { + "x": 0.0, + "y": 0.0, + "z": 40.0 + } + }, + "subsystems": { + "magnet": "v20a", + "pipe": "v16b_1e", + "mvd": "v20c_tr", + "sts": "v19a", + "rich": "v17a_1e", + "trd": "v20b_1e", + "tof": "v20a_1e", + "psd": "v20a", + "platform": "v13a" + } + } + }, + + "digitization": { + "generateRunInfo": false, + "eventMode": false, + "timeSliceLength": -1.0, + "storeAllTimeSlices": false, + "startTime": 1000, + "produceNoise": true, + "input": [ + {"id": 0, + "path": "test", + "rate": "1.e7", + "treeAccessMode": "regular", + "parameterSource": true}, + {"id": -1, + "path": "test_emb", + "embedToId": 0, + "treeAccessMode": "regular"}, + {"id": -1, + "path": "test_beam", + "rate": "1.e9", + "treeAccessMode": "random"} + ], + "output": { + "path": "test", + "overwrite": false + }, + "geometry": { + "deactivate": ["", ""], + "#deactivateAllBut": "" + } + } +} diff --git a/macro/run/run_digi_json_config.C b/macro/run/run_digi_json_config.C new file mode 100644 index 0000000000000000000000000000000000000000..df7ab5b6df25e16ea26a4480bc9440be4d90f3b2 --- /dev/null +++ b/macro/run/run_digi_json_config.C @@ -0,0 +1,58 @@ +/** @file run_digi_json_config.C + ** @author Oleg Golosov <oleg.golosov@gmail.com> + ** @since 31 March 2020 + **/ + +// Includes needed for IDE +#if !defined(__CLING__) +#include "CbmDigitization.h" + +#include "FairSystemInfo.h" + +#include "TStopwatch.h" +#endif + + +/** @brief Macro for detector response simulation in CBM + ** @author Oleg Golosov <oleg.golosov@gmail.com> + ** @since 31 March 2021 + ** @param config Name of config file + ** @param nEvents Number of events to process + ** + ** This macro performs the detector response simulation + ** for multiple transport files using test-based config. + ** Additions to the CbmDigitization settings can be made after + ** the main config is applied. + **/ + +void run_digi_json_config(std::string config = "", int nEvents = 2) +{ + if (config == "") config = Form("%s/macro/run/config.json", gSystem->Getenv("VMCWORKDIR")); + + // ----- Timer -------------------------------------------------------- + TStopwatch timer; + timer.Start(); + // ------------------------------------------------------------------------ + + CbmDigitization run; + if (CbmDigitizationConfig::Load(run, config)) run.Run(nEvents); + else + return; + + // ----- Finish ------------------------------------------------------- + timer.Stop(); + Double_t rtime = timer.RealTime(); + Double_t ctime = timer.CpuTime(); + std::cout << "Macro finished successfully." << std::endl; + std::cout << "Real time " << rtime << " s, CPU time " << ctime << "s" << std::endl; + FairSystemInfo sysInfo; + Float_t maxMemory = sysInfo.GetMaxMemory(); + std::cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">"; + std::cout << maxMemory; + std::cout << "</DartMeasurement>" << std::endl; + Float_t cpuUsage = ctime / rtime; + std::cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">"; + std::cout << cpuUsage; + std::cout << "</DartMeasurement>" << std::endl; + // ------------------------------------------------------------------------ +} diff --git a/macro/run/run_transport_json_config.C b/macro/run/run_transport_json_config.C new file mode 100644 index 0000000000000000000000000000000000000000..d8af8231f0e13e9d01ea11fd65ed1084e22d24f6 --- /dev/null +++ b/macro/run/run_transport_json_config.C @@ -0,0 +1,58 @@ +/** @file run_transport_json_config.C + ** @author Oleg Golosov <oleg.golosov@gmail.com> + ** @since 31 March 2020 + **/ + +// Includes needed for IDE +#if !defined(__CLING__) +#include "CbmTransport.h" + +#include "FairSystemInfo.h" + +#include "TStopwatch.h" +#endif + + +/** @brief Macro for transport simulation of events from file + ** @author Oleg Golosov <oleg.golosov@gmail.com> + ** @since 31 March 2021 + ** @param config Name of config file + ** @param nEvents Number of events to transport + ** + ** This macro performs the transport simulation of externally generated + ** events from an input file using test-based config. + ** Additions to the CbmTransport settings can be made after + ** the main config is applied. + **/ + +void run_transport_json_config(std::string config = "", int nEvents = 2) +{ + if (config == "") config = Form("%s/macro/run/config.json", gSystem->Getenv("VMCWORKDIR")); + + // ----- Timer -------------------------------------------------------- + TStopwatch timer; + timer.Start(); + // ------------------------------------------------------------------------ + + CbmTransport run; + if (CbmTransportConfig::Load(run, config)) run.Run(nEvents); + else + return; + + // ----- Finish ------------------------------------------------------- + timer.Stop(); + Double_t rtime = timer.RealTime(); + Double_t ctime = timer.CpuTime(); + std::cout << "Macro finished successfully." << std::endl; + std::cout << "Real time " << rtime << " s, CPU time " << ctime << "s" << std::endl; + FairSystemInfo sysInfo; + Float_t maxMemory = sysInfo.GetMaxMemory(); + std::cout << "<DartMeasurement name=\"MaxMemory\" type=\"numeric/double\">"; + std::cout << maxMemory; + std::cout << "</DartMeasurement>" << std::endl; + Float_t cpuUsage = ctime / rtime; + std::cout << "<DartMeasurement name=\"CpuLoad\" type=\"numeric/double\">"; + std::cout << cpuUsage; + std::cout << "</DartMeasurement>" << std::endl; + // ------------------------------------------------------------------------ +} diff --git a/sim/response/CMakeLists.txt b/sim/response/CMakeLists.txt index 45a76c11f85e7828f979c8806a22ffb865d8cef2..7c9e4ec40e83bd0151d9aef9d3ae7a5f9e41b8de 100644 --- a/sim/response/CMakeLists.txt +++ b/sim/response/CMakeLists.txt @@ -14,12 +14,15 @@ base/CbmDigitizeInfo.cxx base/CbmMCInput.cxx base/CbmMCInputSet.cxx base/CbmRunAna.cxx +base/CbmDigitizationConfig.cxx ) # --------------------------------------------------------- # ---- Include directories ------------------------------- set(INCLUDE_DIRECTORIES +${CBMROOT_SOURCE_DIR}/core/config + ${CBMROOT_SOURCE_DIR}/sim/response ${CBMROOT_SOURCE_DIR}/sim/response/base diff --git a/sim/response/CbmSimResponseLinkDef.h b/sim/response/CbmSimResponseLinkDef.h index 5d3c66a616ecc068ff8c6a99eac06bfefb95ada8..d62fa29ff68faea0e4e400af33d5b106e6cafd81 100644 --- a/sim/response/CbmSimResponseLinkDef.h +++ b/sim/response/CbmSimResponseLinkDef.h @@ -6,6 +6,7 @@ // --- base #pragma link C++ class CbmDigitization + ; +#pragma link C++ class CbmDigitizationConfig + ; #pragma link C++ class CbmDigitizationSource + ; #pragma link C++ class CbmDigitizeInfo + ; #pragma link C++ class CbmMCInput + ; diff --git a/sim/response/base/CbmDigitizationConfig.cxx b/sim/response/base/CbmDigitizationConfig.cxx new file mode 100644 index 0000000000000000000000000000000000000000..37e5a2db1e07077c9720261c51b6ca45bcc3eb51 --- /dev/null +++ b/sim/response/base/CbmDigitizationConfig.cxx @@ -0,0 +1,163 @@ +#include "CbmDigitizationConfig.h" + +#include "CbmDigitization.h" + +using namespace std; + +string CbmDigitizationConfig::GetModuleTag() { return "digitization"; } + +CbmDigitizationConfig::TagSet_t CbmDigitizationConfig::GetValidationTags() +{ + return {"logScreenLevel", + "logVerbosityLevel", + "generateRunInfo", + "storeAllTimeSlices", + "eventMode", + "startTime", + "timeSliceLength", + "produceNoise", + "input.id", + "input.path", + "input.rate", + "input.embedToId", + "input.treeAccessMode", + "input.parameterSource", + "output.overwrite", + "output.path", + "geometry.path", + "geometry.sourceId", + "geometry.deactivate", + "geometry.deactivateAllBut"}; +} + +bool CbmDigitizationConfig::SetIO(CbmDigitization& obj, const pt::ptree& moduleTree) +{ + map<string, ECbmTreeAccess> stringToECbmTreeAccess = {{"regular", ECbmTreeAccess::kRegular}, + {"repeat", ECbmTreeAccess::kRepeat}, + {"random", ECbmTreeAccess::kRandom}}; + bool eventMode = moduleTree.get<bool>("eventMode", false); + auto inputs = moduleTree.get_child("input"); + uint inputCounter = 0; + vector<string> paths; + bool parametersSet = false; + string parametersPath = ""; + ECbmTreeAccess treeAccessMode; + for (auto& input : inputs) { + pt::ptree pt_input = input.second; + int id = pt_input.get<int>("id", inputCounter); + string path = GetStringValue(pt_input, "path", ""); + auto configRate = pt_input.get_optional<float>("rate"); + string treeAccessModeString = pt_input.get<string>("treeAccessMode", "regular"); + bool parameterSource = pt_input.get<bool>("parameterSource", false); + auto configEmbedToId = pt_input.get_optional<int>("embedToId"); + + if (id < 0) continue; + if (path == "") { + LOG(error) << "CbmDigitizationConfig: no path specified for input #" << id; + return false; + } + paths.push_back(path); + string traFileName = path + ".tra.root"; + if (stringToECbmTreeAccess.find(treeAccessModeString) != stringToECbmTreeAccess.end()) + treeAccessMode = stringToECbmTreeAccess.at(treeAccessModeString); + else { + LOG(error) << "CbmDigitizationConfig: invalid tree access mode: " << treeAccessModeString; + cout << "Available access modes:\n"; + for (auto& p : stringToECbmTreeAccess) + cout << p.first << endl; + return false; + } + + if (configEmbedToId) { + if (configRate) { + LOG(error) << "CbmDigitizationConfig: input.embedToId and input.rate should not be used simultaneously!"; + return false; + } + else { + int embedToId = configEmbedToId.get(); + LOG(info) << "CbmDigitizationConfig: Embedding input: " << traFileName; + obj.EmbedInput(id, traFileName, embedToId); + } + } + else { + if (eventMode && inputCounter > 0) { + LOG(error) << "CbmDigitizationConfig: event mixing is not possible in event-by-event mode!"; + return false; + } + float rate = pt_input.get<float>("rate", -1.); + LOG(info) << "CbmDigitizationConfig: Adding input: " << traFileName; + obj.AddInput(id, path + ".tra.root", rate, treeAccessMode); + } + if (parameterSource) { + if (!parametersSet) { parametersPath = path; } + else { + LOG(error) << "CbmDigitizationConfig: only one parameter source is allowed!"; + return false; + } + } + inputCounter++; + } + + string outputPath = GetStringValue(moduleTree, "output.path", paths.at(0)); + bool overwrite = moduleTree.get<bool>("output.overwrite", false); + + if (!parametersSet) parametersPath = paths.at(0); + LOG(info) << "CbmDigitizationConfig: Parameter source:\n" << parametersPath; + obj.SetParameterRootFile(parametersPath + ".par.root"); + LOG(info) << "CbmDigitizationConfig: Output path:\n" << outputPath; + obj.SetOutputFile(outputPath + ".raw.root", overwrite); + obj.SetMonitorFile((outputPath + ".moni_digi.root").c_str()); + + return true; +} + +bool CbmDigitizationConfig::SetDigitizationParameters(CbmDigitization& obj, const pt::ptree& moduleTree) +{ + + auto produceNoise = moduleTree.get_optional<bool>("produceNoise"); + bool eventMode = moduleTree.get<bool>("eventMode", false); + auto storeAllTimeSlices = moduleTree.get_optional<bool>("storeAllTimeSlices"); + auto timeSliceLength = moduleTree.get_optional<float>("timeSliceLength"); + auto startTime = moduleTree.get_optional<float>("startTime"); + + if (eventMode) { + if (storeAllTimeSlices || timeSliceLength || startTime) { + LOG(error) << "CbmDigitizationConfig: time slice settings should not be used in event mode!"; + return false; + } + } + obj.SetEventMode(eventMode); + + if (timeSliceLength) obj.SetTimeSliceLength(timeSliceLength.get()); + if (startTime) obj.SetStartTime(startTime.get()); + if (produceNoise) obj.SetProduceNoise(produceNoise.get()); + return true; +} + +bool CbmDigitizationConfig::SetGeometry(CbmDigitization& obj, const pt::ptree& moduleTree) +{ + auto modulesToDeactivate = moduleTree.get_child_optional("geometry.deactivate"); + auto deactivateAllBut = moduleTree.get_optional<string>("geometry.deactivateAllBut"); + + if (modulesToDeactivate && deactivateAllBut) { + LOG(error) + << "CbmDigitizationConfig: geometry.deactivate and geometry.deactivateAllBut should not be used simultaneously!"; + return false; + } + + if (deactivateAllBut && deactivateAllBut.get() != "") + obj.DeactivateAllBut(stringToECbmModuleId(deactivateAllBut.get())); + + if (modulesToDeactivate) + for (auto& module : modulesToDeactivate.get()) + if (module.first != "") obj.Deactivate(stringToECbmModuleId(module.first)); + + return true; +} + +bool CbmDigitizationConfig::LoadImpl(CbmDigitization& obj, const pt::ptree& moduleTree) +{ + return SetIO(obj, moduleTree) && SetDigitizationParameters(obj, moduleTree) && SetGeometry(obj, moduleTree); +} + +ClassImp(CbmDigitizationConfig) diff --git a/sim/response/base/CbmDigitizationConfig.h b/sim/response/base/CbmDigitizationConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..6d96f6ea1d5c87e8bba84181ea848c2fd620dcc5 --- /dev/null +++ b/sim/response/base/CbmDigitizationConfig.h @@ -0,0 +1,22 @@ +#pragma once + +#include "CbmConfigBase.h" + +class CbmDigitization; + +class CbmDigitizationConfig : public CbmConfigBase<CbmDigitizationConfig, CbmDigitization> { + +public: + using TagSet_t = CbmConfigBase<CbmDigitizationConfig, CbmDigitization>::TagSet_t; + + static std::string GetModuleTag(); + static TagSet_t GetValidationTags(); + static bool LoadImpl(CbmDigitization& obj, const pt::ptree& moduleTree); + static bool SetIO(CbmDigitization& obj, const pt::ptree& moduleTree); + static bool SetDigitizationParameters(CbmDigitization& obj, const pt::ptree& moduleTree); + static bool SetGeometry(CbmDigitization& obj, const pt::ptree& moduleTree); + + ClassDef(CbmDigitizationConfig, 1); +}; + +//#endif diff --git a/sim/transport/steer/CMakeLists.txt b/sim/transport/steer/CMakeLists.txt index 375b40e617e1003f3a1220ccc95de52cf75db82a..14620992b9ff790dfa465f9a13f557d37ac9f556 100644 --- a/sim/transport/steer/CMakeLists.txt +++ b/sim/transport/steer/CMakeLists.txt @@ -13,6 +13,7 @@ CbmTransport.cxx CbmVMCSettings.cxx CbmGeant3Settings.cxx CbmGeant4Settings.cxx +CbmTransportConfig.cxx ) # --------------------------------------------------------- @@ -34,6 +35,7 @@ ${CBMROOT_SOURCE_DIR}/sim/transport/steer ${CBMROOT_SOURCE_DIR}/sim/transport/geosetup ${CBMDATA_DIR} ${CBMBASE_DIR}/utils +${CBMROOT_SOURCE_DIR}/core/config ) set(SYSTEM_INCLUDE_DIRECTORIES diff --git a/sim/transport/steer/CbmSimSteerLinkDef.h b/sim/transport/steer/CbmSimSteerLinkDef.h index 51f4426add2e553eb8646a5b889493fb46820074..ac2669aed43a32100aa0d6d59daba9f9f5b13477 100644 --- a/sim/transport/steer/CbmSimSteerLinkDef.h +++ b/sim/transport/steer/CbmSimSteerLinkDef.h @@ -10,6 +10,7 @@ #pragma link C++ class CbmVMCSettings + ; #pragma link C++ class CbmGeant3Settings + ; #pragma link C++ class CbmGeant4Settings + ; +#pragma link C++ class CbmTransportConfig + ; #pragma link C++ enum ECbmEngine; diff --git a/sim/transport/steer/CbmTransportConfig.cxx b/sim/transport/steer/CbmTransportConfig.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4042f16c0437b3780a630e81d6c0c483cd597cee --- /dev/null +++ b/sim/transport/steer/CbmTransportConfig.cxx @@ -0,0 +1,306 @@ +#include "CbmTransportConfig.h" + +#include "CbmBeamGenerator.h" +#include "CbmGeant4Settings.h" +#include "CbmPlutoGenerator.h" +#include "CbmTransport.h" + +using namespace std; + +string CbmTransportConfig::GetModuleTag() { return "transport"; } + +CbmTransportConfig::TagSet_t CbmTransportConfig::GetValidationTags() +{ + return {"logScreenLevel", + "logVerbosityLevel", + "input.file", + "input.generator", + "input.plutoPdg", + "input.beamA", + "input.beamZ", + "input.beamQ", + "input.beamP", + "input.beamStartZ", + "output.path", + "target.material", + "target.thickness", + "target.diameter", + "target.position.x", + "target.position.y", + "target.position.z", + "target.rotation.y", + "beam.position.x", + "beam.position.y", + "beam.position.z", + "beam.position.sigmaX", + "beam.position.sigmaY", + "beam.angle.x", + "beam.angle.y", + "beam.angle.sigmaX", + "beam.angle.sigmaY", + "geantVersion", + "geant4vmcSettings.physicsLists", + "geant4vmcSettings.specialProcesses", + "geant4vmcSettings.maxNsteps", + "geant4vmcSettings.geant4commands", + "randomRP", + "geometry.magneticField.position.x", + "geometry.magneticField.position.y", + "geometry.magneticField.position.z", + "geometry.magneticField.scale", + "geometry.magneticField.tag", + "geometry.baseSetup", + "geometry.subsystems", + "geometry.subsystems.cave", + "geometry.subsystems.magnet", + "geometry.subsystems.pipe", + "geometry.subsystems.target", + "geometry.subsystems.mvd", + "geometry.subsystems.sts", + "geometry.subsystems.rich", + "geometry.subsystems.much", + "geometry.subsystems.trd", + "geometry.subsystems.tof", + "geometry.subsystems.psd", + "geometry.subsystems.hodo", + "geometry.subsystems.shield", + "geometry.subsystems.platform"}; +} + +CbmTransportConfig::TagSet_t CbmTransportConfig::GetAcceptedGenerators() { return {"unigen", "pluto", "beam"}; } + +bool CbmTransportConfig::SetIO(CbmTransport& obj, const pt::ptree& moduleTree) +{ + auto inputs = moduleTree.get_child("input"); + int inputCounter = 0; + for (auto& input : inputs) { + pt::ptree pt_input = input.second; + string inputGenerator = pt_input.get<string>("generator", "unigen"); + string inputFile = GetStringValue(pt_input, "file", ""); + + if (inputFile == "") { LOG(error) << "CbmTransportConfig: no input path specified for input #" << inputCounter; } + + if (inputGenerator == "unigen") obj.AddInput(inputFile.c_str(), kUnigen); + else if (inputGenerator == "pluto") { + auto plutoGen = new CbmPlutoGenerator(inputFile.c_str()); + auto manualPdg = pt_input.get_optional<int>("plutoPdg"); + if (manualPdg) plutoGen->SetManualPDG(manualPdg.get()); + obj.AddInput(plutoGen); + } + else if (inputGenerator == "beam") { + auto confBeamA = pt_input.get_optional<int>("beamA"); + auto confBeamZ = pt_input.get_optional<int>("beamZ"); + auto confBeamQ = pt_input.get_optional<int>("beamQ"); + auto confBeamP = pt_input.get_optional<float>("beamP"); + auto confBeamStartZ = pt_input.get_optional<float>("beamStartZ"); + auto targetZ = moduleTree.get_optional<float>("target.position.z"); + int beamA, beamZ, beamQ; + float beamP, beamStartZ; + if (confBeamA && confBeamZ && confBeamP) { + beamA = confBeamA.get(); + beamZ = confBeamZ.get(); + beamP = confBeamP.get(); + if (confBeamQ) beamQ = confBeamQ.get(); + else + beamQ = confBeamA.get(); + if (confBeamStartZ) beamStartZ = confBeamStartZ.get(); + else if (targetZ) { + beamStartZ = targetZ.get() - 1.; + LOG(warning) << "CbmTransportConfig: beamStartZ=targetZ-1. cm"; + } + else { + LOG(error) << "CbmTransportConfig: beam start Z not set!"; + return false; + } + obj.AddInput(new CbmBeamGenerator(beamZ, beamA, beamQ, beamP, beamStartZ)); + LOG(info) << Form("CbmTransportConfig: add beam generator: Z = %d, A = %d, Q = %d, P = %f, startZ = %f", beamZ, + beamA, beamQ, beamP, beamStartZ); + } + else { + LOG(error) << "CbmTransportConfig: Incomplete beam generator configuration: A, Z and P required!"; + return false; + } + } + else { + LOG(error) << "CbmTransportConfig: Unknown generator type " << inputGenerator << endl + << "Accepted generator types:"; + for (auto& gen : GetAcceptedGenerators()) + cout << gen << ", "; + cout << endl; + return false; + } + inputCounter++; + } + + string outputPath = GetStringValue(moduleTree, "output.path", "test"); + LOG(info) << "CbmTransportConfig: Output path: " << outputPath; + obj.SetOutFileName(outputPath + ".tra.root"); + obj.SetParFileName(outputPath + ".par.root"); + obj.SetGeoFileName(outputPath + ".geo.root"); + + return true; +} + +bool CbmTransportConfig::SetTarget(CbmTransport& obj, const pt::ptree& moduleTree) +{ + auto material = moduleTree.get_optional<string>("target.material"); + auto thickness = moduleTree.get_optional<float>("target.thickness"); + auto diameter = moduleTree.get_optional<float>("target.diameter"); + auto x = moduleTree.get_optional<float>("target.position.x"); + auto y = moduleTree.get_optional<float>("target.position.y"); + auto z = moduleTree.get_optional<float>("target.position.z"); + auto rotY = moduleTree.get_optional<float>("target.rotation.y"); + // one can set a target only if all 3 parameters are present in config file + if (material && thickness && diameter) { + if (x && y && z && rotY) + obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get(), x.get(), y.get(), z.get(), rotY.get()); + else if (x && y && z) + obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get(), x.get(), y.get(), z.get()); + else if (x && y) + obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get(), x.get(), y.get()); + else if (x) + obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get(), x.get()); + else + obj.SetTarget(material.get().c_str(), thickness.get(), diameter.get()); + } + else { + LOG(error) << "CbmTransportConfig: Incomplete target configuration (material, thickness and diameter required)\n"; + return false; + } + return true; +} + +bool CbmTransportConfig::SetBeamProfile(CbmTransport& obj, const pt::ptree& moduleTree) +{ + auto posX = moduleTree.get_optional<float>("beam.position.x"); + auto posY = moduleTree.get_optional<float>("beam.position.y"); + auto posZ = moduleTree.get_optional<float>("beam.position.z"); + auto posSigmaX = moduleTree.get_optional<float>("beam.position.sigmaX"); + auto posSigmaY = moduleTree.get_optional<float>("beam.position.sigmaY"); + if (posX && posY) { + if (posSigmaX && posSigmaY && posZ) + obj.SetBeamPosition(posX.get(), posY.get(), posSigmaX.get(), posSigmaY.get(), posZ.get()); + else if (posSigmaX && posSigmaY) + obj.SetBeamPosition(posX.get(), posY.get(), posSigmaX.get(), posSigmaY.get()); + else if (posSigmaX) + obj.SetBeamPosition(posX.get(), posY.get(), posSigmaX.get()); + else if (posX && posY) + obj.SetBeamPosition(posX.get(), posY.get()); + } + else { + LOG(error) << "CbmTransportConfig: Incomplete beam position configuration (x and y required)\n"; + return false; + } + auto angX = moduleTree.get_optional<float>("beam.angle.x"); + auto angY = moduleTree.get_optional<float>("beam.angle.y"); + auto angSigmaX = moduleTree.get_optional<float>("beam.angle.sigmaX"); + auto angSigmaY = moduleTree.get_optional<float>("beam.angle.sigmaY"); + if (angX && angY) { + if (angSigmaX && angSigmaY) obj.SetBeamAngle(angX.get(), angY.get(), angSigmaX.get(), angSigmaY.get()); + else if (angSigmaX) + obj.SetBeamAngle(angX.get(), angY.get(), angSigmaX.get()); + else if (angX && angY) + obj.SetBeamAngle(angX.get(), angY.get()); + } + else { + LOG(error) << "CbmTransportConfig: Incomplete beam angle configuration (x and y required)\n"; + return false; + } + return true; +} + +bool CbmTransportConfig::SetTransportParameters(CbmTransport& obj, const pt::ptree& moduleTree) +{ + bool randomRP = true; + auto configRandomRP = moduleTree.get_optional<float>("randomRP"); + if (configRandomRP) randomRP = configRandomRP.get(); + if (randomRP) obj.SetRandomEventPlane(); + + ECbmEngine engine = kGeant3; + auto geantVersion = moduleTree.get_optional<float>("geantVersion"); + if (geantVersion) { + if (geantVersion.get() == 4) engine = kGeant4; + else if (geantVersion.get() != 3) { + LOG(error) << "CbmTransportConfig: Unknown Geant version: " << geantVersion.get(); + return false; + } + } + obj.SetEngine(engine); + + if (engine == kGeant4) { + auto g4settings = moduleTree.get_child_optional("geant4vmcSettings"); + if (g4settings) { + auto g4settingsTree = g4settings.get(); + auto physicsLists = g4settingsTree.get_optional<string>("physicsLists"); + auto specialProcesses = g4settingsTree.get_optional<string>("specialProcesses"); + auto maxNsteps = g4settingsTree.get_optional<int>("maxNsteps"); + + CbmGeant4Settings* settings = new CbmGeant4Settings(); + + if ((physicsLists && !specialProcesses) || (!physicsLists && specialProcesses)) { + LOG(error) + << "CbmTransportConfig: Incomplete Geant4 configuration: physicsLists and specialProcesses required!"; + return false; + } + else if (physicsLists && specialProcesses) + settings->SetG4RunConfig("geomRoot", physicsLists.get(), specialProcesses.get()); + + if (maxNsteps) settings->SetMaximumNumberOfSteps(maxNsteps.get()); + + auto g4commands = g4settingsTree.get_child_optional("geant4commands"); + if (g4commands) + for (auto& command : g4commands.get()) + settings->AddG4Command(command.second.data()); + settings->Dump(); + obj.SetGeant4Settings(settings); + } + } + return true; +} + +bool CbmTransportConfig::SetGeometry(CbmTransport& obj, const pt::ptree& moduleTree) +{ + auto geometry = moduleTree.get_child_optional("geometry"); + if (!geometry) { + LOG(error) << "CbmTransportConfig: geometry settings missing!"; + return false; + } + auto geometryTree = geometry.get(); + auto baseSetup = geometryTree.get_optional<string>("baseSetup"); + if (baseSetup) obj.LoadSetup(baseSetup.get().c_str()); + + auto setup = obj.GetSetup(); + auto fieldTag = geometryTree.get_optional<string>("magneticField.tag"); + auto fieldScale = geometryTree.get_optional<float>("magneticField.scale"); + auto fieldX = geometryTree.get_optional<float>("magneticField.position.x"); + auto fieldY = geometryTree.get_optional<float>("magneticField.position.y"); + auto fieldZ = geometryTree.get_optional<float>("magneticField.position.z"); + + if (fieldTag && fieldScale && fieldX && fieldY && fieldZ) + setup->SetField(fieldTag.get().c_str(), fieldScale.get(), fieldX.get(), fieldY.get(), fieldZ.get()); + else if (fieldScale) { + if (baseSetup) setup->SetFieldScale(fieldScale.get()); + else { + LOG(error) << "CbmTransportConfig: Incomplete magnetic field configuration: fieldTag, fieldScale, fieldX, fieldY " + "and fieldZ are required if base setup is not defined!"; + return false; + } + } + auto modules = geometryTree.get_child_optional("subsystems"); + if (modules) + for (auto& module : modules.get()) { + auto moduleId = stringToECbmModuleId(module.first); + if (module.second.data() == "") setup->RemoveModule(moduleId); + else + setup->SetModule(moduleId, module.second.data().c_str()); + } + return true; +} + +bool CbmTransportConfig::LoadImpl(CbmTransport& obj, const pt::ptree& moduleTree) +{ + return SetIO(obj, moduleTree) && SetTarget(obj, moduleTree) && SetBeamProfile(obj, moduleTree) + && SetTransportParameters(obj, moduleTree) && SetGeometry(obj, moduleTree); +} + +ClassImp(CbmTransportConfig) diff --git a/sim/transport/steer/CbmTransportConfig.h b/sim/transport/steer/CbmTransportConfig.h new file mode 100644 index 0000000000000000000000000000000000000000..8c15558b683427ade4d63b9430c281a7b69af6c6 --- /dev/null +++ b/sim/transport/steer/CbmTransportConfig.h @@ -0,0 +1,23 @@ +#pragma once + +#include "CbmConfigBase.h" + +class CbmTransport; + +class CbmTransportConfig : public CbmConfigBase<CbmTransportConfig, CbmTransport> { + +public: + using TagSet_t = CbmConfigBase<CbmTransportConfig, CbmTransport>::TagSet_t; + + static std::string GetModuleTag(); + static TagSet_t GetValidationTags(); + static TagSet_t GetAcceptedGenerators(); + static bool LoadImpl(CbmTransport& obj, const pt::ptree& moduleTree); + static bool SetIO(CbmTransport& obj, const pt::ptree& moduleTree); + static bool SetTarget(CbmTransport& obj, const pt::ptree& moduleTree); + static bool SetBeamProfile(CbmTransport& obj, const pt::ptree& moduleTree); + static bool SetTransportParameters(CbmTransport& obj, const pt::ptree& moduleTree); + static bool SetGeometry(CbmTransport& obj, const pt::ptree& moduleTree); + + ClassDef(CbmTransportConfig, 1); +};