diff --git a/algo/base/Definitions.h b/algo/base/Definitions.h index a6f3d35505f2992c9b7f4c7c10a3d2086a684f6f..57e93adc48b6fd87b334df8f68a52a39ffc2044b 100644 --- a/algo/base/Definitions.h +++ b/algo/base/Definitions.h @@ -47,6 +47,12 @@ namespace cbm::algo Track, }; + enum class Setup + { + mCBM2022, + mCBM2024, + }; + } // namespace cbm::algo CBM_ENUM_DICT(fles::Subsystem, @@ -87,4 +93,9 @@ CBM_ENUM_DICT(cbm::algo::RecoData, {"Track", RecoData::Track} ); +CBM_ENUM_DICT(cbm::algo::Setup, + {"mCBM2022", cbm::algo::Setup::mCBM2022}, + {"mCBM2024", cbm::algo::Setup::mCBM2024} +); + #endif diff --git a/core/detectors/sts/CbmStsParSetSensor.cxx b/core/detectors/sts/CbmStsParSetSensor.cxx index 71d67d3913091388e3385ab54792ce5f180065f7..2e64b3308e3f32fe281883ccab30ea7e5faad3bc 100644 --- a/core/detectors/sts/CbmStsParSetSensor.cxx +++ b/core/detectors/sts/CbmStsParSetSensor.cxx @@ -54,7 +54,8 @@ Bool_t CbmStsParSetSensor::getParams(FairParamList*) const CbmStsParSensor& CbmStsParSetSensor::GetParSensor(UInt_t address) { if (fUseGlobal) return fGlobalParams; - assert(fParams.count(address)); + LOG_IF(fatal, fParams.count(address) == 0) + << GetName() << ": Parameters for sensor address " << std::hex << address << std::dec << " not found!"; return fParams[address]; } // -------------------------------------------------------------------------- @@ -78,11 +79,15 @@ void CbmStsParSetSensor::SetParSensor(UInt_t address, const CbmStsParSensor& par std::string CbmStsParSetSensor::ToString() const { std::stringstream ss; - if (fUseGlobal) ss << "(Global) " << fGlobalParams.ToString(); + if (fUseGlobal) + ss << "(Global) " << fGlobalParams.ToString(); else { - if (fParams.empty()) ss << "Empty"; + if (fParams.empty()) + ss << "Empty"; else - ss << "Parameters for " << fParams.size() << " sensors"; + ss << "Parameters for " << fParams.size() << " sensors:\n"; + for (const auto& [address, par] : fParams) + ss << address << "\n"; } return ss.str(); } diff --git a/reco/steer/CMakeLists.txt b/reco/steer/CMakeLists.txt index 440086429ffe8dc62ffd1219d5841dfafc383ece..98b6c7b43a7275a893069e05b63ef7d893a3e0ba 100644 --- a/reco/steer/CMakeLists.txt +++ b/reco/steer/CMakeLists.txt @@ -11,6 +11,7 @@ set(SRCS CbmSourceDigiTimeslice.cxx CbmSourceDigiEvents.cxx CbmSourceTsArchive.cxx + CbmOnlineParWrite.cxx ) @@ -18,6 +19,8 @@ set(LIBRARY_NAME CbmRecoSteer) set(LINKDEF ${LIBRARY_NAME}LinkDef.h) set(PUBLIC_DEPENDENCIES CbmData + CbmSimSteer + CbmRecoTasks FairRoot::Base ROOT::Core ROOT::Hist diff --git a/reco/steer/CbmOnlineParWrite.cxx b/reco/steer/CbmOnlineParWrite.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b4d01d7238c6a3314c76bb29e03bd1a3a10b8c1c --- /dev/null +++ b/reco/steer/CbmOnlineParWrite.cxx @@ -0,0 +1,346 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#include "CbmOnlineParWrite.h" + +#include "CbmMcbmUtils.h" +#include "CbmSetup.h" +#include "CbmSourceDummy.h" +#include "CbmStsAddress.h" +#include "CbmStsParAsic.h" +#include "CbmStsParModule.h" +#include "CbmStsParSensor.h" +#include "CbmStsParSensorCond.h" +#include "CbmStsParSetSensor.h" +#include "CbmStsSetup.h" +#include "CbmTaskStsHitFinderParWrite.h" +#include "CbmTaskTofClusterizerParWrite.h" +#include "CbmTaskTrdHitFinderParWrite.h" + +#include <FairParAsciiFileIo.h> +#include <FairParRootFileIo.h> +#include <FairRootFileSink.h> +#include <FairRunAna.h> +#include <FairRuntimeDb.h> + +#include <TGeoManager.h> +#include <TObjString.h> +#include <TStopwatch.h> + +#include <iostream> + +using namespace cbm::algo; + +void CbmOnlineParWrite::AddDetectors() +{ + // Add detectors here + AddTrd(); + AddTof(); + AddSts(); +} + +// =========================================================================== +// TRD setup +// =========================================================================== +void CbmOnlineParWrite::AddTrd() +{ + // Copied from macro/beamtime/mcbm2022/trd_hitfinder_run.C + fSetup->SetActive(ECbmModuleId::kTrd, kTRUE); + fSetup->SetActive(ECbmModuleId::kTrd2d, kTRUE); + + // ----- TRD digitisation parameters ------------------------------------- + TString geoTagTrd; + if (fSetup->IsActive(ECbmModuleId::kTrd)) { + if (fSetup->GetGeoTag(ECbmModuleId::kTrd, geoTagTrd)) { + TString paramFilesTrd(Form("%s/parameters/trd/trd_%s", fSrcDir.Data(), geoTagTrd.Data())); + std::vector<TString> paramFilesVecTrd = {"asic", "digi", "gas", "gain"}; + for (auto parIt : paramFilesVecTrd) { + fParList->Add(new TObjString(Form("%s.%s.par", paramFilesTrd.Data(), parIt.Data()))); + } + } + for (auto parFileVecIt : *fParList) { + std::cout << Form("TrdParams - %s - added to parameter file list", parFileVecIt->GetName()) << std::endl; + } + } + + // ----- TRD task --------------------------------------------------------- + auto* trdHitfinderPar = new CbmTaskTrdHitFinderParWrite(); + fRun->AddTask(trdHitfinderPar); +} + +// =========================================================================== +// TOF setup +// =========================================================================== +void CbmOnlineParWrite::AddTof() +{ + // Copied from macro/tools/tof_hitfinder_run.C + fSetup->SetActive(ECbmModuleId::kTof, kTRUE); + + TString geoTag; + if (fSetup->IsActive(ECbmModuleId::kTof)) { + fSetup->GetGeoTag(ECbmModuleId::kTof, geoTag); + TObjString* tofBdfFile = new TObjString(fSrcDir + "/parameters/tof/tof_" + geoTag + ".digibdf.par"); + fParList->Add(tofBdfFile); + std::cout << "-I- TOF: Using parameter file " << tofBdfFile->GetString() << std::endl; + } + + // ----- TOF defaults ------------------------ + Int_t calMode = 93; + Int_t calSel = 1; + Double_t dDeadtime = 50.; + + TString TofFileFolder = fSrcDir + "/parameters/mcbm/"; + TString cCalId = "490.100.5.0"; + Int_t iCalSet = 30040500; // calibration settings + + switch (fSetupType) { + case Setup::mCBM2022: + cCalId = "2391.5.000"; + iCalSet = 22002500; + break; + case Setup::mCBM2024: + cCalId = "2912.1"; + iCalSet = 012032500; + break; + default: throw std::runtime_error("TOF: Unknown setup type"); + } + + TString cFname = + Form("%s/%s_set%09d_%02d_%01dtofClust.hst.root", TofFileFolder.Data(), cCalId.Data(), iCalSet, calMode, calSel); + + auto* tofCluster = new CbmTaskTofClusterizerParWrite("Task TOF Clusterizer", 0, 1); + tofCluster->SetCalParFileName(cFname); + tofCluster->SetCalMode(calMode); + tofCluster->SetTotMax(20.); // Tot upper limit for walk corection + tofCluster->SetTotMin(0.); //(12000.); // Tot lower limit for walk correction + tofCluster->SetTotMean(5.); // Tot calibration target value in ns + tofCluster->SetMaxTimeDist(1.0); // default cluster range in ns + tofCluster->SetChannelDeadtime(dDeadtime); // artificial deadtime in ns + tofCluster->PosYMaxScal(0.75); //in % of length + fRun->AddTask(tofCluster); +} + +// =========================================================================== +// STS setup +// =========================================================================== +void CbmOnlineParWrite::AddSts() +{ + // Copied from macro/beamtime/mcbm2022/mcbm_reco.C + + auto* recoSts = new CbmTaskStsHitFinderParWrite{}; + // recoSts->SetMode(ECbmRecoMode::EventByEvent); + + // recoSts->SetTimeCutDigisAbs(20.0); // cluster finder: time cut in ns + // recoSts->SetTimeCutClustersAbs(20.0); // hit finder: time cut in ns + + // Sensor params + CbmStsParSensor sensor6cm(CbmStsSensorClass::kDssdStereo); + sensor6cm.SetPar(0, 6.2092); // Extension in x + sensor6cm.SetPar(1, 6.2); // Extension in y + sensor6cm.SetPar(2, 0.03); // Extension in z + sensor6cm.SetPar(3, 5.9692); // Active size in y + sensor6cm.SetPar(4, 1024.); // Number of strips front side + sensor6cm.SetPar(5, 1024.); // Number of strips back side + sensor6cm.SetPar(6, 0.0058); // Strip pitch front side + sensor6cm.SetPar(7, 0.0058); // Strip pitch back side + sensor6cm.SetPar(8, 0.0); // Stereo angle front side + sensor6cm.SetPar(9, 7.5); // Stereo angle back side + + CbmStsParSensor sensor12cm(sensor6cm); // copy all parameters, change then only the y size + sensor12cm.SetPar(1, 12.4); // Extension in y + sensor12cm.SetPar(3, 12.1692); // Active size in y + + // --- Addresses for sensors + // --- They are defined in each station as sensor 1, module 1, halfladderD (2), ladder 1 + // Int_t GetAddress(UInt_t unit = 0, UInt_t ladder = 0, UInt_t halfladder = 0, UInt_t module = 0, UInt_t sensor = 0, + // UInt_t side = 0, UInt_t version = kCurrentVersion); + + // --- Now we can define the sensor parameter set and tell recoSts to use it + auto sensorParSet = new CbmStsParSetSensor("CbmStsParSetSensor", "STS sensor parameters" + "mcbm2021"); + + // TODO: is it possible to read these values from a parameter file? + if (fSetupType == Setup::mCBM2022) { + + Int_t stsAddress01 = CbmStsAddress::GetAddress(0, 0, 1, 0, 0, 0); // U0 L0 M0 6 cm + Int_t stsAddress02 = CbmStsAddress::GetAddress(0, 0, 1, 1, 0, 0); // U0 L0 M1 6 cm + Int_t stsAddress03 = CbmStsAddress::GetAddress(0, 1, 1, 0, 0, 0); // U0 L1 M0 6 cm + Int_t stsAddress04 = CbmStsAddress::GetAddress(0, 1, 1, 1, 0, 0); // U0 L1 M1 6 cm + Int_t stsAddress05 = CbmStsAddress::GetAddress(1, 0, 1, 0, 0, 0); // U1 L0 M0 6 cm + Int_t stsAddress06 = CbmStsAddress::GetAddress(1, 0, 1, 1, 0, 0); // U1 L0 M1 12 cm + Int_t stsAddress07 = CbmStsAddress::GetAddress(1, 1, 1, 0, 0, 0); // U1 L1 M0 6 cm + Int_t stsAddress08 = CbmStsAddress::GetAddress(1, 1, 1, 1, 0, 0); // U1 L1 M1 12 cm + Int_t stsAddress09 = CbmStsAddress::GetAddress(1, 2, 1, 0, 0, 0); // U1 L2 M0 6 cm + Int_t stsAddress10 = CbmStsAddress::GetAddress(1, 2, 1, 1, 0, 0); // U1 L2 M1 6 cm + Int_t stsAddress11 = CbmStsAddress::GetAddress(1, 2, 1, 2, 0, 0); // U1 L2 M2 6 cm + + LOG(info) << "STS address01 " << CbmStsAddress::ToString(stsAddress01); + LOG(info) << "STS address02 " << CbmStsAddress::ToString(stsAddress02); + LOG(info) << "STS address03 " << CbmStsAddress::ToString(stsAddress03); + LOG(info) << "STS address04 " << CbmStsAddress::ToString(stsAddress04); + LOG(info) << "STS address05 " << CbmStsAddress::ToString(stsAddress05); + LOG(info) << "STS address06 " << CbmStsAddress::ToString(stsAddress06); + LOG(info) << "STS address07 " << CbmStsAddress::ToString(stsAddress07); + LOG(info) << "STS address08 " << CbmStsAddress::ToString(stsAddress08); + LOG(info) << "STS address09 " << CbmStsAddress::ToString(stsAddress09); + LOG(info) << "STS address10 " << CbmStsAddress::ToString(stsAddress10); + LOG(info) << "STS address11 " << CbmStsAddress::ToString(stsAddress11); + + sensorParSet->SetParSensor(stsAddress01, sensor6cm); + sensorParSet->SetParSensor(stsAddress02, sensor6cm); + sensorParSet->SetParSensor(stsAddress03, sensor6cm); + sensorParSet->SetParSensor(stsAddress04, sensor6cm); + sensorParSet->SetParSensor(stsAddress05, sensor6cm); + sensorParSet->SetParSensor(stsAddress06, sensor12cm); + sensorParSet->SetParSensor(stsAddress07, sensor6cm); + sensorParSet->SetParSensor(stsAddress08, sensor12cm); + sensorParSet->SetParSensor(stsAddress09, sensor6cm); + sensorParSet->SetParSensor(stsAddress10, sensor6cm); + sensorParSet->SetParSensor(stsAddress11, sensor6cm); + + // auto *setup = CbmStsSetup::Instance(); + // setup->Init(); // reuse setup from global setup file + } + else if (fSetupType == Setup::mCBM2024) { + uint32_t addr01 = 0x10008012; + uint32_t addr02 = 0x10018012; + uint32_t addr03 = 0x10008412; + uint32_t addr04 = 0x10018412; + uint32_t addr05 = 0x10008422; + uint32_t addr06 = 0x10018422; + uint32_t addr07 = 0x10008822; + uint32_t addr08 = 0x10018822; + uint32_t addr09 = 0x10028822; + uint32_t addr10 = 0x10008022; + uint32_t addr11 = 0x10018022; + uint32_t addr00 = 0x10000002; // New station 0 in mCBM2024 + + LOG(info) << "STS address01 " << CbmStsAddress::ToString(addr01); + LOG(info) << "STS address02 " << CbmStsAddress::ToString(addr02); + LOG(info) << "STS address03 " << CbmStsAddress::ToString(addr03); + LOG(info) << "STS address04 " << CbmStsAddress::ToString(addr04); + LOG(info) << "STS address05 " << CbmStsAddress::ToString(addr05); + LOG(info) << "STS address06 " << CbmStsAddress::ToString(addr06); + LOG(info) << "STS address07 " << CbmStsAddress::ToString(addr07); + LOG(info) << "STS address08 " << CbmStsAddress::ToString(addr08); + LOG(info) << "STS address09 " << CbmStsAddress::ToString(addr09); + LOG(info) << "STS address10 " << CbmStsAddress::ToString(addr10); + LOG(info) << "STS address11 " << CbmStsAddress::ToString(addr11); + LOG(info) << "STS address00 " << CbmStsAddress::ToString(addr00); + + sensorParSet->SetParSensor(addr01, sensor6cm); + sensorParSet->SetParSensor(addr02, sensor6cm); + sensorParSet->SetParSensor(addr03, sensor6cm); + sensorParSet->SetParSensor(addr04, sensor6cm); + sensorParSet->SetParSensor(addr05, sensor6cm); + sensorParSet->SetParSensor(addr06, sensor12cm); + sensorParSet->SetParSensor(addr07, sensor6cm); + sensorParSet->SetParSensor(addr08, sensor12cm); + sensorParSet->SetParSensor(addr09, sensor6cm); + sensorParSet->SetParSensor(addr10, sensor6cm); + sensorParSet->SetParSensor(addr11, sensor6cm); + sensorParSet->SetParSensor(addr00, sensor6cm); + + // auto *setup = CbmStsSetup::Instance(); + // HACK: wrong geometry in global setup file + // setup->Init("/home/weiglhofer/cbm/cbmroot/geometry/sts/sts_v24b_mcbm.geo.root"); + // setup->Init(); + } + else { + throw std::runtime_error("STS: Unknown setup type"); + } + + recoSts->UseSensorParSet(sensorParSet); + + // ASIC params: #ADC channels, dyn. range, threshold, time resol., dead time, + // noise RMS, zero-threshold crossing rate + auto parAsic = new CbmStsParAsic(128, 31, 75000., 3000., 5., 800., 1000., 3.9789e-3); + + // Module params: number of channels, number of channels per ASIC + auto parMod = new CbmStsParModule(2048, 128); + parMod->SetAllAsics(*parAsic); + recoSts->UseModulePar(parMod); + + // Sensor conditions: full depletion voltage, bias voltage, temperature, + // coupling capacitance, inter-strip capacitance + auto sensorCond = new CbmStsParSensorCond(70., 140., 268., 17.5, 1.); + recoSts->UseSensorCond(sensorCond); + + fRun->AddTask(recoSts); +} + +void CbmOnlineParWrite::Run(Setup setup) +{ + // Copied and adjusted from macro/beamtime/mcbm2022/trd_hitfinder_run.C + + static bool callOnce = true; + if (!callOnce) { + throw std::runtime_error("CbmOnlineParWrite::Run() can only be called once at the moment!"); + } + callOnce = false; + + fSetupType = setup; + + // ----- Environment -------------------------------------------------- + fSrcDir = gSystem->Getenv("VMCWORKDIR"); // top source directory + // ------------------------------------------------------------------------ + + // ----- In- and output file names ------------------------------------ + + // --- Load the geometry setup ---- + // This is currently only required by the TRD (parameters) + cbm::mcbm::ToForceLibLoad dummy; /// Needed to trigger loading of the library as no fct dict in ROOT6 and CLING + TString geoSetupTag = ""; + try { + uint64_t runId = -1; + switch (setup) { + case Setup::mCBM2022: runId = 2391; break; + case Setup::mCBM2024: runId = 2918; break; + default: throw std::runtime_error("Unknown setup type"); + } + geoSetupTag = cbm::mcbm::GetSetupFromRunId(runId); + } + catch (const std::invalid_argument& e) { + std::cout << "Error in mapping from runID to setup name: " << e.what() << std::endl; + return; + } + + TString geoFile = fSrcDir + "/macro/mcbm/data/" + geoSetupTag + ".geo.root"; + fSetup = CbmSetup::Instance(); + fSetup->LoadSetup(geoSetupTag); + + //----- Load Parameters -------------------------------------------------- + fParList = new TList(); + + // ----- FairRunAna --------------------------------------------------- + fRun = new FairRunAna(); + + // Dummy source required for the FairRunAna as it will crash without a source + auto* inputSource = new CbmSourceDummy{}; + fRun->SetSource(inputSource); + + + // ----- Add detectors ------------------------------------------------ + AddDetectors(); + + // ----- Parameter database -------------------------------------------- + FairRuntimeDb* rtdb = fRun->GetRuntimeDb(); + FairParAsciiFileIo* parIo2 = new FairParAsciiFileIo(); + parIo2->setAutoWritable(false); + parIo2->open(fParList, "in"); + rtdb->setSecondInput(parIo2); + // ------------------------------------------------------------------------ + + // ----- Run initialisation ------------------------------------------- + fRun->SetGeomFile(geoFile); + fRun->Init(); + + // No need to run the event loop, parameters are written during the initialization + + + // ----- Clean up --------------------------------------------------------- + gGeoManager->GetListOfVolumes()->Delete(); + gGeoManager->GetListOfShapes()->Delete(); + delete gGeoManager; +} diff --git a/reco/steer/CbmOnlineParWrite.h b/reco/steer/CbmOnlineParWrite.h new file mode 100644 index 0000000000000000000000000000000000000000..66b7c144c47e2f8a815a74c43aa8ff82b8f65de5 --- /dev/null +++ b/reco/steer/CbmOnlineParWrite.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#pragma once + +/** + * @file CbmOnlineParWrite.h + * @brief This file contains the declaration of the CbmOnlineParWrite class. +**/ + +#include "Definitions.h" + +#include <TString.h> + +class FairRunAna; +class TList; +class CbmSetup; + +/** + * @class CbmOnlineParWrite + * @brief This class is responsible for writing the online parameters to configuration files. + * @note Currently covers TRD, TOF and STS setup. +**/ +class CbmOnlineParWrite { + + public: + void Run(cbm::algo::Setup setup); + + private: + cbm::algo::Setup fSetupType = cbm::algo::Setup::mCBM2022; // Setup + TString fSrcDir = ""; // CbmRoot Source directory + CbmSetup* fSetup = nullptr; // Global Geometry setup + FairRunAna* fRun = nullptr; // FairRunAna object + TList* fParList = nullptr; // List of parameter files, opened with FairRuntimeDb + + void AddDetectors(); + + void AddTrd(); + void AddTof(); + void AddSts(); +}; diff --git a/reco/steer/CbmSourceDummy.h b/reco/steer/CbmSourceDummy.h new file mode 100644 index 0000000000000000000000000000000000000000..5a84b5e2ea29dd4d5f31b7b13e76a65a952c1d62 --- /dev/null +++ b/reco/steer/CbmSourceDummy.h @@ -0,0 +1,63 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#pragma once + +#include <FairSource.h> + +/** + * @file CbmSourceDummy.h + * @brief Dummy input source +**/ + +/** + * @class CbmSourceDummy + * @brief Dummy input FAIR source. Doesn't create any branches or data. + * @note This is used to work around a bug in FairRunAna, which can trigger into a crash in + * TGeoManager if no input source is set. +**/ +class CbmSourceDummy : public FairSource { + + public: + CbmSourceDummy() = default; + + /** @brief Destructor **/ + virtual ~CbmSourceDummy() = default; + + + /** @brief Demanded by base class **/ + virtual void Close() {} + + + /** @brief Demanded by base class **/ + virtual Source_Type GetSourceType() { return kFILE; } + + + /** @brief Initialisation **/ + virtual Bool_t Init() { return true; } + + + /** @brief Demanded by base class **/ + virtual Bool_t InitUnpackers() { return kTRUE; } + + + /** @brief Demanded by base class **/ + virtual Int_t ReadEvent(UInt_t = 0) { return 0; } + + + /** @brief Demanded by base class **/ + virtual Bool_t ReInitUnpackers() { return kTRUE; } + + + /** @brief Demanded by base class **/ + virtual void Reset() {} + + + /** @brief Demanded by base class **/ + virtual void SetParUnpackers() {} + + + /** @brief Demanded by base class **/ + virtual Bool_t SpecifyRunId() { return kTRUE; } +}; diff --git a/reco/tasks/CMakeLists.txt b/reco/tasks/CMakeLists.txt index 523766f40f565af8370c048949f423599f904516..394be81dfde62c6c028f16cd86cd4332a95c058a 100644 --- a/reco/tasks/CMakeLists.txt +++ b/reco/tasks/CMakeLists.txt @@ -21,6 +21,7 @@ set(SRCS CbmTaskTofClusterizerParWrite.cxx CbmTaskTrdHitFinder.cxx CbmTaskTrdHitFinderParWrite.cxx + CbmTaskStsHitFinderParWrite.cxx CbmTaskUnpack.cxx ) @@ -34,7 +35,9 @@ set(LIBRARY_NAME CbmRecoTasks) set(LINKDEF ${LIBRARY_NAME}LinkDef.h) set(PUBLIC_DEPENDENCIES CbmData + CbmStsBase CbmTofBase + CbmRecoSts FairRoot::Base Algo ROOT::Core diff --git a/reco/tasks/CbmTaskStsHitFinderParWrite.cxx b/reco/tasks/CbmTaskStsHitFinderParWrite.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cb27cbcfc71f78dcaade2853d8b6b96c89483b7d --- /dev/null +++ b/reco/tasks/CbmTaskStsHitFinderParWrite.cxx @@ -0,0 +1,294 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#include "CbmTaskStsHitFinderParWrite.h" + +#include "CbmAddress.h" +#include "CbmStsModule.h" +#include "CbmStsParSetModule.h" +#include "CbmStsParSetSensor.h" +#include "CbmStsParSetSensorCond.h" +#include "CbmStsParSim.h" +#include "CbmStsPhysics.h" +#include "CbmStsRecoModule.h" +#include "CbmStsSetup.h" +#include "sts/HitfinderPars.h" +#include "yaml/Yaml.h" + +#include <FairField.h> +#include <FairRootManager.h> +#include <FairRun.h> +#include <FairRuntimeDb.h> + +#include <TGeoBBox.h> +#include <TGeoPhysicalNode.h> + +#include <iomanip> + +// ----- Constructor --------------------------------------------------- +CbmTaskStsHitFinderParWrite::CbmTaskStsHitFinderParWrite() : FairTask("CbmTaskStsHitFinderParWrite", 1) {} +// ------------------------------------------------------------------------- + + +// ----- Destructor ---------------------------------------------------- +CbmTaskStsHitFinderParWrite::~CbmTaskStsHitFinderParWrite() = default; +// ------------------------------------------------------------------------- + + +// ----- Initialise the cluster finding modules ------------------------ +UInt_t CbmTaskStsHitFinderParWrite::CreateModules() +{ + assert(fSetup); + + std::vector<cbm::algo::sts::HitfinderPars::Module> gpuModules; // for gpu reco + + LOG(info) << GetName() << ": Creating modules"; + LOG(info) << fParSetSensor->ToString(); + + for (Int_t iModule = 0; iModule < fSetup->GetNofModules(); iModule++) { + + // --- Setup module and sensor + CbmStsModule* setupModule = fSetup->GetModule(iModule); + assert(setupModule); + Int_t moduleAddress = Int_t(setupModule->GetAddress()); + assert(setupModule->GetNofDaughters() == 1); + CbmStsElement* setupSensor = setupModule->GetDaughter(0); + assert(setupSensor); + Int_t sensorAddress = Int_t(setupSensor->GetAddress()); + + // --- Module parameters + const CbmStsParModule& modPar = fParSetModule->GetParModule(moduleAddress); + const CbmStsParSensor& sensPar = fParSetSensor->GetParSensor(sensorAddress); + const CbmStsParSensorCond& sensCond = fParSetCond->GetParSensor(sensorAddress); + + // --- Calculate and set average Lorentz shift + // --- This will be used in hit finding for correcting the position. + Double_t lorentzF = 0.; + Double_t lorentzB = 0.; + if (fParSim->LorentzShift()) { + + TGeoBBox* shape = dynamic_cast<TGeoBBox*>(setupSensor->GetPnode()->GetShape()); + assert(shape); + Double_t dZ = 2. * shape->GetDZ(); // Sensor thickness + + // Get the magnetic field in the sensor centre + Double_t by = 0.; + if (FairRun::Instance()->GetField()) { + Double_t local[3] = {0., 0., 0.}; // sensor centre in local C.S. + Double_t global[3]; // sensor centre in global C.S. + setupSensor->GetPnode()->GetMatrix()->LocalToMaster(local, global); + Double_t field[3] = {0., 0., 0.}; // magnetic field components + FairRun::Instance()->GetField()->Field(global, field); + by = field[1] / 10.; // kG->T + } //? field present + + // Calculate average Lorentz shift on sensor sides. + // This is needed in hit finding for correcting the cluster position. + auto lorentzShift = LorentzShift(sensCond, dZ, by); + lorentzF = lorentzShift.first; + lorentzB = lorentzShift.second; + } //? Lorentz-shift correction + + // --- Create reco module + CbmStsRecoModule recoModule{setupModule, modPar, sensPar, lorentzF, lorentzB}; + + // Get Transformation Matrix + cbm::algo::sts::HitfinderPars::ModuleTransform localToGlobal; + TGeoHMatrix* matrix = recoModule.getMatrix(); + std::copy_n(matrix->GetRotationMatrix(), 9, localToGlobal.rotation.begin()); + std::copy_n(matrix->GetTranslation(), 3, localToGlobal.translation.begin()); + + // Collect GPU parameters + cbm::algo::sts::HitfinderPars::Module gpuModulePars{ + .address = moduleAddress, + .dY = sensPar.GetPar(3), + .pitch = sensPar.GetPar(6), + .stereoF = sensPar.GetPar(8), + .stereoB = sensPar.GetPar(9), + .lorentzF = float(lorentzF), + .lorentzB = float(lorentzB), + .localToGlobal = localToGlobal, + }; + gpuModules.emplace_back(gpuModulePars); + } + + const CbmStsParModule& firstModulePars = fParSetModule->GetParModule(gpuModules[0].address); + + CbmStsParAsic asic = firstModulePars.GetParAsic(0); + cbm::algo::sts::HitfinderPars::Asic algoAsic{ + .nAdc = asic.GetNofAdc(), + .dynamicRange = float(asic.GetDynRange()), + .threshold = float(asic.GetThreshold()), + .timeResolution = float(asic.GetTimeResol()), + .deadTime = float(asic.GetDeadTime()), + .noise = float(asic.GetNoise()), + .zeroNoiseRate = float(asic.GetZeroNoiseRate()), + }; + + int nChannels = firstModulePars.GetNofChannels(); + + auto [landauValues, landauStepSize] = CbmStsPhysics::Instance()->GetLandauWidthTable(); + std::vector<float> landauValuesF; + std::copy(landauValues.begin(), landauValues.end(), std::back_inserter(landauValuesF)); + cbm::algo::sts::HitfinderPars pars{ + .asic = algoAsic, + .nChannels = nChannels, + .modules = gpuModules, + .landauTable = + { + .values = landauValuesF, + .stepSize = float(landauStepSize), + }, + }; + + // Write to file + std::string filename = "StsHitfinder.yaml"; + std::ofstream{filename} << cbm::algo::yaml::Dump{}(pars, 4); + + return pars.modules.size(); +} +// ------------------------------------------------------------------------- + + +// ----- Initialisation ------------------------------------------------ +InitStatus CbmTaskStsHitFinderParWrite::Init() +{ + + // --- Something for the screen + LOG(info) << "=========================================================="; + LOG(info) << GetName() << ": Initialising "; + + // --- Check IO-Manager + FairRootManager* ioman = FairRootManager::Instance(); + assert(ioman); + + // --- Simulation settings + assert(fParSim); // Set from SetParContainers() + LOG(info) << GetName() << ": Sim settings " << fParSim->ToString(); + + // --- Parameters + InitParams(); + + // --- Initialise STS setup + fSetup = CbmStsSetup::Instance(); + fSetup->Init(nullptr); + //fSetup->SetSensorParameters(fParSetSensor); + + // --- Create reconstruction modules + UInt_t nModules = CreateModules(); + LOG(info) << GetName() << ": Created " << nModules << " modules"; + + LOG(info) << GetName() << ": Initialisation successful."; + LOG(info) << "=========================================================="; + + return kSUCCESS; +} +// ------------------------------------------------------------------------- + + +// ----- Parameter initialisation -------------------------------------- +void CbmTaskStsHitFinderParWrite::InitParams() +{ + + // --- Module parameters + TString sourceModu = "database"; + assert(fParSetModule); + if (fUserParSetModule) { + fParSetModule->clear(); + *fParSetModule = *fUserParSetModule; + fParSetModule->setChanged(); + fParSetModule->setInputVersion(-2, 1); + sourceModu = "user-defined"; + } + if (fUserParModule) { // global settings override + fParSetModule->clear(); + fParSetModule->SetGlobalPar(*fUserParModule); + fParSetModule->setChanged(); + fParSetModule->setInputVersion(-2, 1); + sourceModu = "user-defined, global"; + } + LOG(info) << GetName() << ": Module parameters (" << sourceModu << ") " << fParSetModule->ToString(); + + // --- Sensor parameters + TString sourceSens = "database"; + assert(fParSetSensor); + if (fUserParSetSensor) { + fParSetSensor->clear(); + *fParSetSensor = *fUserParSetSensor; + fParSetSensor->setChanged(); + fParSetSensor->setInputVersion(-2, 1); + sourceSens = "user-defined"; + } + if (fUserParSensor) { // global settings override + fParSetSensor->clear(); + fParSetSensor->SetGlobalPar(*fUserParSensor); + fParSetSensor->setChanged(); + fParSetSensor->setInputVersion(-2, 1); + sourceSens = "user-defined, global"; + } + LOG(info) << GetName() << ": Sensor parameters (" << sourceSens << ")" << fParSetSensor->ToString(); + + // --- Sensor conditions + TString sourceCond = "database"; + assert(fParSetCond); + if (fUserParSetCond) { + fParSetCond->clear(); + *fParSetCond = *fUserParSetCond; + fParSetCond->setChanged(); + fParSetCond->setInputVersion(-2, 1); + sourceSens = "user-defined"; + } + if (fUserParCond) { // global settings override + fParSetCond->clear(); + fParSetCond->SetGlobalPar(*fUserParCond); + fParSetCond->setChanged(); + fParSetCond->setInputVersion(-2, 1); + sourceCond = "user-defined, global"; + } + LOG(info) << GetName() << ": Sensor conditions (" << sourceCond << ")" << fParSetCond->ToString(); +} +// ------------------------------------------------------------------------- + +// ----- Calculate the mean Lorentz shift in a sensor ------------------ +std::pair<Double_t, Double_t> CbmTaskStsHitFinderParWrite::LorentzShift(const CbmStsParSensorCond& conditions, + Double_t dZ, Double_t bY) +{ + + Double_t vBias = conditions.GetVbias(); // Bias voltage + Double_t vFd = conditions.GetVfd(); // Full-depletion voltage + Double_t eField = (vBias + vFd) / dZ; // Electric field + + // --- Integrate in 1000 steps over the sensor thickness + Int_t nSteps = 1000; + Double_t deltaZ = dZ / nSteps; + Double_t dxMeanE = 0.; + Double_t dxMeanH = 0.; + for (Int_t j = 0; j <= nSteps; j++) { + eField -= 2 * vFd / dZ * deltaZ / dZ; // Electric field [V/cm] + Double_t muHallE = conditions.GetHallMobility(eField, 0); + Double_t muHallH = conditions.GetHallMobility(eField, 1); + dxMeanE += muHallE * (dZ - Double_t(j) * deltaZ); + dxMeanH += muHallH * Double_t(j) * deltaZ; + } + dxMeanE /= Double_t(nSteps); + dxMeanH /= Double_t(nSteps); + Double_t shiftF = dxMeanE * bY * 1.e-4; + Double_t shiftB = dxMeanH * bY * 1.e-4; + // The factor 1.e-4 is because bZ is in T = Vs/m**2, but muHall is in + // cm**2/(Vs) and z in cm. + + return {shiftF, shiftB}; +} +// ------------------------------------------------------------------------- + +// ----- Connect parameter container ----------------------------------- +void CbmTaskStsHitFinderParWrite::SetParContainers() +{ + FairRuntimeDb* db = FairRun::Instance()->GetRuntimeDb(); + fParSim = dynamic_cast<CbmStsParSim*>(db->getContainer("CbmStsParSim")); + fParSetModule = dynamic_cast<CbmStsParSetModule*>(db->getContainer("CbmStsParSetModule")); + fParSetSensor = dynamic_cast<CbmStsParSetSensor*>(db->getContainer("CbmStsParSetSensor")); + fParSetCond = dynamic_cast<CbmStsParSetSensorCond*>(db->getContainer("CbmStsParSetSensorCond")); +} +// ------------------------------------------------------------------------- diff --git a/reco/tasks/CbmTaskStsHitFinderParWrite.h b/reco/tasks/CbmTaskStsHitFinderParWrite.h new file mode 100644 index 0000000000000000000000000000000000000000..f64a6501f7d3b1f56bae06ede11438c6f07d8f3b --- /dev/null +++ b/reco/tasks/CbmTaskStsHitFinderParWrite.h @@ -0,0 +1,148 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ +#pragma once + +#include <FairTask.h> + +class CbmStsElement; +class CbmStsParAsic; +class CbmStsParModule; +class CbmStsParSensor; +class CbmStsParSensorCond; +class CbmStsParSetModule; +class CbmStsParSetSensor; +class CbmStsParSetSensorCond; +class CbmStsParSim; +class CbmStsSensor; +class CbmStsSetup; + +class CbmTaskStsHitFinderParWrite : public FairTask { + + public: + /** @brief Constructor **/ + CbmTaskStsHitFinderParWrite(); + + /** @brief Copy constructor (disabled) **/ + CbmTaskStsHitFinderParWrite(const CbmTaskStsHitFinderParWrite&) = delete; + + /** @brief Assignment operator (disabled) **/ + CbmTaskStsHitFinderParWrite operator=(const CbmTaskStsHitFinderParWrite&) = delete; + + /** @brief Destructor **/ + virtual ~CbmTaskStsHitFinderParWrite(); + + /** @brief Initialisation **/ + virtual InitStatus Init(); + + /** @brief Task execution **/ + virtual void Exec(Option_t*) {} + + /** @brief End-of-run action **/ + virtual void Finish() {} + + /** @brief Define the needed parameter containers **/ + virtual void SetParContainers(); + + + /** @brief User-defined module parameters + ** @param parModule Module parameter object + ** + ** If defined, these parameters will be used for all modules instead + ** of those found in the runtimeDb. + */ + void UseModulePar(CbmStsParModule* modulePar) { fUserParModule = modulePar; } + + + /** @brief User-defined module parameter set + ** @param parModule Module parameter set object + ** + ** If defined, this parameter set will be used instead of that found in the runtimeDb. + */ + void UseModuleParSet(CbmStsParSetModule* moduleParSet) { fUserParSetModule = moduleParSet; } + + + /** @brief User-defined sensor condition parameters + ** @param parModule Sensor condition parameter object + ** + ** If defined, these condition parameters will be used for all sensors instead + ** of those found in the runtimeDb. + */ + void UseSensorCond(CbmStsParSensorCond* sensorCond) { fUserParCond = sensorCond; } + + /** @brief User-defined module parameter set + ** @param parModule Module parameter set object + ** + ** If defined, this parameter set will be used instead of that found in the runtimeDb. + */ + void UseSensorCondSet(CbmStsParSetSensorCond* sensorCondSet) { fUserParSetCond = sensorCondSet; } + + + /** @brief User-defined sensor parameters + ** @param parModule Sensor parameter object + ** + ** If defined, these parameters will be used for all sensors instead + ** of those found in the runtimeDb. + */ + void UseSensorPar(CbmStsParSensor* sensorPar) { fUserParSensor = sensorPar; } + + + /** @brief User-defined module parameter set + ** @param parModule Module parameter set object + ** + ** If defined, this parameter set will be used instead of that found in the runtimeDb. + */ + void UseSensorParSet(CbmStsParSetSensor* sensorParSet) { fUserParSetSensor = sensorParSet; } + + private: + /** @brief Average Lorentz Shift in a sensor + ** @param conditions Sensor operating conditions + ** @param dZ Sensor thickness [cm] + ** @param bY y component of magnetic field in sensor centre + ** @return Mean Lorentz shift front side and back side [cm] + ** + ** The Lorentz shift will be corrected for in hit finding. + **/ + std::pair<Double_t, Double_t> LorentzShift(const CbmStsParSensorCond& conditions, Double_t dZ, Double_t bY); + + + /** @brief Instantiate reconstruction modules + ** @value Number of modules created + **/ + UInt_t CreateModules(); + + + /** @brief Get the sensor parameters + ** @param geoSensor Pointer to setup sensor + **/ + void GetSensorParameters(CbmStsElement* geoSensor); + + + /** @brief Initialise parameters + ** + ** For simulated data, the parameters for modules and sensors are retrieved from the + ** runtimeDb. They can be overridden by user-specified parameter sets using the respective + ** setters. This is necessary when processing experiment data without a prior simulation step. + ** + **/ + void InitParams(); + + private: + // --- Setup and parameters + CbmStsSetup* fSetup = nullptr; //! Instance of STS setup + CbmStsParSim* fParSim = nullptr; ///< Simulation settings + CbmStsParSetModule* fParSetModule = nullptr; ///< Module parameters + CbmStsParSetSensor* fParSetSensor = nullptr; ///< Sensor parameters + CbmStsParSetSensorCond* fParSetCond = nullptr; ///< Sensor conditions + + // --- User-defined parameters, not from database + CbmStsParAsic* fUserParAsic = nullptr; + CbmStsParModule* fUserParModule = nullptr; + CbmStsParSensor* fUserParSensor = nullptr; + CbmStsParSensorCond* fUserParCond = nullptr; + + // --- User-defined parameter sets, not from database + CbmStsParSetModule* fUserParSetModule = nullptr; + CbmStsParSetSensor* fUserParSetSensor = nullptr; + CbmStsParSetSensorCond* fUserParSetCond = nullptr; +}; diff --git a/reco/tasks/CbmTaskTrdHitFinderParWrite.cxx b/reco/tasks/CbmTaskTrdHitFinderParWrite.cxx index 901d53871e030d7c9afbf784fbda53ece1987d93..75ba2be3de7f32c2faf5f68e81266dc55288328f 100644 --- a/reco/tasks/CbmTaskTrdHitFinderParWrite.cxx +++ b/reco/tasks/CbmTaskTrdHitFinderParWrite.cxx @@ -40,7 +40,7 @@ CbmTaskTrdHitFinderParWrite::CbmTaskTrdHitFinderParWrite() : FairTask("TrdCluste //_____________________________________________________________________ void CbmTaskTrdHitFinderParWrite::SetParContainers() { - FairRuntimeDb* rtdb = FairRunAna::Instance()->GetRuntimeDb(); + FairRuntimeDb* rtdb = FairRun::Instance()->GetRuntimeDb(); fAsicPar = static_cast<CbmTrdParSetAsic*>(rtdb->getContainer("CbmTrdParSetAsic")); fDigiPar = static_cast<CbmTrdParSetDigi*>(rtdb->getContainer("CbmTrdParSetDigi")); fGeoPar = static_cast<CbmTrdParSetGeo*>(rtdb->getContainer("CbmTrdParSetGeo")); diff --git a/services/CMakeLists.txt b/services/CMakeLists.txt index 7ccb2f7d10b3277be2bc8456ac2216ec2d16c636..824b7748ebeec61dfcd62fa16b14233f54f2b115 100644 --- a/services/CMakeLists.txt +++ b/services/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(archive_explorer) add_subdirectory(histserv) +add_subdirectory(online_par_dump) diff --git a/services/online_par_dump/Application.cxx b/services/online_par_dump/Application.cxx new file mode 100644 index 0000000000000000000000000000000000000000..17116d0ccb4b276302945c371a3bcfb0a28ca482 --- /dev/null +++ b/services/online_par_dump/Application.cxx @@ -0,0 +1,34 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#include "Application.h" + +#include "CbmOnlineParWrite.h" + +#include <FairLogger.h> + +#include <TString.h> +#include <TSystem.h> + +void Application::Run() +{ + // --- Logger settings ---------------------------------------------------- + TString logLevel = "INFO"; + TString logVerbosity = "LOW"; + // ------------------------------------------------------------------------ + + // ----- Logger settings ---------------------------------------------- + FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data()); + FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data()); + + LOG(info) << "Starting online parameter dump for setup " << fOpts.setup << "..."; + + gSystem->mkdir(fOpts.outputDir.c_str(), kTRUE); + gSystem->cd(fOpts.outputDir.c_str()); + + CbmOnlineParWrite writer; + writer.Run(fOpts.setup); + + LOG(info) << "Online parameter dump finished"; +} diff --git a/services/online_par_dump/Application.h b/services/online_par_dump/Application.h new file mode 100644 index 0000000000000000000000000000000000000000..79cf571acccfc19512f2fce16accf965eb6ee449 --- /dev/null +++ b/services/online_par_dump/Application.h @@ -0,0 +1,18 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#pragma once + +#include "ProgramOptions.h" + +class Application { + + public: + Application(ProgramOptions opts) : fOpts(opts) {} + + void Run(); + + private: + ProgramOptions fOpts; +}; diff --git a/services/online_par_dump/CMakeLists.txt b/services/online_par_dump/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f24f315bb9439758433d4770a154cd5ccf789596 --- /dev/null +++ b/services/online_par_dump/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2024 Johann Wolfgang Goethe-Universitaet Frankfurt, Frankfurt am Main +# SPDX-License-Identifier: GPL-3.0-only +# Authors: Felix Weiglhofer [committer] + +set(APP cbm-online-par-dump) + +set(SRCS + Application.cxx + ProgramOptions.cxx + main.cxx + ) + +set(HEADERS + Application.h + ProgramOptions.h + ) + +add_executable(${APP} ${SRCS} ${HEADERS}) +target_link_libraries(${APP} + PRIVATE + CbmRecoTasks + CbmRecoSteer + CbmBase + Boost::program_options + external::fles_monitoring + external::fles_logging + ) + +install(TARGETS ${APP} DESTINATION bin) diff --git a/services/online_par_dump/ProgramOptions.cxx b/services/online_par_dump/ProgramOptions.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dd0c22fcdaee42fe9531bdfa50bf661647984ccb --- /dev/null +++ b/services/online_par_dump/ProgramOptions.cxx @@ -0,0 +1,54 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#include "ProgramOptions.h" + +#include <boost/program_options.hpp> + +#include <iostream> + +namespace po = boost::program_options; + +ProgramOptions::ProgramOptions(int argc, char** argv) +{ + po::options_description required("Required options"); + // clang-format off + required.add_options() + ("setup,s", po::value(&setup)->value_name("<setup>")->required(), + "Setup: mCBM2022, mCBM2024") + ("outdir,o", po::value(&outputDir)->value_name("<outputDir>")->required(), + "Output directory for the parameter files") + ; + // clang-format on + + po::options_description cmdline_options; + cmdline_options.add(required); + + po::variables_map vm; + po::command_line_parser parser{argc, argv}; + parser.options(cmdline_options); + try { + auto result = parser.run(); + po::store(result, vm); + } + catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + std::cerr << "Use '-h' to display all valid options." << std::endl; + std::exit(EXIT_FAILURE); + } + + if (vm.count("help") > 0) { + std::cout << cmdline_options << std::endl; + std::exit(EXIT_SUCCESS); + } + + try { + po::notify(vm); + } + catch (const po::required_option& e) { + std::cerr << "Error: " << e.what() << std::endl; + std::cerr << "Use '-h' to display all valid options." << std::endl; + std::exit(EXIT_FAILURE); + } +} diff --git a/services/online_par_dump/ProgramOptions.h b/services/online_par_dump/ProgramOptions.h new file mode 100644 index 0000000000000000000000000000000000000000..9dab8b7ca5a5ac2e5d66f95868bd3ffbf72f0d14 --- /dev/null +++ b/services/online_par_dump/ProgramOptions.h @@ -0,0 +1,16 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#pragma once + +#include "Definitions.h" + +#include <string> + +struct ProgramOptions { + ProgramOptions(int argc, char** argv); + + cbm::algo::Setup setup; + std::string outputDir; +}; diff --git a/services/online_par_dump/main.cxx b/services/online_par_dump/main.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ee9a4e9dce7146c84615de902ea786551fbb876b --- /dev/null +++ b/services/online_par_dump/main.cxx @@ -0,0 +1,13 @@ +/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main + SPDX-License-Identifier: GPL-3.0-only + Authors: Felix Weiglhofer [committer] */ + +#include "Application.h" + +int main(int argc, char** argv) +{ + ProgramOptions opts{argc, argv}; + Application app{opts}; + app.Run(); + return 0; +}